Commit | Line | Data |
---|---|---|
473f01f7 | 1 | // SPDX-License-Identifier: GPL-2.0 |
21aeda95 AT |
2 | /* |
3 | * FPGA Bridge Framework Driver | |
4 | * | |
5 | * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. | |
9c1c4b27 | 6 | * Copyright (C) 2017 Intel Corporation |
21aeda95 AT |
7 | */ |
8 | #include <linux/fpga/fpga-bridge.h> | |
9 | #include <linux/idr.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/of_platform.h> | |
13 | #include <linux/slab.h> | |
14 | #include <linux/spinlock.h> | |
15 | ||
16 | static DEFINE_IDA(fpga_bridge_ida); | |
7bb2d219 | 17 | static const struct class fpga_bridge_class; |
21aeda95 AT |
18 | |
19 | /* Lock for adding/removing bridges to linked lists*/ | |
f5187329 | 20 | static DEFINE_SPINLOCK(bridge_list_lock); |
21aeda95 | 21 | |
21aeda95 AT |
22 | /** |
23 | * fpga_bridge_enable - Enable transactions on the bridge | |
24 | * | |
25 | * @bridge: FPGA bridge | |
26 | * | |
27 | * Return: 0 for success, error code otherwise. | |
28 | */ | |
29 | int fpga_bridge_enable(struct fpga_bridge *bridge) | |
30 | { | |
31 | dev_dbg(&bridge->dev, "enable\n"); | |
32 | ||
b1a91ca2 | 33 | if (bridge->br_ops->enable_set) |
21aeda95 AT |
34 | return bridge->br_ops->enable_set(bridge, 1); |
35 | ||
36 | return 0; | |
37 | } | |
38 | EXPORT_SYMBOL_GPL(fpga_bridge_enable); | |
39 | ||
40 | /** | |
41 | * fpga_bridge_disable - Disable transactions on the bridge | |
42 | * | |
43 | * @bridge: FPGA bridge | |
44 | * | |
45 | * Return: 0 for success, error code otherwise. | |
46 | */ | |
47 | int fpga_bridge_disable(struct fpga_bridge *bridge) | |
48 | { | |
49 | dev_dbg(&bridge->dev, "disable\n"); | |
50 | ||
b1a91ca2 | 51 | if (bridge->br_ops->enable_set) |
21aeda95 AT |
52 | return bridge->br_ops->enable_set(bridge, 0); |
53 | ||
54 | return 0; | |
55 | } | |
56 | EXPORT_SYMBOL_GPL(fpga_bridge_disable); | |
57 | ||
1da11f82 | 58 | static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, |
9c1c4b27 | 59 | struct fpga_image_info *info) |
21aeda95 | 60 | { |
21aeda95 | 61 | struct fpga_bridge *bridge; |
21aeda95 | 62 | |
1da11f82 | 63 | bridge = to_fpga_bridge(bridge_dev); |
21aeda95 AT |
64 | |
65 | bridge->info = info; | |
66 | ||
1da11f82 MP |
67 | if (!mutex_trylock(&bridge->mutex)) |
68 | return ERR_PTR(-EBUSY); | |
21aeda95 | 69 | |
1da11f82 MP |
70 | if (!try_module_get(bridge->br_ops_owner)) { |
71 | mutex_unlock(&bridge->mutex); | |
72 | return ERR_PTR(-ENODEV); | |
73 | } | |
21aeda95 AT |
74 | |
75 | dev_dbg(&bridge->dev, "get\n"); | |
76 | ||
77 | return bridge; | |
21aeda95 | 78 | } |
9c1c4b27 AT |
79 | |
80 | /** | |
e7555cf6 | 81 | * of_fpga_bridge_get - get an exclusive reference to an fpga bridge |
9c1c4b27 | 82 | * |
8e665c9c MP |
83 | * @np: node pointer of an FPGA bridge. |
84 | * @info: fpga image specific information. | |
9c1c4b27 | 85 | * |
8e665c9c MP |
86 | * Return: |
87 | * * fpga_bridge struct pointer if successful. | |
88 | * * -EBUSY if someone already has a reference to the bridge. | |
89 | * * -ENODEV if @np is not an FPGA Bridge or can't take parent driver refcount. | |
9c1c4b27 AT |
90 | */ |
91 | struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, | |
92 | struct fpga_image_info *info) | |
93 | { | |
1da11f82 MP |
94 | struct fpga_bridge *bridge; |
95 | struct device *bridge_dev; | |
9c1c4b27 | 96 | |
1da11f82 MP |
97 | bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); |
98 | if (!bridge_dev) | |
9c1c4b27 AT |
99 | return ERR_PTR(-ENODEV); |
100 | ||
1da11f82 MP |
101 | bridge = __fpga_bridge_get(bridge_dev, info); |
102 | if (IS_ERR(bridge)) | |
103 | put_device(bridge_dev); | |
104 | ||
105 | return bridge; | |
9c1c4b27 | 106 | } |
21aeda95 AT |
107 | EXPORT_SYMBOL_GPL(of_fpga_bridge_get); |
108 | ||
9c1c4b27 AT |
109 | static int fpga_bridge_dev_match(struct device *dev, const void *data) |
110 | { | |
111 | return dev->parent == data; | |
112 | } | |
113 | ||
114 | /** | |
e7555cf6 | 115 | * fpga_bridge_get - get an exclusive reference to an fpga bridge |
9c1c4b27 | 116 | * @dev: parent device that fpga bridge was registered with |
7ef1a2c1 | 117 | * @info: fpga image specific information |
9c1c4b27 | 118 | * |
e7555cf6 | 119 | * Given a device, get an exclusive reference to an fpga bridge. |
9c1c4b27 | 120 | * |
b4d9a0e5 | 121 | * Return: fpga bridge struct or IS_ERR() condition containing error code. |
9c1c4b27 AT |
122 | */ |
123 | struct fpga_bridge *fpga_bridge_get(struct device *dev, | |
124 | struct fpga_image_info *info) | |
125 | { | |
1da11f82 | 126 | struct fpga_bridge *bridge; |
9c1c4b27 AT |
127 | struct device *bridge_dev; |
128 | ||
7bb2d219 | 129 | bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, |
9c1c4b27 AT |
130 | fpga_bridge_dev_match); |
131 | if (!bridge_dev) | |
132 | return ERR_PTR(-ENODEV); | |
133 | ||
1da11f82 MP |
134 | bridge = __fpga_bridge_get(bridge_dev, info); |
135 | if (IS_ERR(bridge)) | |
136 | put_device(bridge_dev); | |
137 | ||
138 | return bridge; | |
9c1c4b27 AT |
139 | } |
140 | EXPORT_SYMBOL_GPL(fpga_bridge_get); | |
141 | ||
21aeda95 AT |
142 | /** |
143 | * fpga_bridge_put - release a reference to a bridge | |
144 | * | |
145 | * @bridge: FPGA bridge | |
146 | */ | |
147 | void fpga_bridge_put(struct fpga_bridge *bridge) | |
148 | { | |
149 | dev_dbg(&bridge->dev, "put\n"); | |
150 | ||
151 | bridge->info = NULL; | |
1da11f82 | 152 | module_put(bridge->br_ops_owner); |
21aeda95 AT |
153 | mutex_unlock(&bridge->mutex); |
154 | put_device(&bridge->dev); | |
155 | } | |
156 | EXPORT_SYMBOL_GPL(fpga_bridge_put); | |
157 | ||
158 | /** | |
159 | * fpga_bridges_enable - enable bridges in a list | |
160 | * @bridge_list: list of FPGA bridges | |
161 | * | |
8e665c9c | 162 | * Enable each bridge in the list. If list is empty, do nothing. |
21aeda95 | 163 | * |
8e665c9c | 164 | * Return: 0 for success or empty bridge list or an error code otherwise. |
21aeda95 AT |
165 | */ |
166 | int fpga_bridges_enable(struct list_head *bridge_list) | |
167 | { | |
168 | struct fpga_bridge *bridge; | |
21aeda95 AT |
169 | int ret; |
170 | ||
c37235cc | 171 | list_for_each_entry(bridge, bridge_list, node) { |
21aeda95 AT |
172 | ret = fpga_bridge_enable(bridge); |
173 | if (ret) | |
174 | return ret; | |
175 | } | |
176 | ||
177 | return 0; | |
178 | } | |
179 | EXPORT_SYMBOL_GPL(fpga_bridges_enable); | |
180 | ||
181 | /** | |
182 | * fpga_bridges_disable - disable bridges in a list | |
183 | * | |
184 | * @bridge_list: list of FPGA bridges | |
185 | * | |
8e665c9c | 186 | * Disable each bridge in the list. If list is empty, do nothing. |
21aeda95 | 187 | * |
8e665c9c | 188 | * Return: 0 for success or empty bridge list or an error code otherwise. |
21aeda95 AT |
189 | */ |
190 | int fpga_bridges_disable(struct list_head *bridge_list) | |
191 | { | |
192 | struct fpga_bridge *bridge; | |
21aeda95 AT |
193 | int ret; |
194 | ||
c37235cc | 195 | list_for_each_entry(bridge, bridge_list, node) { |
21aeda95 AT |
196 | ret = fpga_bridge_disable(bridge); |
197 | if (ret) | |
198 | return ret; | |
199 | } | |
200 | ||
201 | return 0; | |
202 | } | |
203 | EXPORT_SYMBOL_GPL(fpga_bridges_disable); | |
204 | ||
205 | /** | |
206 | * fpga_bridges_put - put bridges | |
207 | * | |
208 | * @bridge_list: list of FPGA bridges | |
209 | * | |
210 | * For each bridge in the list, put the bridge and remove it from the list. | |
211 | * If list is empty, do nothing. | |
212 | */ | |
213 | void fpga_bridges_put(struct list_head *bridge_list) | |
214 | { | |
c37235cc | 215 | struct fpga_bridge *bridge, *next; |
21aeda95 AT |
216 | unsigned long flags; |
217 | ||
c37235cc | 218 | list_for_each_entry_safe(bridge, next, bridge_list, node) { |
21aeda95 AT |
219 | fpga_bridge_put(bridge); |
220 | ||
221 | spin_lock_irqsave(&bridge_list_lock, flags); | |
222 | list_del(&bridge->node); | |
223 | spin_unlock_irqrestore(&bridge_list_lock, flags); | |
224 | } | |
225 | } | |
226 | EXPORT_SYMBOL_GPL(fpga_bridges_put); | |
227 | ||
228 | /** | |
9c1c4b27 | 229 | * of_fpga_bridge_get_to_list - get a bridge, add it to a list |
21aeda95 | 230 | * |
e7555cf6 | 231 | * @np: node pointer of an FPGA bridge |
21aeda95 AT |
232 | * @info: fpga image specific information |
233 | * @bridge_list: list of FPGA bridges | |
234 | * | |
0a05cdf1 | 235 | * Get an exclusive reference to the bridge and it to the list. |
21aeda95 | 236 | * |
8e665c9c | 237 | * Return: 0 for success, error code from of_fpga_bridge_get() otherwise. |
21aeda95 | 238 | */ |
9c1c4b27 AT |
239 | int of_fpga_bridge_get_to_list(struct device_node *np, |
240 | struct fpga_image_info *info, | |
241 | struct list_head *bridge_list) | |
242 | { | |
243 | struct fpga_bridge *bridge; | |
244 | unsigned long flags; | |
245 | ||
246 | bridge = of_fpga_bridge_get(np, info); | |
247 | if (IS_ERR(bridge)) | |
248 | return PTR_ERR(bridge); | |
249 | ||
250 | spin_lock_irqsave(&bridge_list_lock, flags); | |
251 | list_add(&bridge->node, bridge_list); | |
252 | spin_unlock_irqrestore(&bridge_list_lock, flags); | |
253 | ||
254 | return 0; | |
255 | } | |
256 | EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); | |
257 | ||
258 | /** | |
259 | * fpga_bridge_get_to_list - given device, get a bridge, add it to a list | |
260 | * | |
261 | * @dev: FPGA bridge device | |
262 | * @info: fpga image specific information | |
263 | * @bridge_list: list of FPGA bridges | |
264 | * | |
0a05cdf1 | 265 | * Get an exclusive reference to the bridge and it to the list. |
9c1c4b27 | 266 | * |
8e665c9c | 267 | * Return: 0 for success, error code from fpga_bridge_get() otherwise. |
9c1c4b27 AT |
268 | */ |
269 | int fpga_bridge_get_to_list(struct device *dev, | |
21aeda95 AT |
270 | struct fpga_image_info *info, |
271 | struct list_head *bridge_list) | |
272 | { | |
273 | struct fpga_bridge *bridge; | |
274 | unsigned long flags; | |
275 | ||
9c1c4b27 | 276 | bridge = fpga_bridge_get(dev, info); |
21aeda95 AT |
277 | if (IS_ERR(bridge)) |
278 | return PTR_ERR(bridge); | |
279 | ||
280 | spin_lock_irqsave(&bridge_list_lock, flags); | |
281 | list_add(&bridge->node, bridge_list); | |
282 | spin_unlock_irqrestore(&bridge_list_lock, flags); | |
283 | ||
284 | return 0; | |
285 | } | |
286 | EXPORT_SYMBOL_GPL(fpga_bridge_get_to_list); | |
287 | ||
288 | static ssize_t name_show(struct device *dev, | |
289 | struct device_attribute *attr, char *buf) | |
290 | { | |
291 | struct fpga_bridge *bridge = to_fpga_bridge(dev); | |
292 | ||
293 | return sprintf(buf, "%s\n", bridge->name); | |
294 | } | |
295 | ||
296 | static ssize_t state_show(struct device *dev, | |
297 | struct device_attribute *attr, char *buf) | |
298 | { | |
299 | struct fpga_bridge *bridge = to_fpga_bridge(dev); | |
48ca6e5f | 300 | int state = 1; |
21aeda95 | 301 | |
b1a91ca2 | 302 | if (bridge->br_ops->enable_show) { |
48ca6e5f MP |
303 | state = bridge->br_ops->enable_show(bridge); |
304 | if (state < 0) | |
305 | return state; | |
306 | } | |
21aeda95 | 307 | |
48ca6e5f | 308 | return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled"); |
21aeda95 AT |
309 | } |
310 | ||
311 | static DEVICE_ATTR_RO(name); | |
312 | static DEVICE_ATTR_RO(state); | |
313 | ||
314 | static struct attribute *fpga_bridge_attrs[] = { | |
315 | &dev_attr_name.attr, | |
316 | &dev_attr_state.attr, | |
317 | NULL, | |
318 | }; | |
319 | ATTRIBUTE_GROUPS(fpga_bridge); | |
320 | ||
321 | /** | |
1da11f82 | 322 | * __fpga_bridge_register - create and register an FPGA Bridge device |
ceb8ab3c | 323 | * @parent: FPGA bridge device from pdev |
21aeda95 AT |
324 | * @name: FPGA bridge name |
325 | * @br_ops: pointer to structure of fpga bridge ops | |
326 | * @priv: FPGA bridge private data | |
1da11f82 | 327 | * @owner: owner module containing the br_ops |
21aeda95 | 328 | * |
0d70af3c | 329 | * Return: struct fpga_bridge pointer or ERR_PTR() |
21aeda95 | 330 | */ |
0d70af3c | 331 | struct fpga_bridge * |
1da11f82 MP |
332 | __fpga_bridge_register(struct device *parent, const char *name, |
333 | const struct fpga_bridge_ops *br_ops, | |
334 | void *priv, struct module *owner) | |
21aeda95 AT |
335 | { |
336 | struct fpga_bridge *bridge; | |
d3fbd739 | 337 | int id, ret; |
21aeda95 | 338 | |
0d70af3c RW |
339 | if (!br_ops) { |
340 | dev_err(parent, "Attempt to register without fpga_bridge_ops\n"); | |
341 | return ERR_PTR(-EINVAL); | |
342 | } | |
343 | ||
21aeda95 | 344 | if (!name || !strlen(name)) { |
ceb8ab3c | 345 | dev_err(parent, "Attempt to register with no name!\n"); |
0d70af3c | 346 | return ERR_PTR(-EINVAL); |
21aeda95 AT |
347 | } |
348 | ||
349 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | |
350 | if (!bridge) | |
0d70af3c | 351 | return ERR_PTR(-ENOMEM); |
21aeda95 | 352 | |
a5e3d775 | 353 | id = ida_alloc(&fpga_bridge_ida, GFP_KERNEL); |
0d70af3c RW |
354 | if (id < 0) { |
355 | ret = id; | |
21aeda95 | 356 | goto error_kfree; |
0d70af3c | 357 | } |
21aeda95 AT |
358 | |
359 | mutex_init(&bridge->mutex); | |
360 | INIT_LIST_HEAD(&bridge->node); | |
361 | ||
362 | bridge->name = name; | |
363 | bridge->br_ops = br_ops; | |
1da11f82 | 364 | bridge->br_ops_owner = owner; |
21aeda95 AT |
365 | bridge->priv = priv; |
366 | ||
845089bb | 367 | bridge->dev.groups = br_ops->groups; |
7bb2d219 | 368 | bridge->dev.class = &fpga_bridge_class; |
ceb8ab3c RW |
369 | bridge->dev.parent = parent; |
370 | bridge->dev.of_node = parent->of_node; | |
21aeda95 | 371 | bridge->dev.id = id; |
21aeda95 AT |
372 | |
373 | ret = dev_set_name(&bridge->dev, "br%d", id); | |
374 | if (ret) | |
375 | goto error_device; | |
376 | ||
0d70af3c RW |
377 | ret = device_register(&bridge->dev); |
378 | if (ret) { | |
379 | put_device(&bridge->dev); | |
380 | return ERR_PTR(ret); | |
381 | } | |
382 | ||
dc70eb86 AL |
383 | of_platform_populate(bridge->dev.of_node, NULL, NULL, &bridge->dev); |
384 | ||
371cd1b1 | 385 | return bridge; |
21aeda95 AT |
386 | |
387 | error_device: | |
a5e3d775 | 388 | ida_free(&fpga_bridge_ida, id); |
21aeda95 AT |
389 | error_kfree: |
390 | kfree(bridge); | |
391 | ||
0d70af3c | 392 | return ERR_PTR(ret); |
21aeda95 | 393 | } |
1da11f82 | 394 | EXPORT_SYMBOL_GPL(__fpga_bridge_register); |
21aeda95 AT |
395 | |
396 | /** | |
e7555cf6 | 397 | * fpga_bridge_unregister - unregister an FPGA bridge |
213befe0 AT |
398 | * |
399 | * @bridge: FPGA bridge struct | |
400 | * | |
e7555cf6 | 401 | * This function is intended for use in an FPGA bridge driver's remove function. |
21aeda95 | 402 | */ |
371cd1b1 | 403 | void fpga_bridge_unregister(struct fpga_bridge *bridge) |
21aeda95 | 404 | { |
21aeda95 AT |
405 | /* |
406 | * If the low level driver provides a method for putting bridge into | |
407 | * a desired state upon unregister, do it. | |
408 | */ | |
b1a91ca2 | 409 | if (bridge->br_ops->fpga_bridge_remove) |
21aeda95 AT |
410 | bridge->br_ops->fpga_bridge_remove(bridge); |
411 | ||
412 | device_unregister(&bridge->dev); | |
413 | } | |
414 | EXPORT_SYMBOL_GPL(fpga_bridge_unregister); | |
415 | ||
416 | static void fpga_bridge_dev_release(struct device *dev) | |
417 | { | |
0d70af3c RW |
418 | struct fpga_bridge *bridge = to_fpga_bridge(dev); |
419 | ||
a5e3d775 | 420 | ida_free(&fpga_bridge_ida, bridge->dev.id); |
0d70af3c | 421 | kfree(bridge); |
21aeda95 AT |
422 | } |
423 | ||
7bb2d219 IO |
424 | static const struct class fpga_bridge_class = { |
425 | .name = "fpga_bridge", | |
426 | .dev_groups = fpga_bridge_groups, | |
427 | .dev_release = fpga_bridge_dev_release, | |
428 | }; | |
429 | ||
21aeda95 AT |
430 | static int __init fpga_bridge_dev_init(void) |
431 | { | |
7bb2d219 | 432 | return class_register(&fpga_bridge_class); |
21aeda95 AT |
433 | } |
434 | ||
435 | static void __exit fpga_bridge_dev_exit(void) | |
436 | { | |
7bb2d219 | 437 | class_unregister(&fpga_bridge_class); |
21aeda95 AT |
438 | ida_destroy(&fpga_bridge_ida); |
439 | } | |
440 | ||
441 | MODULE_DESCRIPTION("FPGA Bridge Driver"); | |
9c1c4b27 | 442 | MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); |
21aeda95 AT |
443 | MODULE_LICENSE("GPL v2"); |
444 | ||
445 | subsys_initcall(fpga_bridge_dev_init); | |
446 | module_exit(fpga_bridge_dev_exit); |