Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fpga/fpga-region.c
26381 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* FPGA Region - Support for FPGA programming under Linux
4
*
5
* Copyright (C) 2013-2016 Altera Corporation
6
* Copyright (C) 2017 Intel Corporation
7
*/
8
#include <linux/fpga/fpga-bridge.h>
9
#include <linux/fpga/fpga-mgr.h>
10
#include <linux/fpga/fpga-region.h>
11
#include <linux/idr.h>
12
#include <linux/kernel.h>
13
#include <linux/list.h>
14
#include <linux/module.h>
15
#include <linux/slab.h>
16
#include <linux/spinlock.h>
17
18
static DEFINE_IDA(fpga_region_ida);
19
static const struct class fpga_region_class;
20
21
struct fpga_region *
22
fpga_region_class_find(struct device *start, const void *data,
23
int (*match)(struct device *, const void *))
24
{
25
struct device *dev;
26
27
dev = class_find_device(&fpga_region_class, start, data, match);
28
if (!dev)
29
return NULL;
30
31
return to_fpga_region(dev);
32
}
33
EXPORT_SYMBOL_GPL(fpga_region_class_find);
34
35
/**
36
* fpga_region_get - get an exclusive reference to an fpga region
37
* @region: FPGA Region struct
38
*
39
* Caller should call fpga_region_put() when done with region.
40
*
41
* Return:
42
* * fpga_region struct if successful.
43
* * -EBUSY if someone already has a reference to the region.
44
* * -ENODEV if can't take parent driver module refcount.
45
*/
46
static struct fpga_region *fpga_region_get(struct fpga_region *region)
47
{
48
struct device *dev = &region->dev;
49
50
if (!mutex_trylock(&region->mutex)) {
51
dev_dbg(dev, "%s: FPGA Region already in use\n", __func__);
52
return ERR_PTR(-EBUSY);
53
}
54
55
get_device(dev);
56
if (!try_module_get(region->ops_owner)) {
57
put_device(dev);
58
mutex_unlock(&region->mutex);
59
return ERR_PTR(-ENODEV);
60
}
61
62
dev_dbg(dev, "get\n");
63
64
return region;
65
}
66
67
/**
68
* fpga_region_put - release a reference to a region
69
*
70
* @region: FPGA region
71
*/
72
static void fpga_region_put(struct fpga_region *region)
73
{
74
struct device *dev = &region->dev;
75
76
dev_dbg(dev, "put\n");
77
78
module_put(region->ops_owner);
79
put_device(dev);
80
mutex_unlock(&region->mutex);
81
}
82
83
/**
84
* fpga_region_program_fpga - program FPGA
85
*
86
* @region: FPGA region
87
*
88
* Program an FPGA using fpga image info (region->info).
89
* If the region has a get_bridges function, the exclusive reference for the
90
* bridges will be held if programming succeeds. This is intended to prevent
91
* reprogramming the region until the caller considers it safe to do so.
92
* The caller will need to call fpga_bridges_put() before attempting to
93
* reprogram the region.
94
*
95
* Return: 0 for success or negative error code.
96
*/
97
int fpga_region_program_fpga(struct fpga_region *region)
98
{
99
struct device *dev = &region->dev;
100
struct fpga_image_info *info = region->info;
101
int ret;
102
103
region = fpga_region_get(region);
104
if (IS_ERR(region)) {
105
dev_err(dev, "failed to get FPGA region\n");
106
return PTR_ERR(region);
107
}
108
109
ret = fpga_mgr_lock(region->mgr);
110
if (ret) {
111
dev_err(dev, "FPGA manager is busy\n");
112
goto err_put_region;
113
}
114
115
/*
116
* In some cases, we already have a list of bridges in the
117
* fpga region struct. Or we don't have any bridges.
118
*/
119
if (region->get_bridges) {
120
ret = region->get_bridges(region);
121
if (ret) {
122
dev_err(dev, "failed to get fpga region bridges\n");
123
goto err_unlock_mgr;
124
}
125
}
126
127
ret = fpga_bridges_disable(&region->bridge_list);
128
if (ret) {
129
dev_err(dev, "failed to disable bridges\n");
130
goto err_put_br;
131
}
132
133
ret = fpga_mgr_load(region->mgr, info);
134
if (ret) {
135
dev_err(dev, "failed to load FPGA image\n");
136
goto err_put_br;
137
}
138
139
ret = fpga_bridges_enable(&region->bridge_list);
140
if (ret) {
141
dev_err(dev, "failed to enable region bridges\n");
142
goto err_put_br;
143
}
144
145
fpga_mgr_unlock(region->mgr);
146
fpga_region_put(region);
147
148
return 0;
149
150
err_put_br:
151
if (region->get_bridges)
152
fpga_bridges_put(&region->bridge_list);
153
err_unlock_mgr:
154
fpga_mgr_unlock(region->mgr);
155
err_put_region:
156
fpga_region_put(region);
157
158
return ret;
159
}
160
EXPORT_SYMBOL_GPL(fpga_region_program_fpga);
161
162
static ssize_t compat_id_show(struct device *dev,
163
struct device_attribute *attr, char *buf)
164
{
165
struct fpga_region *region = to_fpga_region(dev);
166
167
if (!region->compat_id)
168
return -ENOENT;
169
170
return sprintf(buf, "%016llx%016llx\n",
171
(unsigned long long)region->compat_id->id_h,
172
(unsigned long long)region->compat_id->id_l);
173
}
174
175
static DEVICE_ATTR_RO(compat_id);
176
177
static struct attribute *fpga_region_attrs[] = {
178
&dev_attr_compat_id.attr,
179
NULL,
180
};
181
ATTRIBUTE_GROUPS(fpga_region);
182
183
/**
184
* __fpga_region_register_full - create and register an FPGA Region device
185
* @parent: device parent
186
* @info: parameters for FPGA Region
187
* @owner: module containing the get_bridges function
188
*
189
* Return: struct fpga_region or ERR_PTR()
190
*/
191
struct fpga_region *
192
__fpga_region_register_full(struct device *parent, const struct fpga_region_info *info,
193
struct module *owner)
194
{
195
struct fpga_region *region;
196
int id, ret = 0;
197
198
if (!info) {
199
dev_err(parent,
200
"Attempt to register without required info structure\n");
201
return ERR_PTR(-EINVAL);
202
}
203
204
region = kzalloc(sizeof(*region), GFP_KERNEL);
205
if (!region)
206
return ERR_PTR(-ENOMEM);
207
208
id = ida_alloc(&fpga_region_ida, GFP_KERNEL);
209
if (id < 0) {
210
ret = id;
211
goto err_free;
212
}
213
214
region->mgr = info->mgr;
215
region->compat_id = info->compat_id;
216
region->priv = info->priv;
217
region->get_bridges = info->get_bridges;
218
region->ops_owner = owner;
219
220
mutex_init(&region->mutex);
221
INIT_LIST_HEAD(&region->bridge_list);
222
223
region->dev.class = &fpga_region_class;
224
region->dev.parent = parent;
225
region->dev.of_node = parent->of_node;
226
region->dev.id = id;
227
228
ret = dev_set_name(&region->dev, "region%d", id);
229
if (ret)
230
goto err_remove;
231
232
ret = device_register(&region->dev);
233
if (ret) {
234
put_device(&region->dev);
235
return ERR_PTR(ret);
236
}
237
238
return region;
239
240
err_remove:
241
ida_free(&fpga_region_ida, id);
242
err_free:
243
kfree(region);
244
245
return ERR_PTR(ret);
246
}
247
EXPORT_SYMBOL_GPL(__fpga_region_register_full);
248
249
/**
250
* __fpga_region_register - create and register an FPGA Region device
251
* @parent: device parent
252
* @mgr: manager that programs this region
253
* @get_bridges: optional function to get bridges to a list
254
* @owner: module containing the get_bridges function
255
*
256
* This simple version of the register function should be sufficient for most users.
257
* The fpga_region_register_full() function is available for users that need to
258
* pass additional, optional parameters.
259
*
260
* Return: struct fpga_region or ERR_PTR()
261
*/
262
struct fpga_region *
263
__fpga_region_register(struct device *parent, struct fpga_manager *mgr,
264
int (*get_bridges)(struct fpga_region *), struct module *owner)
265
{
266
struct fpga_region_info info = { 0 };
267
268
info.mgr = mgr;
269
info.get_bridges = get_bridges;
270
271
return __fpga_region_register_full(parent, &info, owner);
272
}
273
EXPORT_SYMBOL_GPL(__fpga_region_register);
274
275
/**
276
* fpga_region_unregister - unregister an FPGA region
277
* @region: FPGA region
278
*
279
* This function is intended for use in an FPGA region driver's remove function.
280
*/
281
void fpga_region_unregister(struct fpga_region *region)
282
{
283
device_unregister(&region->dev);
284
}
285
EXPORT_SYMBOL_GPL(fpga_region_unregister);
286
287
static void fpga_region_dev_release(struct device *dev)
288
{
289
struct fpga_region *region = to_fpga_region(dev);
290
291
ida_free(&fpga_region_ida, region->dev.id);
292
kfree(region);
293
}
294
295
static const struct class fpga_region_class = {
296
.name = "fpga_region",
297
.dev_groups = fpga_region_groups,
298
.dev_release = fpga_region_dev_release,
299
};
300
301
/**
302
* fpga_region_init - creates the fpga_region class.
303
*
304
* Return: 0 on success or ERR_PTR() on error.
305
*/
306
static int __init fpga_region_init(void)
307
{
308
return class_register(&fpga_region_class);
309
}
310
311
static void __exit fpga_region_exit(void)
312
{
313
class_unregister(&fpga_region_class);
314
ida_destroy(&fpga_region_ida);
315
}
316
317
subsys_initcall(fpga_region_init);
318
module_exit(fpga_region_exit);
319
320
MODULE_DESCRIPTION("FPGA Region");
321
MODULE_AUTHOR("Alan Tull <[email protected]>");
322
MODULE_LICENSE("GPL v2");
323
324