]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usb: renesas_usbhs: fix the timing of dcp_control_transfer_done
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Tue, 4 Nov 2014 01:05:44 +0000 (10:05 +0900)
committerFelipe Balbi <balbi@ti.com>
Wed, 5 Nov 2014 19:22:12 +0000 (13:22 -0600)
According to the datasheet, this driver should clear the INTSTS0.CTRT
bit before this controller detects the next stage transition. Otherwise,
the driver may not be able to clear the bit after the controller went to
the next stage transition. After that, the driver will not be able to
clear the INTSTS0.VALID, and a usb control transfer will not finish
finally.

If we use the testusb tool, it is easy to reproduce this issue:

 # testusb -a -t 10

Since the previous code handled a data stage and a status stage in
the usbhsf_pio_try_push(), it may not clear the INTSTS0.CTRT at the
right timing.
So, this patch change the timing of usbhs_dcp_control_transfer_done()
to the usbhsg_irq_ctrl_stage().

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod_gadget.c

index b0c97a3f1bfed74e262c3aa818817259f31e987e..0e079256e53386c299dafcff970075c51f5dfb9a 100644 (file)
@@ -577,14 +577,6 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
                usbhs_pipe_number(pipe),
                pkt->length, pkt->actual, *is_done, pkt->zero);
 
-       /*
-        * Transmission end
-        */
-       if (*is_done) {
-               if (usbhs_pipe_is_dcp(pipe))
-                       usbhs_dcp_control_transfer_done(pipe);
-       }
-
        usbhsf_fifo_unselect(pipe, fifo);
 
        return 0;
@@ -722,14 +714,6 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
                usbhs_pipe_number(pipe),
                pkt->length, pkt->actual, *is_done, pkt->zero);
 
-       /*
-        * Transmission end
-        */
-       if (*is_done) {
-               if (usbhs_pipe_is_dcp(pipe))
-                       usbhs_dcp_control_transfer_done(pipe);
-       }
-
 usbhs_fifo_read_busy:
        usbhsf_fifo_unselect(pipe, fifo);
 
index cb2d529e3a33a1fbba444d6fb40a101faf13db38..2457306e0924a62a89f645d25956b83a9650e254 100644 (file)
@@ -485,6 +485,9 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
        case NODATA_STATUS_STAGE:
                pipe->handler = &usbhs_ctrl_stage_end_handler;
                break;
+       case READ_STATUS_STAGE:
+       case WRITE_STATUS_STAGE:
+               usbhs_dcp_control_transfer_done(pipe);
        default:
                return ret;
        }