Skip to content

Commit b0310c2

Browse files
tudorlChristoph Hellwig
authored andcommitted
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 <[email protected]> Tested-by: Fredrik Noring <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent da83a72 commit b0310c2

File tree

7 files changed

+102
-9
lines changed

7 files changed

+102
-9
lines changed

drivers/usb/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ config USB_ARCH_HAS_HCD
4545
config USB
4646
tristate "Support for Host-side USB"
4747
depends on USB_ARCH_HAS_HCD
48+
select GENERIC_ALLOCATOR
4849
select USB_COMMON
4950
select NLS # for UTF-8 strings
5051
---help---

drivers/usb/core/buffer.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/io.h>
1717
#include <linux/dma-mapping.h>
1818
#include <linux/dmapool.h>
19+
#include <linux/genalloc.h>
1920
#include <linux/usb.h>
2021
#include <linux/usb/hcd.h>
2122

@@ -124,6 +125,9 @@ void *hcd_buffer_alloc(
124125
if (size == 0)
125126
return NULL;
126127

128+
if (hcd->localmem_pool)
129+
return gen_pool_dma_alloc(hcd->localmem_pool, size, dma);
130+
127131
/* some USB hosts just use PIO */
128132
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
129133
(!is_device_dma_capable(bus->sysdev) &&
@@ -152,6 +156,11 @@ void hcd_buffer_free(
152156
if (!addr)
153157
return;
154158

159+
if (hcd->localmem_pool) {
160+
gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size);
161+
return;
162+
}
163+
155164
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
156165
(!is_device_dma_capable(bus->sysdev) &&
157166
!(hcd->driver->flags & HCD_LOCAL_MEM))) {

drivers/usb/core/hcd.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <linux/workqueue.h>
3030
#include <linux/pm_runtime.h>
3131
#include <linux/types.h>
32+
#include <linux/genalloc.h>
33+
#include <linux/io.h>
3234

3335
#include <linux/phy/phy.h>
3436
#include <linux/usb.h>
@@ -3039,6 +3041,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
30393041
}
30403042
EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
30413043

3044+
int 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+
}
3076+
EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem);
3077+
30423078
/*-------------------------------------------------------------------------*/
30433079

30443080
#if IS_ENABLED(CONFIG_USB_MON)

drivers/usb/host/ohci-hcd.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <linux/dmapool.h>
4141
#include <linux/workqueue.h>
4242
#include <linux/debugfs.h>
43+
#include <linux/genalloc.h>
4344

4445
#include <asm/io.h>
4546
#include <asm/irq.h>
@@ -505,8 +506,15 @@ static int ohci_init (struct ohci_hcd *ohci)
505506
timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
506507
ohci->prev_frame_no = IO_WATCHDOG_OFF;
507508

508-
ohci->hcca = dma_alloc_coherent (hcd->self.controller,
509-
sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
509+
if (hcd->localmem_pool)
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);
510518
if (!ohci->hcca)
511519
return -ENOMEM;
512520

@@ -990,9 +998,14 @@ static void ohci_stop (struct usb_hcd *hcd)
990998
remove_debug_files (ohci);
991999
ohci_mem_cleanup (ohci);
9921000
if (ohci->hcca) {
993-
dma_free_coherent (hcd->self.controller,
994-
sizeof *ohci->hcca,
995-
ohci->hcca, ohci->hcca_dma);
1001+
if (hcd->localmem_pool)
1002+
gen_pool_free(hcd->localmem_pool,
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);
9961009
ohci->hcca = NULL;
9971010
ohci->hcca_dma = 0;
9981011
}

drivers/usb/host/ohci-mem.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
3636

3737
static int ohci_mem_init (struct ohci_hcd *ohci)
3838
{
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+
3946
ohci->td_cache = dma_pool_create ("ohci_td",
4047
ohci_to_hcd(ohci)->self.controller,
4148
sizeof (struct td),
@@ -84,8 +91,12 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
8491
{
8592
dma_addr_t dma;
8693
struct td *td;
94+
struct usb_hcd *hcd = ohci_to_hcd(hc);
8795

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);
89100
if (td) {
90101
/* in case hc fetches it, make it look dead */
91102
td->hwNextTD = cpu_to_hc32 (hc, dma);
@@ -99,14 +110,20 @@ static void
99110
td_free (struct ohci_hcd *hc, struct td *td)
100111
{
101112
struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
113+
struct usb_hcd *hcd = ohci_to_hcd(hc);
102114

103115
while (*prev && *prev != td)
104116
prev = &(*prev)->td_hash;
105117
if (*prev)
106118
*prev = td->td_hash;
107119
else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
108120
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);
110127
}
111128

112129
/*-------------------------------------------------------------------------*/
@@ -117,8 +134,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
117134
{
118135
dma_addr_t dma;
119136
struct ed *ed;
137+
struct usb_hcd *hcd = ohci_to_hcd(hc);
120138

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);
122143
if (ed) {
123144
INIT_LIST_HEAD (&ed->td_list);
124145
ed->dma = dma;
@@ -129,6 +150,12 @@ ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
129150
static void
130151
ed_free (struct ohci_hcd *hc, struct ed *ed)
131152
{
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);
133160
}
134161

drivers/usb/host/ohci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ struct ohci_hcd {
385385

386386
/*
387387
* memory management for queue data structures
388+
*
389+
* @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used.
388390
*/
389391
struct dma_pool *td_cache;
390392
struct dma_pool *ed_cache;

include/linux/usb/hcd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ struct usb_hcd {
216216
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
217217
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
218218

219+
/* memory pool for HCs having local memory, or %NULL */
220+
struct gen_pool *localmem_pool;
221+
219222
/* more shared queuing code would be good; it should support
220223
* smarter scheduling, handle transaction translators, etc;
221224
* input size of periodic table to an interrupt scheduler.
@@ -461,6 +464,8 @@ extern int usb_add_hcd(struct usb_hcd *hcd,
461464
unsigned int irqnum, unsigned long irqflags);
462465
extern void usb_remove_hcd(struct usb_hcd *hcd);
463466
extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
467+
int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
468+
dma_addr_t dma, size_t size);
464469

465470
struct platform_device;
466471
extern void usb_hcd_platform_shutdown(struct platform_device *dev);

0 commit comments

Comments
 (0)