8a28f730297cac9613cc4994b8049189e272f637
[oweals/openwrt.git] /
1 From 2a15e634d80f78cf2d8aa16ecf0f3cf930e277b4 Mon Sep 17 00:00:00 2001
2 From: Hui Wang <hui.wang@canonical.com>
3 Date: Sun, 17 Nov 2019 10:31:46 +0800
4 Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early
5  (#3332)
6
7 After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't
8 work well on Pi2/3 boards with 1G physical ram. Users experience
9 the failure when copying a file of 600M size to the USB stick. And
10 at the same time, the dmesg shows:
11 usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg
12 sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
13 blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0
14
15 When this happens, the sg_buf sent to the driver is located in the
16 highmem region, the usb_sg_init() in the core/message.c will leave
17 transfer_buffer to NULL if the sg_buf is in highmem, but in the
18 dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer
19 is NULL.
20
21 The driver can handle the situation of buffer to be NULL, if it is in
22 DMA mode, it will convert an address from transfer_dma.
23
24 But if the conversion fails or it is in the PIO mode, we should check
25 buffer and return -EINVAL if it is NULL.
26
27 BugLink: https://bugs.launchpad.net/bugs/1852510
28 Signed-off-by: Hui Wang <hui.wang@canonical.com>
29 ---
30  drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++----
31  1 file changed, 7 insertions(+), 4 deletions(-)
32
33 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
34 +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
35 @@ -821,10 +821,6 @@ static int dwc_otg_urb_enqueue(struct us
36                 dump_urb_info(urb, "dwc_otg_urb_enqueue");
37         }
38  #endif
39 -
40 -       if (!urb->transfer_buffer && urb->transfer_buffer_length)
41 -               return -EINVAL;
42 -
43         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
44             || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
45                 if (!dwc_otg_hcd_is_bandwidth_allocated
46 @@ -881,6 +877,13 @@ static int dwc_otg_urb_enqueue(struct us
47                               &urb->transfer_dma, buf);
48         }
49  
50 +       if (!buf && urb->transfer_buffer_length) {
51 +               DWC_FREE(dwc_otg_urb);
52 +               DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
53 +                          "transfer_buffer and transfer_dma are NULL in DMA mode\n");
54 +               return -EINVAL;
55 +       }
56 +
57         if (!(urb->transfer_flags & URB_NO_INTERRUPT))
58                 flags |= URB_GIVEBACK_ASAP;
59         if (urb->transfer_flags & URB_ZERO_PACKET)