• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/usb/core/
1/*
2 * DMA memory management for framework level HCD code (hc_driver)
3 *
4 * This implementation plugs in through generic "usb_bus" level methods,
5 * and should work with all USB controllers, regardles of bus type.
6 */
7
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/slab.h>
11#include <linux/device.h>
12#include <linux/mm.h>
13#include <asm/io.h>
14#include <linux/dma-mapping.h>
15#include <linux/dmapool.h>
16#include <linux/usb.h>
17#include <linux/usb/hcd.h>
18
19
20/*
21 * DMA-Coherent Buffers
22 */
23
24static const size_t	pool_max [HCD_BUFFER_POOLS] = {
25	/* platforms without dma-friendly caches might need to
26	 * prevent cacheline sharing...
27	 */
28	32,
29	128,
30	512,
31	PAGE_SIZE / 2
32	/* bigger --> allocate pages */
33};
34
35
36/* SETUP primitives */
37
38/**
39 * hcd_buffer_create - initialize buffer pools
40 * @hcd: the bus whose buffer pools are to be initialized
41 * Context: !in_interrupt()
42 *
43 * Call this as part of initializing a host controller that uses the dma
44 * memory allocators.  It initializes some pools of dma-coherent memory that
45 * will be shared by all drivers using that controller, or returns a negative
46 * errno value on error.
47 *
48 * Call hcd_buffer_destroy() to clean up after using those pools.
49 */
50int hcd_buffer_create(struct usb_hcd *hcd)
51{
52	char		name[16];
53	int 		i, size;
54
55	if (!hcd->self.controller->dma_mask &&
56	    !(hcd->driver->flags & HCD_LOCAL_MEM))
57		return 0;
58
59	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
60		size = pool_max[i];
61		if (!size)
62			continue;
63		snprintf(name, sizeof name, "buffer-%d", size);
64		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
65				size, size, 0);
66		if (!hcd->pool [i]) {
67			hcd_buffer_destroy(hcd);
68			return -ENOMEM;
69		}
70	}
71	return 0;
72}
73
74
75/**
76 * hcd_buffer_destroy - deallocate buffer pools
77 * @hcd: the bus whose buffer pools are to be destroyed
78 * Context: !in_interrupt()
79 *
80 * This frees the buffer pools created by hcd_buffer_create().
81 */
82void hcd_buffer_destroy(struct usb_hcd *hcd)
83{
84	int i;
85
86	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
87		struct dma_pool *pool = hcd->pool[i];
88		if (pool) {
89			dma_pool_destroy(pool);
90			hcd->pool[i] = NULL;
91		}
92	}
93}
94
95
96/* sometimes alloc/free could use kmalloc with GFP_DMA, for
97 * better sharing and to leverage mm/slab.c intelligence.
98 */
99
100void *hcd_buffer_alloc(
101	struct usb_bus 	*bus,
102	size_t			size,
103	gfp_t			mem_flags,
104	dma_addr_t		*dma
105)
106{
107	struct usb_hcd		*hcd = bus_to_hcd(bus);
108	int 			i;
109
110	/* some USB hosts just use PIO */
111	if (!bus->controller->dma_mask &&
112	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
113		*dma = ~(dma_addr_t) 0;
114		return kmalloc(size, mem_flags);
115	}
116
117	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
118		if (size <= pool_max [i])
119			return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
120	}
121	return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
122}
123
124void hcd_buffer_free(
125	struct usb_bus 	*bus,
126	size_t			size,
127	void 			*addr,
128	dma_addr_t		dma
129)
130{
131	struct usb_hcd		*hcd = bus_to_hcd(bus);
132	int 			i;
133
134	if (!addr)
135		return;
136
137	if (!bus->controller->dma_mask &&
138	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
139		kfree(addr);
140		return;
141	}
142
143	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
144		if (size <= pool_max [i]) {
145			dma_pool_free(hcd->pool [i], addr, dma);
146			return;
147		}
148	}
149	dma_free_coherent(hcd->self.controller, size, addr, dma);
150}
151