Rev 1049 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1049 | mauro | 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_usb (hcd->pool [i], mem_flags, dma); |
||
118 | } |
||
119 | return pci_alloc_consistent_usb (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 | } |