aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>2014-08-22 07:13:50 -0400
committerFelipe Balbi <balbi@ti.com>2014-09-03 10:15:57 -0400
commit8355b2b3082d302091506703d2e4e239f7deed7f (patch)
tree7d883ae6ca66cb0778b45692bd00bf1342cb20fd /drivers/usb
parentf0798d6a04867ad8db8b41ddea45627d2c8cffe3 (diff)
usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle
Some gadget drivers will call usb_ep_queue() more than once before the first queue doesn't finish. However, this driver didn't handle it correctly. So, this patch fixes the behavior of some usbhs_pkt_handle using the "running" flag. Otherwise, the oops below happens if we use g_ncm driver and when the "iperf -u -c host -b 200M" is running. Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 [00000000] *pgd=00000000 Internal error: Oops: 80000007 [#1] SMP ARM Modules linked in: usb_f_ncm g_ncm libcomposite u_ether CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.17.0-rc1-00008-g8b2be8a-dirty #20 task: c051c7e0 ti: c0512000 task.ti: c0512000 PC is at 0x0 LR is at usbhsf_pkt_handler+0xa8/0x114 pc : [<00000000>] lr : [<c0278fb4>] psr: 60000193 sp : c0513ce8 ip : c0513c58 fp : c0513d24 r10: 00000001 r9 : 00000193 r8 : eebec4a0 r7 : eebec410 r6 : eebe0c6c r5 : 00000000 r4 : ee4a2774 r3 : 00000000 r2 : ee251e00 r1 : c0513cf4 r0 : ee4a2774 Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c25
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c13
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h4
3 files changed, 41 insertions, 1 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 4fd36530bfa3..3efece3c72a3 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -544,6 +544,7 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
544 usbhsf_send_terminator(pipe, fifo); 544 usbhsf_send_terminator(pipe, fifo);
545 545
546 usbhsf_tx_irq_ctrl(pipe, !*is_done); 546 usbhsf_tx_irq_ctrl(pipe, !*is_done);
547 usbhs_pipe_running(pipe, !*is_done);
547 usbhs_pipe_enable(pipe); 548 usbhs_pipe_enable(pipe);
548 549
549 dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", 550 dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n",
@@ -570,12 +571,21 @@ usbhs_fifo_write_busy:
570 * retry in interrupt 571 * retry in interrupt
571 */ 572 */
572 usbhsf_tx_irq_ctrl(pipe, 1); 573 usbhsf_tx_irq_ctrl(pipe, 1);
574 usbhs_pipe_running(pipe, 1);
573 575
574 return ret; 576 return ret;
575} 577}
576 578
579static int usbhsf_pio_prepare_push(struct usbhs_pkt *pkt, int *is_done)
580{
581 if (usbhs_pipe_is_running(pkt->pipe))
582 return 0;
583
584 return usbhsf_pio_try_push(pkt, is_done);
585}
586
577struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { 587struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
578 .prepare = usbhsf_pio_try_push, 588 .prepare = usbhsf_pio_prepare_push,
579 .try_run = usbhsf_pio_try_push, 589 .try_run = usbhsf_pio_try_push,
580}; 590};
581 591
@@ -589,6 +599,9 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
589 if (usbhs_pipe_is_busy(pipe)) 599 if (usbhs_pipe_is_busy(pipe))
590 return 0; 600 return 0;
591 601
602 if (usbhs_pipe_is_running(pipe))
603 return 0;
604
592 /* 605 /*
593 * pipe enable to prepare packet receive 606 * pipe enable to prepare packet receive
594 */ 607 */
@@ -597,6 +610,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
597 610
598 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); 611 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
599 usbhs_pipe_enable(pipe); 612 usbhs_pipe_enable(pipe);
613 usbhs_pipe_running(pipe, 1);
600 usbhsf_rx_irq_ctrl(pipe, 1); 614 usbhsf_rx_irq_ctrl(pipe, 1);
601 615
602 return 0; 616 return 0;
@@ -642,6 +656,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
642 (total_len < maxp)) { /* short packet */ 656 (total_len < maxp)) { /* short packet */
643 *is_done = 1; 657 *is_done = 1;
644 usbhsf_rx_irq_ctrl(pipe, 0); 658 usbhsf_rx_irq_ctrl(pipe, 0);
659 usbhs_pipe_running(pipe, 0);
645 usbhs_pipe_disable(pipe); /* disable pipe first */ 660 usbhs_pipe_disable(pipe); /* disable pipe first */
646 } 661 }
647 662
@@ -805,6 +820,7 @@ static void xfer_work(struct work_struct *work)
805 dev_dbg(dev, " %s %d (%d/ %d)\n", 820 dev_dbg(dev, " %s %d (%d/ %d)\n",
806 fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); 821 fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
807 822
823 usbhs_pipe_running(pipe, 1);
808 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); 824 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
809 usbhs_pipe_enable(pipe); 825 usbhs_pipe_enable(pipe);
810 usbhsf_dma_start(pipe, fifo); 826 usbhsf_dma_start(pipe, fifo);
@@ -836,6 +852,10 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
836 if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ 852 if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
837 goto usbhsf_pio_prepare_push; 853 goto usbhsf_pio_prepare_push;
838 854
855 /* return at this time if the pipe is running */
856 if (usbhs_pipe_is_running(pipe))
857 return 0;
858
839 /* get enable DMA fifo */ 859 /* get enable DMA fifo */
840 fifo = usbhsf_get_dma_fifo(priv, pkt); 860 fifo = usbhsf_get_dma_fifo(priv, pkt);
841 if (!fifo) 861 if (!fifo)
@@ -873,6 +893,7 @@ static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done)
873 pkt->actual = pkt->trans; 893 pkt->actual = pkt->trans;
874 894
875 *is_done = !pkt->zero; /* send zero packet ? */ 895 *is_done = !pkt->zero; /* send zero packet ? */
896 usbhs_pipe_running(pipe, !*is_done);
876 897
877 usbhsf_dma_stop(pipe, pipe->fifo); 898 usbhsf_dma_stop(pipe, pipe->fifo);
878 usbhsf_dma_unmap(pkt); 899 usbhsf_dma_unmap(pkt);
@@ -972,8 +993,10 @@ static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done)
972 if ((pkt->actual == pkt->length) || /* receive all data */ 993 if ((pkt->actual == pkt->length) || /* receive all data */
973 (pkt->trans < maxp)) { /* short packet */ 994 (pkt->trans < maxp)) { /* short packet */
974 *is_done = 1; 995 *is_done = 1;
996 usbhs_pipe_running(pipe, 0);
975 } else { 997 } else {
976 /* re-enable */ 998 /* re-enable */
999 usbhs_pipe_running(pipe, 0);
977 usbhsf_prepare_pop(pkt, is_done); 1000 usbhsf_prepare_pop(pkt, is_done);
978 } 1001 }
979 1002
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 75fbcf6b102e..040bcefcb040 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -578,6 +578,19 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
578 return usbhsp_flags_has(pipe, IS_DIR_HOST); 578 return usbhsp_flags_has(pipe, IS_DIR_HOST);
579} 579}
580 580
581int usbhs_pipe_is_running(struct usbhs_pipe *pipe)
582{
583 return usbhsp_flags_has(pipe, IS_RUNNING);
584}
585
586void usbhs_pipe_running(struct usbhs_pipe *pipe, int running)
587{
588 if (running)
589 usbhsp_flags_set(pipe, IS_RUNNING);
590 else
591 usbhsp_flags_clr(pipe, IS_RUNNING);
592}
593
581void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) 594void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
582{ 595{
583 u16 mask = (SQCLR | SQSET); 596 u16 mask = (SQCLR | SQSET);
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 406f36d050e4..d24a05972370 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -36,6 +36,7 @@ struct usbhs_pipe {
36#define USBHS_PIPE_FLAGS_IS_USED (1 << 0) 36#define USBHS_PIPE_FLAGS_IS_USED (1 << 0)
37#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1) 37#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1)
38#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2) 38#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2)
39#define USBHS_PIPE_FLAGS_IS_RUNNING (1 << 3)
39 40
40 struct usbhs_pkt_handle *handler; 41 struct usbhs_pkt_handle *handler;
41 42
@@ -80,6 +81,9 @@ int usbhs_pipe_probe(struct usbhs_priv *priv);
80void usbhs_pipe_remove(struct usbhs_priv *priv); 81void usbhs_pipe_remove(struct usbhs_priv *priv);
81int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); 82int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
82int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); 83int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe);
84int usbhs_pipe_is_running(struct usbhs_pipe *pipe);
85void usbhs_pipe_running(struct usbhs_pipe *pipe, int running);
86
83void usbhs_pipe_init(struct usbhs_priv *priv, 87void usbhs_pipe_init(struct usbhs_priv *priv,
84 int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); 88 int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
85int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); 89int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);