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