0109-usb-xhci-To-improve-performance-usb-using-lowmem-for.patch 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. From 146eb94a08d12b5831e1d30455469750f7c5f2a3 Mon Sep 17 00:00:00 2001
  2. From: "minda.chen" <[email protected]>
  3. Date: Tue, 18 Oct 2022 09:57:39 +0800
  4. Subject: [PATCH 109/116] usb:xhci:To improve performance,usb using lowmem for
  5. bulk xfer.
  6. Generate an usb low memory pool for usb 3.0 host
  7. read/write transfer, default size is 8M.
  8. Signed-off-by: minda.chen <[email protected]>
  9. ---
  10. arch/riscv/boot/dts/starfive/jh7110-evb.dts | 1 +
  11. drivers/usb/core/hcd.c | 4 +-
  12. drivers/usb/host/xhci-mem.c | 64 +++++++++++++++++++++
  13. drivers/usb/host/xhci-plat.c | 8 +++
  14. drivers/usb/host/xhci-ring.c | 3 +-
  15. drivers/usb/host/xhci.c | 57 +++++++++++++++++-
  16. drivers/usb/host/xhci.h | 11 ++++
  17. 7 files changed, 145 insertions(+), 3 deletions(-)
  18. --- a/arch/riscv/boot/dts/starfive/jh7110-evb.dts
  19. +++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dts
  20. @@ -31,5 +31,6 @@
  21. };
  22. &usb0 {
  23. + xhci-lowmem-pool;
  24. status = "okay";
  25. };
  26. --- a/drivers/usb/core/hcd.c
  27. +++ b/drivers/usb/core/hcd.c
  28. @@ -1439,7 +1439,9 @@ int usb_hcd_map_urb_for_dma(struct usb_h
  29. if (ret == 0)
  30. urb->transfer_flags |= URB_MAP_LOCAL;
  31. } else if (hcd_uses_dma(hcd)) {
  32. - if (urb->num_sgs) {
  33. + if (urb->transfer_flags & URB_MAP_LOCAL)
  34. + return ret;
  35. + else if (urb->num_sgs) {
  36. int n;
  37. /* We don't support sg for isoc transfers ! */
  38. --- a/drivers/usb/host/xhci-mem.c
  39. +++ b/drivers/usb/host/xhci-mem.c
  40. @@ -14,6 +14,7 @@
  41. #include <linux/slab.h>
  42. #include <linux/dmapool.h>
  43. #include <linux/dma-mapping.h>
  44. +#include <linux/genalloc.h>
  45. #include "xhci.h"
  46. #include "xhci-trace.h"
  47. @@ -1842,6 +1843,7 @@ xhci_free_interrupter(struct xhci_hcd *x
  48. void xhci_mem_cleanup(struct xhci_hcd *xhci)
  49. {
  50. struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
  51. + struct xhci_lowmem_pool *pool;
  52. int i, j, num_ports;
  53. cancel_delayed_work_sync(&xhci->cmd_timer);
  54. @@ -1887,6 +1889,13 @@ void xhci_mem_cleanup(struct xhci_hcd *x
  55. xhci_dbg_trace(xhci, trace_xhci_dbg_init,
  56. "Freed medium stream array pool");
  57. + if (xhci->lowmem_pool.pool) {
  58. + pool = &xhci->lowmem_pool;
  59. + dma_free_coherent(dev, pool->size, (void *)pool->cached_base, pool->dma_addr);
  60. + gen_pool_destroy(pool->pool);
  61. + pool->pool = NULL;
  62. + }
  63. +
  64. if (xhci->dcbaa)
  65. dma_free_coherent(dev, sizeof(*xhci->dcbaa),
  66. xhci->dcbaa, xhci->dcbaa->dma);
  67. @@ -2300,6 +2309,55 @@ xhci_add_interrupter(struct xhci_hcd *xh
  68. return 0;
  69. }
  70. +int xhci_setup_local_lowmem(struct xhci_hcd *xhci, size_t size)
  71. +{
  72. + int err;
  73. + void *buffer;
  74. + dma_addr_t dma_addr;
  75. + struct usb_hcd *hcd = xhci_to_hcd(xhci);
  76. + struct xhci_lowmem_pool *pool = &xhci->lowmem_pool;
  77. +
  78. + if (!pool->pool) {
  79. + /* minimal alloc one page */
  80. + pool->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(hcd->self.sysdev));
  81. + if (IS_ERR(pool->pool))
  82. + return PTR_ERR(pool->pool);
  83. + }
  84. +
  85. + buffer = dma_alloc_coherent(hcd->self.sysdev, size, &dma_addr,
  86. + GFP_KERNEL | GFP_DMA32);
  87. +
  88. + if (IS_ERR(buffer)) {
  89. + err = PTR_ERR(buffer);
  90. + goto destroy_pool;
  91. + }
  92. +
  93. + /*
  94. + * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
  95. + * It's not backed by system memory and thus there's no kernel mapping
  96. + * for it.
  97. + */
  98. + err = gen_pool_add_virt(pool->pool, (unsigned long)buffer,
  99. + dma_addr, size, dev_to_node(hcd->self.sysdev));
  100. + if (err < 0) {
  101. + dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
  102. + err);
  103. + dma_free_coherent(hcd->self.sysdev, size, buffer, dma_addr);
  104. + goto destroy_pool;
  105. + }
  106. +
  107. + pool->cached_base = (u64)buffer;
  108. + pool->dma_addr = dma_addr;
  109. +
  110. + return 0;
  111. +
  112. +destroy_pool:
  113. + gen_pool_destroy(pool->pool);
  114. + pool->pool = NULL;
  115. + return err;
  116. +}
  117. +EXPORT_SYMBOL_GPL(xhci_setup_local_lowmem);
  118. +
  119. int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
  120. {
  121. dma_addr_t dma;
  122. @@ -2436,6 +2494,12 @@ int xhci_mem_init(struct xhci_hcd *xhci,
  123. xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
  124. + if (xhci->quirks & XHCI_LOCAL_BUFFER) {
  125. + if (xhci_setup_local_lowmem(xhci,
  126. + xhci->lowmem_pool.size))
  127. + goto fail;
  128. + }
  129. +
  130. /*
  131. * XXX: Might need to set the Interrupter Moderation Register to
  132. * something other than the default (~1ms minimum between interrupts).
  133. --- a/drivers/usb/host/xhci-plat.c
  134. +++ b/drivers/usb/host/xhci-plat.c
  135. @@ -253,6 +253,14 @@ int xhci_plat_probe(struct platform_devi
  136. if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
  137. xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
  138. + if (device_property_read_bool(tmpdev, "xhci-lowmem-pool")) {
  139. + xhci->quirks |= XHCI_LOCAL_BUFFER;
  140. + if (device_property_read_u32(tmpdev, "lowmem-pool-size",
  141. + &xhci->lowmem_pool.size)) {
  142. + xhci->lowmem_pool.size = 8 << 20;
  143. + } else
  144. + xhci->lowmem_pool.size <<= 20;
  145. + }
  146. device_property_read_u32(tmpdev, "imod-interval-ns",
  147. &xhci->imod_interval);
  148. }
  149. --- a/drivers/usb/host/xhci-ring.c
  150. +++ b/drivers/usb/host/xhci-ring.c
  151. @@ -3707,7 +3707,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
  152. full_len = urb->transfer_buffer_length;
  153. /* If we have scatter/gather list, we use it. */
  154. - if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)) {
  155. + if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)
  156. + && !(urb->transfer_flags & URB_MAP_LOCAL)) {
  157. num_sgs = urb->num_mapped_sgs;
  158. sg = urb->sg;
  159. addr = (u64) sg_dma_address(sg);
  160. --- a/drivers/usb/host/xhci.c
  161. +++ b/drivers/usb/host/xhci.c
  162. @@ -19,6 +19,8 @@
  163. #include <linux/slab.h>
  164. #include <linux/dmi.h>
  165. #include <linux/dma-mapping.h>
  166. +#include <linux/dma-map-ops.h>
  167. +#include <linux/genalloc.h>
  168. #include "xhci.h"
  169. #include "xhci-trace.h"
  170. @@ -1286,6 +1288,55 @@ static void xhci_unmap_temp_buf(struct u
  171. urb->transfer_buffer = NULL;
  172. }
  173. +static void xhci_map_urb_local(struct usb_hcd *hcd, struct urb *urb,
  174. + gfp_t mem_flags)
  175. +{
  176. + void *buffer;
  177. + dma_addr_t dma_handle;
  178. + struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  179. + struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
  180. +
  181. + if (lowmem_pool->pool
  182. + && (usb_endpoint_type(&urb->ep->desc) == USB_ENDPOINT_XFER_BULK)
  183. + && (urb->transfer_buffer_length > PAGE_SIZE)
  184. + && urb->num_sgs && urb->sg && (sg_phys(urb->sg) > 0xffffffff)) {
  185. + buffer = gen_pool_dma_alloc(lowmem_pool->pool,
  186. + urb->transfer_buffer_length, &dma_handle);
  187. + if (buffer) {
  188. + urb->transfer_dma = dma_handle;
  189. + urb->transfer_buffer = buffer;
  190. + urb->transfer_flags |= URB_MAP_LOCAL;
  191. + if (usb_urb_dir_out(urb))
  192. + sg_copy_to_buffer(urb->sg, urb->num_sgs,
  193. + (void *)buffer,
  194. + urb->transfer_buffer_length);
  195. + }
  196. + }
  197. +
  198. +}
  199. +
  200. +static void xhci_unmap_urb_local(struct usb_hcd *hcd, struct urb *urb)
  201. +{
  202. + dma_addr_t dma_handle;
  203. + u64 cached_buffer;
  204. + struct xhci_hcd *xhci = hcd_to_xhci(hcd);
  205. + struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
  206. +
  207. + if (urb->transfer_flags & URB_MAP_LOCAL) {
  208. + dma_handle = urb->transfer_dma;
  209. + cached_buffer = lowmem_pool->cached_base +
  210. + ((u32)urb->transfer_dma & (lowmem_pool->size - 1));
  211. + if (usb_urb_dir_in(urb))
  212. + sg_copy_from_buffer(urb->sg, urb->num_sgs,
  213. + (void *)cached_buffer, urb->transfer_buffer_length);
  214. + gen_pool_free(lowmem_pool->pool, (unsigned long)urb->transfer_buffer,
  215. + urb->transfer_buffer_length);
  216. + urb->transfer_flags &= ~URB_MAP_LOCAL;
  217. + urb->transfer_buffer = NULL;
  218. + }
  219. +}
  220. +
  221. +
  222. /*
  223. * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
  224. * we'll copy the actual data into the TRB address register. This is limited to
  225. @@ -1306,9 +1357,11 @@ static int xhci_map_urb_for_dma(struct u
  226. if (xhci_urb_temp_buffer_required(hcd, urb))
  227. return xhci_map_temp_buffer(hcd, urb);
  228. }
  229. + xhci_map_urb_local(hcd, urb, mem_flags);
  230. return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
  231. }
  232. +
  233. static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
  234. {
  235. struct xhci_hcd *xhci;
  236. @@ -1321,8 +1374,10 @@ static void xhci_unmap_urb_for_dma(struc
  237. if ((xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) && unmap_temp_buf)
  238. xhci_unmap_temp_buf(hcd, urb);
  239. - else
  240. + else {
  241. + xhci_unmap_urb_local(hcd, urb);
  242. usb_hcd_unmap_urb_for_dma(hcd, urb);
  243. + }
  244. }
  245. /**
  246. --- a/drivers/usb/host/xhci.h
  247. +++ b/drivers/usb/host/xhci.h
  248. @@ -1509,6 +1509,13 @@ struct xhci_hub {
  249. u8 min_rev;
  250. };
  251. +struct xhci_lowmem_pool {
  252. + struct gen_pool *pool;
  253. + u64 cached_base;
  254. + dma_addr_t dma_addr;
  255. + unsigned int size;
  256. +};
  257. +
  258. /* There is one xhci_hcd structure per controller */
  259. struct xhci_hcd {
  260. struct usb_hcd *main_hcd;
  261. @@ -1663,6 +1670,8 @@ struct xhci_hcd {
  262. #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
  263. #define XHCI_ETRON_HOST BIT_ULL(49)
  264. +#define XHCI_LOCAL_BUFFER BIT_ULL(63)
  265. +
  266. unsigned int num_active_eps;
  267. unsigned int limit_active_eps;
  268. struct xhci_port *hw_ports;
  269. @@ -1692,6 +1701,8 @@ struct xhci_hcd {
  270. struct list_head regset_list;
  271. void *dbc;
  272. + struct xhci_lowmem_pool lowmem_pool;
  273. +
  274. /* platform-specific data -- must come last */
  275. unsigned long priv[] __aligned(sizeof(s64));
  276. };