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_fpga_port_ops *port_ops = dfl_fpga_port_ops_get(pdev);
 235        int port_id;
 236
 237        if (!port_ops || !port_ops->get_id)
 238                return 0;
 239
 240        port_id = port_ops->get_id(pdev);
 241        dfl_fpga_port_ops_put(port_ops);
 242
 243        return port_id == *(int *)pport_id;
 244}
 245EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id);
 246
 247/**
 248 * dfl_fpga_dev_feature_uinit - uinit for sub features of dfl feature device
 249 * @pdev: feature device.
 250 */
 251void dfl_fpga_dev_feature_uinit(struct platform_device *pdev)
 252{
 253        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 254        struct dfl_feature *feature;
 255
 256        dfl_fpga_dev_for_each_feature(pdata, feature)
 257                if (feature->ops) {
 258                        feature->ops->uinit(pdev, feature);
 259                        feature->ops = NULL;
 260                }
 261}
 262EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_uinit);
 263
 264static int dfl_feature_instance_init(struct platform_device *pdev,
 265                                     struct dfl_feature_platform_data *pdata,
 266                                     struct dfl_feature *feature,
 267                                     struct dfl_feature_driver *drv)
 268{
 269        int ret;
 270
 271        ret = drv->ops->init(pdev, feature);
 272        if (ret)
 273                return ret;
 274
 275        feature->ops = drv->ops;
 276
 277        return ret;
 278}
 279
 280/**
 281 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device
 282 * @pdev: feature device.
 283 * @feature_drvs: drvs for sub features.
 284 *
 285 * This function will match sub features with given feature drvs list and
 286 * use matched drv to init related sub feature.
 287 *
 288 * Return: 0 on success, negative error code otherwise.
 289 */
 290int dfl_fpga_dev_feature_init(struct platform_device *pdev,
 291                              struct dfl_feature_driver *feature_drvs)
 292{
 293        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 294        struct dfl_feature_driver *drv = feature_drvs;
 295        struct dfl_feature *feature;
 296        int ret;
 297
 298        while (drv->ops) {
 299                dfl_fpga_dev_for_each_feature(pdata, feature) {
 300                        /* match feature and drv using id */
 301                        if (feature->id == drv->id) {
 302                                ret = dfl_feature_instance_init(pdev, pdata,
 303                                                                feature, drv);
 304                                if (ret)
 305                                        goto exit;
 306                        }
 307                }
 308                drv++;
 309        }
 310
 311        return 0;
 312exit:
 313        dfl_fpga_dev_feature_uinit(pdev);
 314        return ret;
 315}
 316EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_init);
 317
 318static void dfl_chardev_uinit(void)
 319{
 320        int i;
 321
 322        for (i = 0; i < DFL_FPGA_DEVT_MAX; i++)
 323                if (MAJOR(dfl_chrdevs[i].devt)) {
 324                        unregister_chrdev_region(dfl_chrdevs[i].devt,
 325                                                 MINORMASK + 1);
 326                        dfl_chrdevs[i].devt = MKDEV(0, 0);
 327                }
 328}
 329
 330static int dfl_chardev_init(void)
 331{
 332        int i, ret;
 333
 334        for (i = 0; i < DFL_FPGA_DEVT_MAX; i++) {
 335                ret = alloc_chrdev_region(&dfl_chrdevs[i].devt, 0,
 336                                          MINORMASK + 1, dfl_chrdevs[i].name);
 337                if (ret)
 338                        goto exit;
 339        }
 340
 341        return 0;
 342
 343exit:
 344        dfl_chardev_uinit();
 345        return ret;
 346}
 347
 348static dev_t dfl_get_devt(enum dfl_fpga_devt_type type, int id)
 349{
 350        if (type >= DFL_FPGA_DEVT_MAX)
 351                return 0;
 352
 353        return MKDEV(MAJOR(dfl_chrdevs[type].devt), id);
 354}
 355
 356/**
 357 * dfl_fpga_dev_ops_register - register cdev ops for feature dev
 358 *
 359 * @pdev: feature dev.
 360 * @fops: file operations for feature dev's cdev.
 361 * @owner: owning module/driver.
 362 *
 363 * Return: 0 on success, negative error code otherwise.
 364 */
 365int dfl_fpga_dev_ops_register(struct platform_device *pdev,
 366                              const struct file_operations *fops,
 367                              struct module *owner)
 368{
 369        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 370
 371        cdev_init(&pdata->cdev, fops);
 372        pdata->cdev.owner = owner;
 373
 374        /*
 375         * set parent to the feature device so that its refcount is
 376         * decreased after the last refcount of cdev is gone, that
 377         * makes sure the feature device is valid during device
 378         * file's life-cycle.
 379         */
 380        pdata->cdev.kobj.parent = &pdev->dev.kobj;
 381
 382        return cdev_add(&pdata->cdev, pdev->dev.devt, 1);
 383}
 384EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_register);
 385
 386/**
 387 * dfl_fpga_dev_ops_unregister - unregister cdev ops for feature dev
 388 * @pdev: feature dev.
 389 */
 390void dfl_fpga_dev_ops_unregister(struct platform_device *pdev)
 391{
 392        struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
 393
 394        cdev_del(&pdata->cdev);
 395}
 396EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
 397
 398/**
 399 * struct build_feature_devs_info - info collected during feature dev build.
 400 *
 401 * @dev: device to enumerate.
 402 * @cdev: the container device for all feature devices.
 403 * @feature_dev: current feature device.
 404 * @ioaddr: header register region address of feature device in enumeration.
 405 * @sub_features: a sub features linked list for feature device in enumeration.
 406 * @feature_num: number of sub features for feature device in enumeration.
 407 */
 408struct build_feature_devs_info {
 409        struct device *dev;
 410        struct dfl_fpga_cdev *cdev;
 411        struct platform_device *feature_dev;
 412        void __iomem *ioaddr;
 413        struct list_head sub_features;
 414        int feature_num;
 415};
 416
 417/**
 418 * struct dfl_feature_info - sub feature info collected during feature dev build
 419 *
 420 * @fid: id of this sub feature.
 421 * @mmio_res: mmio resource of this sub feature.
 422 * @ioaddr: mapped base address of mmio resource.
 423 * @node: node in sub_features linked list.
 424 */
 425struct dfl_feature_info {
 426        u64 fid;
 427        struct resource mmio_res;
 428        void __iomem *ioaddr;
 429        struct list_head node;
 430};
 431
 432static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
 433                                       struct platform_device *port)
 434{
 435        struct dfl_feature_platform_data *pdata = dev_get_platdata(&port->dev);
 436
 437        mutex_lock(&cdev->lock);
 438        list_add(&pdata->node, &cdev->port_dev_list);
 439        get_device(&pdata->dev->dev);
 440        mutex_unlock(&cdev->lock);
 441}
 442
 443/*
 444 * register current feature device, it is called when we need to switch to
 445 * another feature parsing or we have parsed all features on given device
 446 * feature list.
 447 */
 448static int build_info_commit_dev(struct build_feature_devs_info *binfo)
 449{
 450        struct platform_device *fdev = binfo->feature_dev;
 451        struct dfl_feature_platform_data *pdata;
 452        struct dfl_feature_info *finfo, *p;
 453        enum dfl_id_type type;
 454        int ret, index = 0;
 455
 456        if (!fdev)
 457                return 0;
 458
 459        type = feature_dev_id_type(fdev);
 460        if (WARN_ON_ONCE(type >= DFL_ID_MAX))
 461                return -EINVAL;
 462
 463        /*
 464         * we do not need to care for the memory which is associated with
 465         * the platform device. After calling platform_device_unregister(),
 466         * it will be automatically freed by device's release() callback,
 467         * platform_device_release().
 468         */
 469        pdata = kzalloc(dfl_feature_platform_data_size(binfo->feature_num),
 470                        GFP_KERNEL);
 471        if (!pdata)
 472                return -ENOMEM;
 473
 474        pdata->dev = fdev;
 475        pdata->num = binfo->feature_num;
 476        pdata->dfl_cdev = binfo->cdev;
 477        mutex_init(&pdata->lock);
 478        lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
 479                                   dfl_pdata_key_strings[type]);
 480
 481        /*
 482         * the count should be initialized to 0 to make sure
 483         *__fpga_port_enable() following __fpga_port_disable()
 484         * works properly for port device.
 485         * and it should always be 0 for fme device.
 486         */
 487        WARN_ON(pdata->disable_count);
 488
 489        fdev->dev.platform_data = pdata;
 490
 491        /* each sub feature has one MMIO resource */
 492        fdev->num_resources = binfo->feature_num;
 493        fdev->resource = kcalloc(binfo->feature_num, sizeof(*fdev->resource),
 494                                 GFP_KERNEL);
 495        if (!fdev->resource)
 496                return -ENOMEM;
 497
 498        /* fill features and resource information for feature dev */
 499        list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
 500                struct dfl_feature *feature = &pdata->features[index];
 501
 502                /* save resource information for each feature */
 503                feature->id = finfo->fid;
 504                feature->resource_index = index;
 505                feature->ioaddr = finfo->ioaddr;
 506                fdev->resource[index++] = finfo->mmio_res;
 507
 508                list_del(&finfo->node);
 509                kfree(finfo);
 510        }
 511
 512        ret = platform_device_add(binfo->feature_dev);
 513        if (!ret) {
 514                if (type == PORT_ID)
 515                        dfl_fpga_cdev_add_port_dev(binfo->cdev,
 516                                                   binfo->feature_dev);
 517                else
 518                        binfo->cdev->fme_dev =
 519                                        get_device(&binfo->feature_dev->dev);
 520                /*
 521                 * reset it to avoid build_info_free() freeing their resource.
 522                 *
 523                 * The resource of successfully registered feature devices
 524                 * will be freed by platform_device_unregister(). See the
 525                 * comments in build_info_create_dev().
 526                 */
 527                binfo->feature_dev = NULL;
 528        }
 529
 530        return ret;
 531}
 532
 533static int
 534build_info_create_dev(struct build_feature_devs_info *binfo,
 535                      enum dfl_id_type type, void __iomem *ioaddr)
 536{
 537        struct platform_device *fdev;
 538        int ret;
 539
 540        if (type >= DFL_ID_MAX)
 541                return -EINVAL;
 542
 543        /* we will create a new device, commit current device first */
 544        ret = build_info_commit_dev(binfo);
 545        if (ret)
 546                return ret;
 547
 548        /*
 549         * we use -ENODEV as the initialization indicator which indicates
 550         * whether the id need to be reclaimed
 551         */
 552        fdev = platform_device_alloc(dfl_devs[type].name, -ENODEV);
 553        if (!fdev)
 554                return -ENOMEM;
 555
 556        binfo->feature_dev = fdev;
 557        binfo->feature_num = 0;
 558        binfo->ioaddr = ioaddr;
 559        INIT_LIST_HEAD(&binfo->sub_features);
 560
 561        fdev->id = dfl_id_alloc(type, &fdev->dev);
 562        if (fdev->id < 0)
 563                return fdev->id;
 564
 565        fdev->dev.parent = &binfo->cdev->region->dev;
 566        fdev->dev.devt = dfl_get_devt(dfl_devs[type].devt_type, fdev->id);
 567
 568        return 0;
 569}
 570
 571static void build_info_free(struct build_feature_devs_info *binfo)
 572{
 573        struct dfl_feature_info *finfo, *p;
 574
 575        /*
 576         * it is a valid id, free it. See comments in
 577         * build_info_create_dev()
 578         */
 579        if (binfo->feature_dev && binfo->feature_dev->id >= 0) {
 580                dfl_id_free(feature_dev_id_type(binfo->feature_dev),
 581                            binfo->feature_dev->id);
 582
 583                list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
 584                        list_del(&finfo->node);
 585                        kfree(finfo);
 586                }
 587        }
 588
 589        platform_device_put(binfo->feature_dev);
 590
 591        devm_kfree(binfo->dev, binfo);
 592}
 593
 594static inline u32 feature_size(void __iomem *start)
 595{
 596        u64 v = readq(start + DFH);
 597        u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v);
 598        /* workaround for private features with invalid size, use 4K instead */
 599        return ofst ? ofst : 4096;
 600}
 601
 602static u64 feature_id(void __iomem *start)
 603{
 604        u64 v = readq(start + DFH);
 605        u16 id = FIELD_GET(DFH_ID, v);
 606        u8 type = FIELD_GET(DFH_TYPE, v);
 607
 608        if (type == DFH_TYPE_FIU)
 609                return FEATURE_ID_FIU_HEADER;
 610        else if (type == DFH_TYPE_PRIVATE)
 611                return id;
 612        else if (type == DFH_TYPE_AFU)
 613                return FEATURE_ID_AFU;
 614
 615        WARN_ON(1);
 616        return 0;
 617}
 618
 619/*
 620 * when create sub feature instances, for private features, it doesn't need
 621 * to provide resource size and feature id as they could be read from DFH
 622 * register. For afu sub feature, its register region only contains user
 623 * defined registers, so never trust any information from it, just use the
 624 * resource size information provided by its parent FIU.
 625 */
 626static int
 627create_feature_instance(struct build_feature_devs_info *binfo,
 628                        struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst,
 629                        resource_size_t size, u64 fid)
 630{
 631        struct dfl_feature_info *finfo;
 632
 633        /* read feature size and id if inputs are invalid */
 634        size = size ? size : feature_size(dfl->ioaddr + ofst);
 635        fid = fid ? fid : feature_id(dfl->ioaddr + ofst);
 636
 637        if (dfl->len - ofst < size)
 638                return -EINVAL;
 639
 640        finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
 641        if (!finfo)
 642                return -ENOMEM;
 643
 644        finfo->fid = fid;
 645        finfo->mmio_res.start = dfl->start + ofst;
 646        finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
 647        finfo->mmio_res.flags = IORESOURCE_MEM;
 648        finfo->ioaddr = dfl->ioaddr + ofst;
 649
 650        list_add_tail(&finfo->node, &binfo->sub_features);
 651        binfo->feature_num++;
 652
 653        return 0;
 654}
 655
 656static int parse_feature_port_afu(struct build_feature_devs_info *binfo,
 657                                  struct dfl_fpga_enum_dfl *dfl,
 658                                  resource_size_t ofst)
 659{
 660        u64 v = readq(binfo->ioaddr + PORT_HDR_CAP);
 661        u32 size = FIELD_GET(PORT_CAP_MMIO_SIZE, v) << 10;
 662
 663        WARN_ON(!size);
 664
 665        return create_feature_instance(binfo, dfl, ofst, size, FEATURE_ID_AFU);
 666}
 667
 668static int parse_feature_afu(struct build_feature_devs_info *binfo,
 669                             struct dfl_fpga_enum_dfl *dfl,
 670                             resource_size_t ofst)
 671{
 672        if (!binfo->feature_dev) {
 673                dev_err(binfo->dev, "this AFU does not belong to any FIU.\n");
 674                return -EINVAL;
 675        }
 676
 677        switch (feature_dev_id_type(binfo->feature_dev)) {
 678        case PORT_ID:
 679                return parse_feature_port_afu(binfo, dfl, ofst);
 680        default:
 681                dev_info(binfo->dev, "AFU belonging to FIU %s is not supported yet.\n",
 682                         binfo->feature_dev->name);
 683        }
 684
 685        return 0;
 686}
 687
 688static int parse_feature_fiu(struct build_feature_devs_info *binfo,
 689                             struct dfl_fpga_enum_dfl *dfl,
 690                             resource_size_t ofst)
 691{
 692        u32 id, offset;
 693        u64 v;
 694        int ret = 0;
 695
 696        v = readq(dfl->ioaddr + ofst + DFH);
 697        id = FIELD_GET(DFH_ID, v);
 698
 699        /* create platform device for dfl feature dev */
 700        ret = build_info_create_dev(binfo, dfh_id_to_type(id),
 701                                    dfl->ioaddr + ofst);
 702        if (ret)
 703                return ret;
 704
 705        ret = create_feature_instance(binfo, dfl, ofst, 0, 0);
 706        if (ret)
 707                return ret;
 708        /*
 709         * find and parse FIU's child AFU via its NEXT_AFU register.
 710         * please note that only Port has valid NEXT_AFU pointer per spec.
 711         */
 712        v = readq(dfl->ioaddr + ofst + NEXT_AFU);
 713
 714        offset = FIELD_GET(NEXT_AFU_NEXT_DFH_OFST, v);
 715        if (offset)
 716                return parse_feature_afu(binfo, dfl, ofst + offset);
 717
 718        dev_dbg(binfo->dev, "No AFUs detected on FIU %d\n", id);
 719
 720        return ret;
 721}
 722
 723static int parse_feature_private(struct build_feature_devs_info *binfo,
 724                                 struct dfl_fpga_enum_dfl *dfl,
 725                                 resource_size_t ofst)
 726{
 727        if (!binfo->feature_dev) {
 728                dev_err(binfo->dev, "the private feature %llx does not belong to any AFU.\n",
 729                        (unsigned long long)feature_id(dfl->ioaddr + ofst));
 730                return -EINVAL;
 731        }
 732
 733        return create_feature_instance(binfo, dfl, ofst, 0, 0);
 734}
 735
 736/**
 737 * parse_feature - parse a feature on given device feature list
 738 *
 739 * @binfo: build feature devices information.
 740 * @dfl: device feature list to parse
 741 * @ofst: offset to feature header on this device feature list
 742 */
 743static int parse_feature(struct build_feature_devs_info *binfo,
 744                         struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst)
 745{
 746        u64 v;
 747        u32 type;
 748
 749        v = readq(dfl->ioaddr + ofst + DFH);
 750        type = FIELD_GET(DFH_TYPE, v);
 751
 752        switch (type) {
 753        case DFH_TYPE_AFU:
 754                return parse_feature_afu(binfo, dfl, ofst);
 755        case DFH_TYPE_PRIVATE:
 756                return parse_feature_private(binfo, dfl, ofst);
 757        case DFH_TYPE_FIU:
 758                return parse_feature_fiu(binfo, dfl, ofst);
 759        default:
 760                dev_info(binfo->dev,
 761                         "Feature Type %x is not supported.\n", type);
 762        }
 763
 764        return 0;
 765}
 766
 767static int parse_feature_list(struct build_feature_devs_info *binfo,
 768                              struct dfl_fpga_enum_dfl *dfl)
 769{
 770        void __iomem *start = dfl->ioaddr;
 771        void __iomem *end = dfl->ioaddr + dfl->len;
 772        int ret = 0;
 773        u32 ofst = 0;
 774        u64 v;
 775
 776        /* walk through the device feature list via DFH's next DFH pointer. */
 777        for (; start < end; start += ofst) {
 778                if (end - start < DFH_SIZE) {
 779                        dev_err(binfo->dev, "The region is too small to contain a feature.\n");
 780                        return -EINVAL;
 781                }
 782
 783                ret = parse_feature(binfo, dfl, start - dfl->ioaddr);
 784                if (ret)
 785                        return ret;
 786
 787                v = readq(start + DFH);
 788                ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v);
 789
 790                /* stop parsing if EOL(End of List) is set or offset is 0 */
 791                if ((v & DFH_EOL) || !ofst)
 792                        break;
 793        }
 794
 795        /* commit current feature device when reach the end of list */
 796        return build_info_commit_dev(binfo);
 797}
 798
 799struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev)
 800{
 801        struct dfl_fpga_enum_info *info;
 802
 803        get_device(dev);
 804
 805        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
 806        if (!info) {
 807                put_device(dev);
 808                return NULL;
 809        }
 810
 811        info->dev = dev;
 812        INIT_LIST_HEAD(&info->dfls);
 813
 814        return info;
 815}
 816EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_alloc);
 817
 818void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
 819{
 820        struct dfl_fpga_enum_dfl *tmp, *dfl;
 821        struct device *dev;
 822
 823        if (!info)
 824                return;
 825
 826        dev = info->dev;
 827
 828        /* remove all device feature lists in the list. */
 829        list_for_each_entry_safe(dfl, tmp, &info->dfls, node) {
 830                list_del(&dfl->node);
 831                devm_kfree(dev, dfl);
 832        }
 833
 834        devm_kfree(dev, info);
 835        put_device(dev);
 836}
 837EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_free);
 838
 839/**
 840 * dfl_fpga_enum_info_add_dfl - add info of a device feature list to enum info
 841 *
 842 * @info: ptr to dfl_fpga_enum_info
 843 * @start: mmio resource address of the device feature list.
 844 * @len: mmio resource length of the device feature list.
 845 * @ioaddr: mapped mmio resource address of the device feature list.
 846 *
 847 * One FPGA device may have one or more Device Feature Lists (DFLs), use this
 848 * function to add information of each DFL to common data structure for next
 849 * step enumeration.
 850 *
 851 * Return: 0 on success, negative error code otherwise.
 852 */
 853int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
 854                               resource_size_t start, resource_size_t len,
 855                               void __iomem *ioaddr)
 856{
 857        struct dfl_fpga_enum_dfl *dfl;
 858
 859        dfl = devm_kzalloc(info->dev, sizeof(*dfl), GFP_KERNEL);
 860        if (!dfl)
 861                return -ENOMEM;
 862
 863        dfl->start = start;
 864        dfl->len = len;
 865        dfl->ioaddr = ioaddr;
 866
 867        list_add_tail(&dfl->node, &info->dfls);
 868
 869        return 0;
 870}
 871EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl);
 872
 873static int remove_feature_dev(struct device *dev, void *data)
 874{
 875        struct platform_device *pdev = to_platform_device(dev);
 876        enum dfl_id_type type = feature_dev_id_type(pdev);
 877        int id = pdev->id;
 878
 879        platform_device_unregister(pdev);
 880
 881        dfl_id_free(type, id);
 882
 883        return 0;
 884}
 885
 886static void remove_feature_devs(struct dfl_fpga_cdev *cdev)
 887{
 888        device_for_each_child(&cdev->region->dev, NULL, remove_feature_dev);
 889}
 890
 891/**
 892 * dfl_fpga_feature_devs_enumerate - enumerate feature devices
 893 * @info: information for enumeration.
 894 *
 895 * This function creates a container device (base FPGA region), enumerates
 896 * feature devices based on the enumeration info and creates platform devices
 897 * under the container device.
 898 *
 899 * Return: dfl_fpga_cdev struct on success, -errno on failure
 900 */
 901struct dfl_fpga_cdev *
 902dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
 903{
 904        struct build_feature_devs_info *binfo;
 905        struct dfl_fpga_enum_dfl *dfl;
 906        struct dfl_fpga_cdev *cdev;
 907        int ret = 0;
 908
 909        if (!info->dev)
 910                return ERR_PTR(-ENODEV);
 911
 912        cdev = devm_kzalloc(info->dev, sizeof(*cdev), GFP_KERNEL);
 913        if (!cdev)
 914                return ERR_PTR(-ENOMEM);
 915
 916        cdev->region = devm_fpga_region_create(info->dev, NULL, NULL);
 917        if (!cdev->region) {
 918                ret = -ENOMEM;
 919                goto free_cdev_exit;
 920        }
 921
 922        cdev->parent = info->dev;
 923        mutex_init(&cdev->lock);
 924        INIT_LIST_HEAD(&cdev->port_dev_list);
 925
 926        ret = fpga_region_register(cdev->region);
 927        if (ret)
 928                goto free_cdev_exit;
 929
 930        /* create and init build info for enumeration */
 931        binfo = devm_kzalloc(info->dev, sizeof(*binfo), GFP_KERNEL);
 932        if (!binfo) {
 933                ret = -ENOMEM;
 934                goto unregister_region_exit;
 935        }
 936
 937        binfo->dev = info->dev;
 938        binfo->cdev = cdev;
 939
 940        /*
 941         * start enumeration for all feature devices based on Device Feature
 942         * Lists.
 943         */
 944        list_for_each_entry(dfl, &info->dfls, node) {
 945                ret = parse_feature_list(binfo, dfl);
 946                if (ret) {
 947                        remove_feature_devs(cdev);
 948                        build_info_free(binfo);
 949                        goto unregister_region_exit;
 950                }
 951        }
 952
 953        build_info_free(binfo);
 954
 955        return cdev;
 956
 957unregister_region_exit:
 958        fpga_region_unregister(cdev->region);
 959free_cdev_exit:
 960        devm_kfree(info->dev, cdev);
 961        return ERR_PTR(ret);
 962}
 963EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_enumerate);
 964
 965/**
 966 * dfl_fpga_feature_devs_remove - remove all feature devices
 967 * @cdev: fpga container device.
 968 *
 969 * Remove the container device and all feature devices under given container
 970 * devices.
 971 */
 972void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev)
 973{
 974        struct dfl_feature_platform_data *pdata, *ptmp;
 975
 976        remove_feature_devs(cdev);
 977
 978        mutex_lock(&cdev->lock);
 979        if (cdev->fme_dev) {
 980                /* the fme should be unregistered. */
 981                WARN_ON(device_is_registered(cdev->fme_dev));
 982                put_device(cdev->fme_dev);
 983        }
 984
 985        list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) {
 986                struct platform_device *port_dev = pdata->dev;
 987
 988                /* the port should be unregistered. */
 989                WARN_ON(device_is_registered(&port_dev->dev));
 990                list_del(&pdata->node);
 991                put_device(&port_dev->dev);
 992        }
 993        mutex_unlock(&cdev->lock);
 994
 995        fpga_region_unregister(cdev->region);
 996        devm_kfree(cdev->parent, cdev);
 997}
 998EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove);
 999
1000/**
1001 * __dfl_fpga_cdev_find_port - find a port under given container device
1002 *
1003 * @cdev: container device
1004 * @data: data passed to match function
1005 * @match: match function used to find specific port from the port device list
1006 *
1007 * Find a port device under container device. This function needs to be
1008 * invoked with lock held.
1009 *
1010 * Return: pointer to port's platform device if successful, NULL otherwise.
1011 *
1012 * NOTE: you will need to drop the device reference with put_device() after use.
1013 */
1014struct platform_device *
1015__dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data,
1016                          int (*match)(struct platform_device *, void *))
1017{
1018        struct dfl_feature_platform_data *pdata;
1019        struct platform_device *port_dev;
1020
1021        list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1022                port_dev = pdata->dev;
1023
1024                if (match(port_dev, data) && get_device(&port_dev->dev))
1025                        return port_dev;
1026        }
1027
1028        return NULL;
1029}
1030EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port);
1031
1032static int __init dfl_fpga_init(void)
1033{
1034        int ret;
1035
1036        dfl_ids_init();
1037
1038        ret = dfl_chardev_init();
1039        if (ret)
1040                dfl_ids_destroy();
1041
1042        return ret;
1043}
1044
1045static void __exit dfl_fpga_exit(void)
1046{
1047        dfl_chardev_uinit();
1048        dfl_ids_destroy();
1049}
1050
1051module_init(dfl_fpga_init);
1052module_exit(dfl_fpga_exit);
1053
1054MODULE_DESCRIPTION("FPGA Device Feature List (DFL) Support");
1055MODULE_AUTHOR("Intel Corporation");
1056MODULE_LICENSE("GPL v2");
1057