static int build_info_commit_dev()

in dfl.c [743:857]


static int build_info_commit_dev(struct build_feature_devs_info *binfo)
{
	struct platform_device *fdev = binfo->feature_dev;
	struct dfl_feature_platform_data *pdata;
	struct dfl_feature_info *finfo, *p;
	enum dfl_id_type type;
	int ret, index = 0, res_idx = 0;

	type = feature_dev_id_type(fdev);
	if (WARN_ON_ONCE(type >= DFL_ID_MAX))
		return -EINVAL;

	/*
	 * we do not need to care for the memory which is associated with
	 * the platform device. After calling platform_device_unregister(),
	 * it will be automatically freed by device's release() callback,
	 * platform_device_release().
	 */
	pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	pdata->dev = fdev;
	pdata->num = binfo->feature_num;
	pdata->dfl_cdev = binfo->cdev;
	pdata->id = FEATURE_DEV_ID_UNUSED;
	mutex_init(&pdata->lock);
	lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
				   dfl_pdata_key_strings[type]);

	/*
	 * the count should be initialized to 0 to make sure
	 *__fpga_port_enable() following __fpga_port_disable()
	 * works properly for port device.
	 * and it should always be 0 for fme device.
	 */
	WARN_ON(pdata->disable_count);

	fdev->dev.platform_data = pdata;

	/* each sub feature has one MMIO resource */
	fdev->num_resources = binfo->feature_num;
	fdev->resource = kcalloc(binfo->feature_num, sizeof(*fdev->resource),
				 GFP_KERNEL);
	if (!fdev->resource)
		return -ENOMEM;

	/* fill features and resource information for feature dev */
	list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
		struct dfl_feature *feature = &pdata->features[index++];
		struct dfl_feature_irq_ctx *ctx;
		unsigned int i;

		/* save resource information for each feature */
		feature->dev = fdev;
		feature->id = finfo->fid;
		feature->revision = finfo->revision;

		/*
		 * the FIU header feature has some fundamental functions (sriov
		 * set, port enable/disable) needed for the dfl bus device and
		 * other sub features. So its mmio resource should be mapped by
		 * DFL bus device. And we should not assign it to feature
		 * devices (dfl-fme/afu) again.
		 */
		if (is_header_feature(feature)) {
			feature->resource_index = -1;
			feature->ioaddr =
				devm_ioremap_resource(binfo->dev,
						      &finfo->mmio_res);
			if (IS_ERR(feature->ioaddr))
				return PTR_ERR(feature->ioaddr);
		} else {
			feature->resource_index = res_idx;
			fdev->resource[res_idx++] = finfo->mmio_res;
		}

		if (finfo->nr_irqs) {
			ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs,
					   sizeof(*ctx), GFP_KERNEL);
			if (!ctx)
				return -ENOMEM;

			for (i = 0; i < finfo->nr_irqs; i++)
				ctx[i].irq =
					binfo->irq_table[finfo->irq_base + i];

			feature->irq_ctx = ctx;
			feature->nr_irqs = finfo->nr_irqs;
		}

		list_del(&finfo->node);
		kfree(finfo);
	}

	ret = platform_device_add(binfo->feature_dev);
	if (!ret) {
		if (type == PORT_ID)
			dfl_fpga_cdev_add_port_dev(binfo->cdev,
						   binfo->feature_dev);
		else
			binfo->cdev->fme_dev =
					get_device(&binfo->feature_dev->dev);
		/*
		 * reset it to avoid build_info_free() freeing their resource.
		 *
		 * The resource of successfully registered feature devices
		 * will be freed by platform_device_unregister(). See the
		 * comments in build_info_create_dev().
		 */
		binfo->feature_dev = NULL;
	}

	return ret;
}