/** * fsl_mc_resource_pool_add_device - add allocatable object to a resource * pool of a given fsl-mc bus * * @mc_bus: pointer to the fsl-mc bus * @pool_type: pool type * @mc_dev: pointer to allocatable fsl-mc device
*/ staticint __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus
*mc_bus, enum fsl_mc_pool_type
pool_type, struct fsl_mc_device
*mc_dev)
{ struct fsl_mc_resource_pool *res_pool; struct fsl_mc_resource *resource; struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; int error = -EINVAL;
if (pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES) goto out; if (!fsl_mc_is_allocatable(mc_dev)) goto out; if (mc_dev->resource) goto out;
res_pool = &mc_bus->resource_pools[pool_type]; if (res_pool->type != pool_type) goto out; if (res_pool->mc_bus != mc_bus) goto out;
mutex_lock(&res_pool->mutex);
if (res_pool->max_count < 0) goto out_unlock; if (res_pool->free_count < 0 ||
res_pool->free_count > res_pool->max_count) goto out_unlock;
resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource),
GFP_KERNEL); if (!resource) {
error = -ENOMEM;
dev_err(&mc_bus_dev->dev, "Failed to allocate memory for fsl_mc_resource\n"); goto out_unlock;
}
/** * fsl_mc_resource_pool_remove_device - remove an allocatable device from a * resource pool * * @mc_dev: pointer to allocatable fsl-mc device * * It permanently removes an allocatable fsl-mc device from the resource * pool. It's an error if the device is in use.
*/ staticint __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device
*mc_dev)
{ struct fsl_mc_device *mc_bus_dev; struct fsl_mc_bus *mc_bus; struct fsl_mc_resource_pool *res_pool; struct fsl_mc_resource *resource; int error = -EINVAL;
/* * If the device is currently allocated, its resource is not * in the free list and thus, the device cannot be removed.
*/ if (list_empty(&resource->node)) {
error = -EBUSY;
dev_err(&mc_bus_dev->dev, "Device %s cannot be removed from resource pool\n",
dev_name(&mc_dev->dev)); goto out_unlock;
}
if (!resource) {
error = -ENXIO;
dev_err(&mc_bus_dev->dev, "No more resources of type %s left\n",
fsl_mc_pool_type_strings[pool_type]); goto out_unlock;
}
if (resource->type != pool_type) goto out_unlock; if (resource->parent_pool != res_pool) goto out_unlock; if (res_pool->free_count <= 0 ||
res_pool->free_count > res_pool->max_count) goto out_unlock;
/** * fsl_mc_object_allocate - Allocates an fsl-mc object of the given * pool type from a given fsl-mc bus instance * * @mc_dev: fsl-mc device which is used in conjunction with the * allocated object * @pool_type: pool type * @new_mc_adev: pointer to area where the pointer to the allocated device * is to be returned * * Allocatable objects are always used in conjunction with some functional * device. This function allocates an object of the specified type from * the DPRC containing the functional device. * * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC * portals are allocated using fsl_mc_portal_allocate(), instead of * this function.
*/ int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, enum fsl_mc_pool_type pool_type, struct fsl_mc_device **new_mc_adev)
{ struct fsl_mc_device *mc_bus_dev; struct fsl_mc_bus *mc_bus; struct fsl_mc_device *mc_adev; int error = -EINVAL; struct fsl_mc_resource *resource = NULL;
*new_mc_adev = NULL; if (mc_dev->flags & FSL_MC_IS_DPRC) goto error;
if (!dev_is_fsl_mc(mc_dev->dev.parent)) goto error;
/** * fsl_mc_object_free - Returns an fsl-mc object to the resource * pool where it came from. * @mc_adev: Pointer to the fsl-mc device
*/ void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
{ struct fsl_mc_resource *resource;
resource = mc_adev->resource; if (resource->type == FSL_MC_POOL_DPMCP) return; if (resource->data != mc_adev) return;
/* * A DPRC and the devices in the DPRC all share the same GIC-ITS device * ID. A block of IRQs is pre-allocated and maintained in a pool * from which devices can allocate them when needed.
*/
/* * Initialize the interrupt pool associated with an fsl-mc bus. * It allocates a block of IRQs from the GIC-ITS.
*/ int fsl_mc_populate_irq_pool(struct fsl_mc_device *mc_bus_dev, unsignedint irq_count)
{ unsignedint i; struct fsl_mc_device_irq *irq_resources; struct fsl_mc_device_irq *mc_dev_irq; int error; struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); struct fsl_mc_resource_pool *res_pool =
&mc_bus->resource_pools[FSL_MC_POOL_IRQ];
/* do nothing if the IRQ pool is already populated */ if (mc_bus->irq_resources) return 0;
if (irq_count == 0 ||
irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) return -EINVAL;
error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count); if (error < 0) return error;
/* * Teardown the interrupt pool associated with an fsl-mc bus. * It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
*/ void fsl_mc_cleanup_irq_pool(struct fsl_mc_device *mc_bus_dev)
{ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); struct fsl_mc_resource_pool *res_pool =
&mc_bus->resource_pools[FSL_MC_POOL_IRQ];
if (!mc_bus->irq_resources) return;
if (res_pool->max_count == 0) return;
if (res_pool->free_count != res_pool->max_count) return;
/* * Allocate the IRQs required by a given fsl-mc device.
*/ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
{ int i; int irq_count; int res_allocated_count = 0; int error = -EINVAL; struct fsl_mc_device_irq **irqs = NULL; struct fsl_mc_bus *mc_bus; struct fsl_mc_resource_pool *res_pool;
if (mc_dev->irqs) return -EINVAL;
irq_count = mc_dev->obj_desc.irq_count; if (irq_count == 0) return -EINVAL;
if (is_fsl_mc_bus_dprc(mc_dev))
mc_bus = to_fsl_mc_bus(mc_dev); else
mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
if (!mc_bus->irq_resources) return -EINVAL;
res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; if (res_pool->free_count < irq_count) {
dev_err(&mc_dev->dev, "Not able to allocate %u irqs for device\n", irq_count); return -ENOSPC;
}
irqs = devm_kcalloc(&mc_dev->dev, irq_count, sizeof(irqs[0]),
GFP_KERNEL); if (!irqs) return -ENOMEM;
for (i = 0; i < irq_count; i++) { struct fsl_mc_resource *resource;
/* * Frees the IRQs that were allocated for an fsl-mc device.
*/ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev)
{ int i; int irq_count; struct fsl_mc_bus *mc_bus; struct fsl_mc_device_irq **irqs = mc_dev->irqs;
if (!irqs) return;
irq_count = mc_dev->obj_desc.irq_count;
if (is_fsl_mc_bus_dprc(mc_dev))
mc_bus = to_fsl_mc_bus(mc_dev); else
mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent));
if (!mc_bus->irq_resources) return;
for (i = 0; i < irq_count; i++) {
irqs[i]->mc_dev = NULL;
fsl_mc_resource_free(&irqs[i]->resource);
}
/* * fsl_mc_allocator_probe - callback invoked when an allocatable device is * being added to the system
*/ staticint fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
{ enum fsl_mc_pool_type pool_type; struct fsl_mc_device *mc_bus_dev; struct fsl_mc_bus *mc_bus; int error;
if (!fsl_mc_is_allocatable(mc_dev)) return -EINVAL;
mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); if (!dev_is_fsl_mc(&mc_bus_dev->dev)) return -EINVAL;
/* * fsl_mc_allocator_remove - callback invoked when an allocatable device is * being removed from the system
*/ staticvoid fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev)
{ int error;
if (mc_dev->resource) {
error = fsl_mc_resource_pool_remove_device(mc_dev); if (error < 0) return;
}
dev_dbg(&mc_dev->dev, "Allocatable fsl-mc device unbound from fsl_mc_allocator driver");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.