summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurentiu Tudor <laurentiu.tudor@nxp.com>2019-05-29 06:28:40 -0400
committerChristoph Hellwig <hch@lst.de>2019-06-03 10:00:07 -0400
commitb0310c2f09bbe8aebefb97ed67949a3a7092aca6 (patch)
treea0c1be9e4cf413c4bafcd77e95a84830e0f21dcd
parentda83a722959a82733c3ca60030cc364ca2318c5a (diff)
USB: use genalloc for USB HCs with local memory
For HCs that have local memory, replace the current DMA API usage with a genalloc generic allocator to manage the mappings for these devices. To help users, introduce a new HCD API, usb_hcd_setup_local_mem() that will setup up the genalloc backing up the device local memory. It will be used in subsequent patches. This is in preparation for dropping the existing "coherent" dma mem declaration APIs. The current implementation was relying on a short circuit in the DMA API that in the end, was acting as an allocator for these type of devices. Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> Tested-by: Fredrik Noring <noring@nocrew.org> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/core/buffer.c9
-rw-r--r--drivers/usb/core/hcd.c36
-rw-r--r--drivers/usb/host/ohci-hcd.c23
-rw-r--r--drivers/usb/host/ohci-mem.c35
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--include/linux/usb/hcd.h5
7 files changed, 102 insertions, 9 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index e4b27413f528..389c57d8eba7 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -45,6 +45,7 @@ config USB_ARCH_HAS_HCD
45config USB 45config USB
46 tristate "Support for Host-side USB" 46 tristate "Support for Host-side USB"
47 depends on USB_ARCH_HAS_HCD 47 depends on USB_ARCH_HAS_HCD
48 select GENERIC_ALLOCATOR
48 select USB_COMMON 49 select USB_COMMON
49 select NLS # for UTF-8 strings 50 select NLS # for UTF-8 strings
50 ---help--- 51 ---help---
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index f641342cdec0..d2064ad7ad14 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -16,6 +16,7 @@
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/dma-mapping.h> 17#include <linux/dma-mapping.h>
18#include <linux/dmapool.h> 18#include <linux/dmapool.h>
19#include <linux/genalloc.h>
19#include <linux/usb.h> 20#include <linux/usb.h>
20#include <linux/usb/hcd.h> 21#include <linux/usb/hcd.h>
21 22
@@ -124,6 +125,9 @@ void *hcd_buffer_alloc(
124 if (size == 0) 125 if (size == 0)
125 return NULL; 126 return NULL;
126 127
128 if (hcd->localmem_pool)
129 return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
130
127 /* some USB hosts just use PIO */ 131 /* some USB hosts just use PIO */
128 if (!IS_ENABLED(CONFIG_HAS_DMA) || 132 if (!IS_ENABLED(CONFIG_HAS_DMA) ||
129 (!is_device_dma_capable(bus->sysdev) && 133 (!is_device_dma_capable(bus->sysdev) &&
@@ -152,6 +156,11 @@ void hcd_buffer_free(
152 if (!addr) 156 if (!addr)
153 return; 157 return;
154 158
159 if (hcd->localmem_pool) {
160 gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
161 return;
162 }
163
155 if (!IS_ENABLED(CONFIG_HAS_DMA) || 164 if (!IS_ENABLED(CONFIG_HAS_DMA) ||
156 (!is_device_dma_capable(bus->sysdev) && 165 (!is_device_dma_capable(bus->sysdev) &&
157 !(hcd->driver->flags & HCD_LOCAL_MEM))) { 166 !(hcd->driver->flags & HCD_LOCAL_MEM))) {
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 94d22551fc1b..29b96e5e8621 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -29,6 +29,8 @@
29#include <linux/workqueue.h> 29#include <linux/workqueue.h>
30#include <linux/pm_runtime.h> 30#include <linux/pm_runtime.h>
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/genalloc.h>
33#include <linux/io.h>
32 34
33#include <linux/phy/phy.h> 35#include <linux/phy/phy.h>
34#include <linux/usb.h> 36#include <linux/usb.h>
@@ -3039,6 +3041,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
3039} 3041}
3040EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); 3042EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
3041 3043
3044int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
3045 dma_addr_t dma, size_t size)
3046{
3047 int err;
3048 void *local_mem;
3049
3050 hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, PAGE_SHIFT,
3051 dev_to_node(hcd->self.sysdev),
3052 dev_name(hcd->self.sysdev));
3053 if (IS_ERR(hcd->localmem_pool))
3054 return PTR_ERR(hcd->localmem_pool);
3055
3056 local_mem = devm_memremap(hcd->self.sysdev, phys_addr,
3057 size, MEMREMAP_WC);
3058 if (!local_mem)
3059 return -ENOMEM;
3060
3061 /*
3062 * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
3063 * It's not backed by system memory and thus there's no kernel mapping
3064 * for it.
3065 */
3066 err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem,
3067 dma, size, dev_to_node(hcd->self.sysdev));
3068 if (err < 0) {
3069 dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
3070 err);
3071 return err;
3072 }
3073
3074 return 0;
3075}
3076EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem);
3077
3042/*-------------------------------------------------------------------------*/ 3078/*-------------------------------------------------------------------------*/
3043 3079
3044#if IS_ENABLED(CONFIG_USB_MON) 3080#if IS_ENABLED(CONFIG_USB_MON)
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 210181fd98d2..b200b19b44fa 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -40,6 +40,7 @@
40#include <linux/dmapool.h> 40#include <linux/dmapool.h>
41#include <linux/workqueue.h> 41#include <linux/workqueue.h>
42#include <linux/debugfs.h> 42#include <linux/debugfs.h>
43#include <linux/genalloc.h>
43 44
44#include <asm/io.h> 45#include <asm/io.h>
45#include <asm/irq.h> 46#include <asm/irq.h>
@@ -505,8 +506,15 @@ static int ohci_init (struct ohci_hcd *ohci)
505 timer_setup(&ohci->io_watchdog, io_watchdog_func, 0); 506 timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
506 ohci->prev_frame_no = IO_WATCHDOG_OFF; 507 ohci->prev_frame_no = IO_WATCHDOG_OFF;
507 508
508 ohci->hcca = dma_alloc_coherent (hcd->self.controller, 509 if (hcd->localmem_pool)
509 sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); 510 ohci->hcca = gen_pool_dma_alloc(hcd->localmem_pool,
511 sizeof(*ohci->hcca),
512 &ohci->hcca_dma);
513 else
514 ohci->hcca = dma_alloc_coherent(hcd->self.controller,
515 sizeof(*ohci->hcca),
516 &ohci->hcca_dma,
517 GFP_KERNEL);
510 if (!ohci->hcca) 518 if (!ohci->hcca)
511 return -ENOMEM; 519 return -ENOMEM;
512 520
@@ -990,9 +998,14 @@ static void ohci_stop (struct usb_hcd *hcd)
990 remove_debug_files (ohci); 998 remove_debug_files (ohci);
991 ohci_mem_cleanup (ohci); 999 ohci_mem_cleanup (ohci);
992 if (ohci->hcca) { 1000 if (ohci->hcca) {
993 dma_free_coherent (hcd->self.controller, 1001 if (hcd->localmem_pool)
994 sizeof *ohci->hcca, 1002 gen_pool_free(hcd->localmem_pool,
995 ohci->hcca, ohci->hcca_dma); 1003 (unsigned long)ohci->hcca,
1004 sizeof(*ohci->hcca));
1005 else
1006 dma_free_coherent(hcd->self.controller,
1007 sizeof(*ohci->hcca),
1008 ohci->hcca, ohci->hcca_dma);
996 ohci->hcca = NULL; 1009 ohci->hcca = NULL;
997 ohci->hcca_dma = 0; 1010 ohci->hcca_dma = 0;
998 } 1011 }
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 3965ac0341eb..4afe27cc7e46 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -36,6 +36,13 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
36 36
37static int ohci_mem_init (struct ohci_hcd *ohci) 37static int ohci_mem_init (struct ohci_hcd *ohci)
38{ 38{
39 /*
40 * HCs with local memory allocate from localmem_pool so there's
41 * no need to create the below dma pools.
42 */
43 if (ohci_to_hcd(ohci)->localmem_pool)
44 return 0;
45
39 ohci->td_cache = dma_pool_create ("ohci_td", 46 ohci->td_cache = dma_pool_create ("ohci_td",
40 ohci_to_hcd(ohci)->self.controller, 47 ohci_to_hcd(ohci)->self.controller,
41 sizeof (struct td), 48 sizeof (struct td),
@@ -84,8 +91,12 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
84{ 91{
85 dma_addr_t dma; 92 dma_addr_t dma;
86 struct td *td; 93 struct td *td;
94 struct usb_hcd *hcd = ohci_to_hcd(hc);
87 95
88 td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma); 96 if (hcd->localmem_pool)
97 td = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*td), &dma);
98 else
99 td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma);
89 if (td) { 100 if (td) {
90 /* in case hc fetches it, make it look dead */ 101 /* in case hc fetches it, make it look dead */
91 td->hwNextTD = cpu_to_hc32 (hc, dma); 102 td->hwNextTD = cpu_to_hc32 (hc, dma);
@@ -99,6 +110,7 @@ static void
99td_free (struct ohci_hcd *hc, struct td *td) 110td_free (struct ohci_hcd *hc, struct td *td)
100{ 111{
101 struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; 112 struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
113 struct usb_hcd *hcd = ohci_to_hcd(hc);
102 114
103 while (*prev && *prev != td) 115 while (*prev && *prev != td)
104 prev = &(*prev)->td_hash; 116 prev = &(*prev)->td_hash;
@@ -106,7 +118,12 @@ td_free (struct ohci_hcd *hc, struct td *td)
106 *prev = td->td_hash; 118 *prev = td->td_hash;
107 else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) 119 else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
108 ohci_dbg (hc, "no hash for td %p\n", td); 120 ohci_dbg (hc, "no hash for td %p\n", td);
109 dma_pool_free (hc->td_cache, td, td->td_dma); 121
122 if (hcd->localmem_pool)
123 gen_pool_free(hcd->localmem_pool, (unsigned long)td,
124 sizeof(*td));
125 else
126 dma_pool_free(hc->td_cache, td, td->td_dma);
110} 127}
111 128
112/*-------------------------------------------------------------------------*/ 129/*-------------------------------------------------------------------------*/
@@ -117,8 +134,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
117{ 134{
118 dma_addr_t dma; 135 dma_addr_t dma;
119 struct ed *ed; 136 struct ed *ed;
137 struct usb_hcd *hcd = ohci_to_hcd(hc);
120 138
121 ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma); 139 if (hcd->localmem_pool)
140 ed = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*ed), &dma);
141 else
142 ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma);
122 if (ed) { 143 if (ed) {
123 INIT_LIST_HEAD (&ed->td_list); 144 INIT_LIST_HEAD (&ed->td_list);
124 ed->dma = dma; 145 ed->dma = dma;
@@ -129,6 +150,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
129static void 150static void
130ed_free (struct ohci_hcd *hc, struct ed *ed) 151ed_free (struct ohci_hcd *hc, struct ed *ed)
131{ 152{
132 dma_pool_free (hc->ed_cache, ed, ed->dma); 153 struct usb_hcd *hcd = ohci_to_hcd(hc);
154
155 if (hcd->localmem_pool)
156 gen_pool_free(hcd->localmem_pool, (unsigned long)ed,
157 sizeof(*ed));
158 else
159 dma_pool_free(hc->ed_cache, ed, ed->dma);
133} 160}
134 161
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index ef4813bfc5bf..b015b00774b2 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -385,6 +385,8 @@ struct ohci_hcd {
385 385
386 /* 386 /*
387 * memory management for queue data structures 387 * memory management for queue data structures
388 *
389 * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used.
388 */ 390 */
389 struct dma_pool *td_cache; 391 struct dma_pool *td_cache;
390 struct dma_pool *ed_cache; 392 struct dma_pool *ed_cache;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index bb57b5af4700..127560a4bfa0 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -216,6 +216,9 @@ struct usb_hcd {
216#define HC_IS_RUNNING(state) ((state) & __ACTIVE) 216#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
217#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND) 217#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
218 218
219 /* memory pool for HCs having local memory, or %NULL */
220 struct gen_pool *localmem_pool;
221
219 /* more shared queuing code would be good; it should support 222 /* more shared queuing code would be good; it should support
220 * smarter scheduling, handle transaction translators, etc; 223 * smarter scheduling, handle transaction translators, etc;
221 * input size of periodic table to an interrupt scheduler. 224 * input size of periodic table to an interrupt scheduler.
@@ -461,6 +464,8 @@ extern int usb_add_hcd(struct usb_hcd *hcd,
461 unsigned int irqnum, unsigned long irqflags); 464 unsigned int irqnum, unsigned long irqflags);
462extern void usb_remove_hcd(struct usb_hcd *hcd); 465extern void usb_remove_hcd(struct usb_hcd *hcd);
463extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1); 466extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
467int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
468 dma_addr_t dma, size_t size);
464 469
465struct platform_device; 470struct platform_device;
466extern void usb_hcd_platform_shutdown(struct platform_device *dev); 471extern void usb_hcd_platform_shutdown(struct platform_device *dev);