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 = ®ion->dev; 49 50 if (!mutex_trylock(®ion->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(®ion->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 = ®ion->dev; 75 76 dev_dbg(dev, "put\n"); 77 78 module_put(region->ops_owner); 79 put_device(dev); 80 mutex_unlock(®ion->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 = ®ion->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(®ion->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(®ion->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(®ion->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(®ion->mutex); 221 INIT_LIST_HEAD(®ion->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(®ion->dev, "region%d", id); 229 if (ret) 230 goto err_remove; 231 232 ret = device_register(®ion->dev); 233 if (ret) { 234 put_device(®ion->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(®ion->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 <atull@kernel.org>"); 322 MODULE_LICENSE("GPL v2"); 323