diff options
Diffstat (limited to 'drivers/fpga/fpga-region.c')
-rw-r--r-- | drivers/fpga/fpga-region.c | 91 |
1 files changed, 64 insertions, 27 deletions
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index edab2a2e03ef..6d214d75c7be 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -1,22 +1,10 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * FPGA Region - Device Tree support for FPGA programming under Linux | 3 | * FPGA Region - Device Tree support for FPGA programming under Linux |
3 | * | 4 | * |
4 | * Copyright (C) 2013-2016 Altera Corporation | 5 | * Copyright (C) 2013-2016 Altera Corporation |
5 | * Copyright (C) 2017 Intel Corporation | 6 | * Copyright (C) 2017 Intel Corporation |
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | 7 | */ |
19 | |||
20 | #include <linux/fpga/fpga-bridge.h> | 8 | #include <linux/fpga/fpga-bridge.h> |
21 | #include <linux/fpga/fpga-mgr.h> | 9 | #include <linux/fpga/fpga-mgr.h> |
22 | #include <linux/fpga/fpga-region.h> | 10 | #include <linux/fpga/fpga-region.h> |
@@ -93,8 +81,16 @@ static void fpga_region_put(struct fpga_region *region) | |||
93 | 81 | ||
94 | /** | 82 | /** |
95 | * fpga_region_program_fpga - program FPGA | 83 | * fpga_region_program_fpga - program FPGA |
84 | * | ||
96 | * @region: FPGA region | 85 | * @region: FPGA region |
86 | * | ||
97 | * Program an FPGA using fpga image info (region->info). | 87 | * Program an FPGA using fpga image info (region->info). |
88 | * If the region has a get_bridges function, the exclusive reference for the | ||
89 | * bridges will be held if programming succeeds. This is intended to prevent | ||
90 | * reprogramming the region until the caller considers it safe to do so. | ||
91 | * The caller will need to call fpga_bridges_put() before attempting to | ||
92 | * reprogram the region. | ||
93 | * | ||
98 | * Return 0 for success or negative error code. | 94 | * Return 0 for success or negative error code. |
99 | */ | 95 | */ |
100 | int fpga_region_program_fpga(struct fpga_region *region) | 96 | int fpga_region_program_fpga(struct fpga_region *region) |
@@ -162,45 +158,86 @@ err_put_region: | |||
162 | } | 158 | } |
163 | EXPORT_SYMBOL_GPL(fpga_region_program_fpga); | 159 | EXPORT_SYMBOL_GPL(fpga_region_program_fpga); |
164 | 160 | ||
165 | int fpga_region_register(struct device *dev, struct fpga_region *region) | 161 | /** |
162 | * fpga_region_create - alloc and init a struct fpga_region | ||
163 | * @dev: device parent | ||
164 | * @mgr: manager that programs this region | ||
165 | * @get_bridges: optional function to get bridges to a list | ||
166 | * | ||
167 | * Return: struct fpga_region or NULL | ||
168 | */ | ||
169 | struct fpga_region | ||
170 | *fpga_region_create(struct device *dev, | ||
171 | struct fpga_manager *mgr, | ||
172 | int (*get_bridges)(struct fpga_region *)) | ||
166 | { | 173 | { |
174 | struct fpga_region *region; | ||
167 | int id, ret = 0; | 175 | int id, ret = 0; |
168 | 176 | ||
177 | region = kzalloc(sizeof(*region), GFP_KERNEL); | ||
178 | if (!region) | ||
179 | return NULL; | ||
180 | |||
169 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); | 181 | id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); |
170 | if (id < 0) | 182 | if (id < 0) |
171 | return id; | 183 | goto err_free; |
172 | 184 | ||
185 | region->mgr = mgr; | ||
186 | region->get_bridges = get_bridges; | ||
173 | mutex_init(®ion->mutex); | 187 | mutex_init(®ion->mutex); |
174 | INIT_LIST_HEAD(®ion->bridge_list); | 188 | INIT_LIST_HEAD(®ion->bridge_list); |
189 | |||
175 | device_initialize(®ion->dev); | 190 | device_initialize(®ion->dev); |
176 | region->dev.groups = region->groups; | ||
177 | region->dev.class = fpga_region_class; | 191 | region->dev.class = fpga_region_class; |
178 | region->dev.parent = dev; | 192 | region->dev.parent = dev; |
179 | region->dev.of_node = dev->of_node; | 193 | region->dev.of_node = dev->of_node; |
180 | region->dev.id = id; | 194 | region->dev.id = id; |
181 | dev_set_drvdata(dev, region); | ||
182 | 195 | ||
183 | ret = dev_set_name(®ion->dev, "region%d", id); | 196 | ret = dev_set_name(®ion->dev, "region%d", id); |
184 | if (ret) | 197 | if (ret) |
185 | goto err_remove; | 198 | goto err_remove; |
186 | 199 | ||
187 | ret = device_add(®ion->dev); | 200 | return region; |
188 | if (ret) | ||
189 | goto err_remove; | ||
190 | |||
191 | return 0; | ||
192 | 201 | ||
193 | err_remove: | 202 | err_remove: |
194 | ida_simple_remove(&fpga_region_ida, id); | 203 | ida_simple_remove(&fpga_region_ida, id); |
195 | return ret; | 204 | err_free: |
205 | kfree(region); | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(fpga_region_create); | ||
210 | |||
211 | /** | ||
212 | * fpga_region_free - free a struct fpga_region | ||
213 | * @region: FPGA region created by fpga_region_create | ||
214 | */ | ||
215 | void fpga_region_free(struct fpga_region *region) | ||
216 | { | ||
217 | ida_simple_remove(&fpga_region_ida, region->dev.id); | ||
218 | kfree(region); | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(fpga_region_free); | ||
221 | |||
222 | /** | ||
223 | * fpga_region_register - register a FPGA region | ||
224 | * @region: FPGA region created by fpga_region_create | ||
225 | * Return: 0 or -errno | ||
226 | */ | ||
227 | int fpga_region_register(struct fpga_region *region) | ||
228 | { | ||
229 | return device_add(®ion->dev); | ||
230 | |||
196 | } | 231 | } |
197 | EXPORT_SYMBOL_GPL(fpga_region_register); | 232 | EXPORT_SYMBOL_GPL(fpga_region_register); |
198 | 233 | ||
199 | int fpga_region_unregister(struct fpga_region *region) | 234 | /** |
235 | * fpga_region_unregister - unregister and free a FPGA region | ||
236 | * @region: FPGA region | ||
237 | */ | ||
238 | void fpga_region_unregister(struct fpga_region *region) | ||
200 | { | 239 | { |
201 | device_unregister(®ion->dev); | 240 | device_unregister(®ion->dev); |
202 | |||
203 | return 0; | ||
204 | } | 241 | } |
205 | EXPORT_SYMBOL_GPL(fpga_region_unregister); | 242 | EXPORT_SYMBOL_GPL(fpga_region_unregister); |
206 | 243 | ||
@@ -208,7 +245,7 @@ static void fpga_region_dev_release(struct device *dev) | |||
208 | { | 245 | { |
209 | struct fpga_region *region = to_fpga_region(dev); | 246 | struct fpga_region *region = to_fpga_region(dev); |
210 | 247 | ||
211 | ida_simple_remove(&fpga_region_ida, region->dev.id); | 248 | fpga_region_free(region); |
212 | } | 249 | } |
213 | 250 | ||
214 | /** | 251 | /** |