Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
846 giacomo 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 works with real PCI, or when "pci device == null" makes sense.
6
 */
7
 
8
#include <linuxcomp.h>
9
 
10
#include <linux/config.h>
11
#include <linux/module.h>
12
#include <linux/kernel.h>
13
#include <linux/slab.h>
14
#include <linux/pci.h>
15
 
16
 
17
#ifdef CONFIG_USB_DEBUG
18
        #define DEBUG
19
#else
20
        #undef DEBUG
21
#endif
22
 
23
#include <linux/usb.h>
24
#include "hcd.h"
25
 
26
 
27
/*
28
 * DMA-Coherent Buffers
29
 */
30
 
31
/* FIXME tune these based on pool statistics ... */
32
static const size_t     pool_max [HCD_BUFFER_POOLS] = {
33
        /* platforms without dma-friendly caches might need to
34
         * prevent cacheline sharing...
35
         */
36
        32,
37
        128,
38
        512,
39
        PAGE_SIZE / 2
40
        /* bigger --> allocate pages */
41
};
42
 
43
 
44
/* SETUP primitives */
45
 
46
/**
47
 * hcd_buffer_create - initialize buffer pools
48
 * @hcd: the bus whose buffer pools are to be initialized
49
 * Context: !in_interrupt()
50
 *
51
 * Call this as part of initializing a host controller that uses the pci dma
52
 * memory allocators.  It initializes some pools of dma-consistent memory that
53
 * will be shared by all drivers using that controller, or returns a negative
54
 * errno value on error.
55
 *
56
 * Call hcd_buffer_destroy() to clean up after using those pools.
57
 */
58
int hcd_buffer_create (struct usb_hcd *hcd)
59
{
60
        char            name [16];
61
        int             i, size;
62
 
63
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
64
                if (!(size = pool_max [i]))
65
                        continue;
66
                snprintf26(name, sizeof name, "buffer-%d", size);
67
                hcd->pool [i] = pci_pool_create (name, hcd->pdev,
68
                                size, size, 0);
69
                if (!hcd->pool [i]) {
70
                        hcd_buffer_destroy (hcd);
71
                        return -ENOMEM;
72
                }
73
        }
74
        return 0;
75
}
76
EXPORT_SYMBOL (hcd_buffer_create);
77
 
78
 
79
/**
80
 * hcd_buffer_destroy - deallocate buffer pools
81
 * @hcd: the bus whose buffer pools are to be destroyed
82
 * Context: !in_interrupt()
83
 *
84
 * This frees the buffer pools created by hcd_buffer_create().
85
 */
86
void hcd_buffer_destroy (struct usb_hcd *hcd)
87
{
88
        int             i;
89
 
90
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
91
                struct pci_pool         *pool = hcd->pool [i];
92
                if (pool) {
93
                        pci_pool_destroy (pool);
94
                        hcd->pool [i] = 0;
95
                }
96
        }
97
}
98
EXPORT_SYMBOL (hcd_buffer_destroy);
99
 
100
 
101
/* sometimes alloc/free could use kmalloc with SLAB_DMA, for
102
 * better sharing and to leverage mm/slab.c intelligence.
103
 */
104
 
105
void *hcd_buffer_alloc (
106
        struct usb_bus          *bus,
107
        size_t                  size,
108
        int                     mem_flags,
109
        dma_addr_t              *dma
110
)
111
{
112
        struct usb_hcd          *hcd = bus->hcpriv;
113
        int                     i;
114
 
115
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
116
                if (size <= pool_max [i])
117
                        return pci_pool_alloc (hcd->pool [i], mem_flags, dma);
118
        }
119
        return pci_alloc_consistent (hcd->pdev, size, dma);
120
}
121
 
122
void hcd_buffer_free (
123
        struct usb_bus          *bus,
124
        size_t                  size,
125
        void                    *addr,
126
        dma_addr_t              dma
127
)
128
{
129
        struct usb_hcd          *hcd = bus->hcpriv;
130
        int                     i;
131
 
132
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
133
                if (size <= pool_max [i]) {
134
                        pci_pool_free (hcd->pool [i], addr, dma);
135
                        return;
136
                }
137
        }
138
        pci_free_consistent (hcd->pdev, size, addr, dma);
139
}