root/drivers/fpga/dfl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dfl_ids_init
  2. dfl_ids_destroy
  3. dfl_id_alloc
  4. dfl_id_free
  5. feature_dev_id_type
  6. dfh_id_to_type
  7. dfl_fpga_port_ops_get
  8. dfl_fpga_port_ops_put
  9. dfl_fpga_port_ops_add
  10. dfl_fpga_port_ops_del
  11. dfl_fpga_check_port_id
  12. dfl_fpga_dev_feature_uinit
  13. dfl_feature_instance_init
  14. dfl_feature_drv_match
  15. dfl_fpga_dev_feature_init
  16. dfl_chardev_uinit
  17. dfl_chardev_init
  18. dfl_get_devt
  19. dfl_fpga_dev_ops_register
  20. dfl_fpga_dev_ops_unregister
  21. dfl_fpga_cdev_add_port_dev
  22. build_info_commit_dev
  23. build_info_create_dev
  24. build_info_free
  25. feature_size
  26. feature_id
  27. create_feature_instance
  28. parse_feature_port_afu
  29. parse_feature_afu
  30. parse_feature_fiu
  31. parse_feature_private
  32. parse_feature
  33. parse_feature_list
  34. dfl_fpga_enum_info_alloc
  35. dfl_fpga_enum_info_free
  36. dfl_fpga_enum_info_add_dfl
  37. remove_feature_dev
  38. remove_feature_devs
  39. dfl_fpga_feature_devs_enumerate
  40. dfl_fpga_feature_devs_remove
  41. __dfl_fpga_cdev_find_port
  42. dfl_fpga_init
  43. dfl_fpga_cdev_release_port
  44. dfl_fpga_cdev_assign_port
  45. config_port_access_mode
  46. dfl_fpga_cdev_config_ports_pf
  47. dfl_fpga_cdev_config_ports_vf
  48. dfl_fpga_exit

   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 
  17 static 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  */
  31 enum 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 
  37 enum dfl_fpga_devt_type {
  38         DFL_FPGA_DEVT_FME,
  39         DFL_FPGA_DEVT_PORT,
  40         DFL_FPGA_DEVT_MAX,
  41 };
  42 
  43 static struct lock_class_key dfl_pdata_keys[DFL_ID_MAX];
  44 
  45 static 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  */
  57 struct 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 */
  65 static 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  */
  77 struct dfl_chardev_info {
  78         const char *name;
  79         dev_t devt;
  80 };
  81 
  82 /* indexed by enum dfl_fpga_devt_type */
  83 static struct dfl_chardev_info dfl_chrdevs[] = {
  84         {.name = DFL_FPGA_FEATURE_DEV_FME},
  85         {.name = DFL_FPGA_FEATURE_DEV_PORT},
  86 };
  87 
  88 static 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 
  96 static 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 
 104 static 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 
 116 static 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 
 124 static 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 
 135 static 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 
 156 static DEFINE_MUTEX(dfl_port_ops_mutex);
 157 static 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  */
 166 struct 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;
 184 done:
 185         mutex_unlock(&dfl_port_ops_mutex);
 186         return ops;
 187 }
 188 EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_get);
 189 
 190 /**
 191  * dfl_fpga_port_ops_put - put port ops
 192  * @ops: port ops.
 193  */
 194 void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops)
 195 {
 196         if (ops && ops->owner)
 197                 module_put(ops->owner);
 198 }
 199 EXPORT_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  */
 205 void 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 }
 211 EXPORT_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  */
 217 void 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 }
 223 EXPORT_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  */
 232 int 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 }
 249 EXPORT_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  */
 255 void 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 }
 267 EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_uinit);
 268 
 269 static 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 
 287 static 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  */
 312 int 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;
 333 exit:
 334         dfl_fpga_dev_feature_uinit(pdev);
 335         return ret;
 336 }
 337 EXPORT_SYMBOL_GPL(dfl_fpga_dev_feature_init);
 338 
 339 static 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 
 351 static 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 
 364 exit:
 365         dfl_chardev_uinit();
 366         return ret;
 367 }
 368 
 369 static 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  */
 386 int 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 }
 405 EXPORT_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  */
 411 void 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 }
 417 EXPORT_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  */
 429 struct 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  */
 446 struct dfl_feature_info {
 447         u64 fid;
 448         struct resource mmio_res;
 449         void __iomem *ioaddr;
 450         struct list_head node;
 451 };
 452 
 453 static 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  */
 469 static 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 
 555 static int
 556 build_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 
 593 static 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 
 616 static 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 
 624 static 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  */
 648 static int
 649 create_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 
 678 static 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 
 690 static 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 
 710 static 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 
 745 static 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  */
 765 static 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 
 789 static 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 
 821 struct 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 }
 838 EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_alloc);
 839 
 840 void 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 }
 859 EXPORT_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  */
 875 int 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 }
 893 EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl);
 894 
 895 static 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 
 908 static 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  */
 923 struct dfl_fpga_cdev *
 924 dfl_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 
 979 unregister_region_exit:
 980         fpga_region_unregister(cdev->region);
 981 free_cdev_exit:
 982         devm_kfree(info->dev, cdev);
 983         return ERR_PTR(ret);
 984 }
 985 EXPORT_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  */
 994 void 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 }
1022 EXPORT_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  */
1038 struct 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 }
1054 EXPORT_SYMBOL_GPL(__dfl_fpga_cdev_find_port);
1055 
1056 static 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  */
1080 int 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++;
1102 put_dev_exit:
1103         put_device(&port_pdev->dev);
1104 unlock_exit:
1105         mutex_unlock(&cdev->lock);
1106         return ret;
1107 }
1108 EXPORT_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  */
1121 int 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--;
1143 put_dev_exit:
1144         put_device(&port_pdev->dev);
1145 unlock_exit:
1146         mutex_unlock(&cdev->lock);
1147         return ret;
1148 }
1149 EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port);
1150 
1151 static 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  */
1179 void 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 }
1192 EXPORT_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  */
1205 int 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         }
1227 done:
1228         mutex_unlock(&cdev->lock);
1229         return ret;
1230 }
1231 EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
1232 
1233 static void __exit dfl_fpga_exit(void)
1234 {
1235         dfl_chardev_uinit();
1236         dfl_ids_destroy();
1237 }
1238 
1239 module_init(dfl_fpga_init);
1240 module_exit(dfl_fpga_exit);
1241 
1242 MODULE_DESCRIPTION("FPGA Device Feature List (DFL) Support");
1243 MODULE_AUTHOR("Intel Corporation");
1244 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */