/** * fsl_mc_portal_allocate - Allocates an MC portal * * @mc_dev: MC device for which the MC portal is to be allocated * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated * MC portal. * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object * that wraps the allocated MC portal is to be returned * * This function allocates an MC portal from the device's parent DPRC, * from the corresponding MC bus' pool of MC portals and wraps * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the * portal is allocated from its own MC bus. */ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, uint16_t mc_io_flags, struct fsl_mc_io **new_mc_io) { struct fsl_mc_device *mc_bus_dev; struct fsl_mc_bus *mc_bus; phys_addr_t mc_portal_phys_addr; size_t mc_portal_size; struct fsl_mc_device *mc_adev; int error = -EINVAL; struct fsl_mc_resource *resource = NULL; struct fsl_mc_io *mc_io = NULL; if (mc_dev->flags & FSL_MC_IS_DPRC) { mc_bus_dev = mc_dev; } else { if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type)) return error; mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); } mc_bus = to_fsl_mc_bus(mc_bus_dev); *new_mc_io = NULL; error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource); if (error < 0) return error; mc_adev = resource->data; if (WARN_ON(!mc_adev)) goto error_cleanup_resource; if (WARN_ON(mc_adev->obj_desc.region_count == 0)) goto error_cleanup_resource; mc_portal_phys_addr = mc_adev->regions[0].start; mc_portal_size = mc_adev->regions[0].end - mc_adev->regions[0].start + 1; if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size)) goto error_cleanup_resource; error = fsl_create_mc_io(&mc_bus_dev->dev, mc_portal_phys_addr, mc_portal_size, resource, mc_io_flags, &mc_io); if (error < 0) goto error_cleanup_resource; *new_mc_io = mc_io; return 0; error_cleanup_resource: fsl_mc_resource_free(resource); return error; }
/** * fsl_mc_object_free - Returns an allocatable MC object device to the * corresponding resource pool of a given MC bus. * * @mc_adev: Pointer to the MC object device */ void fsl_mc_object_free(struct fsl_mc_device *mc_adev) { struct fsl_mc_resource *resource; resource = mc_adev->resource; if (WARN_ON(resource->type == FSL_MC_POOL_DPMCP)) return; if (WARN_ON(resource->data != mc_adev)) return; fsl_mc_resource_free(resource); }
/** * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals * of a given MC bus * * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free */ void fsl_mc_portal_free(struct fsl_mc_io *mc_io) { struct fsl_mc_resource *resource; resource = mc_io->resource; if (WARN_ON(resource->type != FSL_MC_POOL_DPMCP)) return; if (WARN_ON(!resource->data)) return; fsl_destroy_mc_io(mc_io); fsl_mc_resource_free(resource); }
/** * fsl_mc_object_allocate - Allocates a MC object device of the given * pool type from a given MC bus * * @mc_dev: MC device for which the MC object device is to be allocated * @pool_type: MC bus resource pool type * @new_mc_dev: Pointer to area where the pointer to the allocated * MC object device is to be returned * * This function allocates a MC object device from the device's parent DPRC, * from the corresponding MC bus' pool of allocatable MC object devices of * the given resource type. mc_dev cannot be a DPRC itself. * * 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 (WARN_ON(mc_dev->flags & FSL_MC_IS_DPRC)) goto error; if (WARN_ON(mc_dev->dev.parent->bus != &fsl_mc_bus_type)) goto error; if (WARN_ON(pool_type == FSL_MC_POOL_DPMCP)) goto error; mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); mc_bus = to_fsl_mc_bus(mc_bus_dev); error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource); if (error < 0) goto error; mc_adev = resource->data; if (WARN_ON(!mc_adev)) goto error; *new_mc_adev = mc_adev; return 0; error: if (resource) fsl_mc_resource_free(resource); return error; }
/** * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals * of a given MC bus * * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free */ void fsl_mc_portal_free(struct fsl_mc_io *mc_io) { struct fsl_mc_device *dpmcp_dev; struct fsl_mc_resource *resource; /* * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed * to have a DPMCP object associated with. */ dpmcp_dev = mc_io->dpmcp_dev; if (WARN_ON(!dpmcp_dev)) return; resource = dpmcp_dev->resource; if (WARN_ON(!resource || resource->type != FSL_MC_POOL_DPMCP)) return; if (WARN_ON(resource->data != dpmcp_dev)) return; fsl_destroy_mc_io(mc_io); fsl_mc_resource_free(resource); }
/** * fsl_mc_portal_allocate - Allocates an MC portal * * @mc_dev: MC device for which the MC portal is to be allocated * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated * MC portal. * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object * that wraps the allocated MC portal is to be returned * * This function allocates an MC portal from the device's parent DPRC, * from the corresponding MC bus' pool of MC portals and wraps * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the * portal is allocated from its own MC bus. */ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, u16 mc_io_flags, struct fsl_mc_io **new_mc_io) { struct fsl_mc_device *mc_bus_dev; struct fsl_mc_bus *mc_bus; phys_addr_t mc_portal_phys_addr; size_t mc_portal_size; struct fsl_mc_device *dpmcp_dev; int error = -EINVAL; struct fsl_mc_resource *resource = NULL; struct fsl_mc_io *mc_io = NULL; if (mc_dev->flags & FSL_MC_IS_DPRC) { mc_bus_dev = mc_dev; } else { if (WARN_ON(!dev_is_fsl_mc(mc_dev->dev.parent))) return error; mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); } mc_bus = to_fsl_mc_bus(mc_bus_dev); *new_mc_io = NULL; error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource); if (error < 0) return error; error = -EINVAL; dpmcp_dev = resource->data; if (WARN_ON(!dpmcp_dev)) goto error_cleanup_resource; if (dpmcp_dev->obj_desc.ver_major < DPMCP_MIN_VER_MAJOR || (dpmcp_dev->obj_desc.ver_major == DPMCP_MIN_VER_MAJOR && dpmcp_dev->obj_desc.ver_minor < DPMCP_MIN_VER_MINOR)) { dev_err(&dpmcp_dev->dev, "ERROR: Version %d.%d of DPMCP not supported.\n", dpmcp_dev->obj_desc.ver_major, dpmcp_dev->obj_desc.ver_minor); error = -ENOTSUPP; goto error_cleanup_resource; } if (WARN_ON(dpmcp_dev->obj_desc.region_count == 0)) goto error_cleanup_resource; mc_portal_phys_addr = dpmcp_dev->regions[0].start; mc_portal_size = dpmcp_dev->regions[0].end - dpmcp_dev->regions[0].start + 1; if (WARN_ON(mc_portal_size != mc_bus_dev->mc_io->portal_size)) goto error_cleanup_resource; error = fsl_create_mc_io(&mc_bus_dev->dev, mc_portal_phys_addr, mc_portal_size, dpmcp_dev, mc_io_flags, &mc_io); if (error < 0) goto error_cleanup_resource; *new_mc_io = mc_io; return 0; error_cleanup_resource: fsl_mc_resource_free(resource); return error; }