Branch data Line data Source code
1 : : /*
2 : : * This program is free software; you can redistribute it and/or modify
3 : : * it under the terms of the GNU General Public License version 2 as
4 : : * published by the Free Software Foundation.
5 : : *
6 : : * This program is distributed in the hope that it will be useful,
7 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 : : * GNU General Public License for more details.
10 : : *
11 : : * Copyright (C) 2012 ARM Limited
12 : : */
13 : :
14 : : #define pr_fmt(fmt) "vexpress-config: " fmt
15 : :
16 : : #include <linux/bitops.h>
17 : : #include <linux/completion.h>
18 : : #include <linux/export.h>
19 : : #include <linux/init.h>
20 : : #include <linux/list.h>
21 : : #include <linux/of.h>
22 : : #include <linux/of_device.h>
23 : : #include <linux/slab.h>
24 : : #include <linux/string.h>
25 : : #include <linux/vexpress.h>
26 : :
27 : :
28 : : #define VEXPRESS_CONFIG_MAX_BRIDGES 2
29 : :
30 : : struct vexpress_config_bridge {
31 : : struct device_node *node;
32 : : struct vexpress_config_bridge_info *info;
33 : : struct list_head transactions;
34 : : spinlock_t transactions_lock;
35 : : } vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
36 : :
37 : : static DECLARE_BITMAP(vexpress_config_bridges_map,
38 : : ARRAY_SIZE(vexpress_config_bridges));
39 : : static DEFINE_MUTEX(vexpress_config_bridges_mutex);
40 : :
41 : 0 : struct vexpress_config_bridge *vexpress_config_bridge_register(
42 : : struct device_node *node,
43 : : struct vexpress_config_bridge_info *info)
44 : : {
45 : : struct vexpress_config_bridge *bridge;
46 : : int i;
47 : :
48 : : pr_debug("Registering bridge '%s'\n", info->name);
49 : :
50 : 0 : mutex_lock(&vexpress_config_bridges_mutex);
51 : 0 : i = find_first_zero_bit(vexpress_config_bridges_map,
52 : : ARRAY_SIZE(vexpress_config_bridges));
53 [ # # ]: 0 : if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
54 : 0 : pr_err("Can't register more bridges!\n");
55 : 0 : mutex_unlock(&vexpress_config_bridges_mutex);
56 : 0 : return NULL;
57 : : }
58 : : __set_bit(i, vexpress_config_bridges_map);
59 : 0 : bridge = &vexpress_config_bridges[i];
60 : :
61 : 0 : bridge->node = node;
62 : 0 : bridge->info = info;
63 : 0 : INIT_LIST_HEAD(&bridge->transactions);
64 : 0 : spin_lock_init(&bridge->transactions_lock);
65 : :
66 : 0 : mutex_unlock(&vexpress_config_bridges_mutex);
67 : :
68 : 0 : return bridge;
69 : : }
70 : : EXPORT_SYMBOL(vexpress_config_bridge_register);
71 : :
72 : 0 : void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
73 : : {
74 : 0 : struct vexpress_config_bridge __bridge = *bridge;
75 : : int i;
76 : :
77 : 0 : mutex_lock(&vexpress_config_bridges_mutex);
78 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
79 [ # # ]: 0 : if (&vexpress_config_bridges[i] == bridge)
80 : : __clear_bit(i, vexpress_config_bridges_map);
81 : 0 : mutex_unlock(&vexpress_config_bridges_mutex);
82 : :
83 [ # # ]: 0 : WARN_ON(!list_empty(&__bridge.transactions));
84 [ # # ]: 0 : while (!list_empty(&__bridge.transactions))
85 : 0 : cpu_relax();
86 : 0 : }
87 : : EXPORT_SYMBOL(vexpress_config_bridge_unregister);
88 : :
89 : :
90 : : struct vexpress_config_func {
91 : : struct vexpress_config_bridge *bridge;
92 : : void *func;
93 : : };
94 : :
95 : 0 : struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
96 : : struct device_node *node)
97 : : {
98 : : struct device_node *bridge_node;
99 : : struct vexpress_config_func *func;
100 : : int i;
101 : :
102 [ # # ][ # # ]: 0 : if (WARN_ON(dev && node && dev->of_node != node))
[ # # ][ # # ]
103 : : return NULL;
104 [ # # ]: 0 : if (dev && !node)
105 : 0 : node = dev->of_node;
106 : :
107 : : func = kzalloc(sizeof(*func), GFP_KERNEL);
108 [ # # ]: 0 : if (!func)
109 : : return NULL;
110 : :
111 : : bridge_node = of_node_get(node);
112 [ # # ]: 0 : while (bridge_node) {
113 : 0 : const __be32 *prop = of_get_property(bridge_node,
114 : : "arm,vexpress,config-bridge", NULL);
115 : :
116 [ # # ]: 0 : if (prop) {
117 : 0 : bridge_node = of_find_node_by_phandle(
118 : : be32_to_cpup(prop));
119 : 0 : break;
120 : : }
121 : :
122 : 0 : bridge_node = of_get_next_parent(bridge_node);
123 : : }
124 : :
125 : 0 : mutex_lock(&vexpress_config_bridges_mutex);
126 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
127 : 0 : struct vexpress_config_bridge *bridge =
128 : : &vexpress_config_bridges[i];
129 : :
130 [ # # ][ # # ]: 0 : if (test_bit(i, vexpress_config_bridges_map) &&
131 : 0 : bridge->node == bridge_node) {
132 : 0 : func->bridge = bridge;
133 : 0 : func->func = bridge->info->func_get(dev, node);
134 : 0 : break;
135 : : }
136 : : }
137 : 0 : mutex_unlock(&vexpress_config_bridges_mutex);
138 : :
139 [ # # ]: 0 : if (!func->func) {
140 : : of_node_put(node);
141 : 0 : kfree(func);
142 : 0 : return NULL;
143 : : }
144 : :
145 : : return func;
146 : : }
147 : : EXPORT_SYMBOL(__vexpress_config_func_get);
148 : :
149 : 0 : void vexpress_config_func_put(struct vexpress_config_func *func)
150 : : {
151 : 0 : func->bridge->info->func_put(func->func);
152 : : of_node_put(func->bridge->node);
153 : 0 : kfree(func);
154 : 0 : }
155 : : EXPORT_SYMBOL(vexpress_config_func_put);
156 : :
157 : : struct vexpress_config_trans {
158 : : struct vexpress_config_func *func;
159 : : int offset;
160 : : bool write;
161 : : u32 *data;
162 : : int status;
163 : : struct completion completion;
164 : : struct list_head list;
165 : : };
166 : :
167 : : static void vexpress_config_dump_trans(const char *what,
168 : : struct vexpress_config_trans *trans)
169 : : {
170 : : pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
171 : : what, trans->write ? "write" : "read", trans,
172 : : trans->func->func, trans->offset,
173 : : trans->data ? *trans->data : 0, trans->status);
174 : : }
175 : :
176 : 0 : static int vexpress_config_schedule(struct vexpress_config_trans *trans)
177 : : {
178 : : int status;
179 : 0 : struct vexpress_config_bridge *bridge = trans->func->bridge;
180 : : unsigned long flags;
181 : :
182 : : init_completion(&trans->completion);
183 : 0 : trans->status = -EFAULT;
184 : :
185 : 0 : spin_lock_irqsave(&bridge->transactions_lock, flags);
186 : :
187 [ # # ]: 0 : if (list_empty(&bridge->transactions)) {
188 : : vexpress_config_dump_trans("Executing", trans);
189 : 0 : status = bridge->info->func_exec(trans->func->func,
190 : : trans->offset, trans->write, trans->data);
191 : : } else {
192 : : vexpress_config_dump_trans("Queuing", trans);
193 : : status = VEXPRESS_CONFIG_STATUS_WAIT;
194 : : }
195 : :
196 [ # # # ]: 0 : switch (status) {
197 : : case VEXPRESS_CONFIG_STATUS_DONE:
198 : : vexpress_config_dump_trans("Finished", trans);
199 : 0 : trans->status = status;
200 : 0 : break;
201 : : case VEXPRESS_CONFIG_STATUS_WAIT:
202 : 0 : list_add_tail(&trans->list, &bridge->transactions);
203 : : break;
204 : : }
205 : :
206 : : spin_unlock_irqrestore(&bridge->transactions_lock, flags);
207 : :
208 : 0 : return status;
209 : : }
210 : :
211 : 0 : void vexpress_config_complete(struct vexpress_config_bridge *bridge,
212 : : int status)
213 : : {
214 : : struct vexpress_config_trans *trans;
215 : : unsigned long flags;
216 : : const char *message = "Completed";
217 : :
218 : 0 : spin_lock_irqsave(&bridge->transactions_lock, flags);
219 : :
220 : 0 : trans = list_first_entry(&bridge->transactions,
221 : : struct vexpress_config_trans, list);
222 : 0 : trans->status = status;
223 : :
224 : : do {
225 : : vexpress_config_dump_trans(message, trans);
226 : : list_del(&trans->list);
227 : 0 : complete(&trans->completion);
228 : :
229 [ # # ]: 0 : if (list_empty(&bridge->transactions))
230 : : break;
231 : :
232 : 0 : trans = list_first_entry(&bridge->transactions,
233 : : struct vexpress_config_trans, list);
234 : : vexpress_config_dump_trans("Executing pending", trans);
235 : 0 : trans->status = bridge->info->func_exec(trans->func->func,
236 : : trans->offset, trans->write, trans->data);
237 : : message = "Finished pending";
238 [ # # ]: 0 : } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE);
239 : :
240 : : spin_unlock_irqrestore(&bridge->transactions_lock, flags);
241 : 0 : }
242 : : EXPORT_SYMBOL(vexpress_config_complete);
243 : :
244 : 0 : int vexpress_config_wait(struct vexpress_config_trans *trans)
245 : : {
246 : 0 : wait_for_completion(&trans->completion);
247 : :
248 : 0 : return trans->status;
249 : : }
250 : : EXPORT_SYMBOL(vexpress_config_wait);
251 : :
252 : 0 : int vexpress_config_read(struct vexpress_config_func *func, int offset,
253 : : u32 *data)
254 : : {
255 : 0 : struct vexpress_config_trans trans = {
256 : : .func = func,
257 : : .offset = offset,
258 : : .write = false,
259 : : .data = data,
260 : : .status = 0,
261 : : };
262 : 0 : int status = vexpress_config_schedule(&trans);
263 : :
264 [ # # ]: 0 : if (status == VEXPRESS_CONFIG_STATUS_WAIT)
265 : : status = vexpress_config_wait(&trans);
266 : :
267 : 0 : return status;
268 : : }
269 : : EXPORT_SYMBOL(vexpress_config_read);
270 : :
271 : 0 : int vexpress_config_write(struct vexpress_config_func *func, int offset,
272 : : u32 data)
273 : : {
274 : 0 : struct vexpress_config_trans trans = {
275 : : .func = func,
276 : : .offset = offset,
277 : : .write = true,
278 : : .data = &data,
279 : : .status = 0,
280 : : };
281 : 0 : int status = vexpress_config_schedule(&trans);
282 : :
283 [ # # ]: 0 : if (status == VEXPRESS_CONFIG_STATUS_WAIT)
284 : : status = vexpress_config_wait(&trans);
285 : :
286 : 0 : return status;
287 : : }
288 : : EXPORT_SYMBOL(vexpress_config_write);
|