linux/drivers/fpga/dfl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for FPGA Device Feature List (DFL) Support
   4 *
   5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
   6 *
   7 * Authors:
   8 *   Kang Luwei <luwei.kang@intel.com>
   9 *   Zhang Yi <yi.z.zhang@intel.com>
  10 *   Wu Hao <hao.wu@intel.com>
  11 *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
  12 */
  13#include <linux/module.h>
  14
  15#include "dfl.h"
  16
  17static DEFINE_MUTEX(dfl_id_mutex);
  18
  19/*
  20 * when adding a new feature dev support in DFL framework, it's required to
  21 * add a new item in enum dfl_id_type and provide related information in below
  22 * dfl_devs table which is indexed by dfl_id_type, e.g. name string used for
  23 * platform device creation (define name strings in dfl.h, as they could be
  24 * reused by platform device drivers).
  25 *
  26 * if the new feature dev needs chardev support, then it's required to add
  27 * a new item in dfl_chardevs table and configure dfl_devs[i].devt_type as
  28 * index to dfl_chardevs table. If no chardev support just set devt_type
  29 * as one invalid index (DFL_FPGA_DEVT_MAX).
  30 */
  31enum dfl_id_type {
  32        FME_ID,         /* fme id allocation and mapping */
  33        PORT_ID,        /* port id allocation and mapping */
  34        DFL_ID_MAX,
  35};
  36
  37enum dfl_fpga_devt_type {
  38        DFL_FPGA_DEVT_FME,
  39        DFL_FPGA_DEVT_PORT,
  40        DFL_FPGA_DEVT_MAX,
  41};
  42
  43static struct lock_class_key dfl_pdata_keys[DFL_ID_MAX];
  44
  45static const char *dfl_pdata_key_strings[DFL_ID_MAX] = {
  46        "dfl-fme-pdata",
  47        "dfl-port-pdata",
  48};
  49
  50/**
  51 * dfl_dev_info - dfl feature device information.
  52 * @name: name string of the feature platform device.
  53 * @dfh_id: id value in Device Feature Header (DFH) register by DFL spec.
  54 * @id: idr id of the feature dev.
  55 * @devt_type: index to dfl_chrdevs[].
  56 */
  57struct dfl_dev_info {
  58        const char *name;
  59        u32 dfh_id;
  60        struct idr id;
  61        enum dfl_fpga_devt_type devt_type;
  62};
  63
  64/* it is indexed by dfl_id_type */
  65static struct dfl_dev_info dfl_devs[] = {
  66        {.name = DFL_FPGA_FEATURE_DEV_FME, .dfh_id = DFH_ID_FIU_FME,
  67         .devt_type = DFL_FPGA_DEVT_FME},
  68        {.name = DFL_FPGA_FEATURE_DEV_PORT, .dfh_id = DFH_ID_FIU_PORT,
  69         .devt_type = DFL_FPGA_DEVT_PORT},
  70};
  71
  72/**
  73 * dfl_chardev_info - chardev information of dfl feature device
  74 * @name: nmae string of the char device.
  75 * @devt: devt of the char device.
  76 */
  77struct dfl_chardev_info {
  78        const char *name;
  79        dev_t devt;
  80};
  81
  82/* indexed by enum dfl_fpga_devt_type */
  83static struct dfl_chardev_info dfl_chrdevs[] = {
  84        {.name = DFL_FPGA_FEATURE_DEV_FME},
  85        {.name = DFL_FPGA_FEATURE_DEV_PORT},
  86};
  87
  88static void dfl_ids_init(void)
  89{
  90        int i;
  91
  92        for (i = 0; i < ARRAY_SIZE(dfl_devs); i++)
  93                idr_init(&dfl_devs[i].id);
  94}
  95
  96static void dfl_ids_destroy(void)
  97{
  98        int i;
  99
 100        for (i = 0; i < ARRAY_SIZE(dfl_devs); i++)
 101                idr_destroy(&dfl_devs[i].id);
 102}
 103
 104static int dfl_id_alloc(enum dfl_id_type type, struct device *dev)
 105{
 106        int id;
 107
 108        WARN_ON(type >= DFL_ID_MAX);
 109        mutex_lock(&dfl_id_mutex);
 110        id = idr_alloc(&dfl_devs[type].id, dev, 0, 0, GFP_KERNEL);
 111        mutex_unlock(&dfl_id_mutex);
 112
 113        return id;
 114}
 115
 116static void dfl_id_free(enum dfl_id_type type, int id)
 117{
 118        WARN_ON(type >= DFL_ID_MAX);
 119        mutex_lock(&dfl_id_mutex);
 120        idr_remove(&dfl_devs[type].id, id);
 121        mutex_unlock(&dfl_id_mutex);
 122}
 123
 124static enum dfl_id_type feature_dev_id_type(struct platform_device *pdev)
 125{
 126        int i;
 127
 128        for (i = 0; i < ARRAY_SIZE(dfl_devs); i++)
 129                if (!strcmp(dfl_devs[i].name, pdev->name))
 130                        return i;
 131
 132        return DFL_ID_MAX;
 133}
 134
 135static enum dfl_id_type dfh_id_to_type(u32 id)
 136{
 137        int i;
 138
 139        for (i = 0; i < ARRAY_SIZE(dfl_devs); i++)
 140                if (dfl_devs[i].dfh_id == id)
 141                        return i;
 142
 143        return DFL_ID_MAX;
 144}
 145
 146/*
 147 * introduce a global port_ops list, it allows port drivers to register ops
 148 * in such list, then other feature devices (e.g. FME), could use the port
 149 * functions even related port platform device is hidden. Below is one example,
 150 * in virtualization case of PCIe-based FPGA DFL device, when SRIOV is
 151 * enabled, port (and it's AFU) is turned into VF and port platform device
 152 * is hidden from system but it's still required to access port to finish FPGA
 153 * reconfiguration function in FME.
 154 */
 155
 156static DEFINE_MUTEX(dfl_port_ops_mutex);
 157static LIST_HEAD(dfl_port_ops_list);
 158
 159/**
 160 * dfl_fpga_port_ops_get - get matched port ops from the global list
 161 * @pdev: platform device to match with associated port ops.
 162 * Return: matched port ops on success, NULL otherwise.
 163 *
 164 * Please note that must dfl_fpga_port_ops_put after use the port_ops.
 165 */
 166struct dfl_fpga_port_ops *dfl_fpga_port_ops_get(struct platform_device *pdev)
 167{
 168        struct dfl_fpga_port_ops *ops = NULL;
 169
 170        mutex_lock(&dfl_port_ops_mutex);
 171        if (list_empty(&dfl_port_ops_list))
 172                goto done;
 173
 174        list_for_each_entry(ops, &dfl_port_ops_list, node) {
 175                /* match port_ops using the name of platform device */
 176                if (!strcmp(pdev->name, ops->name)) {
 177                        if (!try_module_get(ops->owner))
 178                                ops = NULL;
 179                        goto done;
 180                }
 181        }
 182
 183        ops = NULL;
 184done:
 185        mutex_unlock(&dfl_port_ops_mutex);
 186        return ops;
 187}
 188EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_get);
 189
 190/**
 191 * dfl_fpga_port_ops_put - put port ops
 192 * @ops: port ops.
 193 */
 194void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops)
 195{
 196        if (ops && ops->owner)
 197                module_put(ops->owner);
 198}
 199EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_put);
 200
 201/**
 202 * dfl_fpga_port_ops_add - add port_ops to global list
 203 * @ops: port ops to add.
 204 */
 205void dfl_fpga_port_ops_add(struct dfl_fpga_port_ops *ops)
 206{
 207        mutex_lock(&dfl_port_ops_mutex);
 208        list_add_tail(&ops->node, &dfl_port_ops_list);
 209        mutex_unlock(&dfl_port_ops_mutex);
 210}
 211EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_add);
 212
 213/**
 214 * dfl_fpga_port_ops_del - remove port_ops from global list
 215 * @ops: port ops to del.
 216 */
 217void dfl_fpga_port_ops_del(struct dfl_fpga_port_ops *ops)
 218{
 219        mutex_lock(&dfl_port_ops_mutex);
 220        list_del(&ops->node);
 221        mutex_unlock(&dfl_port_ops_mutex);
 222}
 223EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del);
 224
 225/**
 226 * dfl_fpga_check_port_id - check the port id
 227 * @pdev: port platform device.
 228 * @pport_id: port id to compare.
 229 *
 230 * Return: 1 if port device matches with given port id, otherwise 0.
 231 */
 232int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id)
 233{
 234        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 235        struct dfl_fpga_port_ops *port_ops;
 236
 237        if (pdata->id != FEATURE_DEV_ID_UNUSED)
 238                return pdata->id == *(int *)pport_id;
 239
 240        port_ops = dfl_fpga_port_ops_get(pdev);
 241        if (!port_ops || !port_ops->get_id)
 242                return 0;
 243
 244        pdata->id = port_ops->get_id(pdev);
 245        dfl_fpga_port_ops_put(port_ops);
 246
 247        return pdata->id == *(int *)pport_id;
 248}
 249EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id);
 250
 251/**
 252 * dfl_fpga_dev_feature_uinit - uinit for sub features of dfl feature device
 253 * @pdev: feature device.
 254 */
 255void dfl_fpga_dev_feature_uinit(struct platform_device *pdev)
 256{
 257        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 258        struct dfl_feature *feature;
 259
 260        dfl_fpga_dev_for_each_feature(pdata, feature)
 261                if (feature->ops) {
 262                        if (feature->ops->uinit)
 263                                feature->ops->uinit(pdev, feature);
 264                        feature->ops = NULL;
 265                }
 266}
 267EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_uinit);
 268
 269static int dfl_feature_instance_init(struct platform_device *pdev,
 270                                     struct dfl_feature_platform_data *pdata,
 271                                     struct dfl_feature *feature,
 272                                     struct dfl_feature_driver *drv)
 273{
 274        int ret = 0;
 275
 276        if (drv->ops->init) {
 277                ret = drv->ops->init(pdev, feature);
 278                if (ret)
 279                        return ret;
 280        }
 281
 282        feature->ops = drv->ops;
 283
 284        return ret;
 285}
 286
 287static bool dfl_feature_drv_match(struct dfl_feature *feature,
 288                                  struct dfl_feature_driver *driver)
 289{
 290        const struct dfl_feature_id *ids = driver->id_table;
 291
 292        if (ids) {
 293                while (ids->id) {
 294                        if (ids->id == feature->id)
 295                                return true;
 296                        ids++;
 297                }
 298        }
 299        return false;
 300}
 301
 302/**
 303 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device
 304 * @pdev: feature device.
 305 * @feature_drvs: drvs for sub features.
 306 *
 307 * This function will match sub features with given feature drvs list and
 308 * use matched drv to init related sub feature.
 309 *
 310 * Return: 0 on success, negative error code otherwise.
 311 */
 312int dfl_fpga_dev_feature_init(struct platform_device *pdev,
 313                              struct dfl_feature_driver *feature_drvs)
 314{
 315        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 316        struct dfl_feature_driver *drv = feature_drvs;
 317        struct dfl_feature *feature;
 318        int ret;
 319
 320        while (drv->ops) {
 321                dfl_fpga_dev_for_each_feature(pdata, feature) {
 322                        if (dfl_feature_drv_match(feature, drv)) {
 323                                ret = dfl_feature_instance_init(pdev, pdata,
 324                                                                feature, drv);
 325                                if (ret)
 326                                        goto exit;
 327                        }
 328                }
 329                drv++;
 330        }
 331
 332        return 0;
 333exit:
 334        dfl_fpga_dev_feature_uinit(pdev);
 335        return ret;
 336}
 337EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_init);
 338
 339static void dfl_chardev_uinit(void)
 340{
 341        int i;
 342
 343        for (i = 0; i < DFL_FPGA_DEVT_MAX; i++)
 344                if (MAJOR(dfl_chrdevs[i].devt)) {
 345                        unregister_chrdev_region(dfl_chrdevs[i].devt,
 346                                                 MINORMASK + 1);
 347                        dfl_chrdevs[i].devt = MKDEV(0, 0);
 348                }
 349}
 350
 351static int dfl_chardev_init(void)
 352{
 353        int i, ret;
 354
 355        for (i = 0; i < DFL_FPGA_DEVT_MAX; i++) {
 356                ret = alloc_chrdev_region(&dfl_chrdevs[i].devt, 0,
 357                                          MINORMASK + 1, dfl_chrdevs[i].name);
 358                if (ret)
 359                        goto exit;
 360        }
 361
 362        return 0;
 363
 364exit:
 365        dfl_chardev_uinit();
 366        return ret;
 367}
 368
 369static dev_t dfl_get_devt(enum dfl_fpga_devt_type type, int id)
 370{
 371        if (type >= DFL_FPGA_DEVT_MAX)
 372                return 0;
 373
 374        return MKDEV(MAJOR(dfl_chrdevs[type].devt), id);
 375}
 376
 377/**
 378 * dfl_fpga_dev_ops_register - register cdev ops for feature dev
 379 *
 380 * @pdev: feature dev.
 381 * @fops: file operations for feature dev's cdev.
 382 * @owner: owning module/driver.
 383 *
 384 * Return: 0 on success, negative error code otherwise.
 385 */
 386int dfl_fpga_dev_ops_register(struct platform_device *pdev,
 387                              const struct file_operations *fops,
 388                              struct module *owner)
 389{
 390        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 391
 392        cdev_init(&pdata->cdev, fops);
 393        pdata->cdev.owner = owner;
 394
 395        /*
 396         * set parent to the feature device so that its refcount is
 397         * decreased after the last refcount of cdev is gone, that
 398         * makes sure the feature device is valid during device
 399         * file's life-cycle.
 400         */
 401        pdata->cdev.kobj.parent = &pdev->dev.kobj;
 402
 403        return cdev_add(&pdata->cdev, pdev->dev.devt, 1);
 404}
 405EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_register);
 406
 407/**
 408 * dfl_fpga_dev_ops_unregister - unregister cdev ops for feature dev
 409 * @pdev: feature dev.
 410 */
 411void dfl_fpga_dev_ops_unregister(struct platform_device *pdev)
 412{
 413        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 414
 415        cdev_del(&pdata->cdev);
 416}
 417EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
 418
 419/**
 420 * struct build_feature_devs_info - info collected during feature dev build.
 421 *
 422 * @dev: device to enumerate.
 423 * @cdev: the container device for all feature devices.
 424 * @feature_dev: current feature device.
 425 * @ioaddr: header register region address of feature device in enumeration.
 426 * @sub_features: a sub features linked list for feature device in enumeration.
 427 * @feature_num: number of sub features for feature device in enumeration.
 428 */
 429struct build_feature_devs_info {
 430        struct device *dev;
 431        struct dfl_fpga_cdev *cdev;
 432        struct platform_device *feature_dev;
 433        void __iomem *ioaddr;
 434        struct list_head sub_features;
 435        int feature_num;
 436};
 437
 438/**
 439 * struct dfl_feature_info - sub feature info collected during feature dev build
 440 *
 441 * @fid: id of this sub feature.
 442 * @mmio_res: mmio resource of this sub feature.
 443 * @ioaddr: mapped base address of mmio resource.
 444 * @node: node in sub_features linked list.
 445 */
 446struct dfl_feature_info {
 447        u64 fid;
 448        struct resource mmio_res;
 449        void __iomem *ioaddr;
 450        struct list_head node;
 451};
 452
 453static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
 454                                       struct platform_device *port)
 455{
 456        struct dfl_feature_platform_data *pdata = dev_get_platdata(&port->dev);
 457
 458        mutex_lock(&cdev->lock);
 459        list_add(&pdata->node, &cdev->port_dev_list);
 460        get_device(&pdata->dev->dev);
 461        mutex_unlock(&cdev->lock);
 462}
 463
 464/*
 465 * register current feature device, it is called when we need to switch to
 466 * another feature parsing or we have parsed all features on given device
 467 * feature list.
 468 */
 469static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 470{
 471        struct platform_device *fdev = binfo->feature_dev;
 472        struct dfl_feature_platform_data *pdata;
 473        struct dfl_feature_info *finfo, *p;
 474        enum dfl_id_type type;
 475        int ret, index = 0;
 476
 477        if (!fdev)
 478                return 0;
 479
 480        type = feature_dev_id_type(fdev);
 481        if (WARN_ON_ONCE(type >= DFL_ID_MAX))
 482                return -EINVAL;
 483
 484        /*
 485         * we do not need to care for the memory which is associated with
 486         * the platform device. After calling platform_device_unregister(),
 487         * it will be automatically freed by device's release() callback,
 488         * platform_device_release().
 489         */
 490        pdata = kzalloc(dfl_feature_platform_data_size(binfo->feature_num),
 491                        GFP_KERNEL);
 492        if (!pdata)
 493                return -ENOMEM;
 494
 495        pdata->dev = fdev;
 496        pdata->num = binfo->feature_num;
 497        pdata->dfl_cdev = binfo->cdev;
 498        pdata->id = FEATURE_DEV_ID_UNUSED;
 499        mutex_init(&pdata->lock);
 500        lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
 501                                   dfl_pdata_key_strings[type]);
 502
 503        /*
 504         * the count should be initialized to 0 to make sure
 505         *__fpga_port_enable() following __fpga_port_disable()
 506         * works properly for port device.
 507         * and it should always be 0 for fme device.
 508         */
 509        WARN_ON(pdata->disable_count);
 510
 511        fdev->dev.platform_data = pdata;
 512
 513        /* each sub feature has one MMIO resource */
 514        fdev->num_resources = binfo->feature_num;
 515        fdev->resource = kcalloc(binfo->feature_num, sizeof(*fdev->resource),
 516                                 GFP_KERNEL);
 517        if (!fdev->resource)
 518                return -ENOMEM;
 519
 520        /* fill features and resource information for feature dev */
 521        list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
 522                struct dfl_feature *feature = &pdata->features[index];
 523
 524                /* save resource information for each feature */
 525                feature->id = finfo->fid;
 526                feature->resource_index = index;
 527                feature->ioaddr = finfo->ioaddr;
 528                fdev->resource[index++] = finfo->mmio_res;
 529
 530                list_del(&finfo->node);
 531                kfree(finfo);
 532        }
 533
 534        ret = platform_device_add(binfo->feature_dev);
 535        if (!ret) {
 536                if (type == PORT_ID)
 537                        dfl_fpga_cdev_add_port_dev(binfo->cdev,
 538                                                   binfo->feature_dev);
 539                else
 540                        binfo->cdev->fme_dev =
 541                                        get_device(&binfo->feature_dev->dev);
 542                /*
 543                 * reset it to avoid build_info_free() freeing their resource.
 544                 *
 545                 * The resource of successfully registered feature devices
 546                 * will be freed by platform_device_unregister(). See the
 547                 * comments in build_info_create_dev().
 548                 */
 549                binfo->feature_dev = NULL;
 550        }
 551
 552        return ret;
 553}
 554
 555static int
 556build_info_create_dev(struct build_feature_devs_info *binfo,
 557                      enum dfl_id_type type, void __iomem *ioaddr)
 558{
 559        struct platform_device *fdev;
 560        int ret;
 561
 562        if (type >= DFL_ID_MAX)
 563                return -EINVAL;
 564
 565        /* we will create a new device, commit current device first */
 566        ret = build_info_commit_dev(binfo);
 567        if (ret)
 568                return ret;
 569
 570        /*
 571         * we use -ENODEV as the initialization indicator which indicates
 572         * whether the id need to be reclaimed
 573         */
 574        fdev = platform_device_alloc(dfl_devs[type].name, -ENODEV);
 575        if (!fdev)
 576                return -ENOMEM;
 577
 578        binfo->feature_dev = fdev;
 579        binfo->feature_num = 0;
 580        binfo->ioaddr = ioaddr;
 581        INIT_LIST_HEAD(&binfo->sub_features);
 582
 583        fdev->id = dfl_id_alloc(type, &fdev->dev);
 584        if (fdev->id < 0)
 585                return fdev->id;
 586
 587        fdev->dev.parent = &binfo->cdev->region->dev;
 588        fdev->dev.devt = dfl_get_devt(dfl_devs[type].devt_type, fdev->id);
 589
 590        return 0;
 591}
 592
 593static void build_info_free(struct build_feature_devs_info *binfo)
 594{
 595        struct dfl_feature_info *finfo, *p;
 596
 597        /*
 598         * it is a valid id, free it. See comments in
 599         * build_info_create_dev()
 600         */
 601        if (binfo->feature_dev && binfo->feature_dev->id >= 0) {
 602                dfl_id_free(feature_dev_id_type(binfo->feature_dev),
 603                            binfo->feature_dev->id);
 604
 605                list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
 606                        list_del(&finfo->node);
 607                        kfree(finfo);
 608                }
 609        }
 610
 611        platform_device_put(binfo->feature_dev);
 612
 613        devm_kfree(binfo->dev, binfo);
 614}
 615
 616static inline u32 feature_size(void __iomem *start)
 617{
 618        u64 v = readq(start + DFH);
 619        u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v);
 620        /* workaround for private features with invalid size, use 4K instead */
 621        return ofst ? ofst : 4096;
 622}
 623
 624static u64 feature_id(void __iomem *start)
 625{
 626        u64 v = readq(start + DFH);
 627        u16 id = FIELD_GET(DFH_ID, v);
 628        u8 type = FIELD_GET(DFH_TYPE, v);
 629
 630        if (type == DFH_TYPE_FIU)
 631                return FEATURE_ID_FIU_HEADER;
 632        else if (type == DFH_TYPE_PRIVATE)
 633                return id;
 634        else if (type == DFH_TYPE_AFU)
 635                return FEATURE_ID_AFU;
 636
 637        WARN_ON(1);
 638        return 0;
 639}
 640
 641/*
 642 * when create sub feature instances, for private features, it doesn't need
 643 * to provide resource size and feature id as they could be read from DFH
 644 * register. For afu sub feature, its register region only contains user
 645 * defined registers, so never trust any information from it, just use the
 646 * resource size information provided by its parent FIU.
 647 */
 648static int
 649create_feature_instance(struct build_feature_devs_info *binfo,
 650                        struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst,
 651                        resource_size_t size, u64 fid)
 652{
 653        struct dfl_feature_info *finfo;
 654
 655        /* read feature size and id if inputs are invalid */
 656        size = size ? size : feature_size(dfl->ioaddr + ofst);
 657        fid = fid ? fid : feature_id(dfl->ioaddr + ofst);
 658
 659        if (dfl->len - ofst < size)
 660                return -EINVAL;
 661
 662        finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
 663        if (!finfo)
 664                return -ENOMEM;
 665
 666        finfo->fid = fid;
 667        finfo->mmio_res.start = dfl->start + ofst;
 668        finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
 669        finfo->mmio_res.flags = IORESOURCE_MEM;
 670        finfo->ioaddr = dfl->ioaddr + ofst;
 671
 672        list_add_tail(&finfo->node, &binfo->sub_features);
 673        binfo->feature_num++;
 674
 675        return 0;
 676}
 677
 678static int parse_feature_port_afu(struct build_feature_devs_info *binfo,
 679                                  struct dfl_fpga_enum_dfl *dfl,
 680                                  resource_size_t ofst)
 681{
 682        u64 v = readq(binfo->ioaddr + PORT_HDR_CAP);
 683        u32 size = FIELD_GET(PORT_CAP_MMIO_SIZE, v) << 10;
 684
 685        WARN_ON(!size);
 686
 687        return create_feature_instance(binfo, dfl, ofst, size, FEATURE_ID_AFU);
 688}
 689
 690static int parse_feature_afu(struct build_feature_devs_info *binfo,
 691                             struct dfl_fpga_enum_dfl *dfl,
 692                             resource_size_t ofst)
 693{
 694        if (!binfo->feature_dev) {
 695                dev_err(binfo->dev, "this AFU does not belong to any FIU.\n");
 696                return -EINVAL;
 697        }
 698
 699        switch (feature_dev_id_type(binfo->feature_dev)) {
 700        case PORT_ID:
 701                return parse_feature_port_afu(binfo, dfl, ofst);
 702        default:
 703                dev_info(binfo->dev, "AFU belonging to FIU %s is not supported yet.\n",
 704                         binfo->feature_dev->name);
 705        }
 706
 707        return 0;
 708}
 709
 710static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 711                             struct dfl_fpga_enum_dfl *dfl,
 712                             resource_size_t ofst)
 713{
 714        u32 id, offset;
 715        u64 v;
 716        int ret = 0;
 717
 718        v = readq(dfl->ioaddr + ofst + DFH);
 719        id = FIELD_GET(DFH_ID, v);
 720
 721        /* create platform device for dfl feature dev */
 722        ret = build_info_create_dev(binfo, dfh_id_to_type(id),
 723                                    dfl->ioaddr + ofst);
 724        if (ret)
 725                return ret;
 726
 727        ret = create_feature_instance(binfo, dfl, ofst, 0, 0);
 728        if (ret)
 729                return ret;
 730        /*
 731         * find and parse FIU's child AFU via its NEXT_AFU register.
 732         * please note that only Port has valid NEXT_AFU pointer per spec.
 733         */
 734        v = readq(dfl->ioaddr + ofst + NEXT_AFU);
 735
 736        offset = FIELD_GET(NEXT_AFU_NEXT_DFH_OFST, v);
 737        if (offset)
 738                return parse_feature_afu(binfo, dfl, ofst + offset);
 739
 740        dev_dbg(binfo->dev, "No AFUs detected on FIU %d\n", id);
 741
 742        return ret;
 743}
 744
 745static int parse_feature_private(struct build_feature_devs_info *binfo,
 746                                 struct dfl_fpga_enum_dfl *dfl,
 747                                 resource_size_t ofst)
 748{
 749        if (!binfo->feature_dev) {
 750                dev_err(binfo->dev, "the private feature %llx does not belong to any AFU.\n",
 751                        (unsigned long long)feature_id(dfl->ioaddr + ofst));
 752                return -EINVAL;
 753        }
 754
 755        return create_feature_instance(binfo, dfl, ofst, 0, 0);
 756}
 757
 758/**
 759 * parse_feature - parse a feature on given device feature list
 760 *
 761 * @binfo: build feature devices information.
 762 * @dfl: device feature list to parse
 763 * @ofst: offset to feature header on this device feature list
 764 */
 765static int parse_feature(struct build_feature_devs_info *binfo,
 766                         struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst)
 767{
 768        u64 v;
 769        u32 type;
 770
 771        v = readq(dfl->ioaddr + ofst + DFH);
 772        type = FIELD_GET(DFH_TYPE, v);
 773
 774        switch (type) {
 775        case DFH_TYPE_AFU:
 776                return parse_feature_afu(binfo, dfl, ofst);
 777        case DFH_TYPE_PRIVATE:
 778                return parse_feature_private(binfo, dfl, ofst);
 779        case DFH_TYPE_FIU:
 780                return parse_feature_fiu(binfo, dfl, ofst);
 781        default:
 782                dev_info(binfo->dev,
 783                         "Feature Type %x is not supported.\n", type);
 784        }
 785
 786        return 0;
 787}
 788
 789static int parse_feature_list(struct build_feature_devs_info *binfo,
 790                              struct dfl_fpga_enum_dfl *dfl)
 791{
 792        void __iomem *start = dfl->ioaddr;
 793        void __iomem *end = dfl->ioaddr + dfl->len;
 794        int ret = 0;
 795        u32 ofst = 0;
 796        u64 v;
 797
 798        /* walk through the device feature list via DFH's next DFH pointer. */
 799        for (; start < end; start += ofst) {
 800                if (end - start < DFH_SIZE) {
 801                        dev_err(binfo->dev, "The region is too small to contain a feature.\n");
 802                        return -EINVAL;
 803                }
 804
 805                ret = parse_feature(binfo, dfl, start - dfl->ioaddr);
 806                if (ret)
 807                        return ret;
 808
 809                v = readq(start + DFH);
 810                ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v);
 811
 812                /* stop parsing if EOL(End of List) is set or offset is 0 */
 813                if ((v & DFH_EOL) || !ofst)
 814                        break;
 815        }
 816
 817        /* commit current feature device when reach the end of list */
 818        return build_info_commit_dev(binfo);
 819}
 820
 821struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev)
 822{
 823        struct dfl_fpga_enum_info *info;
 824
 825        get_device(dev);
 826
 827        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
 828        if (!info) {
 829                put_device(dev);
 830                return NULL;
 831        }
 832
 833        info->dev = dev;
 834        INIT_LIST_HEAD(&info->dfls);
 835
 836        return info;
 837}
 838EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_alloc);
 839
 840void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
 841{
 842        struct dfl_fpga_enum_dfl *tmp, *dfl;
 843        struct device *dev;
 844
 845        if (!info)
 846                return;
 847
 848        dev = info->dev;
 849
 850        /* remove all device feature lists in the list. */
 851        list_for_each_entry_safe(dfl, tmp, &info->dfls, node) {
 852                list_del(&dfl->node);
 853                devm_kfree(dev, dfl);
 854        }
 855
 856        devm_kfree(dev, info);
 857        put_device(dev);
 858}
 859EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_free);
 860
 861/**
 862 * dfl_fpga_enum_info_add_dfl - add info of a device feature list to enum info
 863 *
 864 * @info: ptr to dfl_fpga_enum_info
 865 * @start: mmio resource address of the device feature list.
 866 * @len: mmio resource length of the device feature list.
 867 * @ioaddr: mapped mmio resource address of the device feature list.
 868 *
 869 * One FPGA device may have one or more Device Feature Lists (DFLs), use this
 870 * function to add information of each DFL to common data structure for next
 871 * step enumeration.
 872 *
 873 * Return: 0 on success, negative error code otherwise.
 874 */
 875int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
 876                               resource_size_t start, resource_size_t len,
 877                               void __iomem *ioaddr)
 878{
 879        struct dfl_fpga_enum_dfl *dfl;
 880
 881        dfl = devm_kzalloc(info->dev, sizeof(*dfl), GFP_KERNEL);
 882        if (!dfl)
 883                return -ENOMEM;
 884
 885        dfl->start = start;
 886        dfl->len = len;
 887        dfl->ioaddr = ioaddr;
 888
 889        list_add_tail(&dfl->node, &info->dfls);
 890
 891        return 0;
 892}
 893EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl);
 894
 895static int remove_feature_dev(struct device *dev, void *data)
 896{
 897        struct platform_device *pdev = to_platform_device(dev);
 898        enum dfl_id_type type = feature_dev_id_type(pdev);
 899        int id = pdev->id;
 900
 901        platform_device_unregister(pdev);
 902
 903        dfl_id_free(type, id);
 904
 905        return 0;
 906}
 907
 908static void remove_feature_devs(struct dfl_fpga_cdev *cdev)
 909{
 910        device_for_each_child(&cdev->region->dev, NULL, remove_feature_dev);
 911}
 912
 913/**
 914 * dfl_fpga_feature_devs_enumerate - enumerate feature devices
 915 * @info: information for enumeration.
 916 *
 917 * This function creates a container device (base FPGA region), enumerates
 918 * feature devices based on the enumeration info and creates platform devices
 919 * under the container device.
 920 *
 921 * Return: dfl_fpga_cdev struct on success, -errno on failure
 922 */
 923struct dfl_fpga_cdev *
 924dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
 925{
 926        struct build_feature_devs_info *binfo;
 927        struct dfl_fpga_enum_dfl *dfl;
 928        struct dfl_fpga_cdev *cdev;
 929        int ret = 0;
 930
 931        if (!info->dev)
 932                return ERR_PTR(-ENODEV);
 933
 934        cdev = devm_kzalloc(info->dev, sizeof(*cdev), GFP_KERNEL);
 935        if (!cdev)
 936                return ERR_PTR(-ENOMEM);
 937
 938        cdev->region = devm_fpga_region_create(info->dev, NULL, NULL);
 939        if (!cdev->region) {
 940                ret = -ENOMEM;
 941                goto free_cdev_exit;
 942        }
 943
 944        cdev->parent = info->dev;
 945        mutex_init(&cdev->lock);
 946        INIT_LIST_HEAD(&cdev->port_dev_list);
 947
 948        ret = fpga_region_register(cdev->region);
 949        if (ret)
 950                goto free_cdev_exit;
 951
 952        /* create and init build info for enumeration */
 953        binfo = devm_kzalloc(info->dev, sizeof(*binfo), GFP_KERNEL);
 954        if (!binfo) {
 955                ret = -ENOMEM;
 956                goto unregister_region_exit;
 957        }
 958
 959        binfo->dev = info->dev;
 960        binfo->cdev = cdev;
 961
 962        /*
 963         * start enumeration for all feature devices based on Device Feature
 964         * Lists.
 965         */
 966        list_for_each_entry(dfl, &info->dfls, node) {
 967                ret = parse_feature_list(binfo, dfl);
 968                if (ret) {
 969                        remove_feature_devs(cdev);
 970                        build_info_free(binfo);
 971                        goto unregister_region_exit;
 972                }
 973        }
 974
 975        build_info_free(binfo);
 976
 977        return cdev;
 978
 979unregister_region_exit:
 980        fpga_region_unregister(cdev->region);
 981free_cdev_exit:
 982        devm_kfree(info->dev, cdev);
 983        return ERR_PTR(ret);
 984}
 985EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_enumerate);
 986
 987/**
 988 * dfl_fpga_feature_devs_remove - remove all feature devices
 989 * @cdev: fpga container device.
 990 *
 991 * Remove the container device and all feature devices under given container
 992 * devices.
 993 */
 994void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev)
 995{
 996        struct dfl_feature_platform_data *pdata, *ptmp;
 997
 998        mutex_lock(&cdev->lock);
 999        if (cdev->fme_dev)
1000                put_device(cdev->fme_dev);
1001
1002        list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) {
1003                struct platform_device *port_dev = pdata->dev;
1004
1005                /* remove released ports */
1006                if (!device_is_registered(&port_dev->dev)) {
1007                        dfl_id_free(feature_dev_id_type(port_dev),
1008                                    port_dev->id);
1009                        platform_device_put(port_dev);
1010                }
1011
1012                list_del(&pdata->node);
1013                put_device(&port_dev->dev);
1014        }
1015        mutex_unlock(&cdev->lock);
1016
1017        remove_feature_devs(cdev);
1018
1019        fpga_region_unregister(cdev->region);
1020        devm_kfree(cdev->parent, cdev);
1021}
1022EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove);
1023
1024/**
1025 * __dfl_fpga_cdev_find_port - find a port under given container device
1026 *
1027 * @cdev: container device
1028 * @data: data passed to match function
1029 * @match: match function used to find specific port from the port device list
1030 *
1031 * Find a port device under container device. This function needs to be
1032 * invoked with lock held.
1033 *
1034 * Return: pointer to port's platform device if successful, NULL otherwise.
1035 *
1036 * NOTE: you will need to drop the device reference with put_device() after use.
1037 */
1038struct platform_device *
1039__dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data,
1040                          int (*match)(struct platform_device *, void *))
1041{
1042        struct dfl_feature_platform_data *pdata;
1043        struct platform_device *port_dev;
1044
1045        list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1046                port_dev = pdata->dev;
1047
1048                if (match(port_dev, data) && get_device(&port_dev->dev))
1049                        return port_dev;
1050        }
1051
1052        return NULL;
1053}
1054EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port);
1055
1056static int __init dfl_fpga_init(void)
1057{
1058        int ret;
1059
1060        dfl_ids_init();
1061
1062        ret = dfl_chardev_init();
1063        if (ret)
1064                dfl_ids_destroy();
1065
1066        return ret;
1067}
1068
1069/**
1070 * dfl_fpga_cdev_release_port - release a port platform device
1071 *
1072 * @cdev: parent container device.
1073 * @port_id: id of the port platform device.
1074 *
1075 * This function allows user to release a port platform device. This is a
1076 * mandatory step before turn a port from PF into VF for SRIOV support.
1077 *
1078 * Return: 0 on success, negative error code otherwise.
1079 */
1080int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id)
1081{
1082        struct platform_device *port_pdev;
1083        int ret = -ENODEV;
1084
1085        mutex_lock(&cdev->lock);
1086        port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1087                                              dfl_fpga_check_port_id);
1088        if (!port_pdev)
1089                goto unlock_exit;
1090
1091        if (!device_is_registered(&port_pdev->dev)) {
1092                ret = -EBUSY;
1093                goto put_dev_exit;
1094        }
1095
1096        ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev));
1097        if (ret)
1098                goto put_dev_exit;
1099
1100        platform_device_del(port_pdev);
1101        cdev->released_port_num++;
1102put_dev_exit:
1103        put_device(&port_pdev->dev);
1104unlock_exit:
1105        mutex_unlock(&cdev->lock);
1106        return ret;
1107}
1108EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port);
1109
1110/**
1111 * dfl_fpga_cdev_assign_port - assign a port platform device back
1112 *
1113 * @cdev: parent container device.
1114 * @port_id: id of the port platform device.
1115 *
1116 * This function allows user to assign a port platform device back. This is
1117 * a mandatory step after disable SRIOV support.
1118 *
1119 * Return: 0 on success, negative error code otherwise.
1120 */
1121int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id)
1122{
1123        struct platform_device *port_pdev;
1124        int ret = -ENODEV;
1125
1126        mutex_lock(&cdev->lock);
1127        port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1128                                              dfl_fpga_check_port_id);
1129        if (!port_pdev)
1130                goto unlock_exit;
1131
1132        if (device_is_registered(&port_pdev->dev)) {
1133                ret = -EBUSY;
1134                goto put_dev_exit;
1135        }
1136
1137        ret = platform_device_add(port_pdev);
1138        if (ret)
1139                goto put_dev_exit;
1140
1141        dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev));
1142        cdev->released_port_num--;
1143put_dev_exit:
1144        put_device(&port_pdev->dev);
1145unlock_exit:
1146        mutex_unlock(&cdev->lock);
1147        return ret;
1148}
1149EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port);
1150
1151static void config_port_access_mode(struct device *fme_dev, int port_id,
1152                                    bool is_vf)
1153{
1154        void __iomem *base;
1155        u64 v;
1156
1157        base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER);
1158
1159        v = readq(base + FME_HDR_PORT_OFST(port_id));
1160
1161        v &= ~FME_PORT_OFST_ACC_CTRL;
1162        v |= FIELD_PREP(FME_PORT_OFST_ACC_CTRL,
1163                        is_vf ? FME_PORT_OFST_ACC_VF : FME_PORT_OFST_ACC_PF);
1164
1165        writeq(v, base + FME_HDR_PORT_OFST(port_id));
1166}
1167
1168#define config_port_vf_mode(dev, id) config_port_access_mode(dev, id, true)
1169#define config_port_pf_mode(dev, id) config_port_access_mode(dev, id, false)
1170
1171/**
1172 * dfl_fpga_cdev_config_ports_pf - configure ports to PF access mode
1173 *
1174 * @cdev: parent container device.
1175 *
1176 * This function is needed in sriov configuration routine. It could be used to
1177 * configure the all released ports from VF access mode to PF.
1178 */
1179void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev)
1180{
1181        struct dfl_feature_platform_data *pdata;
1182
1183        mutex_lock(&cdev->lock);
1184        list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1185                if (device_is_registered(&pdata->dev->dev))
1186                        continue;
1187
1188                config_port_pf_mode(cdev->fme_dev, pdata->id);
1189        }
1190        mutex_unlock(&cdev->lock);
1191}
1192EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf);
1193
1194/**
1195 * dfl_fpga_cdev_config_ports_vf - configure ports to VF access mode
1196 *
1197 * @cdev: parent container device.
1198 * @num_vfs: VF device number.
1199 *
1200 * This function is needed in sriov configuration routine. It could be used to
1201 * configure the released ports from PF access mode to VF.
1202 *
1203 * Return: 0 on success, negative error code otherwise.
1204 */
1205int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs)
1206{
1207        struct dfl_feature_platform_data *pdata;
1208        int ret = 0;
1209
1210        mutex_lock(&cdev->lock);
1211        /*
1212         * can't turn multiple ports into 1 VF device, only 1 port for 1 VF
1213         * device, so if released port number doesn't match VF device number,
1214         * then reject the request with -EINVAL error code.
1215         */
1216        if (cdev->released_port_num != num_vfs) {
1217                ret = -EINVAL;
1218                goto done;
1219        }
1220
1221        list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1222                if (device_is_registered(&pdata->dev->dev))
1223                        continue;
1224
1225                config_port_vf_mode(cdev->fme_dev, pdata->id);
1226        }
1227done:
1228        mutex_unlock(&cdev->lock);
1229        return ret;
1230}
1231EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
1232
1233static void __exit dfl_fpga_exit(void)
1234{
1235        dfl_chardev_uinit();
1236        dfl_ids_destroy();
1237}
1238
1239module_init(dfl_fpga_init);
1240module_exit(dfl_fpga_exit);
1241
1242MODULE_DESCRIPTION("FPGA Device Feature List (DFL) Support");
1243MODULE_AUTHOR("Intel Corporation");
1244MODULE_LICENSE("GPL v2");
1245