diff options
-rw-r--r-- | drivers/of/dma.c | 89 | ||||
-rw-r--r-- | include/linux/of_dma.h | 5 |
2 files changed, 70 insertions, 24 deletions
diff --git a/drivers/of/dma.c b/drivers/of/dma.c index 4bed490a69e4..59631b2c4666 100644 --- a/drivers/of/dma.c +++ b/drivers/of/dma.c | |||
@@ -19,28 +19,61 @@ | |||
19 | #include <linux/of_dma.h> | 19 | #include <linux/of_dma.h> |
20 | 20 | ||
21 | static LIST_HEAD(of_dma_list); | 21 | static LIST_HEAD(of_dma_list); |
22 | static DEFINE_SPINLOCK(of_dma_lock); | ||
22 | 23 | ||
23 | /** | 24 | /** |
24 | * of_dma_find_controller - Find a DMA controller in DT DMA helpers list | 25 | * of_dma_get_controller - Get a DMA controller in DT DMA helpers list |
25 | * @np: device node of DMA controller | 26 | * @dma_spec: pointer to DMA specifier as found in the device tree |
27 | * | ||
28 | * Finds a DMA controller with matching device node and number for dma cells | ||
29 | * in a list of registered DMA controllers. If a match is found the use_count | ||
30 | * variable is increased and a valid pointer to the DMA data stored is retuned. | ||
31 | * A NULL pointer is returned if no match is found. | ||
26 | */ | 32 | */ |
27 | static struct of_dma *of_dma_find_controller(struct device_node *np) | 33 | static struct of_dma *of_dma_get_controller(struct of_phandle_args *dma_spec) |
28 | { | 34 | { |
29 | struct of_dma *ofdma; | 35 | struct of_dma *ofdma; |
30 | 36 | ||
37 | spin_lock(&of_dma_lock); | ||
38 | |||
31 | if (list_empty(&of_dma_list)) { | 39 | if (list_empty(&of_dma_list)) { |
32 | pr_err("empty DMA controller list\n"); | 40 | spin_unlock(&of_dma_lock); |
33 | return NULL; | 41 | return NULL; |
34 | } | 42 | } |
35 | 43 | ||
36 | list_for_each_entry_rcu(ofdma, &of_dma_list, of_dma_controllers) | 44 | list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers) |
37 | if (ofdma->of_node == np) | 45 | if ((ofdma->of_node == dma_spec->np) && |
46 | (ofdma->of_dma_nbcells == dma_spec->args_count)) { | ||
47 | ofdma->use_count++; | ||
48 | spin_unlock(&of_dma_lock); | ||
38 | return ofdma; | 49 | return ofdma; |
50 | } | ||
51 | |||
52 | spin_unlock(&of_dma_lock); | ||
53 | |||
54 | pr_debug("%s: can't find DMA controller %s\n", __func__, | ||
55 | dma_spec->np->full_name); | ||
39 | 56 | ||
40 | return NULL; | 57 | return NULL; |
41 | } | 58 | } |
42 | 59 | ||
43 | /** | 60 | /** |
61 | * of_dma_put_controller - Decrement use count for a registered DMA controller | ||
62 | * @of_dma: pointer to DMA controller data | ||
63 | * | ||
64 | * Decrements the use_count variable in the DMA data structure. This function | ||
65 | * should be called only when a valid pointer is returned from | ||
66 | * of_dma_get_controller() and no further accesses to data referenced by that | ||
67 | * pointer are needed. | ||
68 | */ | ||
69 | static void of_dma_put_controller(struct of_dma *ofdma) | ||
70 | { | ||
71 | spin_lock(&of_dma_lock); | ||
72 | ofdma->use_count--; | ||
73 | spin_unlock(&of_dma_lock); | ||
74 | } | ||
75 | |||
76 | /** | ||
44 | * of_dma_controller_register - Register a DMA controller to DT DMA helpers | 77 | * of_dma_controller_register - Register a DMA controller to DT DMA helpers |
45 | * @np: device node of DMA controller | 78 | * @np: device node of DMA controller |
46 | * @of_dma_xlate: translation function which converts a phandle | 79 | * @of_dma_xlate: translation function which converts a phandle |
@@ -81,9 +114,10 @@ int of_dma_controller_register(struct device_node *np, | |||
81 | ofdma->of_dma_nbcells = nbcells; | 114 | ofdma->of_dma_nbcells = nbcells; |
82 | ofdma->of_dma_xlate = of_dma_xlate; | 115 | ofdma->of_dma_xlate = of_dma_xlate; |
83 | ofdma->of_dma_data = data; | 116 | ofdma->of_dma_data = data; |
117 | ofdma->use_count = 0; | ||
84 | 118 | ||
85 | /* Now queue of_dma controller structure in list */ | 119 | /* Now queue of_dma controller structure in list */ |
86 | list_add_tail_rcu(&ofdma->of_dma_controllers, &of_dma_list); | 120 | list_add_tail(&ofdma->of_dma_controllers, &of_dma_list); |
87 | 121 | ||
88 | return 0; | 122 | return 0; |
89 | } | 123 | } |
@@ -95,15 +129,32 @@ EXPORT_SYMBOL_GPL(of_dma_controller_register); | |||
95 | * | 129 | * |
96 | * Memory allocated by of_dma_controller_register() is freed here. | 130 | * Memory allocated by of_dma_controller_register() is freed here. |
97 | */ | 131 | */ |
98 | void of_dma_controller_free(struct device_node *np) | 132 | int of_dma_controller_free(struct device_node *np) |
99 | { | 133 | { |
100 | struct of_dma *ofdma; | 134 | struct of_dma *ofdma; |
101 | 135 | ||
102 | ofdma = of_dma_find_controller(np); | 136 | spin_lock(&of_dma_lock); |
103 | if (ofdma) { | 137 | |
104 | list_del_rcu(&ofdma->of_dma_controllers); | 138 | if (list_empty(&of_dma_list)) { |
105 | kfree(ofdma); | 139 | spin_unlock(&of_dma_lock); |
140 | return -ENODEV; | ||
106 | } | 141 | } |
142 | |||
143 | list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers) | ||
144 | if (ofdma->of_node == np) { | ||
145 | if (ofdma->use_count) { | ||
146 | spin_unlock(&of_dma_lock); | ||
147 | return -EBUSY; | ||
148 | } | ||
149 | |||
150 | list_del(&ofdma->of_dma_controllers); | ||
151 | spin_unlock(&of_dma_lock); | ||
152 | kfree(ofdma); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | spin_unlock(&of_dma_lock); | ||
157 | return -ENODEV; | ||
107 | } | 158 | } |
108 | EXPORT_SYMBOL_GPL(of_dma_controller_free); | 159 | EXPORT_SYMBOL_GPL(of_dma_controller_free); |
109 | 160 | ||
@@ -166,21 +217,15 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, | |||
166 | if (of_dma_match_channel(np, name, i, &dma_spec)) | 217 | if (of_dma_match_channel(np, name, i, &dma_spec)) |
167 | continue; | 218 | continue; |
168 | 219 | ||
169 | ofdma = of_dma_find_controller(dma_spec.np); | 220 | ofdma = of_dma_get_controller(&dma_spec); |
170 | if (!ofdma) { | ||
171 | pr_debug("%s: can't find DMA controller %s\n", | ||
172 | np->full_name, dma_spec.np->full_name); | ||
173 | continue; | ||
174 | } | ||
175 | 221 | ||
176 | if (dma_spec.args_count != ofdma->of_dma_nbcells) { | 222 | if (!ofdma) |
177 | pr_debug("%s: wrong #dma-cells for %s\n", np->full_name, | ||
178 | dma_spec.np->full_name); | ||
179 | continue; | 223 | continue; |
180 | } | ||
181 | 224 | ||
182 | chan = ofdma->of_dma_xlate(&dma_spec, ofdma); | 225 | chan = ofdma->of_dma_xlate(&dma_spec, ofdma); |
183 | 226 | ||
227 | of_dma_put_controller(ofdma); | ||
228 | |||
184 | of_node_put(dma_spec.np); | 229 | of_node_put(dma_spec.np); |
185 | 230 | ||
186 | if (chan) | 231 | if (chan) |
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h index 67158ddd1f3e..84b64f857e23 100644 --- a/include/linux/of_dma.h +++ b/include/linux/of_dma.h | |||
@@ -25,6 +25,7 @@ struct of_dma { | |||
25 | struct dma_chan *(*of_dma_xlate) | 25 | struct dma_chan *(*of_dma_xlate) |
26 | (struct of_phandle_args *, struct of_dma *); | 26 | (struct of_phandle_args *, struct of_dma *); |
27 | void *of_dma_data; | 27 | void *of_dma_data; |
28 | int use_count; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct of_dma_filter_info { | 31 | struct of_dma_filter_info { |
@@ -37,7 +38,7 @@ extern int of_dma_controller_register(struct device_node *np, | |||
37 | struct dma_chan *(*of_dma_xlate) | 38 | struct dma_chan *(*of_dma_xlate) |
38 | (struct of_phandle_args *, struct of_dma *), | 39 | (struct of_phandle_args *, struct of_dma *), |
39 | void *data); | 40 | void *data); |
40 | extern void of_dma_controller_free(struct device_node *np); | 41 | extern int of_dma_controller_free(struct device_node *np); |
41 | extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, | 42 | extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np, |
42 | char *name); | 43 | char *name); |
43 | extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, | 44 | extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, |
@@ -51,7 +52,7 @@ static int of_dma_controller_register(struct device_node *np, | |||
51 | return -ENODEV; | 52 | return -ENODEV; |
52 | } | 53 | } |
53 | 54 | ||
54 | static void of_dma_controller_free(struct device_node *np) | 55 | static int of_dma_controller_free(struct device_node *np) |
55 | { | 56 | { |
56 | } | 57 | } |
57 | 58 | ||