| /* |
| * Copyright (C) 2010-2016 ARM Limited. All rights reserved. |
| * |
| * This program is free software and is provided to you under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. |
| * |
| * A copy of the licence is included with the program, and can also be obtained from Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "mali_kernel_common.h" |
| #include "mali_session.h" |
| #include "mali_osk.h" |
| #include "mali_osk_mali.h" |
| #include "mali_ukk.h" |
| #include "mali_kernel_core.h" |
| #include "mali_memory.h" |
| #include "mali_mem_validation.h" |
| #include "mali_mmu.h" |
| #include "mali_mmu_page_directory.h" |
| #include "mali_dlbu.h" |
| #include "mali_broadcast.h" |
| #include "mali_gp.h" |
| #include "mali_pp.h" |
| #include "mali_executor.h" |
| #include "mali_pp_job.h" |
| #include "mali_group.h" |
| #include "mali_pm.h" |
| #include "mali_pmu.h" |
| #include "mali_scheduler.h" |
| #include "mali_kernel_utilization.h" |
| #include "mali_l2_cache.h" |
| #include "mali_timeline.h" |
| #include "mali_soft_job.h" |
| #include "mali_pm_domain.h" |
| #if defined(CONFIG_MALI400_PROFILING) |
| #include "mali_osk_profiling.h" |
| #endif |
| #if defined(CONFIG_MALI400_INTERNAL_PROFILING) |
| #include "mali_profiling_internal.h" |
| #endif |
| #include "mali_control_timer.h" |
| #include "mali_dvfs_policy.h" |
| #include <linux/sched.h> |
| #include <linux/atomic.h> |
| #if defined(CONFIG_MALI_DMA_BUF_FENCE) |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) |
| #include <linux/dma-fence.h> |
| #else |
| #include <linux/fence.h> |
| #endif |
| #endif |
| |
| #define MALI_SHARED_MEMORY_DEFAULT_SIZE 0xffffffff |
| |
| /* Mali GPU memory. Real values come from module parameter or from device specific data */ |
| unsigned int mali_dedicated_mem_start = 0; |
| unsigned int mali_dedicated_mem_size = 0; |
| |
| /* Default shared memory size is set to 4G. */ |
| unsigned int mali_shared_mem_size = MALI_SHARED_MEMORY_DEFAULT_SIZE; |
| |
| /* Frame buffer memory to be accessible by Mali GPU */ |
| int mali_fb_start = 0; |
| int mali_fb_size = 0; |
| |
| /* Mali max job runtime */ |
| extern int mali_max_job_runtime; |
| |
| /** Start profiling from module load? */ |
| int mali_boot_profiling = 0; |
| |
| /** Limits for the number of PP cores behind each L2 cache. */ |
| int mali_max_pp_cores_group_1 = 0xFF; |
| int mali_max_pp_cores_group_2 = 0xFF; |
| |
| int mali_inited_pp_cores_group_1 = 0; |
| int mali_inited_pp_cores_group_2 = 0; |
| |
| static _mali_product_id_t global_product_id = _MALI_PRODUCT_ID_UNKNOWN; |
| static uintptr_t global_gpu_base_address = 0; |
| static u32 global_gpu_major_version = 0; |
| static u32 global_gpu_minor_version = 0; |
| |
| mali_bool mali_gpu_class_is_mali450 = MALI_FALSE; |
| mali_bool mali_gpu_class_is_mali470 = MALI_FALSE; |
| |
| static _mali_osk_errcode_t mali_set_global_gpu_base_address(void) |
| { |
| _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; |
| |
| global_gpu_base_address = _mali_osk_resource_base_address(); |
| if (0 == global_gpu_base_address) { |
| err = _MALI_OSK_ERR_ITEM_NOT_FOUND; |
| } |
| |
| return err; |
| } |
| |
| static u32 mali_get_bcast_id(_mali_osk_resource_t *resource_pp) |
| { |
| switch (resource_pp->base - global_gpu_base_address) { |
| case 0x08000: |
| case 0x20000: /* fall-through for aliased mapping */ |
| return 0x01; |
| case 0x0A000: |
| case 0x22000: /* fall-through for aliased mapping */ |
| return 0x02; |
| case 0x0C000: |
| case 0x24000: /* fall-through for aliased mapping */ |
| return 0x04; |
| case 0x0E000: |
| case 0x26000: /* fall-through for aliased mapping */ |
| return 0x08; |
| case 0x28000: |
| return 0x10; |
| case 0x2A000: |
| return 0x20; |
| case 0x2C000: |
| return 0x40; |
| case 0x2E000: |
| return 0x80; |
| default: |
| return 0; |
| } |
| } |
| |
| static _mali_osk_errcode_t mali_parse_product_info(void) |
| { |
| _mali_osk_resource_t first_pp_resource; |
| |
| /* Find the first PP core resource (again) */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_PP0, &first_pp_resource)) { |
| /* Create a dummy PP object for this core so that we can read the version register */ |
| struct mali_group *group = mali_group_create(NULL, NULL, NULL, MALI_DOMAIN_INDEX_PP0); |
| if (NULL != group) { |
| struct mali_pp_core *pp_core = mali_pp_create(&first_pp_resource, group, MALI_FALSE, mali_get_bcast_id(&first_pp_resource)); |
| if (NULL != pp_core) { |
| u32 pp_version; |
| |
| pp_version = mali_pp_core_get_version(pp_core); |
| |
| mali_group_delete(group); |
| |
| global_gpu_major_version = (pp_version >> 8) & 0xFF; |
| global_gpu_minor_version = pp_version & 0xFF; |
| |
| switch (pp_version >> 16) { |
| case MALI200_PP_PRODUCT_ID: |
| global_product_id = _MALI_PRODUCT_ID_MALI200; |
| MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-200 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); |
| MALI_PRINT_ERROR(("Mali-200 is not supported by this driver.\n")); |
| _mali_osk_abort(); |
| break; |
| case MALI300_PP_PRODUCT_ID: |
| global_product_id = _MALI_PRODUCT_ID_MALI300; |
| MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-300 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); |
| break; |
| case MALI400_PP_PRODUCT_ID: |
| global_product_id = _MALI_PRODUCT_ID_MALI400; |
| MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-400 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); |
| break; |
| case MALI450_PP_PRODUCT_ID: |
| global_product_id = _MALI_PRODUCT_ID_MALI450; |
| MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-450 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); |
| break; |
| case MALI470_PP_PRODUCT_ID: |
| global_product_id = _MALI_PRODUCT_ID_MALI470; |
| MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-470 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); |
| break; |
| default: |
| MALI_DEBUG_PRINT(2, ("Found unknown Mali GPU (r%up%u)\n", global_gpu_major_version, global_gpu_minor_version)); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| return _MALI_OSK_ERR_OK; |
| } else { |
| MALI_PRINT_ERROR(("Failed to create initial PP object\n")); |
| } |
| } else { |
| MALI_PRINT_ERROR(("Failed to create initial group object\n")); |
| } |
| } else { |
| MALI_PRINT_ERROR(("First PP core not specified in config file\n")); |
| } |
| |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| static void mali_delete_groups(void) |
| { |
| struct mali_group *group; |
| |
| group = mali_group_get_glob_group(0); |
| while (NULL != group) { |
| mali_group_delete(group); |
| group = mali_group_get_glob_group(0); |
| } |
| |
| MALI_DEBUG_ASSERT(0 == mali_group_get_glob_num_groups()); |
| } |
| |
| static void mali_delete_l2_cache_cores(void) |
| { |
| struct mali_l2_cache_core *l2; |
| |
| l2 = mali_l2_cache_core_get_glob_l2_core(0); |
| while (NULL != l2) { |
| mali_l2_cache_delete(l2); |
| l2 = mali_l2_cache_core_get_glob_l2_core(0); |
| } |
| |
| MALI_DEBUG_ASSERT(0 == mali_l2_cache_core_get_glob_num_l2_cores()); |
| } |
| |
| static struct mali_l2_cache_core *mali_create_l2_cache_core(_mali_osk_resource_t *resource, u32 domain_index) |
| { |
| struct mali_l2_cache_core *l2_cache = NULL; |
| |
| if (NULL != resource) { |
| |
| MALI_DEBUG_PRINT(3, ("Found L2 cache %s\n", resource->description)); |
| |
| l2_cache = mali_l2_cache_create(resource, domain_index); |
| if (NULL == l2_cache) { |
| MALI_PRINT_ERROR(("Failed to create L2 cache object\n")); |
| return NULL; |
| } |
| } |
| MALI_DEBUG_PRINT(3, ("Created L2 cache core object\n")); |
| |
| return l2_cache; |
| } |
| |
| static _mali_osk_errcode_t mali_parse_config_l2_cache(void) |
| { |
| struct mali_l2_cache_core *l2_cache = NULL; |
| |
| if (mali_is_mali400()) { |
| _mali_osk_resource_t l2_resource; |
| if (_MALI_OSK_ERR_OK != _mali_osk_resource_find(MALI400_OFFSET_L2_CACHE0, &l2_resource)) { |
| MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache in config file\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| l2_cache = mali_create_l2_cache_core(&l2_resource, MALI_DOMAIN_INDEX_L20); |
| if (NULL == l2_cache) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } else if (mali_is_mali450()) { |
| /* |
| * L2 for GP at 0x10000 |
| * L2 for PP0-3 at 0x01000 |
| * L2 for PP4-7 at 0x11000 (optional) |
| */ |
| |
| _mali_osk_resource_t l2_gp_resource; |
| _mali_osk_resource_t l2_pp_grp0_resource; |
| _mali_osk_resource_t l2_pp_grp1_resource; |
| |
| /* Make cluster for GP's L2 */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI450_OFFSET_L2_CACHE0, &l2_gp_resource)) { |
| MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for GP\n")); |
| l2_cache = mali_create_l2_cache_core(&l2_gp_resource, MALI_DOMAIN_INDEX_L20); |
| if (NULL == l2_cache) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } else { |
| MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for GP in config file\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Find corresponding l2 domain */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI450_OFFSET_L2_CACHE1, &l2_pp_grp0_resource)) { |
| MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for PP group 0\n")); |
| l2_cache = mali_create_l2_cache_core(&l2_pp_grp0_resource, MALI_DOMAIN_INDEX_L21); |
| if (NULL == l2_cache) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } else { |
| MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for PP group 0 in config file\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Second PP core group is optional, don't fail if we don't find it */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI450_OFFSET_L2_CACHE2, &l2_pp_grp1_resource)) { |
| MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for PP group 1\n")); |
| l2_cache = mali_create_l2_cache_core(&l2_pp_grp1_resource, MALI_DOMAIN_INDEX_L22); |
| if (NULL == l2_cache) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } |
| } else if (mali_is_mali470()) { |
| _mali_osk_resource_t l2c1_resource; |
| |
| /* Make cluster for L2C1 */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI470_OFFSET_L2_CACHE1, &l2c1_resource)) { |
| MALI_DEBUG_PRINT(3, ("Creating Mali-470 L2 cache 1\n")); |
| l2_cache = mali_create_l2_cache_core(&l2c1_resource, MALI_DOMAIN_INDEX_L21); |
| if (NULL == l2_cache) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } else { |
| MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for L2C1\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static struct mali_group *mali_create_group(struct mali_l2_cache_core *cache, |
| _mali_osk_resource_t *resource_mmu, |
| _mali_osk_resource_t *resource_gp, |
| _mali_osk_resource_t *resource_pp, |
| u32 domain_index) |
| { |
| struct mali_mmu_core *mmu; |
| struct mali_group *group; |
| |
| MALI_DEBUG_PRINT(3, ("Starting new group for MMU %s\n", resource_mmu->description)); |
| |
| /* Create the group object */ |
| group = mali_group_create(cache, NULL, NULL, domain_index); |
| if (NULL == group) { |
| MALI_PRINT_ERROR(("Failed to create group object for MMU %s\n", resource_mmu->description)); |
| return NULL; |
| } |
| |
| /* Create the MMU object inside group */ |
| mmu = mali_mmu_create(resource_mmu, group, MALI_FALSE); |
| if (NULL == mmu) { |
| MALI_PRINT_ERROR(("Failed to create MMU object\n")); |
| mali_group_delete(group); |
| return NULL; |
| } |
| |
| if (NULL != resource_gp) { |
| /* Create the GP core object inside this group */ |
| struct mali_gp_core *gp_core = mali_gp_create(resource_gp, group); |
| if (NULL == gp_core) { |
| /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ |
| MALI_PRINT_ERROR(("Failed to create GP object\n")); |
| mali_group_delete(group); |
| return NULL; |
| } |
| } |
| |
| if (NULL != resource_pp) { |
| struct mali_pp_core *pp_core; |
| |
| /* Create the PP core object inside this group */ |
| pp_core = mali_pp_create(resource_pp, group, MALI_FALSE, mali_get_bcast_id(resource_pp)); |
| if (NULL == pp_core) { |
| /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ |
| MALI_PRINT_ERROR(("Failed to create PP object\n")); |
| mali_group_delete(group); |
| return NULL; |
| } |
| } |
| |
| return group; |
| } |
| |
| static _mali_osk_errcode_t mali_create_virtual_group(_mali_osk_resource_t *resource_mmu_pp_bcast, |
| _mali_osk_resource_t *resource_pp_bcast, |
| _mali_osk_resource_t *resource_dlbu, |
| _mali_osk_resource_t *resource_bcast) |
| { |
| struct mali_mmu_core *mmu_pp_bcast_core; |
| struct mali_pp_core *pp_bcast_core; |
| struct mali_dlbu_core *dlbu_core; |
| struct mali_bcast_unit *bcast_core; |
| struct mali_group *group; |
| |
| MALI_DEBUG_PRINT(2, ("Starting new virtual group for MMU PP broadcast core %s\n", resource_mmu_pp_bcast->description)); |
| |
| /* Create the DLBU core object */ |
| dlbu_core = mali_dlbu_create(resource_dlbu); |
| if (NULL == dlbu_core) { |
| MALI_PRINT_ERROR(("Failed to create DLBU object \n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Create the Broadcast unit core */ |
| bcast_core = mali_bcast_unit_create(resource_bcast); |
| if (NULL == bcast_core) { |
| MALI_PRINT_ERROR(("Failed to create Broadcast unit object!\n")); |
| mali_dlbu_delete(dlbu_core); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Create the group object */ |
| #if defined(DEBUG) |
| /* Get a physical PP group to temporarily add to broadcast unit. IRQ |
| * verification needs a physical group in the broadcast unit to test |
| * the broadcast unit interrupt line. */ |
| { |
| struct mali_group *phys_group = NULL; |
| int i; |
| for (i = 0; i < mali_group_get_glob_num_groups(); i++) { |
| phys_group = mali_group_get_glob_group(i); |
| if (NULL != mali_group_get_pp_core(phys_group)) break; |
| } |
| MALI_DEBUG_ASSERT(NULL != mali_group_get_pp_core(phys_group)); |
| |
| /* Add the group temporarily to the broadcast, and update the |
| * broadcast HW. Since the HW is not updated when removing the |
| * group the IRQ check will work when the virtual PP is created |
| * later. |
| * |
| * When the virtual group gets populated, the actually used |
| * groups will be added to the broadcast unit and the HW will |
| * be updated. |
| */ |
| mali_bcast_add_group(bcast_core, phys_group); |
| mali_bcast_reset(bcast_core); |
| mali_bcast_remove_group(bcast_core, phys_group); |
| } |
| #endif /* DEBUG */ |
| group = mali_group_create(NULL, dlbu_core, bcast_core, MALI_DOMAIN_INDEX_DUMMY); |
| if (NULL == group) { |
| MALI_PRINT_ERROR(("Failed to create group object for MMU PP broadcast core %s\n", resource_mmu_pp_bcast->description)); |
| mali_bcast_unit_delete(bcast_core); |
| mali_dlbu_delete(dlbu_core); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Create the MMU object inside group */ |
| mmu_pp_bcast_core = mali_mmu_create(resource_mmu_pp_bcast, group, MALI_TRUE); |
| if (NULL == mmu_pp_bcast_core) { |
| MALI_PRINT_ERROR(("Failed to create MMU PP broadcast object\n")); |
| mali_group_delete(group); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Create the PP core object inside this group */ |
| pp_bcast_core = mali_pp_create(resource_pp_bcast, group, MALI_TRUE, 0); |
| if (NULL == pp_bcast_core) { |
| /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ |
| MALI_PRINT_ERROR(("Failed to create PP object\n")); |
| mali_group_delete(group); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static _mali_osk_errcode_t mali_parse_config_groups(void) |
| { |
| struct mali_group *group; |
| int cluster_id_gp = 0; |
| int cluster_id_pp_grp0 = 0; |
| int cluster_id_pp_grp1 = 0; |
| int i; |
| |
| _mali_osk_resource_t resource_gp; |
| _mali_osk_resource_t resource_gp_mmu; |
| _mali_osk_resource_t resource_pp[8]; |
| _mali_osk_resource_t resource_pp_mmu[8]; |
| _mali_osk_resource_t resource_pp_mmu_bcast; |
| _mali_osk_resource_t resource_pp_bcast; |
| _mali_osk_resource_t resource_dlbu; |
| _mali_osk_resource_t resource_bcast; |
| _mali_osk_errcode_t resource_gp_found; |
| _mali_osk_errcode_t resource_gp_mmu_found; |
| _mali_osk_errcode_t resource_pp_found[8]; |
| _mali_osk_errcode_t resource_pp_mmu_found[8]; |
| _mali_osk_errcode_t resource_pp_mmu_bcast_found; |
| _mali_osk_errcode_t resource_pp_bcast_found; |
| _mali_osk_errcode_t resource_dlbu_found; |
| _mali_osk_errcode_t resource_bcast_found; |
| |
| if (!(mali_is_mali400() || mali_is_mali450() || mali_is_mali470())) { |
| /* No known HW core */ |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| if (MALI_MAX_JOB_RUNTIME_DEFAULT == mali_max_job_runtime) { |
| /* Group settings are not overridden by module parameters, so use device settings */ |
| _mali_osk_device_data data = { 0, }; |
| |
| if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { |
| /* Use device specific settings (if defined) */ |
| if (0 != data.max_job_runtime) { |
| mali_max_job_runtime = data.max_job_runtime; |
| } |
| } |
| } |
| |
| if (mali_is_mali450()) { |
| /* Mali-450 have separate L2s for GP, and PP core group(s) */ |
| cluster_id_pp_grp0 = 1; |
| cluster_id_pp_grp1 = 2; |
| } |
| |
| resource_gp_found = _mali_osk_resource_find(MALI_OFFSET_GP, &resource_gp); |
| resource_gp_mmu_found = _mali_osk_resource_find(MALI_OFFSET_GP_MMU, &resource_gp_mmu); |
| resource_pp_found[0] = _mali_osk_resource_find(MALI_OFFSET_PP0, &(resource_pp[0])); |
| resource_pp_found[1] = _mali_osk_resource_find(MALI_OFFSET_PP1, &(resource_pp[1])); |
| resource_pp_found[2] = _mali_osk_resource_find(MALI_OFFSET_PP2, &(resource_pp[2])); |
| resource_pp_found[3] = _mali_osk_resource_find(MALI_OFFSET_PP3, &(resource_pp[3])); |
| resource_pp_found[4] = _mali_osk_resource_find(MALI_OFFSET_PP4, &(resource_pp[4])); |
| resource_pp_found[5] = _mali_osk_resource_find(MALI_OFFSET_PP5, &(resource_pp[5])); |
| resource_pp_found[6] = _mali_osk_resource_find(MALI_OFFSET_PP6, &(resource_pp[6])); |
| resource_pp_found[7] = _mali_osk_resource_find(MALI_OFFSET_PP7, &(resource_pp[7])); |
| resource_pp_mmu_found[0] = _mali_osk_resource_find(MALI_OFFSET_PP0_MMU, &(resource_pp_mmu[0])); |
| resource_pp_mmu_found[1] = _mali_osk_resource_find(MALI_OFFSET_PP1_MMU, &(resource_pp_mmu[1])); |
| resource_pp_mmu_found[2] = _mali_osk_resource_find(MALI_OFFSET_PP2_MMU, &(resource_pp_mmu[2])); |
| resource_pp_mmu_found[3] = _mali_osk_resource_find(MALI_OFFSET_PP3_MMU, &(resource_pp_mmu[3])); |
| resource_pp_mmu_found[4] = _mali_osk_resource_find(MALI_OFFSET_PP4_MMU, &(resource_pp_mmu[4])); |
| resource_pp_mmu_found[5] = _mali_osk_resource_find(MALI_OFFSET_PP5_MMU, &(resource_pp_mmu[5])); |
| resource_pp_mmu_found[6] = _mali_osk_resource_find(MALI_OFFSET_PP6_MMU, &(resource_pp_mmu[6])); |
| resource_pp_mmu_found[7] = _mali_osk_resource_find(MALI_OFFSET_PP7_MMU, &(resource_pp_mmu[7])); |
| |
| |
| if (mali_is_mali450() || mali_is_mali470()) { |
| resource_bcast_found = _mali_osk_resource_find(MALI_OFFSET_BCAST, &resource_bcast); |
| resource_dlbu_found = _mali_osk_resource_find(MALI_OFFSET_DLBU, &resource_dlbu); |
| resource_pp_mmu_bcast_found = _mali_osk_resource_find(MALI_OFFSET_PP_BCAST_MMU, &resource_pp_mmu_bcast); |
| resource_pp_bcast_found = _mali_osk_resource_find(MALI_OFFSET_PP_BCAST, &resource_pp_bcast); |
| |
| if (_MALI_OSK_ERR_OK != resource_bcast_found || |
| _MALI_OSK_ERR_OK != resource_dlbu_found || |
| _MALI_OSK_ERR_OK != resource_pp_mmu_bcast_found || |
| _MALI_OSK_ERR_OK != resource_pp_bcast_found) { |
| /* Missing mandatory core(s) for Mali-450 or Mali-470 */ |
| MALI_DEBUG_PRINT(2, ("Missing mandatory resources, Mali-450 needs DLBU, Broadcast unit, virtual PP core and virtual MMU\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } |
| |
| if (_MALI_OSK_ERR_OK != resource_gp_found || |
| _MALI_OSK_ERR_OK != resource_gp_mmu_found || |
| _MALI_OSK_ERR_OK != resource_pp_found[0] || |
| _MALI_OSK_ERR_OK != resource_pp_mmu_found[0]) { |
| /* Missing mandatory core(s) */ |
| MALI_DEBUG_PRINT(2, ("Missing mandatory resource, need at least one GP and one PP, both with a separate MMU\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| MALI_DEBUG_ASSERT(1 <= mali_l2_cache_core_get_glob_num_l2_cores()); |
| group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_gp), &resource_gp_mmu, &resource_gp, NULL, MALI_DOMAIN_INDEX_GP); |
| if (NULL == group) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| /* Create group for first (and mandatory) PP core */ |
| MALI_DEBUG_ASSERT(mali_l2_cache_core_get_glob_num_l2_cores() >= (cluster_id_pp_grp0 + 1)); /* >= 1 on Mali-300 and Mali-400, >= 2 on Mali-450 */ |
| group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp0), &resource_pp_mmu[0], NULL, &resource_pp[0], MALI_DOMAIN_INDEX_PP0); |
| if (NULL == group) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| mali_inited_pp_cores_group_1++; |
| |
| /* Create groups for rest of the cores in the first PP core group */ |
| for (i = 1; i < 4; i++) { /* First half of the PP cores belong to first core group */ |
| if (mali_inited_pp_cores_group_1 < mali_max_pp_cores_group_1) { |
| if (_MALI_OSK_ERR_OK == resource_pp_found[i] && _MALI_OSK_ERR_OK == resource_pp_mmu_found[i]) { |
| group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp0), &resource_pp_mmu[i], NULL, &resource_pp[i], MALI_DOMAIN_INDEX_PP0 + i); |
| if (NULL == group) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| mali_inited_pp_cores_group_1++; |
| } |
| } |
| } |
| |
| /* Create groups for cores in the second PP core group */ |
| for (i = 4; i < 8; i++) { /* Second half of the PP cores belong to second core group */ |
| if (mali_inited_pp_cores_group_2 < mali_max_pp_cores_group_2) { |
| if (_MALI_OSK_ERR_OK == resource_pp_found[i] && _MALI_OSK_ERR_OK == resource_pp_mmu_found[i]) { |
| MALI_DEBUG_ASSERT(mali_l2_cache_core_get_glob_num_l2_cores() >= 2); /* Only Mali-450 have a second core group */ |
| group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp1), &resource_pp_mmu[i], NULL, &resource_pp[i], MALI_DOMAIN_INDEX_PP0 + i); |
| if (NULL == group) { |
| return _MALI_OSK_ERR_FAULT; |
| } |
| |
| mali_inited_pp_cores_group_2++; |
| } |
| } |
| } |
| |
| if (mali_is_mali450() || mali_is_mali470()) { |
| _mali_osk_errcode_t err = mali_create_virtual_group(&resource_pp_mmu_bcast, &resource_pp_bcast, &resource_dlbu, &resource_bcast); |
| if (_MALI_OSK_ERR_OK != err) { |
| return err; |
| } |
| } |
| |
| mali_max_pp_cores_group_1 = mali_inited_pp_cores_group_1; |
| mali_max_pp_cores_group_2 = mali_inited_pp_cores_group_2; |
| MALI_DEBUG_PRINT(2, ("%d+%d PP cores initialized\n", mali_inited_pp_cores_group_1, mali_inited_pp_cores_group_2)); |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static _mali_osk_errcode_t mali_check_shared_interrupts(void) |
| { |
| #if !defined(CONFIG_MALI_SHARED_INTERRUPTS) |
| if (MALI_TRUE == _mali_osk_shared_interrupts()) { |
| MALI_PRINT_ERROR(("Shared interrupts detected, but driver support is not enabled\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| #endif /* !defined(CONFIG_MALI_SHARED_INTERRUPTS) */ |
| |
| /* It is OK to compile support for shared interrupts even if Mali is not using it. */ |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static _mali_osk_errcode_t mali_parse_config_pmu(void) |
| { |
| _mali_osk_resource_t resource_pmu; |
| |
| MALI_DEBUG_ASSERT(0 != global_gpu_base_address); |
| |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_PMU, &resource_pmu)) { |
| struct mali_pmu_core *pmu; |
| |
| pmu = mali_pmu_create(&resource_pmu); |
| if (NULL == pmu) { |
| MALI_PRINT_ERROR(("Failed to create PMU\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| } |
| |
| /* It's ok if the PMU doesn't exist */ |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static _mali_osk_errcode_t mali_parse_config_memory(void) |
| { |
| _mali_osk_device_data data = { 0, }; |
| _mali_osk_errcode_t ret; |
| |
| /* The priority of setting the value of mali_shared_mem_size, |
| * mali_dedicated_mem_start and mali_dedicated_mem_size: |
| * 1. module parameter; |
| * 2. platform data; |
| * 3. default value; |
| **/ |
| if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { |
| /* Memory settings are not overridden by module parameters, so use device settings */ |
| if (0 == mali_dedicated_mem_start && 0 == mali_dedicated_mem_size) { |
| /* Use device specific settings (if defined) */ |
| mali_dedicated_mem_start = data.dedicated_mem_start; |
| mali_dedicated_mem_size = data.dedicated_mem_size; |
| } |
| |
| if (MALI_SHARED_MEMORY_DEFAULT_SIZE == mali_shared_mem_size && |
| 0 != data.shared_mem_size) { |
| mali_shared_mem_size = data.shared_mem_size; |
| } |
| } |
| |
| if (0 < mali_dedicated_mem_size && 0 != mali_dedicated_mem_start) { |
| MALI_DEBUG_PRINT(2, ("Mali memory settings (dedicated: 0x%08X@0x%08X)\n", |
| mali_dedicated_mem_size, mali_dedicated_mem_start)); |
| |
| /* Dedicated memory */ |
| ret = mali_memory_core_resource_dedicated_memory(mali_dedicated_mem_start, mali_dedicated_mem_size); |
| if (_MALI_OSK_ERR_OK != ret) { |
| MALI_PRINT_ERROR(("Failed to register dedicated memory\n")); |
| mali_memory_terminate(); |
| return ret; |
| } |
| } |
| |
| if (0 < mali_shared_mem_size) { |
| MALI_DEBUG_PRINT(2, ("Mali memory settings (shared: 0x%08X)\n", mali_shared_mem_size)); |
| |
| /* Shared OS memory */ |
| ret = mali_memory_core_resource_os_memory(mali_shared_mem_size); |
| if (_MALI_OSK_ERR_OK != ret) { |
| MALI_PRINT_ERROR(("Failed to register shared OS memory\n")); |
| mali_memory_terminate(); |
| return ret; |
| } |
| } |
| |
| if (0 == mali_fb_start && 0 == mali_fb_size) { |
| /* Frame buffer settings are not overridden by module parameters, so use device settings */ |
| _mali_osk_device_data data = { 0, }; |
| |
| if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { |
| /* Use device specific settings (if defined) */ |
| mali_fb_start = data.fb_start; |
| mali_fb_size = data.fb_size; |
| } |
| |
| MALI_DEBUG_PRINT(2, ("Using device defined frame buffer settings (0x%08X@0x%08X)\n", |
| mali_fb_size, mali_fb_start)); |
| } else { |
| MALI_DEBUG_PRINT(2, ("Using module defined frame buffer settings (0x%08X@0x%08X)\n", |
| mali_fb_size, mali_fb_start)); |
| } |
| |
| if (0 != mali_fb_size) { |
| /* Register frame buffer */ |
| ret = mali_mem_validation_add_range(mali_fb_start, mali_fb_size); |
| if (_MALI_OSK_ERR_OK != ret) { |
| MALI_PRINT_ERROR(("Failed to register frame buffer memory region\n")); |
| mali_memory_terminate(); |
| return ret; |
| } |
| } |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| static void mali_detect_gpu_class(void) |
| { |
| if (_mali_osk_identify_gpu_resource() == 0x450) |
| mali_gpu_class_is_mali450 = MALI_TRUE; |
| |
| if (_mali_osk_identify_gpu_resource() == 0x470) |
| mali_gpu_class_is_mali470 = MALI_TRUE; |
| } |
| |
| static _mali_osk_errcode_t mali_init_hw_reset(void) |
| { |
| #if (defined(CONFIG_MALI450) || defined(CONFIG_MALI470)) |
| _mali_osk_resource_t resource_bcast; |
| |
| /* Ensure broadcast unit is in a good state before we start creating |
| * groups and cores. |
| */ |
| if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_BCAST, &resource_bcast)) { |
| struct mali_bcast_unit *bcast_core; |
| |
| bcast_core = mali_bcast_unit_create(&resource_bcast); |
| if (NULL == bcast_core) { |
| MALI_PRINT_ERROR(("Failed to create Broadcast unit object!\n")); |
| return _MALI_OSK_ERR_FAULT; |
| } |
| mali_bcast_unit_delete(bcast_core); |
| } |
| #endif /* (defined(CONFIG_MALI450) || defined(CONFIG_MALI470)) */ |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| _mali_osk_errcode_t mali_initialize_subsystems(void) |
| { |
| _mali_osk_errcode_t err; |
| |
| #ifdef CONFIG_MALI_DT |
| err = _mali_osk_resource_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| #endif |
| |
| mali_pp_job_initialize(); |
| |
| err = mali_timeline_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| err = mali_session_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /*Try to init gpu secure mode */ |
| _mali_osk_gpu_secure_mode_init(); |
| |
| #if defined(CONFIG_MALI400_PROFILING) |
| err = _mali_osk_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE); |
| if (_MALI_OSK_ERR_OK != err) { |
| /* No biggie if we weren't able to initialize the profiling */ |
| MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n")); |
| } |
| #endif |
| |
| err = mali_memory_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| err = mali_executor_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| err = mali_scheduler_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Configure memory early, needed by mali_mmu_initialize. */ |
| err = mali_parse_config_memory(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| err = mali_set_global_gpu_base_address(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Detect GPU class (uses L2 cache count) */ |
| mali_detect_gpu_class(); |
| |
| err = mali_check_shared_interrupts(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Initialize the MALI PMU (will not touch HW!) */ |
| err = mali_parse_config_pmu(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Initialize the power management module */ |
| err = mali_pm_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Make sure the entire GPU stays on for the rest of this function */ |
| mali_pm_init_begin(); |
| |
| /* Ensure HW is in a good state before starting to access cores. */ |
| err = mali_init_hw_reset(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Detect which Mali GPU we are dealing with */ |
| err = mali_parse_product_info(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* The global_product_id is now populated with the correct Mali GPU */ |
| |
| /* Start configuring the actual Mali hardware. */ |
| |
| err = mali_mmu_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| if (mali_is_mali450() || mali_is_mali470()) { |
| err = mali_dlbu_initialize(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| } |
| |
| err = mali_parse_config_l2_cache(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| err = mali_parse_config_groups(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Move groups into executor */ |
| mali_executor_populate(); |
| |
| /* Need call after all group has assigned a domain */ |
| mali_pm_power_cost_setup(); |
| |
| /* Initialize the GPU timer */ |
| err = mali_control_timer_init(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| /* Initialize the GPU utilization tracking */ |
| err = mali_utilization_init(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| |
| #if defined(CONFIG_MALI_DVFS) |
| err = mali_dvfs_policy_init(); |
| if (_MALI_OSK_ERR_OK != err) { |
| mali_pm_init_end(); |
| mali_terminate_subsystems(); |
| return err; |
| } |
| #endif |
| |
| /* Allowing the system to be turned off */ |
| mali_pm_init_end(); |
| |
| return _MALI_OSK_ERR_OK; /* all ok */ |
| } |
| |
| void mali_terminate_subsystems(void) |
| { |
| struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); |
| |
| MALI_DEBUG_PRINT(2, ("terminate_subsystems() called\n")); |
| |
| mali_utilization_term(); |
| mali_control_timer_term(); |
| |
| mali_executor_depopulate(); |
| mali_delete_groups(); /* Delete groups not added to executor */ |
| mali_executor_terminate(); |
| |
| mali_scheduler_terminate(); |
| mali_pp_job_terminate(); |
| mali_delete_l2_cache_cores(); |
| mali_mmu_terminate(); |
| |
| if (mali_is_mali450() || mali_is_mali470()) { |
| mali_dlbu_terminate(); |
| } |
| |
| mali_pm_terminate(); |
| |
| if (NULL != pmu) { |
| mali_pmu_delete(pmu); |
| } |
| |
| #if defined(CONFIG_MALI400_PROFILING) |
| _mali_osk_profiling_term(); |
| #endif |
| |
| _mali_osk_gpu_secure_mode_deinit(); |
| |
| mali_memory_terminate(); |
| |
| mali_session_terminate(); |
| |
| mali_timeline_terminate(); |
| |
| global_gpu_base_address = 0; |
| } |
| |
| _mali_product_id_t mali_kernel_core_get_product_id(void) |
| { |
| return global_product_id; |
| } |
| |
| u32 mali_kernel_core_get_gpu_major_version(void) |
| { |
| return global_gpu_major_version; |
| } |
| |
| u32 mali_kernel_core_get_gpu_minor_version(void) |
| { |
| return global_gpu_minor_version; |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_get_api_version(_mali_uk_get_api_version_s *args) |
| { |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| /* check compatability */ |
| if (args->version == _MALI_UK_API_VERSION) { |
| args->compatible = 1; |
| } else { |
| args->compatible = 0; |
| } |
| |
| args->version = _MALI_UK_API_VERSION; /* report our version */ |
| |
| /* success regardless of being compatible or not */ |
| MALI_SUCCESS; |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_get_api_version_v2(_mali_uk_get_api_version_v2_s *args) |
| { |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| /* check compatability */ |
| if (args->version == _MALI_UK_API_VERSION) { |
| args->compatible = 1; |
| } else { |
| args->compatible = 0; |
| } |
| |
| args->version = _MALI_UK_API_VERSION; /* report our version */ |
| |
| /* success regardless of being compatible or not */ |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_wait_for_notification(_mali_uk_wait_for_notification_s *args) |
| { |
| _mali_osk_errcode_t err; |
| _mali_osk_notification_t *notification; |
| _mali_osk_notification_queue_t *queue; |
| struct mali_session_data *session; |
| |
| /* check input */ |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| session = (struct mali_session_data *)(uintptr_t)args->ctx; |
| queue = session->ioctl_queue; |
| |
| /* if the queue does not exist we're currently shutting down */ |
| if (NULL == queue) { |
| MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n")); |
| args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS; |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| /* receive a notification, might sleep */ |
| err = _mali_osk_notification_queue_receive(queue, ¬ification); |
| if (_MALI_OSK_ERR_OK != err) { |
| MALI_ERROR(err); /* errcode returned, pass on to caller */ |
| } |
| |
| /* copy the buffer to the user */ |
| args->type = (_mali_uk_notification_type)notification->notification_type; |
| _mali_osk_memcpy(&args->data, notification->result_buffer, notification->result_buffer_size); |
| |
| /* finished with the notification */ |
| _mali_osk_notification_delete(notification); |
| |
| return _MALI_OSK_ERR_OK; /* all ok */ |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_post_notification(_mali_uk_post_notification_s *args) |
| { |
| _mali_osk_notification_t *notification; |
| _mali_osk_notification_queue_t *queue; |
| struct mali_session_data *session; |
| |
| /* check input */ |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| session = (struct mali_session_data *)(uintptr_t)args->ctx; |
| queue = session->ioctl_queue; |
| |
| /* if the queue does not exist we're currently shutting down */ |
| if (NULL == queue) { |
| MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n")); |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| notification = _mali_osk_notification_create(args->type, 0); |
| if (NULL == notification) { |
| MALI_PRINT_ERROR(("Failed to create notification object\n")); |
| return _MALI_OSK_ERR_NOMEM; |
| } |
| |
| _mali_osk_notification_queue_send(queue, notification); |
| |
| return _MALI_OSK_ERR_OK; /* all ok */ |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_pending_submit(_mali_uk_pending_submit_s *args) |
| { |
| wait_queue_head_t *queue; |
| |
| /* check input */ |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| queue = mali_session_get_wait_queue(); |
| |
| /* check pending big job number, might sleep if larger than MAX allowed number */ |
| if (wait_event_interruptible(*queue, MALI_MAX_PENDING_BIG_JOB > mali_scheduler_job_gp_big_job_count())) { |
| return _MALI_OSK_ERR_RESTARTSYSCALL; |
| } |
| |
| return _MALI_OSK_ERR_OK; /* all ok */ |
| } |
| |
| |
| _mali_osk_errcode_t _mali_ukk_request_high_priority(_mali_uk_request_high_priority_s *args) |
| { |
| struct mali_session_data *session; |
| |
| MALI_DEBUG_ASSERT_POINTER(args); |
| MALI_DEBUG_ASSERT(NULL != (void *)(uintptr_t)args->ctx); |
| |
| session = (struct mali_session_data *)(uintptr_t)args->ctx; |
| |
| if (!session->use_high_priority_job_queue) { |
| session->use_high_priority_job_queue = MALI_TRUE; |
| MALI_DEBUG_PRINT(2, ("Session 0x%08X with pid %d was granted higher priority.\n", session, _mali_osk_get_pid())); |
| } |
| |
| return _MALI_OSK_ERR_OK; |
| } |
| |
| _mali_osk_errcode_t _mali_ukk_open(void **context) |
| { |
| u32 i; |
| struct mali_session_data *session; |
| |
| /* allocated struct to track this session */ |
| session = (struct mali_session_data *)_mali_osk_calloc(1, sizeof(struct mali_session_data)); |
| MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_NOMEM); |
| |
| MALI_DEBUG_PRINT(3, ("Session starting\n")); |
| |
| /* create a response queue for this session */ |
| session->ioctl_queue = _mali_osk_notification_queue_init(); |
| if (NULL == session->ioctl_queue) { |
| goto err; |
| } |
| |
| /*create a wait queue for this session */ |
| session->wait_queue = _mali_osk_wait_queue_init(); |
| if (NULL == session->wait_queue) { |
| goto err_wait_queue; |
| } |
| |
| session->page_directory = mali_mmu_pagedir_alloc(); |
| if (NULL == session->page_directory) { |
| goto err_mmu; |
| } |
| |
| if (_MALI_OSK_ERR_OK != mali_mmu_pagedir_map(session->page_directory, MALI_DLBU_VIRT_ADDR, _MALI_OSK_MALI_PAGE_SIZE)) { |
| MALI_PRINT_ERROR(("Failed to map DLBU page into session\n")); |
| goto err_mmu; |
| } |
| |
| if (0 != mali_dlbu_phys_addr) { |
| mali_mmu_pagedir_update(session->page_directory, MALI_DLBU_VIRT_ADDR, mali_dlbu_phys_addr, |
| _MALI_OSK_MALI_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT); |
| } |
| |
| if (_MALI_OSK_ERR_OK != mali_memory_session_begin(session)) { |
| goto err_session; |
| } |
| |
| /* Create soft system. */ |
| session->soft_job_system = mali_soft_job_system_create(session); |
| if (NULL == session->soft_job_system) { |
| goto err_soft; |
| } |
| |
| /* Initialize the dma fence context.*/ |
| #if defined(CONFIG_MALI_DMA_BUF_FENCE) |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) |
| session->fence_context = dma_fence_context_alloc(1); |
| #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) |
| session->fence_context = fence_context_alloc(1); |
| _mali_osk_atomic_init(&session->fence_seqno, 0); |
| #else |
| MALI_PRINT_ERROR(("The kernel version not support dma fence!\n")); |
| goto err_time_line; |
| #endif |
| #endif |
| |
| /* Create timeline system. */ |
| session->timeline_system = mali_timeline_system_create(session); |
| if (NULL == session->timeline_system) { |
| goto err_time_line; |
| } |
| |
| #if defined(CONFIG_MALI_DVFS) |
| _mali_osk_atomic_init(&session->number_of_window_jobs, 0); |
| #endif |
| |
| _mali_osk_atomic_init(&session->number_of_pp_jobs, 0); |
| |
| session->use_high_priority_job_queue = MALI_FALSE; |
| |
| /* Initialize list of PP jobs on this session. */ |
| _MALI_OSK_INIT_LIST_HEAD(&session->pp_job_list); |
| |
| /* Initialize the pp_job_fb_lookup_list array used to quickly lookup jobs from a given frame builder */ |
| for (i = 0; i < MALI_PP_JOB_FB_LOOKUP_LIST_SIZE; ++i) { |
| _MALI_OSK_INIT_LIST_HEAD(&session->pp_job_fb_lookup_list[i]); |
| } |
| |
| session->pid = _mali_osk_get_pid(); |
| session->comm = _mali_osk_get_comm(); |
| session->max_mali_mem_allocated_size = 0; |
| for (i = 0; i < MALI_MEM_TYPE_MAX; i ++) { |
| atomic_set(&session->mali_mem_array[i], 0); |
| } |
| atomic_set(&session->mali_mem_allocated_pages, 0); |
| *context = (void *)session; |
| |
| /* Add session to the list of all sessions. */ |
| mali_session_add(session); |
| |
| MALI_DEBUG_PRINT(3, ("Session started\n")); |
| return _MALI_OSK_ERR_OK; |
| |
| err_time_line: |
| mali_soft_job_system_destroy(session->soft_job_system); |
| err_soft: |
| mali_memory_session_end(session); |
| err_session: |
| mali_mmu_pagedir_free(session->page_directory); |
| err_mmu: |
| _mali_osk_wait_queue_term(session->wait_queue); |
| err_wait_queue: |
| _mali_osk_notification_queue_term(session->ioctl_queue); |
| err: |
| _mali_osk_free(session); |
| MALI_ERROR(_MALI_OSK_ERR_NOMEM); |
| |
| } |
| |
| #if defined(DEBUG) |
| /* parameter used for debug */ |
| extern u32 num_pm_runtime_resume; |
| extern u32 num_pm_updates; |
| extern u32 num_pm_updates_up; |
| extern u32 num_pm_updates_down; |
| #endif |
| |
| _mali_osk_errcode_t _mali_ukk_close(void **context) |
| { |
| struct mali_session_data *session; |
| MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); |
| session = (struct mali_session_data *)*context; |
| |
| MALI_DEBUG_PRINT(3, ("Session ending\n")); |
| |
| MALI_DEBUG_ASSERT_POINTER(session->soft_job_system); |
| MALI_DEBUG_ASSERT_POINTER(session->timeline_system); |
| |
| /* Remove session from list of all sessions. */ |
| mali_session_remove(session); |
| |
| /* This flag is used to prevent queueing of jobs due to activation. */ |
| session->is_aborting = MALI_TRUE; |
| |
| /* Stop the soft job timer. */ |
| mali_timeline_system_stop_timer(session->timeline_system); |
| |
| /* Abort queued jobs */ |
| mali_scheduler_abort_session(session); |
| |
| /* Abort executing jobs */ |
| mali_executor_abort_session(session); |
| |
| /* Abort the soft job system. */ |
| mali_soft_job_system_abort(session->soft_job_system); |
| |
| /* Force execution of all pending bottom half processing for GP and PP. */ |
| _mali_osk_wq_flush(); |
| |
| /* The session PP list should now be empty. */ |
| MALI_DEBUG_ASSERT(_mali_osk_list_empty(&session->pp_job_list)); |
| |
| /* At this point the GP and PP scheduler no longer has any jobs queued or running from this |
| * session, and all soft jobs in the soft job system has been destroyed. */ |
| |
| /* Any trackers left in the timeline system are directly or indirectly waiting on external |
| * sync fences. Cancel all sync fence waiters to trigger activation of all remaining |
| * trackers. This call will sleep until all timelines are empty. */ |
| mali_timeline_system_abort(session->timeline_system); |
| |
| /* Flush pending work. |
| * Needed to make sure all bottom half processing related to this |
| * session has been completed, before we free internal data structures. |
| */ |
| _mali_osk_wq_flush(); |
| |
| /* Destroy timeline system. */ |
| mali_timeline_system_destroy(session->timeline_system); |
| session->timeline_system = NULL; |
| |
| /* Destroy soft system. */ |
| mali_soft_job_system_destroy(session->soft_job_system); |
| session->soft_job_system = NULL; |
| |
| /*Wait for the session job lists become empty.*/ |
| _mali_osk_wait_queue_wait_event(session->wait_queue, mali_session_pp_job_is_empty, (void *) session); |
| |
| /* Free remaining memory allocated to this session */ |
| mali_memory_session_end(session); |
| |
| #if defined(CONFIG_MALI_DVFS) |
| _mali_osk_atomic_term(&session->number_of_window_jobs); |
| #endif |
| |
| #if defined(CONFIG_MALI400_PROFILING) |
| _mali_osk_profiling_stop_sampling(session->pid); |
| #endif |
| |
| /* Free session data structures */ |
| mali_mmu_pagedir_unmap(session->page_directory, MALI_DLBU_VIRT_ADDR, _MALI_OSK_MALI_PAGE_SIZE); |
| mali_mmu_pagedir_free(session->page_directory); |
| _mali_osk_wait_queue_term(session->wait_queue); |
| _mali_osk_notification_queue_term(session->ioctl_queue); |
| _mali_osk_free(session); |
| |
| *context = NULL; |
| |
| MALI_DEBUG_PRINT(3, ("Session has ended\n")); |
| |
| #if defined(DEBUG) |
| MALI_DEBUG_PRINT(3, ("Stats: # runtime resumes: %u\n", num_pm_runtime_resume)); |
| MALI_DEBUG_PRINT(3, (" # PM updates: .... %u (up %u, down %u)\n", num_pm_updates, num_pm_updates_up, num_pm_updates_down)); |
| |
| num_pm_runtime_resume = 0; |
| num_pm_updates = 0; |
| num_pm_updates_up = 0; |
| num_pm_updates_down = 0; |
| #endif |
| |
| return _MALI_OSK_ERR_OK;; |
| } |
| |
| #if MALI_STATE_TRACKING |
| u32 _mali_kernel_core_dump_state(char *buf, u32 size) |
| { |
| int n = 0; /* Number of bytes written to buf */ |
| |
| n += mali_scheduler_dump_state(buf + n, size - n); |
| n += mali_executor_dump_state(buf + n, size - n); |
| |
| return n; |
| } |
| #endif |