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;
}