linux/drivers/fpga/fpga-region.c
<<
>>
Prefs
   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
  18static DEFINE_IDA(fpga_region_ida);
  19static struct class *fpga_region_class;
  20
  21struct fpga_region *fpga_region_class_find(
  22        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}
  33EXPORT_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 fpga_region struct if successful.
  42 * Return -EBUSY if someone already has a reference to the region.
  43 * Return -ENODEV if @np is not an FPGA Region.
  44 */
  45static struct fpga_region *fpga_region_get(struct fpga_region *region)
  46{
  47        struct device *dev = &region->dev;
  48
  49        if (!mutex_trylock(&region->mutex)) {
  50                dev_dbg(dev, "%s: FPGA Region already in use\n", __func__);
  51                return ERR_PTR(-EBUSY);
  52        }
  53
  54        get_device(dev);
  55        if (!try_module_get(dev->parent->driver->owner)) {
  56                put_device(dev);
  57                mutex_unlock(&region->mutex);
  58                return ERR_PTR(-ENODEV);
  59        }
  60
  61        dev_dbg(dev, "get\n");
  62
  63        return region;
  64}
  65
  66/**
  67 * fpga_region_put - release a reference to a region
  68 *
  69 * @region: FPGA region
  70 */
  71static void fpga_region_put(struct fpga_region *region)
  72{
  73        struct device *dev = &region->dev;
  74
  75        dev_dbg(dev, "put\n");
  76
  77        module_put(dev->parent->driver->owner);
  78        put_device(dev);
  79        mutex_unlock(&region->mutex);
  80}
  81
  82/**
  83 * fpga_region_program_fpga - program FPGA
  84 *
  85 * @region: FPGA region
  86 *
  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 *
  94 * Return 0 for success or negative error code.
  95 */
  96int fpga_region_program_fpga(struct fpga_region *region)
  97{
  98        struct device *dev = &region->dev;
  99        struct fpga_image_info *info = region->info;
 100        int ret;
 101
 102        region = fpga_region_get(region);
 103        if (IS_ERR(region)) {
 104                dev_err(dev, "failed to get FPGA region\n");
 105                return PTR_ERR(region);
 106        }
 107
 108        ret = fpga_mgr_lock(region->mgr);
 109        if (ret) {
 110                dev_err(dev, "FPGA manager is busy\n");
 111                goto err_put_region;
 112        }
 113
 114        /*
 115         * In some cases, we already have a list of bridges in the
 116         * fpga region struct.  Or we don't have any bridges.
 117         */
 118        if (region->get_bridges) {
 119                ret = region->get_bridges(region);
 120                if (ret) {
 121                        dev_err(dev, "failed to get fpga region bridges\n");
 122                        goto err_unlock_mgr;
 123                }
 124        }
 125
 126        ret = fpga_bridges_disable(&region->bridge_list);
 127        if (ret) {
 128                dev_err(dev, "failed to disable bridges\n");
 129                goto err_put_br;
 130        }
 131
 132        ret = fpga_mgr_load(region->mgr, info);
 133        if (ret) {
 134                dev_err(dev, "failed to load FPGA image\n");
 135                goto err_put_br;
 136        }
 137
 138        ret = fpga_bridges_enable(&region->bridge_list);
 139        if (ret) {
 140                dev_err(dev, "failed to enable region bridges\n");
 141                goto err_put_br;
 142        }
 143
 144        fpga_mgr_unlock(region->mgr);
 145        fpga_region_put(region);
 146
 147        return 0;
 148
 149err_put_br:
 150        if (region->get_bridges)
 151                fpga_bridges_put(&region->bridge_list);
 152err_unlock_mgr:
 153        fpga_mgr_unlock(region->mgr);
 154err_put_region:
 155        fpga_region_put(region);
 156
 157        return ret;
 158}
 159EXPORT_SYMBOL_GPL(fpga_region_program_fpga);
 160
 161static ssize_t compat_id_show(struct device *dev,
 162                              struct device_attribute *attr, char *buf)
 163{
 164        struct fpga_region *region = to_fpga_region(dev);
 165
 166        if (!region->compat_id)
 167                return -ENOENT;
 168
 169        return sprintf(buf, "%016llx%016llx\n",
 170                       (unsigned long long)region->compat_id->id_h,
 171                       (unsigned long long)region->compat_id->id_l);
 172}
 173
 174static DEVICE_ATTR_RO(compat_id);
 175
 176static struct attribute *fpga_region_attrs[] = {
 177        &dev_attr_compat_id.attr,
 178        NULL,
 179};
 180ATTRIBUTE_GROUPS(fpga_region);
 181
 182/**
 183 * fpga_region_create - alloc and init a struct fpga_region
 184 * @parent: device parent
 185 * @mgr: manager that programs this region
 186 * @get_bridges: optional function to get bridges to a list
 187 *
 188 * The caller of this function is responsible for freeing the resulting region
 189 * struct with fpga_region_free().  Using devm_fpga_region_create() instead is
 190 * recommended.
 191 *
 192 * Return: struct fpga_region or NULL
 193 */
 194struct fpga_region
 195*fpga_region_create(struct device *parent,
 196                    struct fpga_manager *mgr,
 197                    int (*get_bridges)(struct fpga_region *))
 198{
 199        struct fpga_region *region;
 200        int id, ret = 0;
 201
 202        region = kzalloc(sizeof(*region), GFP_KERNEL);
 203        if (!region)
 204                return NULL;
 205
 206        id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL);
 207        if (id < 0)
 208                goto err_free;
 209
 210        region->mgr = mgr;
 211        region->get_bridges = get_bridges;
 212        mutex_init(&region->mutex);
 213        INIT_LIST_HEAD(&region->bridge_list);
 214
 215        device_initialize(&region->dev);
 216        region->dev.class = fpga_region_class;
 217        region->dev.parent = parent;
 218        region->dev.of_node = parent->of_node;
 219        region->dev.id = id;
 220
 221        ret = dev_set_name(&region->dev, "region%d", id);
 222        if (ret)
 223                goto err_remove;
 224
 225        return region;
 226
 227err_remove:
 228        ida_simple_remove(&fpga_region_ida, id);
 229err_free:
 230        kfree(region);
 231
 232        return NULL;
 233}
 234EXPORT_SYMBOL_GPL(fpga_region_create);
 235
 236/**
 237 * fpga_region_free - free an FPGA region created by fpga_region_create()
 238 * @region: FPGA region
 239 */
 240void fpga_region_free(struct fpga_region *region)
 241{
 242        ida_simple_remove(&fpga_region_ida, region->dev.id);
 243        kfree(region);
 244}
 245EXPORT_SYMBOL_GPL(fpga_region_free);
 246
 247static void devm_fpga_region_release(struct device *dev, void *res)
 248{
 249        struct fpga_region *region = *(struct fpga_region **)res;
 250
 251        fpga_region_free(region);
 252}
 253
 254/**
 255 * devm_fpga_region_create - create and initialize a managed FPGA region struct
 256 * @parent: device parent
 257 * @mgr: manager that programs this region
 258 * @get_bridges: optional function to get bridges to a list
 259 *
 260 * This function is intended for use in an FPGA region driver's probe function.
 261 * After the region driver creates the region struct with
 262 * devm_fpga_region_create(), it should register it with fpga_region_register().
 263 * The region driver's remove function should call fpga_region_unregister().
 264 * The region struct allocated with this function will be freed automatically on
 265 * driver detach.  This includes the case of a probe function returning error
 266 * before calling fpga_region_register(), the struct will still get cleaned up.
 267 *
 268 * Return: struct fpga_region or NULL
 269 */
 270struct fpga_region
 271*devm_fpga_region_create(struct device *parent,
 272                         struct fpga_manager *mgr,
 273                         int (*get_bridges)(struct fpga_region *))
 274{
 275        struct fpga_region **ptr, *region;
 276
 277        ptr = devres_alloc(devm_fpga_region_release, sizeof(*ptr), GFP_KERNEL);
 278        if (!ptr)
 279                return NULL;
 280
 281        region = fpga_region_create(parent, mgr, get_bridges);
 282        if (!region) {
 283                devres_free(ptr);
 284        } else {
 285                *ptr = region;
 286                devres_add(parent, ptr);
 287        }
 288
 289        return region;
 290}
 291EXPORT_SYMBOL_GPL(devm_fpga_region_create);
 292
 293/**
 294 * fpga_region_register - register an FPGA region
 295 * @region: FPGA region
 296 *
 297 * Return: 0 or -errno
 298 */
 299int fpga_region_register(struct fpga_region *region)
 300{
 301        return device_add(&region->dev);
 302}
 303EXPORT_SYMBOL_GPL(fpga_region_register);
 304
 305/**
 306 * fpga_region_unregister - unregister an FPGA region
 307 * @region: FPGA region
 308 *
 309 * This function is intended for use in an FPGA region driver's remove function.
 310 */
 311void fpga_region_unregister(struct fpga_region *region)
 312{
 313        device_unregister(&region->dev);
 314}
 315EXPORT_SYMBOL_GPL(fpga_region_unregister);
 316
 317static void fpga_region_dev_release(struct device *dev)
 318{
 319}
 320
 321/**
 322 * fpga_region_init - init function for fpga_region class
 323 * Creates the fpga_region class and registers a reconfig notifier.
 324 */
 325static int __init fpga_region_init(void)
 326{
 327        fpga_region_class = class_create(THIS_MODULE, "fpga_region");
 328        if (IS_ERR(fpga_region_class))
 329                return PTR_ERR(fpga_region_class);
 330
 331        fpga_region_class->dev_groups = fpga_region_groups;
 332        fpga_region_class->dev_release = fpga_region_dev_release;
 333
 334        return 0;
 335}
 336
 337static void __exit fpga_region_exit(void)
 338{
 339        class_destroy(fpga_region_class);
 340        ida_destroy(&fpga_region_ida);
 341}
 342
 343subsys_initcall(fpga_region_init);
 344module_exit(fpga_region_exit);
 345
 346MODULE_DESCRIPTION("FPGA Region");
 347MODULE_AUTHOR("Alan Tull <atull@kernel.org>");
 348MODULE_LICENSE("GPL v2");
 349