kernel: backport mtd support for subpartitions in DT
[oweals/openwrt.git] / target / linux / generic / pending-4.14 / 170-usb-dwc2-Fix-DMA-alignment-to-start-at-allocated-boun.patch
1 From 028c9191bdf88f120f65626920a6a679170fcc3e Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= <a.seppala@gmail.com>
3 Date: Thu, 5 Jul 2018 11:37:03 +0300
4 Subject: [PATCH 1/2] usb: dwc2: Fix DMA alignment to start at allocated
5  boundary
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 The commit 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more
11 supported way") introduced a common way to align DMA allocations.
12 The code in the commit aligns the struct dma_aligned_buffer but the
13 actual DMA address pointed by data[0] gets aligned to an offset from
14 the allocated boundary by the kmalloc_ptr and the old_xfer_buffer
15 pointers.
16
17 This is against the recommendation in Documentation/DMA-API.txt which
18 states:
19
20   Therefore, it is recommended that driver writers who don't take
21   special care to determine the cache line size at run time only map
22   virtual regions that begin and end on page boundaries (which are
23   guaranteed also to be cache line boundaries).
24
25 The effect of this is that architectures with non-coherent DMA caches
26 may run into memory corruption or kernel crashes with Unhandled
27 kernel unaligned accesses exceptions.
28
29 Fix the alignment by positioning the DMA area in front of the allocation
30 and use memory at the end of the area for storing the orginal
31 transfer_buffer pointer. This may have the added benefit of increased
32 performance as the DMA area is now fully aligned on all architectures.
33
34 Tested with Lantiq xRX200 (MIPS) and RPi Model B Rev 2 (ARM).
35
36 Fixes: 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more
37 supported way")
38
39 Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
40 ---
41  drivers/usb/dwc2/hcd.c | 44 +++++++++++++++++++++++---------------------
42  1 file changed, 23 insertions(+), 21 deletions(-)
43
44 --- a/drivers/usb/dwc2/hcd.c
45 +++ b/drivers/usb/dwc2/hcd.c
46 @@ -2628,34 +2628,29 @@ static void dwc2_hc_init_xfer(struct dwc
47  
48  #define DWC2_USB_DMA_ALIGN 4
49  
50 -struct dma_aligned_buffer {
51 -       void *kmalloc_ptr;
52 -       void *old_xfer_buffer;
53 -       u8 data[0];
54 -};
55 -
56  static void dwc2_free_dma_aligned_buffer(struct urb *urb)
57  {
58 -       struct dma_aligned_buffer *temp;
59 +       void *stored_xfer_buffer;
60  
61         if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
62                 return;
63  
64 -       temp = container_of(urb->transfer_buffer,
65 -                           struct dma_aligned_buffer, data);
66 +       /* Restore urb->transfer_buffer from the end of the allocated area */
67 +       memcpy(&stored_xfer_buffer, urb->transfer_buffer +
68 +              urb->transfer_buffer_length, sizeof(urb->transfer_buffer));
69  
70         if (usb_urb_dir_in(urb))
71 -               memcpy(temp->old_xfer_buffer, temp->data,
72 +               memcpy(stored_xfer_buffer, urb->transfer_buffer,
73                        urb->transfer_buffer_length);
74 -       urb->transfer_buffer = temp->old_xfer_buffer;
75 -       kfree(temp->kmalloc_ptr);
76 +       kfree(urb->transfer_buffer);
77 +       urb->transfer_buffer = stored_xfer_buffer;
78  
79         urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
80  }
81  
82  static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
83  {
84 -       struct dma_aligned_buffer *temp, *kmalloc_ptr;
85 +       void *kmalloc_ptr;
86         size_t kmalloc_size;
87  
88         if (urb->num_sgs || urb->sg ||
89 @@ -2663,22 +2658,29 @@ static int dwc2_alloc_dma_aligned_buffer
90             !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1)))
91                 return 0;
92  
93 -       /* Allocate a buffer with enough padding for alignment */
94 +       /*
95 +        * Allocate a buffer with enough padding for original transfer_buffer
96 +        * pointer. This allocation is guaranteed to be aligned properly for
97 +        * DMA
98 +        */
99         kmalloc_size = urb->transfer_buffer_length +
100 -               sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1;
101 +               sizeof(urb->transfer_buffer);
102  
103         kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
104         if (!kmalloc_ptr)
105                 return -ENOMEM;
106  
107 -       /* Position our struct dma_aligned_buffer such that data is aligned */
108 -       temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1;
109 -       temp->kmalloc_ptr = kmalloc_ptr;
110 -       temp->old_xfer_buffer = urb->transfer_buffer;
111 +       /*
112 +        * Position value of original urb->transfer_buffer pointer to the end
113 +        * of allocation for later referencing
114 +        */
115 +       memcpy(kmalloc_ptr + urb->transfer_buffer_length,
116 +              &urb->transfer_buffer, sizeof(urb->transfer_buffer));
117 +
118         if (usb_urb_dir_out(urb))
119 -               memcpy(temp->data, urb->transfer_buffer,
120 +               memcpy(kmalloc_ptr, urb->transfer_buffer,
121                        urb->transfer_buffer_length);
122 -       urb->transfer_buffer = temp->data;
123 +       urb->transfer_buffer = kmalloc_ptr;
124  
125         urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
126