History

usb: renesas_usbhs: add a workaround for a race condition of workqueue

The old commit 6e4b74e4690d ("usb: renesas: fix scheduling in atomic context bug") fixed an atomic issue by using workqueue for the shdmac dmaengine driver. However, this has a potential race condition issue between the work pending and usbhsg_ep_free_request() in gadget mode. When usbhsg_ep_free_request() is called while pending the queue, since the work_struct will be freed and then the work handler is called, kernel panic happens on process_one_work(). To fix the issue, if we could call cancel_work_sync() at somewhere before the free request, it could be easy. However, the usbhsg_ep_free_request() is called on atomic (e.g. f_ncm driver calls free request via gether_disconnect()). For now, almost all users are having "USB-DMAC" and the DMAengine driver can be used on atomic. So, this patch adds a workaround for a race condition to call the DMAengine APIs without the workqueue. This means we still have TODO on shdmac environment (SH7724), but since it doesn't have SMP, the race condition might not happen.

Yoshihiro Shimoda committed 7 years ago

Commit b2357831 parent 4aef7961 file · +22 −12Browse files

Unified · Split

drivers/usb/renesas_usbhs/fifo.c+22−12
@@ -803,9 +803,8 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) · 802 unmodified lines
803}803}
804 804
805static void usbhsf_dma_complete(void *arg);805static void usbhsf_dma_complete(void *arg);
806static void xfer_work(struct work_struct *work)806static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
807{807{
808 struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
809 struct usbhs_pipe *pipe = pkt->pipe;808 struct usbhs_pipe *pipe = pkt->pipe;
810 struct usbhs_fifo *fifo;809 struct usbhs_fifo *fifo;
811 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);810 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -813,12 +812,10 @@ static void xfer_work(struct work_struct *work) · 1 unmodified line
813 struct dma_chan *chan;812 struct dma_chan *chan;
814 struct device *dev = usbhs_priv_to_dev(priv);813 struct device *dev = usbhs_priv_to_dev(priv);
815 enum dma_transfer_direction dir;814 enum dma_transfer_direction dir;
816 unsigned long flags;
817 815
818 usbhs_lock(priv, flags);
819 fifo = usbhs_pipe_to_fifo(pipe);816 fifo = usbhs_pipe_to_fifo(pipe);
820 if (!fifo)817 if (!fifo)
821 goto xfer_work_end;818 return;
822 819
823 chan = usbhsf_dma_chan_get(fifo, pkt);820 chan = usbhsf_dma_chan_get(fifo, pkt);
824 dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;821 dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
@@ -827,7 +824,7 @@ static void xfer_work(struct work_struct *work) · 2 unmodified lines
827 pkt->trans, dir,824 pkt->trans, dir,
828 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);825 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
829 if (!desc)826 if (!desc)
830 goto xfer_work_end;827 return;
831 828
832 desc->callback = usbhsf_dma_complete;829 desc->callback = usbhsf_dma_complete;
833 desc->callback_param = pipe;830 desc->callback_param = pipe;
@@ -835,7 +832,7 @@ static void xfer_work(struct work_struct *work) · 1 unmodified line
835 pkt->cookie = dmaengine_submit(desc);832 pkt->cookie = dmaengine_submit(desc);
836 if (pkt->cookie < 0) {833 if (pkt->cookie < 0) {
837 dev_err(dev, "Failed to submit dma descriptor\n");834 dev_err(dev, "Failed to submit dma descriptor\n");
838 goto xfer_work_end;835 return;
839 }836 }
840 837
841 dev_dbg(dev, " %s %d (%d/ %d)\n",838 dev_dbg(dev, " %s %d (%d/ %d)\n",
@@ -846,8 +843,17 @@ static void xfer_work(struct work_struct *work) · 4 unmodified lines
846 dma_async_issue_pending(chan);843 dma_async_issue_pending(chan);
847 usbhsf_dma_start(pipe, fifo);844 usbhsf_dma_start(pipe, fifo);
848 usbhs_pipe_enable(pipe);845 usbhs_pipe_enable(pipe);
846}
847
848static void xfer_work(struct work_struct *work)
849{
850 struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
851 struct usbhs_pipe *pipe = pkt->pipe;
852 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
853 unsigned long flags;
849 854
850xfer_work_end:855 usbhs_lock(priv, flags);
856 usbhsf_dma_xfer_preparing(pkt);
851 usbhs_unlock(priv, flags);857 usbhs_unlock(priv, flags);
852}858}
853 859
@@ -900,8 +906,13 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) · 46 unmodified lines
900 pkt->trans = len;906 pkt->trans = len;
901 907
902 usbhsf_tx_irq_ctrl(pipe, 0);908 usbhsf_tx_irq_ctrl(pipe, 0);
903 INIT_WORK(&pkt->work, xfer_work);909 /* FIXME: Workaound for usb dmac that driver can be used in atomic */
904 schedule_work(&pkt->work);910 if (usbhs_get_dparam(priv, has_usb_dmac)) {
911 usbhsf_dma_xfer_preparing(pkt);
912 } else {
913 INIT_WORK(&pkt->work, xfer_work);
914 schedule_work(&pkt->work);
915 }
905 916
906 return 0;917 return 0;
907 918
@@ -1007,8 +1018,7 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, · 99 unmodified lines
1007 1018
1008 pkt->trans = pkt->length;1019 pkt->trans = pkt->length;
1009 1020
1010 INIT_WORK(&pkt->work, xfer_work);1021 usbhsf_dma_xfer_preparing(pkt);
1011 schedule_work(&pkt->work);
1012 1022
1013 return 0;1023 return 0;
1014 1024

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t