linux/drivers/fpga/dfl-fme-main.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for FPGA Management Engine (FME)
   4 *
   5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
   6 *
   7 * Authors:
   8 *   Kang Luwei <luwei.kang@intel.com>
   9 *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
  10 *   Joseph Grecco <joe.grecco@intel.com>
  11 *   Enno Luebbers <enno.luebbers@intel.com>
  12 *   Tim Whisonant <tim.whisonant@intel.com>
  13 *   Ananda Ravuri <ananda.ravuri@intel.com>
  14 *   Henry Mitchel <henry.mitchel@intel.com>
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/fpga-dfl.h>
  20
  21#include "dfl.h"
  22#include "dfl-fme.h"
  23
  24static ssize_t ports_num_show(struct device *dev,
  25                              struct device_attribute *attr, char *buf)
  26{
  27        void __iomem *base;
  28        u64 v;
  29
  30        base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
  31
  32        v = readq(base + FME_HDR_CAP);
  33
  34        return scnprintf(buf, PAGE_SIZE, "%u\n",
  35                         (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v));
  36}
  37static DEVICE_ATTR_RO(ports_num);
  38
  39/*
  40 * Bitstream (static FPGA region) identifier number. It contains the
  41 * detailed version and other information of this static FPGA region.
  42 */
  43static ssize_t bitstream_id_show(struct device *dev,
  44                                 struct device_attribute *attr, char *buf)
  45{
  46        void __iomem *base;
  47        u64 v;
  48
  49        base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
  50
  51        v = readq(base + FME_HDR_BITSTREAM_ID);
  52
  53        return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
  54}
  55static DEVICE_ATTR_RO(bitstream_id);
  56
  57/*
  58 * Bitstream (static FPGA region) meta data. It contains the synthesis
  59 * date, seed and other information of this static FPGA region.
  60 */
  61static ssize_t bitstream_metadata_show(struct device *dev,
  62                                       struct device_attribute *attr, char *buf)
  63{
  64        void __iomem *base;
  65        u64 v;
  66
  67        base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
  68
  69        v = readq(base + FME_HDR_BITSTREAM_MD);
  70
  71        return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
  72}
  73static DEVICE_ATTR_RO(bitstream_metadata);
  74
  75static const struct attribute *fme_hdr_attrs[] = {
  76        &dev_attr_ports_num.attr,
  77        &dev_attr_bitstream_id.attr,
  78        &dev_attr_bitstream_metadata.attr,
  79        NULL,
  80};
  81
  82static int fme_hdr_init(struct platform_device *pdev,
  83                        struct dfl_feature *feature)
  84{
  85        void __iomem *base = feature->ioaddr;
  86        int ret;
  87
  88        dev_dbg(&pdev->dev, "FME HDR Init.\n");
  89        dev_dbg(&pdev->dev, "FME cap %llx.\n",
  90                (unsigned long long)readq(base + FME_HDR_CAP));
  91
  92        ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs);
  93        if (ret)
  94                return ret;
  95
  96        return 0;
  97}
  98
  99static void fme_hdr_uinit(struct platform_device *pdev,
 100                          struct dfl_feature *feature)
 101{
 102        dev_dbg(&pdev->dev, "FME HDR UInit.\n");
 103        sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs);
 104}
 105
 106static const struct dfl_feature_ops fme_hdr_ops = {
 107        .init = fme_hdr_init,
 108        .uinit = fme_hdr_uinit,
 109};
 110
 111static struct dfl_feature_driver fme_feature_drvs[] = {
 112        {
 113                .id = FME_FEATURE_ID_HEADER,
 114                .ops = &fme_hdr_ops,
 115        },
 116        {
 117                .id = FME_FEATURE_ID_PR_MGMT,
 118                .ops = &pr_mgmt_ops,
 119        },
 120        {
 121                .ops = NULL,
 122        },
 123};
 124
 125static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
 126                                      unsigned long arg)
 127{
 128        /* No extension support for now */
 129        return 0;
 130}
 131
 132static int fme_open(struct inode *inode, struct file *filp)
 133{
 134        struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode);
 135        struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev);
 136        int ret;
 137
 138        if (WARN_ON(!pdata))
 139                return -ENODEV;
 140
 141        ret = dfl_feature_dev_use_begin(pdata);
 142        if (ret)
 143                return ret;
 144
 145        dev_dbg(&fdev->dev, "Device File Open\n");
 146        filp->private_data = pdata;
 147
 148        return 0;
 149}
 150
 151static int fme_release(struct inode *inode, struct file *filp)
 152{
 153        struct dfl_feature_platform_data *pdata = filp->private_data;
 154        struct platform_device *pdev = pdata->dev;
 155
 156        dev_dbg(&pdev->dev, "Device File Release\n");
 157        dfl_feature_dev_use_end(pdata);
 158
 159        return 0;
 160}
 161
 162static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 163{
 164        struct dfl_feature_platform_data *pdata = filp->private_data;
 165        struct platform_device *pdev = pdata->dev;
 166        struct dfl_feature *f;
 167        long ret;
 168
 169        dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd);
 170
 171        switch (cmd) {
 172        case DFL_FPGA_GET_API_VERSION:
 173                return DFL_FPGA_API_VERSION;
 174        case DFL_FPGA_CHECK_EXTENSION:
 175                return fme_ioctl_check_extension(pdata, arg);
 176        default:
 177                /*
 178                 * Let sub-feature's ioctl function to handle the cmd.
 179                 * Sub-feature's ioctl returns -ENODEV when cmd is not
 180                 * handled in this sub feature, and returns 0 or other
 181                 * error code if cmd is handled.
 182                 */
 183                dfl_fpga_dev_for_each_feature(pdata, f) {
 184                        if (f->ops && f->ops->ioctl) {
 185                                ret = f->ops->ioctl(pdev, f, cmd, arg);
 186                                if (ret != -ENODEV)
 187                                        return ret;
 188                        }
 189                }
 190        }
 191
 192        return -EINVAL;
 193}
 194
 195static int fme_dev_init(struct platform_device *pdev)
 196{
 197        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 198        struct dfl_fme *fme;
 199
 200        fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL);
 201        if (!fme)
 202                return -ENOMEM;
 203
 204        fme->pdata = pdata;
 205
 206        mutex_lock(&pdata->lock);
 207        dfl_fpga_pdata_set_private(pdata, fme);
 208        mutex_unlock(&pdata->lock);
 209
 210        return 0;
 211}
 212
 213static void fme_dev_destroy(struct platform_device *pdev)
 214{
 215        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 216        struct dfl_fme *fme;
 217
 218        mutex_lock(&pdata->lock);
 219        fme = dfl_fpga_pdata_get_private(pdata);
 220        dfl_fpga_pdata_set_private(pdata, NULL);
 221        mutex_unlock(&pdata->lock);
 222}
 223
 224static const struct file_operations fme_fops = {
 225        .owner          = THIS_MODULE,
 226        .open           = fme_open,
 227        .release        = fme_release,
 228        .unlocked_ioctl = fme_ioctl,
 229};
 230
 231static int fme_probe(struct platform_device *pdev)
 232{
 233        int ret;
 234
 235        ret = fme_dev_init(pdev);
 236        if (ret)
 237                goto exit;
 238
 239        ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
 240        if (ret)
 241                goto dev_destroy;
 242
 243        ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
 244        if (ret)
 245                goto feature_uinit;
 246
 247        return 0;
 248
 249feature_uinit:
 250        dfl_fpga_dev_feature_uinit(pdev);
 251dev_destroy:
 252        fme_dev_destroy(pdev);
 253exit:
 254        return ret;
 255}
 256
 257static int fme_remove(struct platform_device *pdev)
 258{
 259        dfl_fpga_dev_ops_unregister(pdev);
 260        dfl_fpga_dev_feature_uinit(pdev);
 261        fme_dev_destroy(pdev);
 262
 263        return 0;
 264}
 265
 266static struct platform_driver fme_driver = {
 267        .driver = {
 268                .name    = DFL_FPGA_FEATURE_DEV_FME,
 269        },
 270        .probe   = fme_probe,
 271        .remove  = fme_remove,
 272};
 273
 274module_platform_driver(fme_driver);
 275
 276MODULE_DESCRIPTION("FPGA Management Engine driver");
 277MODULE_AUTHOR("Intel Corporation");
 278MODULE_LICENSE("GPL v2");
 279MODULE_ALIAS("platform:dfl-fme");
 280