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(dev->parent->driver->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(dev->parent->driver->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 * 188 * Return: struct fpga_region or ERR_PTR() 189 */ 190 struct fpga_region * 191 fpga_region_register_full(struct device *parent, const struct fpga_region_info *info) 192 { 193 struct fpga_region *region; 194 int id, ret = 0; 195 196 if (!info) { 197 dev_err(parent, 198 "Attempt to register without required info structure\n"); 199 return ERR_PTR(-EINVAL); 200 } 201 202 region = kzalloc(sizeof(*region), GFP_KERNEL); 203 if (!region) 204 return ERR_PTR(-ENOMEM); 205 206 id = ida_alloc(&fpga_region_ida, GFP_KERNEL); 207 if (id < 0) { 208 ret = id; 209 goto err_free; 210 } 211 212 region->mgr = info->mgr; 213 region->compat_id = info->compat_id; 214 region->priv = info->priv; 215 region->get_bridges = info->get_bridges; 216 217 mutex_init(®ion->mutex); 218 INIT_LIST_HEAD(®ion->bridge_list); 219 220 region->dev.class = &fpga_region_class; 221 region->dev.parent = parent; 222 region->dev.of_node = parent->of_node; 223 region->dev.id = id; 224 225 ret = dev_set_name(®ion->dev, "region%d", id); 226 if (ret) 227 goto err_remove; 228 229 ret = device_register(®ion->dev); 230 if (ret) { 231 put_device(®ion->dev); 232 return ERR_PTR(ret); 233 } 234 235 return region; 236 237 err_remove: 238 ida_free(&fpga_region_ida, id); 239 err_free: 240 kfree(region); 241 242 return ERR_PTR(ret); 243 } 244 EXPORT_SYMBOL_GPL(fpga_region_register_full); 245 246 /** 247 * fpga_region_register - create and register an FPGA Region device 248 * @parent: device parent 249 * @mgr: manager that programs this region 250 * @get_bridges: optional function to get bridges to a list 251 * 252 * This simple version of the register function should be sufficient for most users. 253 * The fpga_region_register_full() function is available for users that need to 254 * pass additional, optional parameters. 255 * 256 * Return: struct fpga_region or ERR_PTR() 257 */ 258 struct fpga_region * 259 fpga_region_register(struct device *parent, struct fpga_manager *mgr, 260 int (*get_bridges)(struct fpga_region *)) 261 { 262 struct fpga_region_info info = { 0 }; 263 264 info.mgr = mgr; 265 info.get_bridges = get_bridges; 266 267 return fpga_region_register_full(parent, &info); 268 } 269 EXPORT_SYMBOL_GPL(fpga_region_register); 270 271 /** 272 * fpga_region_unregister - unregister an FPGA region 273 * @region: FPGA region 274 * 275 * This function is intended for use in an FPGA region driver's remove function. 276 */ 277 void fpga_region_unregister(struct fpga_region *region) 278 { 279 device_unregister(®ion->dev); 280 } 281 EXPORT_SYMBOL_GPL(fpga_region_unregister); 282 283 static void fpga_region_dev_release(struct device *dev) 284 { 285 struct fpga_region *region = to_fpga_region(dev); 286 287 ida_free(&fpga_region_ida, region->dev.id); 288 kfree(region); 289 } 290 291 static const struct class fpga_region_class = { 292 .name = "fpga_region", 293 .dev_groups = fpga_region_groups, 294 .dev_release = fpga_region_dev_release, 295 }; 296 297 /** 298 * fpga_region_init - creates the fpga_region class. 299 * 300 * Return: 0 on success or ERR_PTR() on error. 301 */ 302 static int __init fpga_region_init(void) 303 { 304 return class_register(&fpga_region_class); 305 } 306 307 static void __exit fpga_region_exit(void) 308 { 309 class_unregister(&fpga_region_class); 310 ida_destroy(&fpga_region_ida); 311 } 312 313 subsys_initcall(fpga_region_init); 314 module_exit(fpga_region_exit); 315 316 MODULE_DESCRIPTION("FPGA Region"); 317 MODULE_AUTHOR("Alan Tull <atull@kernel.org>"); 318 MODULE_LICENSE("GPL v2"); 319