18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fsl-mc object allocator driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/msi.h> 118c2ecf20Sopenharmony_ci#include <linux/fsl/mc.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "fsl-mc-private.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic bool __must_check fsl_mc_is_allocatable(struct fsl_mc_device *mc_dev) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci return is_fsl_mc_bus_dpbp(mc_dev) || 188c2ecf20Sopenharmony_ci is_fsl_mc_bus_dpmcp(mc_dev) || 198c2ecf20Sopenharmony_ci is_fsl_mc_bus_dpcon(mc_dev); 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/** 238c2ecf20Sopenharmony_ci * fsl_mc_resource_pool_add_device - add allocatable object to a resource 248c2ecf20Sopenharmony_ci * pool of a given fsl-mc bus 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * @mc_bus: pointer to the fsl-mc bus 278c2ecf20Sopenharmony_ci * @pool_type: pool type 288c2ecf20Sopenharmony_ci * @mc_dev: pointer to allocatable fsl-mc device 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus 318c2ecf20Sopenharmony_ci *mc_bus, 328c2ecf20Sopenharmony_ci enum fsl_mc_pool_type 338c2ecf20Sopenharmony_ci pool_type, 348c2ecf20Sopenharmony_ci struct fsl_mc_device 358c2ecf20Sopenharmony_ci *mc_dev) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool; 388c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 398c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; 408c2ecf20Sopenharmony_ci int error = -EINVAL; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES) 438c2ecf20Sopenharmony_ci goto out; 448c2ecf20Sopenharmony_ci if (!fsl_mc_is_allocatable(mc_dev)) 458c2ecf20Sopenharmony_ci goto out; 468c2ecf20Sopenharmony_ci if (mc_dev->resource) 478c2ecf20Sopenharmony_ci goto out; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci res_pool = &mc_bus->resource_pools[pool_type]; 508c2ecf20Sopenharmony_ci if (res_pool->type != pool_type) 518c2ecf20Sopenharmony_ci goto out; 528c2ecf20Sopenharmony_ci if (res_pool->mc_bus != mc_bus) 538c2ecf20Sopenharmony_ci goto out; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci mutex_lock(&res_pool->mutex); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (res_pool->max_count < 0) 588c2ecf20Sopenharmony_ci goto out_unlock; 598c2ecf20Sopenharmony_ci if (res_pool->free_count < 0 || 608c2ecf20Sopenharmony_ci res_pool->free_count > res_pool->max_count) 618c2ecf20Sopenharmony_ci goto out_unlock; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci resource = devm_kzalloc(&mc_bus_dev->dev, sizeof(*resource), 648c2ecf20Sopenharmony_ci GFP_KERNEL); 658c2ecf20Sopenharmony_ci if (!resource) { 668c2ecf20Sopenharmony_ci error = -ENOMEM; 678c2ecf20Sopenharmony_ci dev_err(&mc_bus_dev->dev, 688c2ecf20Sopenharmony_ci "Failed to allocate memory for fsl_mc_resource\n"); 698c2ecf20Sopenharmony_ci goto out_unlock; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci resource->type = pool_type; 738c2ecf20Sopenharmony_ci resource->id = mc_dev->obj_desc.id; 748c2ecf20Sopenharmony_ci resource->data = mc_dev; 758c2ecf20Sopenharmony_ci resource->parent_pool = res_pool; 768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&resource->node); 778c2ecf20Sopenharmony_ci list_add_tail(&resource->node, &res_pool->free_list); 788c2ecf20Sopenharmony_ci mc_dev->resource = resource; 798c2ecf20Sopenharmony_ci res_pool->free_count++; 808c2ecf20Sopenharmony_ci res_pool->max_count++; 818c2ecf20Sopenharmony_ci error = 0; 828c2ecf20Sopenharmony_ciout_unlock: 838c2ecf20Sopenharmony_ci mutex_unlock(&res_pool->mutex); 848c2ecf20Sopenharmony_ciout: 858c2ecf20Sopenharmony_ci return error; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/** 898c2ecf20Sopenharmony_ci * fsl_mc_resource_pool_remove_device - remove an allocatable device from a 908c2ecf20Sopenharmony_ci * resource pool 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * @mc_dev: pointer to allocatable fsl-mc device 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * It permanently removes an allocatable fsl-mc device from the resource 958c2ecf20Sopenharmony_ci * pool. It's an error if the device is in use. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device 988c2ecf20Sopenharmony_ci *mc_dev) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_bus_dev; 1018c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus; 1028c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool; 1038c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 1048c2ecf20Sopenharmony_ci int error = -EINVAL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (!fsl_mc_is_allocatable(mc_dev)) 1078c2ecf20Sopenharmony_ci goto out; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci resource = mc_dev->resource; 1108c2ecf20Sopenharmony_ci if (!resource || resource->data != mc_dev) 1118c2ecf20Sopenharmony_ci goto out; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); 1148c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(mc_bus_dev); 1158c2ecf20Sopenharmony_ci res_pool = resource->parent_pool; 1168c2ecf20Sopenharmony_ci if (res_pool != &mc_bus->resource_pools[resource->type]) 1178c2ecf20Sopenharmony_ci goto out; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mutex_lock(&res_pool->mutex); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (res_pool->max_count <= 0) 1228c2ecf20Sopenharmony_ci goto out_unlock; 1238c2ecf20Sopenharmony_ci if (res_pool->free_count <= 0 || 1248c2ecf20Sopenharmony_ci res_pool->free_count > res_pool->max_count) 1258c2ecf20Sopenharmony_ci goto out_unlock; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * If the device is currently allocated, its resource is not 1298c2ecf20Sopenharmony_ci * in the free list and thus, the device cannot be removed. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci if (list_empty(&resource->node)) { 1328c2ecf20Sopenharmony_ci error = -EBUSY; 1338c2ecf20Sopenharmony_ci dev_err(&mc_bus_dev->dev, 1348c2ecf20Sopenharmony_ci "Device %s cannot be removed from resource pool\n", 1358c2ecf20Sopenharmony_ci dev_name(&mc_dev->dev)); 1368c2ecf20Sopenharmony_ci goto out_unlock; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci list_del_init(&resource->node); 1408c2ecf20Sopenharmony_ci res_pool->free_count--; 1418c2ecf20Sopenharmony_ci res_pool->max_count--; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci devm_kfree(&mc_bus_dev->dev, resource); 1448c2ecf20Sopenharmony_ci mc_dev->resource = NULL; 1458c2ecf20Sopenharmony_ci error = 0; 1468c2ecf20Sopenharmony_ciout_unlock: 1478c2ecf20Sopenharmony_ci mutex_unlock(&res_pool->mutex); 1488c2ecf20Sopenharmony_ciout: 1498c2ecf20Sopenharmony_ci return error; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const char *const fsl_mc_pool_type_strings[] = { 1538c2ecf20Sopenharmony_ci [FSL_MC_POOL_DPMCP] = "dpmcp", 1548c2ecf20Sopenharmony_ci [FSL_MC_POOL_DPBP] = "dpbp", 1558c2ecf20Sopenharmony_ci [FSL_MC_POOL_DPCON] = "dpcon", 1568c2ecf20Sopenharmony_ci [FSL_MC_POOL_IRQ] = "irq", 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int __must_check object_type_to_pool_type(const char *object_type, 1608c2ecf20Sopenharmony_ci enum fsl_mc_pool_type 1618c2ecf20Sopenharmony_ci *pool_type) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci unsigned int i; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fsl_mc_pool_type_strings); i++) { 1668c2ecf20Sopenharmony_ci if (strcmp(object_type, fsl_mc_pool_type_strings[i]) == 0) { 1678c2ecf20Sopenharmony_ci *pool_type = i; 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ciint __must_check fsl_mc_resource_allocate(struct fsl_mc_bus *mc_bus, 1768c2ecf20Sopenharmony_ci enum fsl_mc_pool_type pool_type, 1778c2ecf20Sopenharmony_ci struct fsl_mc_resource **new_resource) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool; 1808c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 1818c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; 1828c2ecf20Sopenharmony_ci int error = -EINVAL; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(fsl_mc_pool_type_strings) != 1858c2ecf20Sopenharmony_ci FSL_MC_NUM_POOL_TYPES); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci *new_resource = NULL; 1888c2ecf20Sopenharmony_ci if (pool_type < 0 || pool_type >= FSL_MC_NUM_POOL_TYPES) 1898c2ecf20Sopenharmony_ci goto out; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci res_pool = &mc_bus->resource_pools[pool_type]; 1928c2ecf20Sopenharmony_ci if (res_pool->mc_bus != mc_bus) 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mutex_lock(&res_pool->mutex); 1968c2ecf20Sopenharmony_ci resource = list_first_entry_or_null(&res_pool->free_list, 1978c2ecf20Sopenharmony_ci struct fsl_mc_resource, node); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!resource) { 2008c2ecf20Sopenharmony_ci error = -ENXIO; 2018c2ecf20Sopenharmony_ci dev_err(&mc_bus_dev->dev, 2028c2ecf20Sopenharmony_ci "No more resources of type %s left\n", 2038c2ecf20Sopenharmony_ci fsl_mc_pool_type_strings[pool_type]); 2048c2ecf20Sopenharmony_ci goto out_unlock; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (resource->type != pool_type) 2088c2ecf20Sopenharmony_ci goto out_unlock; 2098c2ecf20Sopenharmony_ci if (resource->parent_pool != res_pool) 2108c2ecf20Sopenharmony_ci goto out_unlock; 2118c2ecf20Sopenharmony_ci if (res_pool->free_count <= 0 || 2128c2ecf20Sopenharmony_ci res_pool->free_count > res_pool->max_count) 2138c2ecf20Sopenharmony_ci goto out_unlock; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci list_del_init(&resource->node); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci res_pool->free_count--; 2188c2ecf20Sopenharmony_ci error = 0; 2198c2ecf20Sopenharmony_ciout_unlock: 2208c2ecf20Sopenharmony_ci mutex_unlock(&res_pool->mutex); 2218c2ecf20Sopenharmony_ci *new_resource = resource; 2228c2ecf20Sopenharmony_ciout: 2238c2ecf20Sopenharmony_ci return error; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_resource_allocate); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_civoid fsl_mc_resource_free(struct fsl_mc_resource *resource) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci res_pool = resource->parent_pool; 2328c2ecf20Sopenharmony_ci if (resource->type != res_pool->type) 2338c2ecf20Sopenharmony_ci return; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mutex_lock(&res_pool->mutex); 2368c2ecf20Sopenharmony_ci if (res_pool->free_count < 0 || 2378c2ecf20Sopenharmony_ci res_pool->free_count >= res_pool->max_count) 2388c2ecf20Sopenharmony_ci goto out_unlock; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!list_empty(&resource->node)) 2418c2ecf20Sopenharmony_ci goto out_unlock; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci list_add_tail(&resource->node, &res_pool->free_list); 2448c2ecf20Sopenharmony_ci res_pool->free_count++; 2458c2ecf20Sopenharmony_ciout_unlock: 2468c2ecf20Sopenharmony_ci mutex_unlock(&res_pool->mutex); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_resource_free); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/** 2518c2ecf20Sopenharmony_ci * fsl_mc_object_allocate - Allocates an fsl-mc object of the given 2528c2ecf20Sopenharmony_ci * pool type from a given fsl-mc bus instance 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * @mc_dev: fsl-mc device which is used in conjunction with the 2558c2ecf20Sopenharmony_ci * allocated object 2568c2ecf20Sopenharmony_ci * @pool_type: pool type 2578c2ecf20Sopenharmony_ci * @new_mc_dev: pointer to area where the pointer to the allocated device 2588c2ecf20Sopenharmony_ci * is to be returned 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * Allocatable objects are always used in conjunction with some functional 2618c2ecf20Sopenharmony_ci * device. This function allocates an object of the specified type from 2628c2ecf20Sopenharmony_ci * the DPRC containing the functional device. 2638c2ecf20Sopenharmony_ci * 2648c2ecf20Sopenharmony_ci * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC 2658c2ecf20Sopenharmony_ci * portals are allocated using fsl_mc_portal_allocate(), instead of 2668c2ecf20Sopenharmony_ci * this function. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ciint __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, 2698c2ecf20Sopenharmony_ci enum fsl_mc_pool_type pool_type, 2708c2ecf20Sopenharmony_ci struct fsl_mc_device **new_mc_adev) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_bus_dev; 2738c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus; 2748c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_adev; 2758c2ecf20Sopenharmony_ci int error = -EINVAL; 2768c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource = NULL; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci *new_mc_adev = NULL; 2798c2ecf20Sopenharmony_ci if (mc_dev->flags & FSL_MC_IS_DPRC) 2808c2ecf20Sopenharmony_ci goto error; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (!dev_is_fsl_mc(mc_dev->dev.parent)) 2838c2ecf20Sopenharmony_ci goto error; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (pool_type == FSL_MC_POOL_DPMCP) 2868c2ecf20Sopenharmony_ci goto error; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); 2898c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(mc_bus_dev); 2908c2ecf20Sopenharmony_ci error = fsl_mc_resource_allocate(mc_bus, pool_type, &resource); 2918c2ecf20Sopenharmony_ci if (error < 0) 2928c2ecf20Sopenharmony_ci goto error; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci mc_adev = resource->data; 2958c2ecf20Sopenharmony_ci if (!mc_adev) { 2968c2ecf20Sopenharmony_ci error = -EINVAL; 2978c2ecf20Sopenharmony_ci goto error; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mc_adev->consumer_link = device_link_add(&mc_dev->dev, 3018c2ecf20Sopenharmony_ci &mc_adev->dev, 3028c2ecf20Sopenharmony_ci DL_FLAG_AUTOREMOVE_CONSUMER); 3038c2ecf20Sopenharmony_ci if (!mc_adev->consumer_link) { 3048c2ecf20Sopenharmony_ci error = -EINVAL; 3058c2ecf20Sopenharmony_ci goto error; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci *new_mc_adev = mc_adev; 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_cierror: 3118c2ecf20Sopenharmony_ci if (resource) 3128c2ecf20Sopenharmony_ci fsl_mc_resource_free(resource); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return error; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_object_allocate); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/** 3198c2ecf20Sopenharmony_ci * fsl_mc_object_free - Returns an fsl-mc object to the resource 3208c2ecf20Sopenharmony_ci * pool where it came from. 3218c2ecf20Sopenharmony_ci * @mc_adev: Pointer to the fsl-mc device 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_civoid fsl_mc_object_free(struct fsl_mc_device *mc_adev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci resource = mc_adev->resource; 3288c2ecf20Sopenharmony_ci if (resource->type == FSL_MC_POOL_DPMCP) 3298c2ecf20Sopenharmony_ci return; 3308c2ecf20Sopenharmony_ci if (resource->data != mc_adev) 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci fsl_mc_resource_free(resource); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci mc_adev->consumer_link = NULL; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_object_free); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * A DPRC and the devices in the DPRC all share the same GIC-ITS device 3418c2ecf20Sopenharmony_ci * ID. A block of IRQs is pre-allocated and maintained in a pool 3428c2ecf20Sopenharmony_ci * from which devices can allocate them when needed. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* 3468c2ecf20Sopenharmony_ci * Initialize the interrupt pool associated with an fsl-mc bus. 3478c2ecf20Sopenharmony_ci * It allocates a block of IRQs from the GIC-ITS. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ciint fsl_mc_populate_irq_pool(struct fsl_mc_device *mc_bus_dev, 3508c2ecf20Sopenharmony_ci unsigned int irq_count) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci unsigned int i; 3538c2ecf20Sopenharmony_ci struct msi_desc *msi_desc; 3548c2ecf20Sopenharmony_ci struct fsl_mc_device_irq *irq_resources; 3558c2ecf20Sopenharmony_ci struct fsl_mc_device_irq *mc_dev_irq; 3568c2ecf20Sopenharmony_ci int error; 3578c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 3588c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool = 3598c2ecf20Sopenharmony_ci &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* do nothing if the IRQ pool is already populated */ 3628c2ecf20Sopenharmony_ci if (mc_bus->irq_resources) 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (irq_count == 0 || 3668c2ecf20Sopenharmony_ci irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) 3678c2ecf20Sopenharmony_ci return -EINVAL; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci error = fsl_mc_msi_domain_alloc_irqs(&mc_bus_dev->dev, irq_count); 3708c2ecf20Sopenharmony_ci if (error < 0) 3718c2ecf20Sopenharmony_ci return error; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci irq_resources = devm_kcalloc(&mc_bus_dev->dev, 3748c2ecf20Sopenharmony_ci irq_count, sizeof(*irq_resources), 3758c2ecf20Sopenharmony_ci GFP_KERNEL); 3768c2ecf20Sopenharmony_ci if (!irq_resources) { 3778c2ecf20Sopenharmony_ci error = -ENOMEM; 3788c2ecf20Sopenharmony_ci goto cleanup_msi_irqs; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (i = 0; i < irq_count; i++) { 3828c2ecf20Sopenharmony_ci mc_dev_irq = &irq_resources[i]; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* 3858c2ecf20Sopenharmony_ci * NOTE: This mc_dev_irq's MSI addr/value pair will be set 3868c2ecf20Sopenharmony_ci * by the fsl_mc_msi_write_msg() callback 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci mc_dev_irq->resource.type = res_pool->type; 3898c2ecf20Sopenharmony_ci mc_dev_irq->resource.data = mc_dev_irq; 3908c2ecf20Sopenharmony_ci mc_dev_irq->resource.parent_pool = res_pool; 3918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mc_dev_irq->resource.node); 3928c2ecf20Sopenharmony_ci list_add_tail(&mc_dev_irq->resource.node, &res_pool->free_list); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci for_each_msi_entry(msi_desc, &mc_bus_dev->dev) { 3968c2ecf20Sopenharmony_ci mc_dev_irq = &irq_resources[msi_desc->fsl_mc.msi_index]; 3978c2ecf20Sopenharmony_ci mc_dev_irq->msi_desc = msi_desc; 3988c2ecf20Sopenharmony_ci mc_dev_irq->resource.id = msi_desc->irq; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci res_pool->max_count = irq_count; 4028c2ecf20Sopenharmony_ci res_pool->free_count = irq_count; 4038c2ecf20Sopenharmony_ci mc_bus->irq_resources = irq_resources; 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cicleanup_msi_irqs: 4078c2ecf20Sopenharmony_ci fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); 4088c2ecf20Sopenharmony_ci return error; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/** 4138c2ecf20Sopenharmony_ci * Teardown the interrupt pool associated with an fsl-mc bus. 4148c2ecf20Sopenharmony_ci * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_civoid fsl_mc_cleanup_irq_pool(struct fsl_mc_device *mc_bus_dev) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 4198c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool = 4208c2ecf20Sopenharmony_ci &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (!mc_bus->irq_resources) 4238c2ecf20Sopenharmony_ci return; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (res_pool->max_count == 0) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (res_pool->free_count != res_pool->max_count) 4298c2ecf20Sopenharmony_ci return; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&res_pool->free_list); 4328c2ecf20Sopenharmony_ci res_pool->max_count = 0; 4338c2ecf20Sopenharmony_ci res_pool->free_count = 0; 4348c2ecf20Sopenharmony_ci mc_bus->irq_resources = NULL; 4358c2ecf20Sopenharmony_ci fsl_mc_msi_domain_free_irqs(&mc_bus_dev->dev); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/** 4408c2ecf20Sopenharmony_ci * Allocate the IRQs required by a given fsl-mc device. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ciint __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int i; 4458c2ecf20Sopenharmony_ci int irq_count; 4468c2ecf20Sopenharmony_ci int res_allocated_count = 0; 4478c2ecf20Sopenharmony_ci int error = -EINVAL; 4488c2ecf20Sopenharmony_ci struct fsl_mc_device_irq **irqs = NULL; 4498c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus; 4508c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (mc_dev->irqs) 4538c2ecf20Sopenharmony_ci return -EINVAL; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci irq_count = mc_dev->obj_desc.irq_count; 4568c2ecf20Sopenharmony_ci if (irq_count == 0) 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (is_fsl_mc_bus_dprc(mc_dev)) 4608c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(mc_dev); 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!mc_bus->irq_resources) 4658c2ecf20Sopenharmony_ci return -EINVAL; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; 4688c2ecf20Sopenharmony_ci if (res_pool->free_count < irq_count) { 4698c2ecf20Sopenharmony_ci dev_err(&mc_dev->dev, 4708c2ecf20Sopenharmony_ci "Not able to allocate %u irqs for device\n", irq_count); 4718c2ecf20Sopenharmony_ci return -ENOSPC; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci irqs = devm_kcalloc(&mc_dev->dev, irq_count, sizeof(irqs[0]), 4758c2ecf20Sopenharmony_ci GFP_KERNEL); 4768c2ecf20Sopenharmony_ci if (!irqs) 4778c2ecf20Sopenharmony_ci return -ENOMEM; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci for (i = 0; i < irq_count; i++) { 4808c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_IRQ, 4838c2ecf20Sopenharmony_ci &resource); 4848c2ecf20Sopenharmony_ci if (error < 0) 4858c2ecf20Sopenharmony_ci goto error_resource_alloc; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci irqs[i] = to_fsl_mc_irq(resource); 4888c2ecf20Sopenharmony_ci res_allocated_count++; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci irqs[i]->mc_dev = mc_dev; 4918c2ecf20Sopenharmony_ci irqs[i]->dev_irq_index = i; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci mc_dev->irqs = irqs; 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cierror_resource_alloc: 4988c2ecf20Sopenharmony_ci for (i = 0; i < res_allocated_count; i++) { 4998c2ecf20Sopenharmony_ci irqs[i]->mc_dev = NULL; 5008c2ecf20Sopenharmony_ci fsl_mc_resource_free(&irqs[i]->resource); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return error; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * Frees the IRQs that were allocated for an fsl-mc device. 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_civoid fsl_mc_free_irqs(struct fsl_mc_device *mc_dev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci int i; 5138c2ecf20Sopenharmony_ci int irq_count; 5148c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus; 5158c2ecf20Sopenharmony_ci struct fsl_mc_device_irq **irqs = mc_dev->irqs; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (!irqs) 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci irq_count = mc_dev->obj_desc.irq_count; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (is_fsl_mc_bus_dprc(mc_dev)) 5238c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(mc_dev); 5248c2ecf20Sopenharmony_ci else 5258c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(to_fsl_mc_device(mc_dev->dev.parent)); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (!mc_bus->irq_resources) 5288c2ecf20Sopenharmony_ci return; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci for (i = 0; i < irq_count; i++) { 5318c2ecf20Sopenharmony_ci irqs[i]->mc_dev = NULL; 5328c2ecf20Sopenharmony_ci fsl_mc_resource_free(&irqs[i]->resource); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci mc_dev->irqs = NULL; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_mc_free_irqs); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_civoid fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci int pool_type; 5428c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) { 5458c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool = 5468c2ecf20Sopenharmony_ci &mc_bus->resource_pools[pool_type]; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci res_pool->type = pool_type; 5498c2ecf20Sopenharmony_ci res_pool->max_count = 0; 5508c2ecf20Sopenharmony_ci res_pool->free_count = 0; 5518c2ecf20Sopenharmony_ci res_pool->mc_bus = mc_bus; 5528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&res_pool->free_list); 5538c2ecf20Sopenharmony_ci mutex_init(&res_pool->mutex); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic void fsl_mc_cleanup_resource_pool(struct fsl_mc_device *mc_bus_dev, 5588c2ecf20Sopenharmony_ci enum fsl_mc_pool_type pool_type) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct fsl_mc_resource *resource; 5618c2ecf20Sopenharmony_ci struct fsl_mc_resource *next; 5628c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 5638c2ecf20Sopenharmony_ci struct fsl_mc_resource_pool *res_pool = 5648c2ecf20Sopenharmony_ci &mc_bus->resource_pools[pool_type]; 5658c2ecf20Sopenharmony_ci int free_count = 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci list_for_each_entry_safe(resource, next, &res_pool->free_list, node) { 5688c2ecf20Sopenharmony_ci free_count++; 5698c2ecf20Sopenharmony_ci devm_kfree(&mc_bus_dev->dev, resource); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_civoid fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci int pool_type; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci for (pool_type = 0; pool_type < FSL_MC_NUM_POOL_TYPES; pool_type++) 5788c2ecf20Sopenharmony_ci fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/** 5828c2ecf20Sopenharmony_ci * fsl_mc_allocator_probe - callback invoked when an allocatable device is 5838c2ecf20Sopenharmony_ci * being added to the system 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci enum fsl_mc_pool_type pool_type; 5888c2ecf20Sopenharmony_ci struct fsl_mc_device *mc_bus_dev; 5898c2ecf20Sopenharmony_ci struct fsl_mc_bus *mc_bus; 5908c2ecf20Sopenharmony_ci int error; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (!fsl_mc_is_allocatable(mc_dev)) 5938c2ecf20Sopenharmony_ci return -EINVAL; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); 5968c2ecf20Sopenharmony_ci if (!dev_is_fsl_mc(&mc_bus_dev->dev)) 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci mc_bus = to_fsl_mc_bus(mc_bus_dev); 6008c2ecf20Sopenharmony_ci error = object_type_to_pool_type(mc_dev->obj_desc.type, &pool_type); 6018c2ecf20Sopenharmony_ci if (error < 0) 6028c2ecf20Sopenharmony_ci return error; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci error = fsl_mc_resource_pool_add_device(mc_bus, pool_type, mc_dev); 6058c2ecf20Sopenharmony_ci if (error < 0) 6068c2ecf20Sopenharmony_ci return error; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci dev_dbg(&mc_dev->dev, 6098c2ecf20Sopenharmony_ci "Allocatable fsl-mc device bound to fsl_mc_allocator driver"); 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/** 6148c2ecf20Sopenharmony_ci * fsl_mc_allocator_remove - callback invoked when an allocatable device is 6158c2ecf20Sopenharmony_ci * being removed from the system 6168c2ecf20Sopenharmony_ci */ 6178c2ecf20Sopenharmony_cistatic int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci int error; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (!fsl_mc_is_allocatable(mc_dev)) 6228c2ecf20Sopenharmony_ci return -EINVAL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (mc_dev->resource) { 6258c2ecf20Sopenharmony_ci error = fsl_mc_resource_pool_remove_device(mc_dev); 6268c2ecf20Sopenharmony_ci if (error < 0) 6278c2ecf20Sopenharmony_ci return error; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci dev_dbg(&mc_dev->dev, 6318c2ecf20Sopenharmony_ci "Allocatable fsl-mc device unbound from fsl_mc_allocator driver"); 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic const struct fsl_mc_device_id match_id_table[] = { 6368c2ecf20Sopenharmony_ci { 6378c2ecf20Sopenharmony_ci .vendor = FSL_MC_VENDOR_FREESCALE, 6388c2ecf20Sopenharmony_ci .obj_type = "dpbp", 6398c2ecf20Sopenharmony_ci }, 6408c2ecf20Sopenharmony_ci { 6418c2ecf20Sopenharmony_ci .vendor = FSL_MC_VENDOR_FREESCALE, 6428c2ecf20Sopenharmony_ci .obj_type = "dpmcp", 6438c2ecf20Sopenharmony_ci }, 6448c2ecf20Sopenharmony_ci { 6458c2ecf20Sopenharmony_ci .vendor = FSL_MC_VENDOR_FREESCALE, 6468c2ecf20Sopenharmony_ci .obj_type = "dpcon", 6478c2ecf20Sopenharmony_ci }, 6488c2ecf20Sopenharmony_ci {.vendor = 0x0}, 6498c2ecf20Sopenharmony_ci}; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic struct fsl_mc_driver fsl_mc_allocator_driver = { 6528c2ecf20Sopenharmony_ci .driver = { 6538c2ecf20Sopenharmony_ci .name = "fsl_mc_allocator", 6548c2ecf20Sopenharmony_ci .pm = NULL, 6558c2ecf20Sopenharmony_ci }, 6568c2ecf20Sopenharmony_ci .match_id_table = match_id_table, 6578c2ecf20Sopenharmony_ci .probe = fsl_mc_allocator_probe, 6588c2ecf20Sopenharmony_ci .remove = fsl_mc_allocator_remove, 6598c2ecf20Sopenharmony_ci}; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ciint __init fsl_mc_allocator_driver_init(void) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci return fsl_mc_driver_register(&fsl_mc_allocator_driver); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_civoid fsl_mc_allocator_driver_exit(void) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci fsl_mc_driver_unregister(&fsl_mc_allocator_driver); 6698c2ecf20Sopenharmony_ci} 670