in fsl-mc/fsl-mc-bus.c [783:914]
int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
struct fsl_mc_io *mc_io,
struct device *parent_dev,
struct fsl_mc_device **new_mc_dev)
{
int error;
struct fsl_mc_device *mc_dev = NULL;
struct fsl_mc_bus *mc_bus = NULL;
struct fsl_mc_device *parent_mc_dev;
if (dev_is_fsl_mc(parent_dev))
parent_mc_dev = to_fsl_mc_device(parent_dev);
else
parent_mc_dev = NULL;
if (strcmp(obj_desc->type, "dprc") == 0) {
/*
* Allocate an MC bus device object:
*/
mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL);
if (!mc_bus)
return -ENOMEM;
mutex_init(&mc_bus->scan_mutex);
mc_dev = &mc_bus->mc_dev;
} else {
/*
* Allocate a regular fsl_mc_device object:
*/
mc_dev = kzalloc(sizeof(*mc_dev), GFP_KERNEL);
if (!mc_dev)
return -ENOMEM;
}
mc_dev->obj_desc = *obj_desc;
mc_dev->mc_io = mc_io;
device_initialize(&mc_dev->dev);
mc_dev->dev.parent = parent_dev;
mc_dev->dev.bus = &fsl_mc_bus_type;
mc_dev->dev.release = fsl_mc_device_release;
mc_dev->dev.type = fsl_mc_get_device_type(obj_desc->type);
if (!mc_dev->dev.type) {
error = -ENODEV;
dev_err(parent_dev, "unknown device type %s\n", obj_desc->type);
goto error_cleanup_dev;
}
dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id);
if (strcmp(obj_desc->type, "dprc") == 0) {
struct fsl_mc_io *mc_io2;
mc_dev->flags |= FSL_MC_IS_DPRC;
/*
* To get the DPRC's ICID, we need to open the DPRC
* in get_dprc_icid(). For child DPRCs, we do so using the
* parent DPRC's MC portal instead of the child DPRC's MC
* portal, in case the child DPRC is already opened with
* its own portal (e.g., the DPRC used by AIOP).
*
* NOTE: There cannot be more than one active open for a
* given MC object, using the same MC portal.
*/
if (parent_mc_dev) {
/*
* device being added is a child DPRC device
*/
mc_io2 = parent_mc_dev->mc_io;
} else {
/*
* device being added is the root DPRC device
*/
if (!mc_io) {
error = -EINVAL;
goto error_cleanup_dev;
}
mc_io2 = mc_io;
}
error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid);
if (error < 0)
goto error_cleanup_dev;
} else {
/*
* A non-DPRC object has to be a child of a DPRC, use the
* parent's ICID and interrupt domain.
*/
mc_dev->icid = parent_mc_dev->icid;
mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK;
mc_dev->dev.dma_mask = &mc_dev->dma_mask;
mc_dev->dev.coherent_dma_mask = mc_dev->dma_mask;
dev_set_msi_domain(&mc_dev->dev,
dev_get_msi_domain(&parent_mc_dev->dev));
}
/*
* Get MMIO regions for the device from the MC:
*
* NOTE: the root DPRC is a special case as its MMIO region is
* obtained from the device tree
*/
if (parent_mc_dev && obj_desc->region_count != 0) {
error = fsl_mc_device_get_mmio_regions(mc_dev,
parent_mc_dev);
if (error < 0)
goto error_cleanup_dev;
}
/*
* The device-specific probe callback will get invoked by device_add()
*/
error = device_add(&mc_dev->dev);
if (error < 0) {
dev_err(parent_dev,
"device_add() failed for device %s: %d\n",
dev_name(&mc_dev->dev), error);
goto error_cleanup_dev;
}
dev_dbg(parent_dev, "added %s\n", dev_name(&mc_dev->dev));
*new_mc_dev = mc_dev;
return 0;
error_cleanup_dev:
kfree(mc_dev->regions);
kfree(mc_bus);
kfree(mc_dev);
return error;
}