123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- From 146eb94a08d12b5831e1d30455469750f7c5f2a3 Mon Sep 17 00:00:00 2001
- From: "minda.chen" <[email protected]>
- Date: Tue, 18 Oct 2022 09:57:39 +0800
- Subject: [PATCH 109/116] usb:xhci:To improve performance,usb using lowmem for
- bulk xfer.
- Generate an usb low memory pool for usb 3.0 host
- read/write transfer, default size is 8M.
- Signed-off-by: minda.chen <[email protected]>
- ---
- arch/riscv/boot/dts/starfive/jh7110-evb.dts | 1 +
- drivers/usb/core/hcd.c | 4 +-
- drivers/usb/host/xhci-mem.c | 64 +++++++++++++++++++++
- drivers/usb/host/xhci-plat.c | 8 +++
- drivers/usb/host/xhci-ring.c | 3 +-
- drivers/usb/host/xhci.c | 57 +++++++++++++++++-
- drivers/usb/host/xhci.h | 11 ++++
- 7 files changed, 145 insertions(+), 3 deletions(-)
- --- a/arch/riscv/boot/dts/starfive/jh7110-evb.dts
- +++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dts
- @@ -31,5 +31,6 @@
- };
-
- &usb0 {
- + xhci-lowmem-pool;
- status = "okay";
- };
- --- a/drivers/usb/core/hcd.c
- +++ b/drivers/usb/core/hcd.c
- @@ -1439,7 +1439,9 @@ int usb_hcd_map_urb_for_dma(struct usb_h
- if (ret == 0)
- urb->transfer_flags |= URB_MAP_LOCAL;
- } else if (hcd_uses_dma(hcd)) {
- - if (urb->num_sgs) {
- + if (urb->transfer_flags & URB_MAP_LOCAL)
- + return ret;
- + else if (urb->num_sgs) {
- int n;
-
- /* We don't support sg for isoc transfers ! */
- --- a/drivers/usb/host/xhci-mem.c
- +++ b/drivers/usb/host/xhci-mem.c
- @@ -14,6 +14,7 @@
- #include <linux/slab.h>
- #include <linux/dmapool.h>
- #include <linux/dma-mapping.h>
- +#include <linux/genalloc.h>
-
- #include "xhci.h"
- #include "xhci-trace.h"
- @@ -1842,6 +1843,7 @@ xhci_free_interrupter(struct xhci_hcd *x
- void xhci_mem_cleanup(struct xhci_hcd *xhci)
- {
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
- + struct xhci_lowmem_pool *pool;
- int i, j, num_ports;
-
- cancel_delayed_work_sync(&xhci->cmd_timer);
- @@ -1887,6 +1889,13 @@ void xhci_mem_cleanup(struct xhci_hcd *x
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Freed medium stream array pool");
-
- + if (xhci->lowmem_pool.pool) {
- + pool = &xhci->lowmem_pool;
- + dma_free_coherent(dev, pool->size, (void *)pool->cached_base, pool->dma_addr);
- + gen_pool_destroy(pool->pool);
- + pool->pool = NULL;
- + }
- +
- if (xhci->dcbaa)
- dma_free_coherent(dev, sizeof(*xhci->dcbaa),
- xhci->dcbaa, xhci->dcbaa->dma);
- @@ -2300,6 +2309,55 @@ xhci_add_interrupter(struct xhci_hcd *xh
- return 0;
- }
-
- +int xhci_setup_local_lowmem(struct xhci_hcd *xhci, size_t size)
- +{
- + int err;
- + void *buffer;
- + dma_addr_t dma_addr;
- + struct usb_hcd *hcd = xhci_to_hcd(xhci);
- + struct xhci_lowmem_pool *pool = &xhci->lowmem_pool;
- +
- + if (!pool->pool) {
- + /* minimal alloc one page */
- + pool->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(hcd->self.sysdev));
- + if (IS_ERR(pool->pool))
- + return PTR_ERR(pool->pool);
- + }
- +
- + buffer = dma_alloc_coherent(hcd->self.sysdev, size, &dma_addr,
- + GFP_KERNEL | GFP_DMA32);
- +
- + if (IS_ERR(buffer)) {
- + err = PTR_ERR(buffer);
- + goto destroy_pool;
- + }
- +
- + /*
- + * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
- + * It's not backed by system memory and thus there's no kernel mapping
- + * for it.
- + */
- + err = gen_pool_add_virt(pool->pool, (unsigned long)buffer,
- + dma_addr, size, dev_to_node(hcd->self.sysdev));
- + if (err < 0) {
- + dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
- + err);
- + dma_free_coherent(hcd->self.sysdev, size, buffer, dma_addr);
- + goto destroy_pool;
- + }
- +
- + pool->cached_base = (u64)buffer;
- + pool->dma_addr = dma_addr;
- +
- + return 0;
- +
- +destroy_pool:
- + gen_pool_destroy(pool->pool);
- + pool->pool = NULL;
- + return err;
- +}
- +EXPORT_SYMBOL_GPL(xhci_setup_local_lowmem);
- +
- int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
- {
- dma_addr_t dma;
- @@ -2436,6 +2494,12 @@ int xhci_mem_init(struct xhci_hcd *xhci,
-
- xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
-
- + if (xhci->quirks & XHCI_LOCAL_BUFFER) {
- + if (xhci_setup_local_lowmem(xhci,
- + xhci->lowmem_pool.size))
- + goto fail;
- + }
- +
- /*
- * XXX: Might need to set the Interrupter Moderation Register to
- * something other than the default (~1ms minimum between interrupts).
- --- a/drivers/usb/host/xhci-plat.c
- +++ b/drivers/usb/host/xhci-plat.c
- @@ -253,6 +253,14 @@ int xhci_plat_probe(struct platform_devi
- if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
- xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
-
- + if (device_property_read_bool(tmpdev, "xhci-lowmem-pool")) {
- + xhci->quirks |= XHCI_LOCAL_BUFFER;
- + if (device_property_read_u32(tmpdev, "lowmem-pool-size",
- + &xhci->lowmem_pool.size)) {
- + xhci->lowmem_pool.size = 8 << 20;
- + } else
- + xhci->lowmem_pool.size <<= 20;
- + }
- device_property_read_u32(tmpdev, "imod-interval-ns",
- &xhci->imod_interval);
- }
- --- a/drivers/usb/host/xhci-ring.c
- +++ b/drivers/usb/host/xhci-ring.c
- @@ -3707,7 +3707,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
-
- full_len = urb->transfer_buffer_length;
- /* If we have scatter/gather list, we use it. */
- - if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)) {
- + if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)
- + && !(urb->transfer_flags & URB_MAP_LOCAL)) {
- num_sgs = urb->num_mapped_sgs;
- sg = urb->sg;
- addr = (u64) sg_dma_address(sg);
- --- a/drivers/usb/host/xhci.c
- +++ b/drivers/usb/host/xhci.c
- @@ -19,6 +19,8 @@
- #include <linux/slab.h>
- #include <linux/dmi.h>
- #include <linux/dma-mapping.h>
- +#include <linux/dma-map-ops.h>
- +#include <linux/genalloc.h>
-
- #include "xhci.h"
- #include "xhci-trace.h"
- @@ -1286,6 +1288,55 @@ static void xhci_unmap_temp_buf(struct u
- urb->transfer_buffer = NULL;
- }
-
- +static void xhci_map_urb_local(struct usb_hcd *hcd, struct urb *urb,
- + gfp_t mem_flags)
- +{
- + void *buffer;
- + dma_addr_t dma_handle;
- + struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- + struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
- +
- + if (lowmem_pool->pool
- + && (usb_endpoint_type(&urb->ep->desc) == USB_ENDPOINT_XFER_BULK)
- + && (urb->transfer_buffer_length > PAGE_SIZE)
- + && urb->num_sgs && urb->sg && (sg_phys(urb->sg) > 0xffffffff)) {
- + buffer = gen_pool_dma_alloc(lowmem_pool->pool,
- + urb->transfer_buffer_length, &dma_handle);
- + if (buffer) {
- + urb->transfer_dma = dma_handle;
- + urb->transfer_buffer = buffer;
- + urb->transfer_flags |= URB_MAP_LOCAL;
- + if (usb_urb_dir_out(urb))
- + sg_copy_to_buffer(urb->sg, urb->num_sgs,
- + (void *)buffer,
- + urb->transfer_buffer_length);
- + }
- + }
- +
- +}
- +
- +static void xhci_unmap_urb_local(struct usb_hcd *hcd, struct urb *urb)
- +{
- + dma_addr_t dma_handle;
- + u64 cached_buffer;
- + struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- + struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
- +
- + if (urb->transfer_flags & URB_MAP_LOCAL) {
- + dma_handle = urb->transfer_dma;
- + cached_buffer = lowmem_pool->cached_base +
- + ((u32)urb->transfer_dma & (lowmem_pool->size - 1));
- + if (usb_urb_dir_in(urb))
- + sg_copy_from_buffer(urb->sg, urb->num_sgs,
- + (void *)cached_buffer, urb->transfer_buffer_length);
- + gen_pool_free(lowmem_pool->pool, (unsigned long)urb->transfer_buffer,
- + urb->transfer_buffer_length);
- + urb->transfer_flags &= ~URB_MAP_LOCAL;
- + urb->transfer_buffer = NULL;
- + }
- +}
- +
- +
- /*
- * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
- * we'll copy the actual data into the TRB address register. This is limited to
- @@ -1306,9 +1357,11 @@ static int xhci_map_urb_for_dma(struct u
- if (xhci_urb_temp_buffer_required(hcd, urb))
- return xhci_map_temp_buffer(hcd, urb);
- }
- + xhci_map_urb_local(hcd, urb, mem_flags);
- return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
- }
-
- +
- static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
- {
- struct xhci_hcd *xhci;
- @@ -1321,8 +1374,10 @@ static void xhci_unmap_urb_for_dma(struc
-
- if ((xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) && unmap_temp_buf)
- xhci_unmap_temp_buf(hcd, urb);
- - else
- + else {
- + xhci_unmap_urb_local(hcd, urb);
- usb_hcd_unmap_urb_for_dma(hcd, urb);
- + }
- }
-
- /**
- --- a/drivers/usb/host/xhci.h
- +++ b/drivers/usb/host/xhci.h
- @@ -1509,6 +1509,13 @@ struct xhci_hub {
- u8 min_rev;
- };
-
- +struct xhci_lowmem_pool {
- + struct gen_pool *pool;
- + u64 cached_base;
- + dma_addr_t dma_addr;
- + unsigned int size;
- +};
- +
- /* There is one xhci_hcd structure per controller */
- struct xhci_hcd {
- struct usb_hcd *main_hcd;
- @@ -1663,6 +1670,8 @@ struct xhci_hcd {
- #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
- #define XHCI_ETRON_HOST BIT_ULL(49)
-
- +#define XHCI_LOCAL_BUFFER BIT_ULL(63)
- +
- unsigned int num_active_eps;
- unsigned int limit_active_eps;
- struct xhci_port *hw_ports;
- @@ -1692,6 +1701,8 @@ struct xhci_hcd {
- struct list_head regset_list;
-
- void *dbc;
- + struct xhci_lowmem_pool lowmem_pool;
- +
- /* platform-specific data -- must come last */
- unsigned long priv[] __aligned(sizeof(s64));
- };
|