Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
   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");