Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: renesas_usbhs: getting residue from callback_result

This driver assumed that dmaengine_tx_status() could return
the residue even if the transfer was completed. However,
this was not correct usage [1] and this caused to break getting
the residue after the commit 24461d9792c2 ("dmaengine:
virt-dma: Fix access after free in vchan_complete()") actually.
So, this is possible to get wrong received size if the usb
controller gets a short packet. For example, g_zero driver
causes "bad OUT byte" errors.

The usb-dmac driver will support the callback_result, so this
driver can use it to get residue correctly. Note that even if
the usb-dmac driver has not supported the callback_result yet,
this patch doesn't cause any side-effects.

[1]
https://lore.kernel.org/dmaengine/20200616165550.GP2324254@vkoul-mobl/

Reported-by: Hien Dang <hien.dang.eb@renesas.com>
Fixes: 24461d9792c2 ("dmaengine: virt-dma: Fix access after free in vchan_complete()")
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Link: https://lore.kernel.org/r/1592482277-19563-1-git-send-email-yoshihiro.shimoda.uh@renesas.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Yoshihiro Shimoda and committed by
Greg Kroah-Hartman
ea0efd68 ad38beb3

+14 -11
+13 -10
drivers/usb/renesas_usbhs/fifo.c
··· 803 803 return info->dma_map_ctrl(chan->device->dev, pkt, map); 804 804 } 805 805 806 - static void usbhsf_dma_complete(void *arg); 806 + static void usbhsf_dma_complete(void *arg, 807 + const struct dmaengine_result *result); 807 808 static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt) 808 809 { 809 810 struct usbhs_pipe *pipe = pkt->pipe; ··· 814 813 struct dma_chan *chan; 815 814 struct device *dev = usbhs_priv_to_dev(priv); 816 815 enum dma_transfer_direction dir; 816 + dma_cookie_t cookie; 817 817 818 818 fifo = usbhs_pipe_to_fifo(pipe); 819 819 if (!fifo) ··· 829 827 if (!desc) 830 828 return; 831 829 832 - desc->callback = usbhsf_dma_complete; 833 - desc->callback_param = pipe; 830 + desc->callback_result = usbhsf_dma_complete; 831 + desc->callback_param = pkt; 834 832 835 - pkt->cookie = dmaengine_submit(desc); 836 - if (pkt->cookie < 0) { 833 + cookie = dmaengine_submit(desc); 834 + if (cookie < 0) { 837 835 dev_err(dev, "Failed to submit dma descriptor\n"); 838 836 return; 839 837 } ··· 1154 1152 struct dma_chan *chan, int dtln) 1155 1153 { 1156 1154 struct usbhs_pipe *pipe = pkt->pipe; 1157 - struct dma_tx_state state; 1158 1155 size_t received_size; 1159 1156 int maxp = usbhs_pipe_get_maxpacket(pipe); 1160 1157 1161 - dmaengine_tx_status(chan, pkt->cookie, &state); 1162 - received_size = pkt->length - state.residue; 1158 + received_size = pkt->length - pkt->dma_result->residue; 1163 1159 1164 1160 if (dtln) { 1165 1161 received_size -= USBHS_USB_DMAC_XFER_SIZE; ··· 1363 1363 return 0; 1364 1364 } 1365 1365 1366 - static void usbhsf_dma_complete(void *arg) 1366 + static void usbhsf_dma_complete(void *arg, 1367 + const struct dmaengine_result *result) 1367 1368 { 1368 - struct usbhs_pipe *pipe = arg; 1369 + struct usbhs_pkt *pkt = arg; 1370 + struct usbhs_pipe *pipe = pkt->pipe; 1369 1371 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 1370 1372 struct device *dev = usbhs_priv_to_dev(priv); 1371 1373 int ret; 1372 1374 1375 + pkt->dma_result = result; 1373 1376 ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_DMA_DONE); 1374 1377 if (ret < 0) 1375 1378 dev_err(dev, "dma_complete run_error %d : %d\n",
+1 -1
drivers/usb/renesas_usbhs/fifo.h
··· 50 50 struct usbhs_pkt *pkt); 51 51 struct work_struct work; 52 52 dma_addr_t dma; 53 - dma_cookie_t cookie; 53 + const struct dmaengine_result *dma_result; 54 54 void *buf; 55 55 int length; 56 56 int trans;