diff options
Diffstat (limited to 'drivers/media/video/samsung/mali/common')
86 files changed, 10312 insertions, 17216 deletions
diff --git a/drivers/media/video/samsung/mali/common/mali_block_allocator.c b/drivers/media/video/samsung/mali/common/mali_block_allocator.c index 5f421f0..269e662 100644 --- a/drivers/media/video/samsung/mali/common/mali_block_allocator.c +++ b/drivers/media/video/samsung/mali/common/mali_block_allocator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -76,7 +76,7 @@ mali_physical_memory_allocator * mali_block_allocator_create(u32 base_address, u info = _mali_osk_malloc(sizeof(block_allocator)); if (NULL != info) { - info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED, 0, 105); + info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_MEM_INFO); if (NULL != info->mutex) { info->all_blocks = _mali_osk_malloc(sizeof(block_info) * num_blocks); @@ -355,7 +355,7 @@ static void block_allocator_release_page_table_block( mali_page_table_block *pag _mali_osk_mem_unmapioregion( page_table_block->phys_base, page_table_block->size, page_table_block->mapping ); /** @note This loop handles the case where more than one block_info was linked. - * Probably unnecssary for page table block releasing. */ + * Probably unnecessary for page table block releasing. */ while (block) { next = block->next; diff --git a/drivers/media/video/samsung/mali/common/mali_cluster.c b/drivers/media/video/samsung/mali/common/mali_cluster.c new file mode 100644 index 0000000..f0fb2b6 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_cluster.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2011-2012 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_cluster.h" +#include "mali_osk.h" +#include "mali_group.h" +#include "mali_l2_cache.h" +#include "mali_scheduler.h" + +static struct mali_cluster *mali_global_clusters[MALI_MAX_NUMBER_OF_CLUSTERS] = { NULL, NULL, NULL }; +static u32 mali_global_num_clusters = 0; + +/** + * The structure represents a render cluster + * A render cluster is defined by all the cores that share the same Mali L2 cache + */ +struct mali_cluster +{ + struct mali_l2_cache_core *l2; + u32 number_of_groups; + struct mali_group* groups[MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER]; + u32 last_invalidated_id; + mali_bool power_is_enabled; +}; + +struct mali_cluster *mali_cluster_create(struct mali_l2_cache_core *l2_cache) +{ + struct mali_cluster *cluster = NULL; + + if (mali_global_num_clusters >= MALI_MAX_NUMBER_OF_CLUSTERS) + { + MALI_PRINT_ERROR(("Mali cluster: Too many cluster objects created\n")); + return NULL; + } + + cluster = _mali_osk_malloc(sizeof(struct mali_cluster)); + if (NULL != cluster) + { + _mali_osk_memset(cluster, 0, sizeof(struct mali_cluster)); + cluster->l2 = l2_cache; /* This cluster now owns this L2 cache object */ + cluster->last_invalidated_id = 0; + cluster->power_is_enabled = MALI_TRUE; + + mali_global_clusters[mali_global_num_clusters] = cluster; + mali_global_num_clusters++; + + return cluster; + } + + return NULL; +} + +void mali_cluster_power_is_enabled_set(struct mali_cluster * cluster, mali_bool power_is_enabled) +{ + cluster->power_is_enabled = power_is_enabled; +} + +mali_bool mali_cluster_power_is_enabled_get(struct mali_cluster * cluster) +{ + return cluster->power_is_enabled; +} + + +void mali_cluster_add_group(struct mali_cluster *cluster, struct mali_group *group) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (cluster->number_of_groups < MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER) + { + /* This cluster now owns the group object */ + cluster->groups[cluster->number_of_groups] = group; + cluster->number_of_groups++; + } +} + +void mali_cluster_delete(struct mali_cluster *cluster) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(cluster); + + /* Free all the resources we own */ + for (i = 0; i < cluster->number_of_groups; i++) + { + mali_group_delete(cluster->groups[i]); + } + + if (NULL != cluster->l2) + { + mali_l2_cache_delete(cluster->l2); + } + + for (i = 0; i < mali_global_num_clusters; i++) + { + if (mali_global_clusters[i] == cluster) + { + mali_global_clusters[i] = NULL; + mali_global_num_clusters--; + break; + } + } + + _mali_osk_free(cluster); +} + +void mali_cluster_reset(struct mali_cluster *cluster) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(cluster); + + /* Free all the resources we own */ + for (i = 0; i < cluster->number_of_groups; i++) + { + struct mali_group *group = cluster->groups[i]; + + mali_group_reset(group); + } + + if (NULL != cluster->l2) + { + mali_l2_cache_reset(cluster->l2); + } +} + +struct mali_l2_cache_core* mali_cluster_get_l2_cache_core(struct mali_cluster *cluster) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + return cluster->l2; +} + +struct mali_group *mali_cluster_get_group(struct mali_cluster *cluster, u32 index) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (index < cluster->number_of_groups) + { + return cluster->groups[index]; + } + + return NULL; +} + +struct mali_cluster *mali_cluster_get_global_cluster(u32 index) +{ + if (MALI_MAX_NUMBER_OF_CLUSTERS > index) + { + return mali_global_clusters[index]; + } + + return NULL; +} + +u32 mali_cluster_get_glob_num_clusters(void) +{ + return mali_global_num_clusters; +} + +mali_bool mali_cluster_l2_cache_invalidate_all(struct mali_cluster *cluster, u32 id) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (NULL != cluster->l2) + { + /* If the last cache invalidation was done by a job with a higher id we + * don't have to flush. Since user space will store jobs w/ their + * corresponding memory in sequence (first job #0, then job #1, ...), + * we don't have to flush for job n-1 if job n has already invalidated + * the cache since we know for sure that job n-1's memory was already + * written when job n was started. */ + if (((s32)id) <= ((s32)cluster->last_invalidated_id)) + { + return MALI_FALSE; + } + else + { + cluster->last_invalidated_id = mali_scheduler_get_new_id(); + } + + mali_l2_cache_invalidate_all(cluster->l2); + } + return MALI_TRUE; +} + +void mali_cluster_l2_cache_invalidate_all_force(struct mali_cluster *cluster) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (NULL != cluster->l2) + { + cluster->last_invalidated_id = mali_scheduler_get_new_id(); + mali_l2_cache_invalidate_all(cluster->l2); + } +} + +void mali_cluster_invalidate_pages(u32 *pages, u32 num_pages) +{ + u32 i; + + for (i = 0; i < mali_global_num_clusters; i++) + { + /*additional check for cluster*/ + if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_clusters[i]->l2)) + { + mali_l2_cache_invalidate_pages(mali_global_clusters[i]->l2, pages, num_pages); + } + mali_l2_cache_unlock_power_state(mali_global_clusters[i]->l2); + /*check for failed power locking???*/ + } +} diff --git a/drivers/media/video/samsung/mali/common/mali_cluster.h b/drivers/media/video/samsung/mali/common/mali_cluster.h new file mode 100644 index 0000000..33debdb --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_cluster.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_CLUSTER_H__ +#define __MALI_CLUSTER_H__ + +#include "mali_osk.h" +#include "mali_l2_cache.h" + +/* Maximum 1 GP and 4 PP for a cluster (Mali-400 Quad-core) */ +#define MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER 5 +#define MALI_MAX_NUMBER_OF_CLUSTERS 3 + +struct mali_cluster; +struct mali_group; + +struct mali_cluster *mali_cluster_create(struct mali_l2_cache_core *l2_cache); +void mali_cluster_add_group(struct mali_cluster *cluster, struct mali_group *group); +void mali_cluster_delete(struct mali_cluster *cluster); + +void mali_cluster_power_is_enabled_set(struct mali_cluster * cluster, mali_bool power_is_enabled); +mali_bool mali_cluster_power_is_enabled_get(struct mali_cluster * cluster); + +void mali_cluster_reset(struct mali_cluster *cluster); + +struct mali_l2_cache_core* mali_cluster_get_l2_cache_core(struct mali_cluster *cluster); +struct mali_group *mali_cluster_get_group(struct mali_cluster *cluster, u32 index); + +struct mali_cluster *mali_cluster_get_global_cluster(u32 index); +u32 mali_cluster_get_glob_num_clusters(void); + +/* Returns MALI_TRUE if it did the flush */ +mali_bool mali_cluster_l2_cache_invalidate_all(struct mali_cluster *cluster, u32 id); +void mali_cluster_l2_cache_invalidate_all_force(struct mali_cluster *cluster); +void mali_cluster_invalidate_pages(u32 *pages, u32 num_pages); + +#endif /* __MALI_CLUSTER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c new file mode 100644 index 0000000..6af1279 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2010-2012 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. + */ + +/** + * @file mali_device_pause_resume.c + * Implementation of the Mali pause/resume functionality + */ + +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_pm.h" + +void mali_dev_pause(mali_bool *power_is_on) +{ + mali_gp_scheduler_suspend(); + mali_pp_scheduler_suspend(); + + /* + * Take and hold the PM lock to be sure we don't change power state as well. + * (it might be unsafe to for instance change frequency if Mali GPU is powered off) + */ + mali_pm_execute_state_change_lock(); + if (NULL != power_is_on) + { + *power_is_on = mali_pm_is_powered_on(); + } +} + +void mali_dev_resume(void) +{ + mali_pm_execute_state_change_unlock(); + mali_gp_scheduler_resume(); + mali_pp_scheduler_resume(); +} + +/* +EXPORT_SYMBOL(mali_dev_pause); +EXPORT_SYMBOL(mali_dev_resume); +*/ diff --git a/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h new file mode 100644 index 0000000..6be75b0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __MALI_DEVICE_PAUSE_RESUME_H__ +#define __MALI_DEVICE_PAUSE_RESUME_H__ + +#include "mali_osk.h" + +/** + * Pause the scheduling and power state changes of Mali device driver. + * mali_dev_resume() must always be called as soon as possible after this function + * in order to resume normal operation of the Mali driver. + * + * @param power_is_on Receives the power current status of Mali GPU. MALI_TRUE if GPU is powered on + */ +void mali_dev_pause(mali_bool *power_is_on); + +/** + * Resume scheduling and allow power changes in Mali device driver. + * This must always be called after mali_dev_pause(). + */ +void mali_dev_resume(void); + +#endif /* __MALI_DEVICE_PAUSE_RESUME_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_dlbu.c b/drivers/media/video/samsung/mali/common/mali_dlbu.c new file mode 100644 index 0000000..fcc51fa --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_dlbu.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2012 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_dlbu.h" +#include "mali_memory.h" +#include "mali_pp.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "mali_hw_core.h" + +/** + * Size of DLBU registers in bytes + */ +#define MALI_DLBU_SIZE 0x400 + +u32 mali_dlbu_phys_addr = 0; +static mali_io_address mali_dlbu_cpu_addr = 0; + +static u32 mali_dlbu_tile_position; + +/** + * DLBU register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_dlbu_register { + MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR = 0x0000, /**< Master tile list physical base address; + 31:12 Physical address to the page used for the DLBU + 0 DLBU enable - set this bit to 1 enables the AXI bus + between PPs and L2s, setting to 0 disables the router and + no further transactions are sent to DLBU */ + MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR = 0x0004, /**< Master tile list virtual base address; + 31:12 Virtual address to the page used for the DLBU */ + MALI_DLBU_REGISTER_TLLIST_VBASEADDR = 0x0008, /**< Tile list virtual base address; + 31:12 Virtual address to the tile list. This address is used when + calculating the call address sent to PP.*/ + MALI_DLBU_REGISTER_FB_DIM = 0x000C, /**< Framebuffer dimension; + 23:16 Number of tiles in Y direction-1 + 7:0 Number of tiles in X direction-1 */ + MALI_DLBU_REGISTER_TLLIST_CONF = 0x0010, /**< Tile list configuration; + 29:28 select the size of each allocated block: 0=128 bytes, 1=256, 2=512, 3=1024 + 21:16 2^n number of tiles to be binned to one tile list in Y direction + 5:0 2^n number of tiles to be binned to one tile list in X direction */ + MALI_DLBU_REGISTER_START_TILE_POS = 0x0014, /**< Start tile positions; + 31:24 start position in Y direction for group 1 + 23:16 start position in X direction for group 1 + 15:8 start position in Y direction for group 0 + 7:0 start position in X direction for group 0 */ + MALI_DLBU_REGISTER_PP_ENABLE_MASK = 0x0018, /**< PP enable mask; + 7 enable PP7 for load balancing + 6 enable PP6 for load balancing + 5 enable PP5 for load balancing + 4 enable PP4 for load balancing + 3 enable PP3 for load balancing + 2 enable PP2 for load balancing + 1 enable PP1 for load balancing + 0 enable PP0 for load balancing */ +} mali_dlbu_register; + +typedef enum +{ + PP0ENABLE = 0, + PP1ENABLE, + PP2ENABLE, + PP3ENABLE, + PP4ENABLE, + PP5ENABLE, + PP6ENABLE, + PP7ENABLE +} mali_dlbu_pp_enable; + +struct mali_dlbu_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + u32 pp_cores_mask; /**< This is a mask for the PP cores whose operation will be controlled by LBU + see MALI_DLBU_REGISTER_PP_ENABLE_MASK register */ +}; + +_mali_osk_errcode_t mali_dlbu_initialize(void) +{ + + MALI_DEBUG_PRINT(2, ("Dynamic Load Balancing Unit initializing\n")); + + if (_MALI_OSK_ERR_OK == mali_mmu_get_table_page(&mali_dlbu_phys_addr, &mali_dlbu_cpu_addr)) + { + MALI_SUCCESS; + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_dlbu_terminate(void) +{ + MALI_DEBUG_PRINT(3, ("Mali DLBU: terminating\n")); + + mali_mmu_release_table_page(mali_dlbu_phys_addr); +} + +struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource) +{ + struct mali_dlbu_core *core = NULL; + + MALI_DEBUG_PRINT(2, ("Mali DLBU: Creating Mali dynamic load balancing unit: %s\n", resource->description)); + + core = _mali_osk_malloc(sizeof(struct mali_dlbu_core)); + if (NULL != core) + { + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI_DLBU_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_dlbu_reset(core)) + { + mali_hw_core_register_write(&core->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR, MALI_DLB_VIRT_ADDR); + + return core; + } + MALI_PRINT_ERROR(("Failed to reset DLBU %s\n", core->hw_core.description)); + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Mali DLBU: Failed to allocate memory for DLBU core\n")); + } + + return NULL; +} + +void mali_dlbu_delete(struct mali_dlbu_core *dlbu) +{ + mali_dlbu_reset(dlbu); + mali_hw_core_delete(&dlbu->hw_core); + _mali_osk_free(dlbu); +} + +void mali_dlbu_enable(struct mali_dlbu_core *dlbu) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR); + + wval |= 0x1; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, wval); +} + +void mali_dlbu_disable(struct mali_dlbu_core *dlbu) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR); + + wval |= (wval & 0xFFFFFFFE); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, wval); +} + +_mali_osk_errcode_t mali_dlbu_enable_pp_core(struct mali_dlbu_core *dlbu, u32 pp_core_enable, u32 val) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK); + + if((pp_core_enable < mali_pp_get_glob_num_pp_cores()) && ((0 == val) || (1 == val))) /* check for valid input parameters */ + { + if (val == 1) + { + val = (wval | (pp_core_enable <<= 0x1)); + } + if (val == 0) + { + val = (wval & ~(pp_core_enable << 0x1)); + } + wval |= val; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, wval); + dlbu->pp_cores_mask = wval; + + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_dlbu_enable_all_pp_cores(struct mali_dlbu_core *dlbu) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask); +} + +void mali_dlbu_disable_all_pp_cores(struct mali_dlbu_core *dlbu) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, 0x0); +} + +void mali_dlbu_setup(struct mali_dlbu_core *dlbu, u8 fb_xdim, u8 fb_ydim, u8 xtilesize, u8 ytilesize, u8 blocksize, u8 xgr0, u8 ygr0, u8 xgr1, u8 ygr1) +{ + u32 wval = 0x0; + + /* write the framebuffer dimensions */ + wval = (16 << (u32)fb_ydim) | (u32)fb_xdim; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_FB_DIM, wval); + + /* write the tile list configuration */ + wval = 0x0; + wval = (28 << (u32)blocksize) | (16 << (u32)ytilesize) | ((u32)xtilesize); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_CONF, wval); + + /* write the start tile position */ + wval = 0x0; + wval = (24 << (u32)ygr1 | (16 << (u32)xgr1) | 8 << (u32)ygr0) | (u32)xgr0; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, wval); +} + +_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + MALI_DEBUG_ASSERT_POINTER(dlbu); + + MALI_DEBUG_PRINT(4, ("Mali DLBU: mali_dlbu_reset: %s\n", dlbu->hw_core.description)); + + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, mali_dlbu_phys_addr); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_FB_DIM, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_CONF, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, 0x00); + + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask); + + err = _MALI_OSK_ERR_OK; + + return err; +} + +_mali_osk_errcode_t mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + u32 wval, rval; + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + + /* find the core id and set the mask */ + + if (NULL != pp_core) + { + wval = mali_pp_core_get_id(pp_core); + rval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, (wval << 0x1) | rval); + err = _MALI_OSK_ERR_OK; + } + + return err; +} + +void mali_dlbu_set_tllist_base_address(struct mali_dlbu_core *dlbu, u32 val) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, val); +} + +void mali_dlbu_pp_jobs_stop(struct mali_dlbu_core *dlbu) +{ + /* this function to implement (see documentation): + * 1) clear all bits in the enable register + * 2) wait until all PPs have finished - mali_pp_scheduler.c code - this done in interrupts call? + * 3) read the current tile position registers to get current tile positions - + * note that current tile position register is the same as start tile position - perhaps the name should be changed!!! */ + + /* 1) */ + mali_dlbu_disable_all_pp_cores(dlbu); + + /* 3) */ + mali_dlbu_tile_position = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS); +} + +void mali_dlbu_pp_jobs_restart(struct mali_dlbu_core *dlbu) +{ + /* this function to implement (see the document): + * 1) configure the dynamic load balancing unit as normal + * 2) set the current tile position registers as read when stopping the job + * 3) configure the PPs to start the job as normal - done by another part of the system - scheduler */ + + /* 1) */ + mali_dlbu_reset(dlbu); + /* ++ setup the needed values - see this */ + + /* 2) */ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, mali_dlbu_tile_position); +} diff --git a/drivers/media/video/samsung/mali/common/mali_dlbu.h b/drivers/media/video/samsung/mali/common/mali_dlbu.h new file mode 100644 index 0000000..e3c3b9d --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_dlbu.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef __MALI_DLBU_H__ +#define __MALI_DLBU_H__ + +#include "mali_osk.h" +#include "mali_group.h" + +#define MALI_DLB_VIRT_ADDR 0xFFF00000 /* master tile virtual address fixed at this value and mapped into every session */ + +extern u32 mali_dlbu_phys_addr; + +struct mali_dlbu_core; + +_mali_osk_errcode_t mali_dlbu_initialize(void); +void mali_dlbu_terminate(void); + +struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource); +void mali_dlbu_delete(struct mali_dlbu_core *dlbu); + +void mali_dlbu_enable(struct mali_dlbu_core *dlbu); +void mali_dlbu_disable(struct mali_dlbu_core *dlbu); + +_mali_osk_errcode_t mali_dlbu_enable_pp_core(struct mali_dlbu_core *dlbu, u32 pp_core_enable, u32 val); +void mali_dlbu_enable_all_pp_cores(struct mali_dlbu_core *dlbu); +void mali_dlbu_disable_all_pp_cores(struct mali_dlbu_core *dlbu); + +_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu); +void mali_dlbu_setup(struct mali_dlbu_core *dlbu, u8 fb_xdim, u8 fb_ydim, u8 xtilesize, u8 ytilesize, u8 blocksize, u8 xgr0, u8 ygr0, u8 xgr1, u8 ygr1); + +_mali_osk_errcode_t mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group); +void mali_dlbu_set_tllist_base_address(struct mali_dlbu_core *dlbu, u32 val); + +void mali_dlbu_pp_jobs_stop(struct mali_dlbu_core *dlbu); +void mali_dlbu_pp_jobs_restart(struct mali_dlbu_core *dlbu); + +#endif /* __MALI_DLBU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp.c b/drivers/media/video/samsung/mali/common/mali_gp.c new file mode 100644 index 0000000..d03721c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2011-2012 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_gp.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "regs/mali_gp_regs.h" +#include "mali_kernel_common.h" +#include "mali_kernel_core.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" +#endif + +/** + * Definition of the GP core struct + * Used to track a GP core in the system. + */ +struct mali_gp_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent group for this core */ + _mali_osk_irq_t *irq; /**< IRQ handler */ + struct mali_gp_job *running_job; /**< Current running job */ + _mali_osk_timer_t *timeout_timer; /**< timeout timer for this core */ + u32 timeout_job_id; /**< job id for the timed out job - relevant only if gp_core_timed_out == MALI_TRUE */ + mali_bool core_timed_out; /**< if MALI_TRUE, this gp core has timed out; if MALI_FALSE, no timeout on this gp core */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src0_used; /**< The selected performance counter 0 when a job is running */ + u32 counter_src1_used; /**< The selected performance counter 1 when a job is running */ +}; + +static struct mali_gp_core *mali_global_gp_core = NULL; + +/* Interrupt handlers */ +static _mali_osk_errcode_t mali_gp_upper_half(void *data); +static void mali_gp_bottom_half(void *data); +static void mali_gp_irq_probe_trigger(void *data); +static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data); +static void mali_gp_post_process_job(struct mali_gp_core *core, mali_bool suspend); +static void mali_gp_timeout(void *data); + +struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group) +{ + struct mali_gp_core* core = NULL; + + MALI_DEBUG_ASSERT(NULL == mali_global_gp_core); + MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource->description)); + + core = _mali_osk_malloc(sizeof(struct mali_gp_core)); + if (NULL != core) + { + core->group = group; + core->running_job = NULL; + core->counter_src0 = MALI_HW_CORE_NO_COUNTER; + core->counter_src1 = MALI_HW_CORE_NO_COUNTER; + core->counter_src0_used = MALI_HW_CORE_NO_COUNTER; + core->counter_src1_used = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALIGP2_REGISTER_ADDRESS_SPACE_SIZE)) + { + _mali_osk_errcode_t ret; + + mali_group_lock(group); + ret = mali_gp_reset(core); + mali_group_unlock(group); + + if (_MALI_OSK_ERR_OK == ret) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + core->irq = _mali_osk_irq_init(resource->irq, + mali_gp_upper_half, + mali_gp_bottom_half, + mali_gp_irq_probe_trigger, + mali_gp_irq_probe_ack, + core, + "mali_gp_irq_handlers"); + if (NULL != core->irq) + { + /* Initialise the timeout timer */ + core->timeout_timer = _mali_osk_timer_init(); + if(NULL != core->timeout_timer) + { + _mali_osk_timer_setcallback(core->timeout_timer, mali_gp_timeout, (void *)core); + MALI_DEBUG_PRINT(4, ("Mali GP: set global gp core from 0x%08X to 0x%08X\n", mali_global_gp_core, core)); + mali_global_gp_core = core; + + return core; + } + else + { + MALI_PRINT_ERROR(("Failed to setup timeout timer for GP core %s\n", core->hw_core.description)); + /* Release IRQ handlers */ + _mali_osk_irq_term(core->irq); + } + } + else + { + MALI_PRINT_ERROR(("Failed to setup interrupt handlers for GP core %s\n", core->hw_core.description)); + } + } + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n")); + } + + return NULL; +} + +void mali_gp_delete(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + _mali_osk_timer_term(core->timeout_timer); + _mali_osk_irq_term(core->irq); + mali_hw_core_delete(&core->hw_core); + mali_global_gp_core = NULL; + _mali_osk_free(core); +} + +void mali_gp_stop_bus(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); +} + +_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + + /* Send the stop bus command. */ + mali_gp_stop_bus(core); + + /* Wait for bus to be stopped */ + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} + +void mali_gp_hard_reset(struct mali_gp_core *core) +{ + const int reset_finished_loop_count = 15; + const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW; + const u32 reset_invalid_value = 0xC0FFE000; + const u32 reset_check_value = 0xC01A0000; + const u32 reset_default_value = 0; + int i; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_gp_post_process_job(core, MALI_FALSE); + + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_invalid_value); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET); + + for (i = 0; i < reset_finished_loop_count; i++) + { + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_check_value); + if (reset_check_value == mali_hw_core_register_read(&core->hw_core, reset_wait_target_register)) + { + break; + } + } + + if (i == reset_finished_loop_count) + { + MALI_PRINT_ERROR(("Mali GP: The hard reset loop didn't work, unable to recover\n")); + } + + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_default_value); /* set it back to the default */ + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + +} + +_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_gp_post_process_job(core, MALI_FALSE); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ + +#if defined(USING_MALI200) + + /* On Mali-200, stop the bus, then do a hard reset of the core */ + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to stop bus for core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } + + /* the bus was stopped OK, do the hard reset */ + mali_gp_hard_reset(core); + +#elif defined(USING_MALI400) + + /* Mali-300 and Mali-400 have a safe reset command which we use */ + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to reset core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } +#else +#error "no supported mali core defined" +#endif + + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job) +{ + u32 startcmd = 0; + u32 *frame_registers = mali_gp_job_get_frame_registers(job); + core->counter_src0_used = core->counter_src0; + core->counter_src1_used = core->counter_src1; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (mali_gp_job_has_vs_job(job)) + { + startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS; + } + + if (mali_gp_job_has_plbu_job(job)) + { + startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU; + } + + MALI_DEBUG_ASSERT(0 != startcmd); + + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, frame_registers, MALIGP2_NUM_REGS_FRAME); + + /* This selects which performance counters we are reading */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used || MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + /* global_config has enabled HW counters, this will override anything specified by user space */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + } + else + { + /* Use HW counters from job object, if any */ + u32 perf_counter_flag = mali_gp_job_get_perf_counter_flag(job); + if (0 != perf_counter_flag) + { + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) + { + core->counter_src0_used = mali_gp_job_get_perf_counter_src0(job); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) + { + core->counter_src1_used = mali_gp_job_get_perf_counter_src1(job); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + } + } + + MALI_DEBUG_PRINT(3, ("Mali GP: Starting job (0x%08x) on core %s with command 0x%08X\n", job, core->hw_core.description, startcmd)); + + /* Barrier to make sure the previous register write is finished */ + _mali_osk_write_mem_barrier(); + + /* This is the command that starts the core. */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd); + + /* Barrier to make sure the previous register write is finished */ + _mali_osk_write_mem_barrier(); + + /* Setup the timeout timer value and save the job id for the job running on the gp core */ + + _mali_osk_timer_add(core->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); + core->timeout_job_id = mali_gp_job_get_id(job); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, + job->frame_builder_id, job->flush_id, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), job->pid, job->tid, 0, 0, 0); +#endif + + core->running_job = job; +} + +void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr) +{ + u32 irq_readout; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT); + + if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | MALIGP2_REG_VAL_IRQ_HANG)); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* re-enable interrupts */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, start_addr); + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, end_addr); + + MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n")); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); + _mali_osk_write_mem_barrier(); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), 0, 0, 0, 0, 0); +#endif + } + /* + * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response. + * A timeout or a page fault on Mali-200 PP core can cause this behaviour. + */ +} + +void mali_gp_abort_job(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (_MALI_OSK_ERR_FAULT != mali_gp_reset(core)) + { + _mali_osk_timer_del(core->timeout_timer); + } +} + +u32 mali_gp_core_get_version(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION); +} + +mali_bool mali_gp_core_set_counter_src0(struct mali_gp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src0 = counter; + return MALI_TRUE; +} + +mali_bool mali_gp_core_set_counter_src1(struct mali_gp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src1 = counter; + return MALI_TRUE; +} + +u32 mali_gp_core_get_counter_src0(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src0; +} + +u32 mali_gp_core_get_counter_src1(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src1; +} + +struct mali_gp_core *mali_gp_get_global_gp_core(void) +{ + return mali_global_gp_core; +} + +/* ------------- interrupt handling below ------------------ */ +static _mali_osk_errcode_t mali_gp_upper_half(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); + if (MALIGP2_REG_VAL_IRQ_MASK_NONE != irq_readout) + { + /* Mask out all IRQs from this core until IRQ is handled */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_NONE); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); +#endif + + /* We do need to handle this in a bottom half */ + _mali_osk_irq_schedulework(core->irq); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_gp_bottom_half(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + u32 irq_errors; + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_START| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid()+11000, 0, 0, 0); +#endif +#endif + + mali_group_lock(core->group); /* Group lock grabbed in core handlers, but released in common group handler */ + + if ( MALI_FALSE == mali_group_power_is_on(core->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", core->hw_core.description)); + mali_group_unlock(core->group); + return; + } + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALIGP2_REG_VAL_IRQ_MASK_USED; + MALI_DEBUG_PRINT(4, ("Mali GP: Bottom half IRQ 0x%08X from core %s\n", irq_readout, core->hw_core.description)); + + if (irq_readout & (MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST)) + { + u32 core_status = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS); + if (0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE)) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_DEBUG_PRINT(4, ("Mali GP: Job completed, calling group handler\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_COMPLETED); /* Will release group lock */ + return; + } + } + + /* + * Now lets look at the possible error cases (IRQ indicating error or timeout) + * END_CMD_LST, HANG and PLBU_OOM interrupts are not considered error. + */ + irq_errors = irq_readout & ~(MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST|MALIGP2_REG_VAL_IRQ_HANG|MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM); + if (0 != irq_errors) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_PRINT_ERROR(("Mali GP: Unknown interrupt 0x%08X from core %s, aborting job\n", irq_readout, core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_FAILED); /* Will release group lock */ + return; + } + else if (MALI_TRUE == core->core_timed_out) /* SW timeout */ + { + if (core->timeout_job_id == mali_gp_job_get_id(core->running_job)) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_DEBUG_PRINT(2, ("Mali GP: Job %d timed out\n", mali_gp_job_get_id(core->running_job))); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_TIMED_OUT); + } + core->core_timed_out = MALI_FALSE; + return; + } + else if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) + { + /* GP wants more memory in order to continue. + * + * This must be handled prior to HANG because this actually can + * generate a HANG while waiting for more memory. + * And it must be handled before the completion interrupts, + * since the PLBU can run out of memory after VS is complete; + * in which case the OOM must be handled before to complete the + * PLBU work. + */ + mali_gp_post_process_job(core, MALI_TRUE); + MALI_DEBUG_PRINT(3, ("Mali GP: PLBU needs more heap memory\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_OOM); /* Will release group lock */ + return; + } + else if (irq_readout & MALIGP2_REG_VAL_IRQ_HANG) + { + /* Just ignore hang interrupts, the job timer will detect hanging jobs anyways */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_HANG); + } + + /* + * The only way to get here is if we got a HANG interrupt, which we ignore, or only one of two needed END_CMD_LST interrupts. + * Re-enable interrupts and let core continue to run. + */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + mali_group_unlock(core->group); + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_STOP| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid()+11000, 0, 0, 0); +#endif +#endif +} + +static void mali_gp_irq_probe_trigger(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* @@@@ This should not be needed */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_CMD_FORCE_HANG); + _mali_osk_mem_barrier(); +} + +static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); + if (MALIGP2_REG_VAL_IRQ_FORCE_HANG & irq_readout) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +/* ------ local helper functions below --------- */ + +static void mali_gp_post_process_job(struct mali_gp_core *core, mali_bool suspend) +{ + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (NULL != core->running_job) + { + u32 val0 = 0; + u32 val1 = 0; +#if MALI_TIMELINE_PROFILING_ENABLED + u32 event_id; +#endif + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + val0 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); + if (mali_gp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE && mali_gp_job_get_perf_counter_src0(core->running_job) == core->counter_src0_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_gp_job_set_perf_counter_value0(core->running_job, val0); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_gp_job_set_perf_counter_value0(core->running_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(COUNTER_VP_C0, val0); +#endif + + } + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + val1 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); + if (mali_gp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE && mali_gp_job_get_perf_counter_src1(core->running_job) == core->counter_src1_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_gp_job_set_perf_counter_value1(core->running_job, val1); + } + else + { + /* User space asked for a counter, but this is not what we retrieved (overridden by counter src set on core) */ + mali_gp_job_set_perf_counter_value1(core->running_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(COUNTER_VP_C1, val1); +#endif + } + +#if MALI_TIMELINE_PROFILING_ENABLED + if (MALI_TRUE == suspend) + { + event_id = MALI_PROFILING_EVENT_TYPE_SUSPEND|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0); + } + else + { + event_id = MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0); + } + _mali_osk_profiling_add_event(event_id, val0, val1, core->counter_src0_used | (core->counter_src1_used << 8), 0, 0); +#endif + + mali_gp_job_set_current_heap_addr(core->running_job, + mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR)); + + if (MALI_TRUE != suspend) + { + /* We are no longer running a job... */ + core->running_job = NULL; + _mali_osk_timer_del(core->timeout_timer); + } + } +} + +/* callback function for gp core timeout */ +static void mali_gp_timeout(void *data) +{ + struct mali_gp_core * core = ((struct mali_gp_core *)data); + + MALI_DEBUG_PRINT(3, ("Mali GP: TIMEOUT callback \n")); + core->core_timed_out = MALI_TRUE; + _mali_osk_irq_schedulework(core->irq); +} + +#if 0 +void mali_gp_print_state(struct mali_gp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali GP: State: 0x%08x\n", mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) )); +} +#endif + +#if MALI_STATE_TRACKING +u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_gp.h b/drivers/media/video/samsung/mali/common/mali_gp.h new file mode 100644 index 0000000..3175b75 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_GP_H__ +#define __MALI_GP_H__ + +#include "mali_osk.h" +#include "mali_gp_job.h" + +struct mali_gp_core; +struct mali_group; + +_mali_osk_errcode_t mali_gp_initialize(void); +void mali_gp_terminate(void); + +struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group); +void mali_gp_delete(struct mali_gp_core *core); + +void mali_gp_stop_bus(struct mali_gp_core *core); +_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core); +void mali_gp_hard_reset(struct mali_gp_core *core); +_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core); + +void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job); +void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr); + +void mali_gp_abort_job(struct mali_gp_core *core); + +u32 mali_gp_core_get_version(struct mali_gp_core *core); + +mali_bool mali_gp_core_set_counter_src0(struct mali_gp_core *core, u32 counter); +mali_bool mali_gp_core_set_counter_src1(struct mali_gp_core *core, u32 counter); +u32 mali_gp_core_get_counter_src0(struct mali_gp_core *core); +u32 mali_gp_core_get_counter_src1(struct mali_gp_core *core); +struct mali_gp_core *mali_gp_get_global_gp_core(void); + +u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size); + +#endif /* __MALI_GP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp_job.c b/drivers/media/video/samsung/mali/common/mali_gp_job.c new file mode 100644 index 0000000..abe1d93 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_job.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011-2012 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_gp_job.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" + +struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *args, u32 id) +{ + struct mali_gp_job *job; + + job = _mali_osk_malloc(sizeof(struct mali_gp_job)); + if (NULL != job) + { + _mali_osk_list_init(&job->list); + job->session = session; + job->id = id; + job->user_id = args->user_job_ptr; + _mali_osk_memcpy(job->frame_registers, args->frame_registers, sizeof(job->frame_registers)); + job->heap_current_addr = args->frame_registers[4]; + job->perf_counter_flag = args->perf_counter_flag; + job->perf_counter_src0 = args->perf_counter_src0; + job->perf_counter_src1 = args->perf_counter_src1; + job->perf_counter_value0 = 0; + job->perf_counter_value1 = 0; + + job->pid = _mali_osk_get_pid(); + job->tid = _mali_osk_get_tid(); + job->frame_builder_id = args->frame_builder_id; + job->flush_id = args->flush_id; + + return job; + } + + return NULL; +} + +void mali_gp_job_delete(struct mali_gp_job *job) +{ + _mali_osk_free(job); +} diff --git a/drivers/media/video/samsung/mali/common/mali_gp_job.h b/drivers/media/video/samsung/mali/common/mali_gp_job.h new file mode 100644 index 0000000..9c29f1c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_job.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_GP_JOB_H__ +#define __MALI_GP_JOB_H__ + +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" +#include "mali_session.h" + +/** + * The structure represends a GP job, including all sub-jobs + * (This struct unfortunatly needs to be public because of how the _mali_osk_list_* + * mechanism works) + */ +struct mali_gp_job +{ + _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ + struct mali_session_data *session; /**< Session which submitted this job */ + u32 id; /**< identifier for this job in kernel space (sequential numbering) */ + u32 user_id; /**< identifier for the job in user space */ + u32 frame_registers[MALIGP2_NUM_REGS_FRAME]; /**< core specific registers associated with this job, see ARM DDI0415A */ + u32 heap_current_addr; /**< Holds the current HEAP address when the job has completed */ + u32 perf_counter_flag; /**< bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ + u32 perf_counter_src0; /**< source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_src1; /**< source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_value0; /**< Value of performance counter 0 (to be returned to user space) */ + u32 perf_counter_value1; /**< Value of performance counter 1 (to be returned to user space) */ + u32 pid; /**< Process ID of submitting process */ + u32 tid; /**< Thread ID of submitting thread */ + u32 frame_builder_id; /**< id of the originating frame builder */ + u32 flush_id; /**< flush id within the originating frame builder */ +}; + +struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *args, u32 id); +void mali_gp_job_delete(struct mali_gp_job *job); + +MALI_STATIC_INLINE u32 mali_gp_job_get_id(struct mali_gp_job *job) +{ + return (NULL == job) ? 0 : job->id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_user_id(struct mali_gp_job *job) +{ + return job->user_id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_frame_builder_id(struct mali_gp_job *job) +{ + return job->frame_builder_id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_flush_id(struct mali_gp_job *job) +{ + return job->flush_id; +} + +MALI_STATIC_INLINE u32* mali_gp_job_get_frame_registers(struct mali_gp_job *job) +{ + return job->frame_registers; +} + +MALI_STATIC_INLINE struct mali_session_data *mali_gp_job_get_session(struct mali_gp_job *job) +{ + return job->session; +} + +MALI_STATIC_INLINE mali_bool mali_gp_job_has_vs_job(struct mali_gp_job *job) +{ + return (job->frame_registers[0] != job->frame_registers[1]) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE mali_bool mali_gp_job_has_plbu_job(struct mali_gp_job *job) +{ + return (job->frame_registers[2] != job->frame_registers[3]) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_current_heap_addr(struct mali_gp_job *job) +{ + return job->heap_current_addr; +} + +MALI_STATIC_INLINE void mali_gp_job_set_current_heap_addr(struct mali_gp_job *job, u32 heap_addr) +{ + job->heap_current_addr = heap_addr; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_flag(struct mali_gp_job *job) +{ + return job->perf_counter_flag; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src0(struct mali_gp_job *job) +{ + return job->perf_counter_src0; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src1(struct mali_gp_job *job) +{ + return job->perf_counter_src1; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value0(struct mali_gp_job *job) +{ + return job->perf_counter_value0; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value1(struct mali_gp_job *job) +{ + return job->perf_counter_value1; +} + +MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value0(struct mali_gp_job *job, u32 value) +{ + job->perf_counter_value0 = value; +} + +MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value1(struct mali_gp_job *job, u32 value) +{ + job->perf_counter_value1 = value; +} + +#endif /* __MALI_GP_JOB_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c new file mode 100644 index 0000000..05f00fc --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2012 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_gp_scheduler.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_scheduler.h" +#include "mali_gp.h" +#include "mali_gp_job.h" +#include "mali_group.h" +#include "mali_cluster.h" + +enum mali_gp_slot_state +{ + MALI_GP_SLOT_STATE_IDLE, + MALI_GP_SLOT_STATE_WORKING, +}; + +/* A render slot is an entity which jobs can be scheduled onto */ +struct mali_gp_slot +{ + struct mali_group *group; + /* + * We keep track of the state here as well as in the group object + * so we don't need to take the group lock so often (and also avoid clutter with the working lock) + */ + enum mali_gp_slot_state state; + u32 returned_cookie; +}; + +static u32 gp_version = 0; +static _MALI_OSK_LIST_HEAD(job_queue); /* List of jobs with some unscheduled work */ +static struct mali_gp_slot slot; + +/* Variables to allow safe pausing of the scheduler */ +static _mali_osk_wait_queue_t *gp_scheduler_working_wait_queue = NULL; +static u32 pause_count = 0; + +static mali_bool mali_gp_scheduler_is_suspended(void); + +static _mali_osk_lock_t *gp_scheduler_lock = NULL; +/* Contains tid of thread that locked the scheduler or 0, if not locked */ + +_mali_osk_errcode_t mali_gp_scheduler_initialize(void) +{ + u32 i; + + _MALI_OSK_INIT_LIST_HEAD(&job_queue); + + gp_scheduler_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_SCHEDULER); + gp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); + + if (NULL == gp_scheduler_lock) + { + return _MALI_OSK_ERR_NOMEM; + } + + if (NULL == gp_scheduler_working_wait_queue) + { + _mali_osk_lock_term(gp_scheduler_lock); + return _MALI_OSK_ERR_NOMEM; + } + + /* Find all the available GP cores */ + for (i = 0; i < mali_cluster_get_glob_num_clusters(); i++) + { + u32 group_id = 0; + struct mali_cluster *curr_cluster = mali_cluster_get_global_cluster(i); + struct mali_group *group = mali_cluster_get_group(curr_cluster, group_id); + while (NULL != group) + { + struct mali_gp_core *gp_core = mali_group_get_gp_core(group); + if (NULL != gp_core) + { + if (0 == gp_version) + { + /* Retrieve GP version */ + gp_version = mali_gp_core_get_version(gp_core); + } + slot.group = group; + slot.state = MALI_GP_SLOT_STATE_IDLE; + break; /* There are only one GP, no point in looking for more */ + } + group_id++; + group = mali_cluster_get_group(curr_cluster, group_id); + } + } + + return _MALI_OSK_ERR_OK; +} + +void mali_gp_scheduler_terminate(void) +{ + _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue); + _mali_osk_lock_term(gp_scheduler_lock); +} + +MALI_STATIC_INLINE void mali_gp_scheduler_lock(void) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali GP scheduler: GP scheduler lock taken\n")); +} + +MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void) +{ + MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n")); + _mali_osk_lock_signal(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +MALI_STATIC_INLINE void mali_gp_scheduler_assert_locked(void) +{ + MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); +} +#define MALI_ASSERT_GP_SCHEDULER_LOCKED() mali_gp_scheduler_assert_locked() +#else +#define MALI_ASSERT_GP_SCHEDULER_LOCKED() +#endif + +static void mali_gp_scheduler_schedule(void) +{ + struct mali_gp_job *job; + + MALI_ASSERT_GP_SCHEDULER_LOCKED(); + + if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state || _mali_osk_list_empty(&job_queue)) + { + MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", + pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0)); + return; /* Nothing to do, so early out */ + } + + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_gp_job, list); + + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Starting job %u (0x%08X)\n", mali_gp_job_get_id(job), job)); + if (_MALI_OSK_ERR_OK == mali_group_start_gp_job(slot.group, job)) + { + /* Mark slot as busy */ + slot.state = MALI_GP_SLOT_STATE_WORKING; + + /* Remove from queue of unscheduled jobs */ + _mali_osk_list_del(&job->list); + } + else + { + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Failed to start GP job\n")); + } +} + +static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success) +{ + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s)); + if (NULL != notobj) + { + _mali_uk_gp_job_finished_s *jobres = notobj->result_buffer; + _mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ + jobres->user_job_ptr = mali_gp_job_get_user_id(job); + if (MALI_TRUE == success) + { + jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; + } + else + { + jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; + } + + jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job); + jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job); + jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job); + + mali_session_send_notification(mali_gp_job_get_session(job), notobj); + } + else + { + MALI_PRINT_ERROR(("Mali GP scheduler: Unable to allocate notification object\n")); + } + + mali_gp_job_delete(job); +} + + +void mali_gp_scheduler_do_schedule(void) +{ + mali_gp_scheduler_lock(); + + mali_gp_scheduler_schedule(); + + mali_gp_scheduler_unlock(); +} + +void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success) +{ + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) completed (%s)\n", mali_gp_job_get_id(job), job, success ? "success" : "failure")); + + mali_gp_scheduler_lock(); + + /* Mark slot as idle again */ + slot.state = MALI_GP_SLOT_STATE_IDLE; + + /* If paused, then this was the last job, so wake up sleeping workers */ + if (pause_count > 0) + { + _mali_osk_wait_queue_wake_up(gp_scheduler_working_wait_queue); + } + else + { + mali_gp_scheduler_schedule(); + } + + mali_gp_scheduler_unlock(); + + mali_gp_scheduler_return_job_to_user(job, success); +} + +void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job) +{ + _mali_osk_notification_t *notobj; + + notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s)); + + if (NULL != notobj) + { + _mali_uk_gp_job_suspended_s * jobres; + + mali_gp_scheduler_lock(); + + jobres = (_mali_uk_gp_job_suspended_s *)notobj->result_buffer; + + jobres->user_job_ptr = mali_gp_job_get_user_id(job); + jobres->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY; + jobres->cookie = mali_gp_job_get_id(job); + slot.returned_cookie = jobres->cookie; + + mali_session_send_notification(mali_gp_job_get_session(job), notobj); + + mali_gp_scheduler_unlock(); + } + + /* + * If this function failed, then we could return the job to user space right away, + * but there is a job timer anyway that will do that eventually. + * This is not exactly a common case anyway. + */ +} + +void mali_gp_scheduler_suspend(void) +{ + mali_gp_scheduler_lock(); + pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ + mali_gp_scheduler_unlock(); + + _mali_osk_wait_queue_wait_event(gp_scheduler_working_wait_queue, mali_gp_scheduler_is_suspended); +} + +void mali_gp_scheduler_resume(void) +{ + mali_gp_scheduler_lock(); + pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ + if (0 == pause_count) + { + mali_gp_scheduler_schedule(); + } + mali_gp_scheduler_unlock(); +} + +_mali_osk_errcode_t _mali_ukk_gp_start_job(_mali_uk_gp_start_job_s *args) +{ + struct mali_session_data *session; + struct mali_gp_job *job; + + MALI_DEBUG_ASSERT_POINTER(args); + + if (NULL == args->ctx) + { + return _MALI_OSK_ERR_INVALID_ARGS; + } + + session = (struct mali_session_data*)args->ctx; + if (NULL == session) + { + return _MALI_OSK_ERR_FAULT; + } + + job = mali_gp_job_create(session, args, mali_scheduler_get_new_id()); + if (NULL == job) + { + return _MALI_OSK_ERR_NOMEM; + } + + mali_gp_scheduler_lock(); + + _mali_osk_list_addtail(&job->list, &job_queue); + + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n", mali_gp_job_get_id(job), job)); + + mali_gp_scheduler_schedule(); + + mali_gp_scheduler_unlock(); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + args->number_of_cores = 1; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + args->version = gp_version; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args) +{ + struct mali_session_data *session; + _mali_osk_errcode_t ret = _MALI_OSK_ERR_FAULT; + + MALI_DEBUG_ASSERT_POINTER(args); + + if (NULL == args->ctx) + { + return _MALI_OSK_ERR_INVALID_ARGS; + } + + session = (struct mali_session_data*)args->ctx; + if (NULL == session) + { + return _MALI_OSK_ERR_FAULT; + } + + mali_gp_scheduler_lock(); + + /* Make sure that the cookie returned by user space is the same as we provided in the first place */ + if (args->cookie != slot.returned_cookie) + { + MALI_DEBUG_PRINT(2, ("Mali GP scheduler: Got an illegal cookie from user space, expected %u but got %u (job id)\n", slot.returned_cookie, args->cookie)) ; + mali_gp_scheduler_unlock(); + return _MALI_OSK_ERR_FAULT; + } + + mali_gp_scheduler_unlock(); + + switch (args->code) + { + case _MALIGP_JOB_RESUME_WITH_NEW_HEAP: + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1])); + mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]); + ret = _MALI_OSK_ERR_OK; + break; + + case _MALIGP_JOB_ABORT: + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie)); + mali_group_abort_gp_job(slot.group, args->cookie); + ret = _MALI_OSK_ERR_OK; + break; + + default: + MALI_PRINT_ERROR(("Mali GP scheduler: Wrong suspend response from user space\n")); + ret = _MALI_OSK_ERR_FAULT; + break; + } + + return ret; + +} + +void mali_gp_scheduler_abort_session(struct mali_session_data *session) +{ + struct mali_gp_job *job, *tmp; + + mali_gp_scheduler_lock(); + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting all jobs from session 0x%08x\n", session)); + + /* Check queue for jobs and remove */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_gp_job, list) + { + if (mali_gp_job_get_session(job) == session) + { + MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Removing GP job 0x%08x from queue\n", job)); + _mali_osk_list_del(&(job->list)); + mali_gp_job_delete(job); + } + } + + mali_gp_scheduler_unlock(); + + /* Abort running jobs from this session. It is safe to do this outside + * the scheduler lock as there is only one GP core, and the queue has + * already been emptied, as long as there are no new jobs coming in + * from user space. */ + mali_group_abort_session(slot.group, session); +} + +static mali_bool mali_gp_scheduler_is_suspended(void) +{ + mali_bool ret; + + mali_gp_scheduler_lock(); + ret = pause_count > 0 && slot.state == MALI_GP_SLOT_STATE_IDLE; + mali_gp_scheduler_unlock(); + + return ret; +} + + +#if MALI_STATE_TRACKING +u32 mali_gp_scheduler_dump_state(char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "GP\n"); + n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); + + n += mali_group_dump_state(slot.group, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", mali_group_gp_state(slot.group)); + n += _mali_osk_snprintf(buf + n, size - n, "\n"); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h new file mode 100644 index 0000000..ef58509 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef __MALI_GP_SCHEDULER_H__ +#define __MALI_GP_SCHEDULER_H__ + +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_gp_job.h" + +_mali_osk_errcode_t mali_gp_scheduler_initialize(void); +void mali_gp_scheduler_terminate(void); + +void mali_gp_scheduler_do_schedule(void); +void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success); +void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job); +void mali_gp_scheduler_abort_session(struct mali_session_data *session); +u32 mali_gp_scheduler_dump_state(char *buf, u32 size); + +void mali_gp_scheduler_suspend(void); +void mali_gp_scheduler_resume(void); + +#endif /* __MALI_GP_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_group.c b/drivers/media/video/samsung/mali/common/mali_group.c new file mode 100644 index 0000000..9202bc1 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_group.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2011-2012 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_group.h" +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_mmu.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_pm.h" + +/* + * The group object is the most important object in the device driver, + * and acts as the center of many HW operations. + * The reason for this is that operations on the MMU will affect all + * cores connected to this MMU (a group is defined by the MMU and the + * cores which are connected to this). + * The group lock is thus the most important lock, followed by the + * GP and PP scheduler locks. They must be taken in the following + * order: + * GP/PP lock first, then group lock(s). + */ + +/** + * The structure represents a render group + * A render group is defined by all the cores that share the same Mali MMU + */ + +struct mali_group +{ + struct mali_cluster *cluster; + + struct mali_mmu_core *mmu; + struct mali_session_data *session; + int page_dir_ref_count; + mali_bool power_is_on; +#if defined(USING_MALI200) + mali_bool pagedir_activation_failed; +#endif + + struct mali_gp_core *gp_core; + enum mali_group_core_state gp_state; + struct mali_gp_job *gp_running_job; + + struct mali_pp_core *pp_core; + enum mali_group_core_state pp_state; + struct mali_pp_job *pp_running_job; + u32 pp_running_sub_job; + + _mali_osk_lock_t *lock; +}; + +static struct mali_group *mali_global_groups[MALI_MAX_NUMBER_OF_GROUPS]; +static u32 mali_global_num_groups = 0; + +enum mali_group_activate_pd_status +{ + MALI_GROUP_ACTIVATE_PD_STATUS_FAILED, + MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD, + MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD, +}; + +/* local helper functions */ +static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session); +static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session); +static void mali_group_recovery_reset(struct mali_group *group); +static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success); + +void mali_group_lock(struct mali_group *group) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(group->lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali group: Group lock taken 0x%08X\n", group)); +} + +void mali_group_unlock(struct mali_group *group) +{ + MALI_DEBUG_PRINT(5, ("Mali group: Releasing group lock 0x%08X\n", group)); + _mali_osk_lock_signal(group->lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +void mali_group_assert_locked(struct mali_group *group) +{ + MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); +} +#endif + + +struct mali_group *mali_group_create(struct mali_cluster *cluster, struct mali_mmu_core *mmu) +{ + struct mali_group *group = NULL; + + if (mali_global_num_groups >= MALI_MAX_NUMBER_OF_GROUPS) + { + MALI_PRINT_ERROR(("Mali group: Too many group objects created\n")); + return NULL; + } + + group = _mali_osk_malloc(sizeof(struct mali_group)); + if (NULL != group) + { + _mali_osk_memset(group, 0, sizeof(struct mali_group)); + group->lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_GROUP); + if (NULL != group->lock) + { + group->cluster = cluster; + group->mmu = mmu; /* This group object now owns the MMU object */ + group->session = NULL; + group->page_dir_ref_count = 0; + group->power_is_on = MALI_TRUE; + + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_FALSE; +#endif + mali_global_groups[mali_global_num_groups] = group; + mali_global_num_groups++; + + return group; + } + _mali_osk_free(group); + } + + return NULL; +} + +void mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core) +{ + /* This group object now owns the GP core object */ + group->gp_core = gp_core; +} + +void mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core) +{ + /* This group object now owns the PP core object */ + group->pp_core = pp_core; +} + +void mali_group_delete(struct mali_group *group) +{ + u32 i; + + /* Delete the resources that this group owns */ + if (NULL != group->gp_core) + { + mali_gp_delete(group->gp_core); + } + + if (NULL != group->pp_core) + { + mali_pp_delete(group->pp_core); + } + + if (NULL != group->mmu) + { + mali_mmu_delete(group->mmu); + } + + for (i = 0; i < mali_global_num_groups; i++) + { + if (mali_global_groups[i] == group) + { + mali_global_groups[i] = NULL; + mali_global_num_groups--; + break; + } + } + + _mali_osk_lock_term(group->lock); + + _mali_osk_free(group); +} + +/* Called from mali_cluster_reset() when the system is re-turned on */ +void mali_group_reset(struct mali_group *group) +{ + mali_group_lock(group); + + group->session = NULL; + + if (NULL != group->mmu) + { + mali_mmu_reset(group->mmu); + } + + if (NULL != group->gp_core) + { + mali_gp_reset(group->gp_core); + } + + if (NULL != group->pp_core) + { + mali_pp_reset(group->pp_core); + } + + mali_group_unlock(group); +} + +struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group) +{ + return group->gp_core; +} + +struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group) +{ + return group->pp_core; +} + +_mali_osk_errcode_t mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job) +{ + struct mali_session_data *session; + enum mali_group_activate_pd_status activate_status; + + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + + mali_pm_core_event(MALI_CORE_EVENT_GP_START); + + session = mali_gp_job_get_session(job); + + mali_group_lock(group); + + mali_cluster_l2_cache_invalidate_all(group->cluster, mali_gp_job_get_id(job)); + + activate_status = mali_group_activate_page_directory(group, session); + if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status) + { + /* if session is NOT kept Zapping is done as part of session switch */ + if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status) + { + mali_mmu_zap_tlb_without_stall(group->mmu); + } + mali_gp_job_start(group->gp_core, job); + group->gp_running_job = job; + group->gp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); + + return _MALI_OSK_ERR_OK; + } + +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_TRUE; +#endif + + mali_group_unlock(group); + + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_GP_START */ + return _MALI_OSK_ERR_FAULT; +} + +_mali_osk_errcode_t mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job) +{ + struct mali_session_data *session; + enum mali_group_activate_pd_status activate_status; + + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + + mali_pm_core_event(MALI_CORE_EVENT_PP_START); + + session = mali_pp_job_get_session(job); + + mali_group_lock(group); + + mali_cluster_l2_cache_invalidate_all(group->cluster, mali_pp_job_get_id(job)); + + activate_status = mali_group_activate_page_directory(group, session); + if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status) + { + /* if session is NOT kept Zapping is done as part of session switch */ + if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status) + { + MALI_DEBUG_PRINT(3, ("PP starting job PD_Switch 0 Flush 1 Zap 1\n")); + mali_mmu_zap_tlb_without_stall(group->mmu); + } + mali_pp_job_start(group->pp_core, job, sub_job); + group->pp_running_job = job; + group->pp_running_sub_job = sub_job; + group->pp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); + + return _MALI_OSK_ERR_OK; + } + +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_TRUE; +#endif + + mali_group_unlock(group); + + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_PP_START */ + return _MALI_OSK_ERR_FAULT; +} + +void mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr) +{ + mali_group_lock(group); + + if (group->gp_state != MALI_GROUP_CORE_STATE_OOM || + mali_gp_job_get_id(group->gp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* Illegal request or job has already been aborted */ + } + + mali_cluster_l2_cache_invalidate_all_force(group->cluster); + mali_mmu_zap_tlb_without_stall(group->mmu); + + mali_gp_resume_with_new_heap(group->gp_core, start_addr, end_addr); + group->gp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); +} + +void mali_group_abort_gp_job(struct mali_group *group, u32 job_id) +{ + mali_group_lock(group); + + if (group->gp_state == MALI_GROUP_CORE_STATE_IDLE || + mali_gp_job_get_id(group->gp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* No need to cancel or job has already been aborted or completed */ + } + + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* Will release group lock */ +} + +void mali_group_abort_pp_job(struct mali_group *group, u32 job_id) +{ + mali_group_lock(group); + + if (group->pp_state == MALI_GROUP_CORE_STATE_IDLE || + mali_pp_job_get_id(group->pp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* No need to cancel or job has already been aborted or completed */ + } + + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* Will release group lock */ +} + +void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session) +{ + struct mali_gp_job *gp_job; + struct mali_pp_job *pp_job; + u32 gp_job_id = 0; + u32 pp_job_id = 0; + mali_bool abort_pp = MALI_FALSE; + mali_bool abort_gp = MALI_FALSE; + + mali_group_lock(group); + + gp_job = group->gp_running_job; + pp_job = group->pp_running_job; + + if (gp_job && mali_gp_job_get_session(gp_job) == session) + { + MALI_DEBUG_PRINT(4, ("Aborting GP job 0x%08x from session 0x%08x\n", gp_job, session)); + + gp_job_id = mali_gp_job_get_id(gp_job); + abort_gp = MALI_TRUE; + } + + if (pp_job && mali_pp_job_get_session(pp_job) == session) + { + MALI_DEBUG_PRINT(4, ("Mali group: Aborting PP job 0x%08x from session 0x%08x\n", pp_job, session)); + + pp_job_id = mali_pp_job_get_id(pp_job); + abort_pp = MALI_TRUE; + } + + mali_group_unlock(group); + + /* These functions takes and releases the group lock */ + if (0 != abort_gp) + { + mali_group_abort_gp_job(group, gp_job_id); + } + if (0 != abort_pp) + { + mali_group_abort_pp_job(group, pp_job_id); + } + + mali_group_lock(group); + mali_group_remove_session_if_unused(group, session); + mali_group_unlock(group); +} + +enum mali_group_core_state mali_group_gp_state(struct mali_group *group) +{ + return group->gp_state; +} + +enum mali_group_core_state mali_group_pp_state(struct mali_group *group) +{ + return group->pp_state; +} + +/* group lock need to be taken before calling mali_group_bottom_half */ +void mali_group_bottom_half(struct mali_group *group, enum mali_group_event_t event) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + switch (event) + { + case GROUP_EVENT_PP_JOB_COMPLETED: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_TRUE); /* PP job SUCCESS */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_PP_JOB_FAILED: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_PP_JOB_TIMED_OUT: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job TIMEOUT */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_COMPLETED: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_TRUE); /* GP job SUCCESS */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_FAILED: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_TIMED_OUT: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job TIMEOUT */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_OOM: + group->gp_state = MALI_GROUP_CORE_STATE_OOM; + mali_group_unlock(group); /* Nothing to do on the HW side, so just release group lock right away */ + mali_gp_scheduler_oom(group, group->gp_running_job); + break; + case GROUP_EVENT_MMU_PAGE_FAULT: + mali_group_complete_jobs(group, MALI_TRUE, MALI_TRUE, MALI_FALSE); /* GP and PP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + default: + break; + } +} + +struct mali_mmu_core *mali_group_get_mmu(struct mali_group *group) +{ + return group->mmu; +} + +struct mali_session_data *mali_group_get_session(struct mali_group *group) +{ + return group->session; +} + +struct mali_group *mali_group_get_glob_group(u32 index) +{ + if(mali_global_num_groups > index) + { + return mali_global_groups[index]; + } + + return NULL; +} + +u32 mali_group_get_glob_num_groups(void) +{ + return mali_global_num_groups; +} + +/* Used to check if scheduler for the other core type needs to be called on job completion. + * + * Used only for Mali-200, where job start may fail if the only MMU is busy + * with another session's address space. + */ +static inline mali_bool mali_group_other_reschedule_needed(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + +#if defined(USING_MALI200) + if (group->pagedir_activation_failed) + { + group->pagedir_activation_failed = MALI_FALSE; + return MALI_TRUE; + } + else +#endif + { + return MALI_FALSE; + } +} + +static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session) +{ + enum mali_group_activate_pd_status retval; + MALI_ASSERT_GROUP_LOCKED(group); + + MALI_DEBUG_PRINT(5, ("Mali group: Activating page directory 0x%08X from session 0x%08X on group 0x%08X\n", mali_session_get_page_directory(session), session, group)); + MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count); + + if (0 != group->page_dir_ref_count) + { + if (group->session != session) + { + MALI_DEBUG_PRINT(4, ("Mali group: Activating session FAILED: 0x%08x on group 0x%08X. Existing session: 0x%08x\n", session, group, group->session)); + return MALI_GROUP_ACTIVATE_PD_STATUS_FAILED; + } + else + { + MALI_DEBUG_PRINT(4, ("Mali group: Activating session already activated: 0x%08x on group 0x%08X. New Ref: %d\n", session, group, 1+group->page_dir_ref_count)); + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD; + + } + } + else + { + /* There might be another session here, but it is ok to overwrite it since group->page_dir_ref_count==0 */ + if (group->session != session) + { + mali_bool activate_success; + MALI_DEBUG_PRINT(5, ("Mali group: Activate session: %08x previous: %08x on group 0x%08X. Ref: %d\n", session, group->session, group, 1+group->page_dir_ref_count)); + + activate_success = mali_mmu_activate_page_directory(group->mmu, mali_session_get_page_directory(session)); + MALI_DEBUG_ASSERT(activate_success); + if ( MALI_FALSE== activate_success ) return MALI_FALSE; + group->session = session; + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD; + } + else + { + MALI_DEBUG_PRINT(4, ("Mali group: Activate existing session 0x%08X on group 0x%08X. Ref: %d\n", session->page_directory, group, 1+group->page_dir_ref_count)); + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD; + } + } + + group->page_dir_ref_count++; + return retval; +} + +static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + MALI_DEBUG_ASSERT(0 < group->page_dir_ref_count); + MALI_DEBUG_ASSERT(session == group->session); + + group->page_dir_ref_count--; + + /* As an optimization, the MMU still points to the group->session even if (0 == group->page_dir_ref_count), + and we do not call mali_mmu_activate_empty_page_directory(group->mmu); */ + MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count); +} + +void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + if (0 == group->page_dir_ref_count) + { + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + + if (group->session == session) + { + MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on); + MALI_DEBUG_PRINT(3, ("Mali group: Deactivating unused session 0x%08X on group %08X\n", session, group)); + mali_mmu_activate_empty_page_directory(group->mmu); + group->session = NULL; + } + } +} + +void mali_group_power_on(void) +{ + int i; + for (i = 0; i < mali_global_num_groups; i++) + { + struct mali_group *group = mali_global_groups[i]; + mali_group_lock(group); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + MALI_DEBUG_ASSERT_POINTER(group->cluster); + group->power_is_on = MALI_TRUE; + mali_cluster_power_is_enabled_set(group->cluster, MALI_TRUE); + mali_group_unlock(group); + } + MALI_DEBUG_PRINT(3,("group: POWER ON\n")); +} + +mali_bool mali_group_power_is_on(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + return group->power_is_on; +} + +void mali_group_power_off(void) +{ + int i; + /* It is necessary to set group->session = NULL; so that the powered off MMU is not written to on map /unmap */ + /* It is necessary to set group->power_is_on=MALI_FALSE so that pending bottom_halves does not access powered off cores. */ + for (i = 0; i < mali_global_num_groups; i++) + { + struct mali_group *group = mali_global_groups[i]; + mali_group_lock(group); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + MALI_DEBUG_ASSERT_POINTER(group->cluster); + group->session = NULL; + MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on); + group->power_is_on = MALI_FALSE; + mali_cluster_power_is_enabled_set(group->cluster, MALI_FALSE); + mali_group_unlock(group); + } + MALI_DEBUG_PRINT(3,("group: POWER OFF\n")); +} + + +static void mali_group_recovery_reset(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + /* Stop cores, bus stop */ + if (NULL != group->pp_core) + { + mali_pp_stop_bus(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_stop_bus(group->gp_core); + } + + /* Flush MMU */ + mali_mmu_activate_fault_flush_page_directory(group->mmu); + mali_mmu_page_fault_done(group->mmu); + + /* Wait for cores to stop bus */ + if (NULL != group->pp_core) + { + mali_pp_stop_bus_wait(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_stop_bus_wait(group->gp_core); + } + + /* Reset cores */ + if (NULL != group->pp_core) + { + mali_pp_hard_reset(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_hard_reset(group->gp_core); + } + + /* Reset MMU */ + mali_mmu_reset(group->mmu); + group->session = NULL; +} + +/* Group lock need to be taken before calling mali_group_complete_jobs. Will release the lock here. */ +static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success) +{ + mali_bool need_group_reset = MALI_FALSE; + mali_bool gp_success = success; + mali_bool pp_success = success; + + MALI_ASSERT_GROUP_LOCKED(group); + + if (complete_gp && !complete_pp) + { + MALI_DEBUG_ASSERT_POINTER(group->gp_core); + if (_MALI_OSK_ERR_OK == mali_gp_reset(group->gp_core)) + { + struct mali_gp_job *gp_job_to_return = group->gp_running_job; + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->gp_running_job = NULL; + + MALI_DEBUG_ASSERT_POINTER(gp_job_to_return); + + mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return)); + + if(mali_group_other_reschedule_needed(group)) + { + mali_group_unlock(group); + mali_pp_scheduler_do_schedule(); + } + else + { + mali_group_unlock(group); + } + + mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success); + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + + return; + } + else + { + need_group_reset = MALI_TRUE; + MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset GP, need to reset entire group\n")); + pp_success = MALI_FALSE; /* This might kill PP as well, so this should fail */ + } + } + if (complete_pp && !complete_gp) + { + MALI_DEBUG_ASSERT_POINTER(group->pp_core); + if (_MALI_OSK_ERR_OK == mali_pp_reset(group->pp_core)) + { + struct mali_pp_job *pp_job_to_return = group->pp_running_job; + u32 pp_sub_job_to_return = group->pp_running_sub_job; + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_running_job = NULL; + + MALI_DEBUG_ASSERT_POINTER(pp_job_to_return); + + mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return)); + + if(mali_group_other_reschedule_needed(group)) + { + mali_group_unlock(group); + mali_gp_scheduler_do_schedule(); + } + else + { + mali_group_unlock(group); + } + + mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success); + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + + return; + } + else + { + need_group_reset = MALI_TRUE; + MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset PP, need to reset entire group\n")); + gp_success = MALI_FALSE; /* This might kill GP as well, so this should fail */ + } + } + else if (complete_gp && complete_pp) + { + need_group_reset = MALI_TRUE; + } + + if (MALI_TRUE == need_group_reset) + { + struct mali_gp_job *gp_job_to_return = group->gp_running_job; + struct mali_pp_job *pp_job_to_return = group->pp_running_job; + u32 pp_sub_job_to_return = group->pp_running_sub_job; + mali_bool schedule_other = MALI_FALSE; + + MALI_DEBUG_PRINT(3, ("Mali group: Resetting entire group\n")); + + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->gp_running_job = NULL; + if (NULL != gp_job_to_return) + { + mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return)); + } + + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_running_job = NULL; + if (NULL != pp_job_to_return) + { + mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return)); + } + + /* The reset has to be done after mali_group_deactivate_page_directory() */ + mali_group_recovery_reset(group); + + if (mali_group_other_reschedule_needed(group) && (NULL == gp_job_to_return || NULL == pp_job_to_return)) + { + schedule_other = MALI_TRUE; + } + + mali_group_unlock(group); + + if (NULL != gp_job_to_return) + { + mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success); + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + } + else if (schedule_other) + { + mali_pp_scheduler_do_schedule(); + } + + if (NULL != pp_job_to_return) + { + mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success); + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + } + else if (schedule_other) + { + mali_gp_scheduler_do_schedule(); + } + + return; + } + + mali_group_unlock(group); +} + +#if MALI_STATE_TRACKING +u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "Group: %p\n", group); + if (group->gp_core) + { + n += mali_gp_dump_state(group->gp_core, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\tGP state: %d\n", group->gp_state); + n += _mali_osk_snprintf(buf + n, size - n, "\tGP job: %p\n", group->gp_running_job); + } + if (group->pp_core) + { + n += mali_pp_dump_state(group->pp_core, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\tPP state: %d\n", group->pp_state); + n += _mali_osk_snprintf(buf + n, size - n, "\tPP job: %p, subjob %d \n", + group->pp_running_job, group->pp_running_sub_job); + } + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_group.h b/drivers/media/video/samsung/mali/common/mali_group.h new file mode 100644 index 0000000..3533d13 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_group.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_GROUP_H__ +#define __MALI_GROUP_H__ + +#include "linux/jiffies.h" +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_mmu.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_session.h" + +/* max runtime [ms] for a core job - used by timeout timers */ +#define MAX_RUNTIME 5000 +/** @brief A mali group object represents a MMU and a PP and/or a GP core. + * + */ +#define MALI_MAX_NUMBER_OF_GROUPS 9 + +struct mali_group; + +enum mali_group_event_t +{ + GROUP_EVENT_PP_JOB_COMPLETED, /**< PP job completed successfully */ + GROUP_EVENT_PP_JOB_FAILED, /**< PP job completed with failure */ + GROUP_EVENT_PP_JOB_TIMED_OUT, /**< PP job reached max runtime */ + GROUP_EVENT_GP_JOB_COMPLETED, /**< GP job completed successfully */ + GROUP_EVENT_GP_JOB_FAILED, /**< GP job completed with failure */ + GROUP_EVENT_GP_JOB_TIMED_OUT, /**< GP job reached max runtime */ + GROUP_EVENT_GP_OOM, /**< GP job ran out of heap memory */ + GROUP_EVENT_MMU_PAGE_FAULT, /**< MMU page fault */ +}; + +enum mali_group_core_state +{ + MALI_GROUP_CORE_STATE_IDLE, + MALI_GROUP_CORE_STATE_WORKING, + MALI_GROUP_CORE_STATE_OOM +}; + +/** @brief Create a new Mali group object + * + * @param cluster Pointer to the cluster to which the group is connected. + * @param mmu Pointer to the MMU that defines this group + * @return A pointer to a new group object + */ +struct mali_group *mali_group_create(struct mali_cluster *cluster, struct mali_mmu_core *mmu); +void mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core); +void mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core); +void mali_group_delete(struct mali_group *group); + +/** @brief Reset group + * + * This function will reset the entire group, including all the cores present in the group. + * + * @param group Pointer to the group to reset + */ +void mali_group_reset(struct mali_group *group); + +/** @brief Get pointer to GP core object + */ +struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group); + +/** @brief Get pointer to PP core object + */ +struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group); + +/** @brief Lock group object + * + * Most group functions will lock the group object themselves. The expection is + * the group_bottom_half which requires the group to be locked on entry. + * + * @param group Pointer to group to lock + */ +void mali_group_lock(struct mali_group *group); + +/** @brief Unlock group object + * + * @param group Pointer to group to unlock + */ +void mali_group_unlock(struct mali_group *group); +#ifdef DEBUG +void mali_group_assert_locked(struct mali_group *group); +#define MALI_ASSERT_GROUP_LOCKED(group) mali_group_assert_locked(group) +#else +#define MALI_ASSERT_GROUP_LOCKED(group) +#endif + +/** @brief Start GP job + */ +_mali_osk_errcode_t mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job); +/** @brief Start fragment of PP job + */ +_mali_osk_errcode_t mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job); + +/** @brief Resume GP job that suspended waiting for more heap memory + */ +void mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr); +/** @brief Abort GP job + * + * Used to abort suspended OOM jobs when user space failed to allocte more memory. + */ +void mali_group_abort_gp_job(struct mali_group *group, u32 job_id); +/** @brief Abort all GP jobs from \a session + * + * Used on session close when terminating all running and queued jobs from \a session. + */ +void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session); + +enum mali_group_core_state mali_group_gp_state(struct mali_group *group); +enum mali_group_core_state mali_group_pp_state(struct mali_group *group); + +/** @brief The common group bottom half interrupt handler + * + * This is only called from the GP and PP bottom halves. + * + * The action taken is dictated by the \a event. + * + * @param event The event code + */ +void mali_group_bottom_half(struct mali_group *group, enum mali_group_event_t event); + +struct mali_mmu_core *mali_group_get_mmu(struct mali_group *group); +struct mali_session_data *mali_group_get_session(struct mali_group *group); + +void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session_data); + +void mali_group_power_on(void); +void mali_group_power_off(void); +mali_bool mali_group_power_is_on(struct mali_group *group); + +struct mali_group *mali_group_get_glob_group(u32 index); +u32 mali_group_get_glob_num_groups(void); + +u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size); + +#endif /* __MALI_GROUP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_hw_core.c b/drivers/media/video/samsung/mali/common/mali_hw_core.c new file mode 100644 index 0000000..0b08622 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_hw_core.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011-2012 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_hw_core.h" +#include "mali_osk.h" +#include "mali_kernel_common.h" + +_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size) +{ + core->phys_addr = resource->base; + core->description = resource->description; + core->size = reg_size; + if (_MALI_OSK_ERR_OK == _mali_osk_mem_reqregion(core->phys_addr, core->size, core->description)) + { + core->mapped_registers = _mali_osk_mem_mapioregion(core->phys_addr, core->size, core->description); + if (NULL != core->mapped_registers) + { + return _MALI_OSK_ERR_OK; + } + else + { + MALI_PRINT_ERROR(("Failed to map memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); + } + _mali_osk_mem_unreqregion(core->phys_addr, core->size); + } + else + { + MALI_PRINT_ERROR(("Failed to request memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_hw_core_delete(struct mali_hw_core *core) +{ + _mali_osk_mem_unmapioregion(core->phys_addr, core->size, core->mapped_registers); + core->mapped_registers = NULL; + _mali_osk_mem_unreqregion(core->phys_addr, core->size); +} diff --git a/drivers/media/video/samsung/mali/common/mali_hw_core.h b/drivers/media/video/samsung/mali/common/mali_hw_core.h new file mode 100644 index 0000000..c797804 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_hw_core.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_HW_CORE_H__ +#define __MALI_HW_CORE_H__ + +#include "mali_osk.h" +#include "mali_kernel_common.h" + +/** + * The common parts for all Mali HW cores (GP, PP, MMU, L2 and PMU) + * This struct is embedded inside all core specific structs. + */ +struct mali_hw_core +{ + u32 phys_addr; /**< Physical address of the registers */ + u32 size; /**< Size of registers */ + mali_io_address mapped_registers; /**< Virtual mapping of the registers */ + const char* description; /**< Name of unit (as specified in device configuration) */ +}; + +#define MALI_HW_CORE_NO_COUNTER ((u32)-1) +#define MALI_HW_CORE_INVALID_VALUE ((u32)-1) + +_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size); +void mali_hw_core_delete(struct mali_hw_core *core); + +MALI_STATIC_INLINE u32 mali_hw_core_register_read(struct mali_hw_core *core, u32 relative_address) +{ + u32 read_val; + read_val = _mali_osk_mem_ioread32(core->mapped_registers, relative_address); + MALI_DEBUG_PRINT(6, ("register_read for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, read_val)); + return read_val; +} + +MALI_STATIC_INLINE void mali_hw_core_register_write_relaxed(struct mali_hw_core *core, u32 relative_address, u32 new_val) +{ + MALI_DEBUG_PRINT(6, ("register_write_relaxed for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, new_val)); + _mali_osk_mem_iowrite32_relaxed(core->mapped_registers, relative_address, new_val); +} + +MALI_STATIC_INLINE void mali_hw_core_register_write(struct mali_hw_core *core, u32 relative_address, u32 new_val) +{ + MALI_DEBUG_PRINT(6, ("register_write for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, new_val)); + _mali_osk_mem_iowrite32(core->mapped_registers, relative_address, new_val); +} + +MALI_STATIC_INLINE void mali_hw_core_register_write_array_relaxed(struct mali_hw_core *core, u32 relative_address, u32 *write_array, u32 nr_of_regs) +{ + u32 i; + MALI_DEBUG_PRINT(6, ("register_write_array: for core %s, relative addr=0x%04X, nr of regs=%u\n", + core->description,relative_address, nr_of_regs)); + + /* Do not use burst writes against the registers */ + for (i = 0; i< nr_of_regs; i++) + { + mali_hw_core_register_write_relaxed(core, relative_address + i*4, write_array[i]); + } +} + +#endif /* __MALI_HW_CORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c b/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c deleted file mode 100644 index cfd70f4..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c +++ /dev/null @@ -1,1493 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ -//added for SPI -#include <linux/kernel.h> - -#include "mali_kernel_common.h" -#include "mali_kernel_core.h" -#include "mali_kernel_subsystem.h" -#include "regs/mali_gp_regs.h" -#include "mali_kernel_rendercore.h" -#include "mali_osk.h" -#include "mali_osk_list.h" -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#if defined(USING_MALI400_L2_CACHE) -#include "mali_kernel_l2_cache.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" /* Needed for mali_kernel_mmu_force_bus_reset() */ -#endif - -#if defined(USING_MALI200) -#define MALI_GP_SUBSYSTEM_NAME "MaliGP2" -#define MALI_GP_CORE_TYPE _MALI_GP2 -#elif defined(USING_MALI400) -#define MALI_GP_SUBSYSTEM_NAME "Mali-400 GP" -#define MALI_GP_CORE_TYPE _MALI_400_GP -#else -#error "No supported mali core defined" -#endif - -#define GET_JOB_EMBEDDED_PTR(job) (&((job)->embedded_core_job)) -#define GET_JOBGP2_PTR(job_extern) _MALI_OSK_CONTAINER_OF(job_extern, maligp_job, embedded_core_job) - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_gp_id = -1; - -static mali_core_renderunit * last_gp_core_cookie = NULL; - -/* Describing a maligp job settings */ -typedef struct maligp_job -{ - /* The general job struct common for all mali cores */ - mali_core_job embedded_core_job; - _mali_uk_gp_start_job_s user_input; - - u32 irq_status; - u32 status_reg_on_stop; - u32 perf_counter0; - u32 perf_counter1; - u32 vscl_stop_addr; - u32 plbcl_stop_addr; - u32 heap_current_addr; - - /* The data we will return back to the user */ - _mali_osk_notification_t *notification_obj; - - int is_stalled_waiting_for_more_memory; - - u32 active_mask; - /* progress checking */ - u32 last_vscl; - u32 last_plbcl; - /* extended progress checking, only enabled when we can use one of the performance counters */ - u32 have_extended_progress_checking; - u32 vertices; - -#if defined(USING_MALI400_L2_CACHE) - u32 perf_counter_l2_src0; - u32 perf_counter_l2_src1; - u32 perf_counter_l2_val0; - u32 perf_counter_l2_val1; -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - u32 pid; - u32 tid; -#endif -} maligp_job; - -/*Functions Exposed to the General External System through - function pointers.*/ - -static _mali_osk_errcode_t maligp_subsystem_startup(mali_kernel_subsystem_identifier id); -#if USING_MMU -static _mali_osk_errcode_t maligp_subsystem_mmu_connect(mali_kernel_subsystem_identifier id); -#endif -static void maligp_subsystem_terminate(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t maligp_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); -static void maligp_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); -static _mali_osk_errcode_t maligp_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t maligp_renderunit_create(_mali_osk_resource_t * resource); -#if USING_MMU -static void maligp_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif -#if MALI_STATE_TRACKING -u32 maligp_subsystem_dump_state(char *buf, u32 size); -#endif - -/* Internal support functions */ -static _mali_osk_errcode_t maligp_core_version_legal( mali_core_renderunit *core ); -static void maligp_raw_reset( mali_core_renderunit *core); -static void maligp_reset_hard(struct mali_core_renderunit * core); -static void maligp_reset(mali_core_renderunit *core); -static void maligp_initialize_registers_mgmt(mali_core_renderunit *core ); - -#ifdef DEBUG -static void maligp_print_regs(int debug_level, mali_core_renderunit *core); -#endif - -/* Functions exposed to mali_core system through functionpointers - in the subsystem struct. */ -static _mali_osk_errcode_t subsystem_maligp_start_job(mali_core_job * job, mali_core_renderunit * core); -static u32 subsystem_maligp_irq_handler_upper_half(mali_core_renderunit * core); -static int subsystem_maligp_irq_handler_bottom_half(mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_maligp_get_new_job_from_user(struct mali_core_session * session, void * argument); -static _mali_osk_errcode_t subsystem_maligp_suspend_response(struct mali_core_session * session, void * argument); -static void subsystem_maligp_return_job_to_user(mali_core_job * job, mali_subsystem_job_end_code end_status); -static void subsystem_maligp_renderunit_delete(mali_core_renderunit * core); -static void subsystem_maligp_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style ); -static void subsystem_maligp_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_maligp_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core); -static void subsystem_maligp_renderunit_stop_bus(struct mali_core_renderunit* core); - -/* Variables */ -static register_address_and_value default_mgmt_regs[] = -{ - { MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED } -}; - - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ - -struct mali_kernel_subsystem mali_subsystem_gp2= -{ - maligp_subsystem_startup, /* startup */ - NULL, /*maligp_subsystem_terminate,*/ /* shutdown */ -#if USING_MMU - maligp_subsystem_mmu_connect, /* load_complete */ -#else - NULL, -#endif - maligp_subsystem_core_system_info_fill, /* system_info_fill */ - maligp_subsystem_session_begin, /* session_begin */ - maligp_subsystem_session_end, /* session_end */ -#if USING_MMU - maligp_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - maligp_subsystem_dump_state, /* dump_state */ -#endif -} ; - -static mali_core_subsystem subsystem_maligp ; - -static _mali_osk_errcode_t maligp_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem * subsystem; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_startup\n") ) ; - - mali_subsystem_gp_id = id; - - /* All values get 0 as default */ - _mali_osk_memset(&subsystem_maligp, 0, sizeof(*subsystem)); - - subsystem = &subsystem_maligp; - subsystem->start_job = &subsystem_maligp_start_job; - subsystem->irq_handler_upper_half = &subsystem_maligp_irq_handler_upper_half; - subsystem->irq_handler_bottom_half = &subsystem_maligp_irq_handler_bottom_half; - subsystem->get_new_job_from_user = &subsystem_maligp_get_new_job_from_user; - subsystem->suspend_response = &subsystem_maligp_suspend_response; - subsystem->return_job_to_user = &subsystem_maligp_return_job_to_user; - subsystem->renderunit_delete = &subsystem_maligp_renderunit_delete; - subsystem->reset_core = &subsystem_maligp_renderunit_reset_core; - subsystem->stop_bus = &subsystem_maligp_renderunit_stop_bus; - subsystem->probe_core_irq_trigger = &subsystem_maligp_renderunit_probe_core_irq_trigger; - subsystem->probe_core_irq_acknowledge = &subsystem_maligp_renderunit_probe_core_irq_finished; - - /* Setting variables in the general core part of the subsystem.*/ - subsystem->name = MALI_GP_SUBSYSTEM_NAME; - subsystem->core_type = MALI_GP_CORE_TYPE; - subsystem->id = id; - - /* Initiates the rest of the general core part of the subsystem */ - MALI_CHECK_NO_ERROR(mali_core_subsystem_init( subsystem )); - - /* This will register the function for adding MALIGP2 cores to the subsystem */ -#if defined(USING_MALI200) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALIGP2, maligp_renderunit_create)); -#endif -#if defined(USING_MALI400) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI400GP, maligp_renderunit_create)); -#endif - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_startup\n") ) ; - - MALI_SUCCESS; -} - -#if USING_MMU -static _mali_osk_errcode_t maligp_subsystem_mmu_connect(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem_attach_mmu(&subsystem_maligp); - MALI_SUCCESS; /* OK */ -} -#endif - -static void maligp_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_terminate\n") ) ; - mali_core_subsystem_cleanup(&subsystem_maligp); -} - -static _mali_osk_errcode_t maligp_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_session_begin\n") ) ; - MALI_CHECK_NON_NULL(session = _mali_osk_malloc( sizeof(*session) ), _MALI_OSK_ERR_FAULT); - - _mali_osk_memset(session, 0, sizeof(*session) ); - *slot = (mali_kernel_subsystem_session_slot)session; - - session->subsystem = &subsystem_maligp; - - session->notification_queue = queue; - -#if USING_MMU - session->mmu_session = mali_session_data; -#endif - - mali_core_session_begin(session); - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_session_begin\n") ) ; - - MALI_SUCCESS; -} - -static void maligp_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - mali_core_session * session; - /** @note mali_session_data not needed here */ - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_session_end\n") ) ; - if ( NULL==slot || NULL==*slot) - { - MALI_PRINT_ERROR(("Input slot==NULL")); - return; - } - session = (mali_core_session *)*slot; - mali_core_session_close(session); - - _mali_osk_free(session); - *slot = NULL; - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_session_end\n") ) ; -} - -/** - * We fill in info about all the cores we have - * @param info Pointer to system info struct to update - * @return _MALI_OSK_ERR_OK on success, or another _mali_osk_errcode_t for errors. - */ -static _mali_osk_errcode_t maligp_subsystem_core_system_info_fill(_mali_system_info* info) -{ - return mali_core_subsystem_system_info_fill(&subsystem_maligp, info); -} - -static _mali_osk_errcode_t maligp_renderunit_create(_mali_osk_resource_t * resource) -{ - mali_core_renderunit *core; - int err; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_renderunit_create\n") ) ; - /* Checking that the resource settings are correct */ -#if defined(USING_MALI200) - if(MALIGP2 != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_GP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#elif defined(USING_MALI400) - if(MALI400GP != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_GP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - if ( 0 != resource->size ) - { - MALI_PRINT_ERROR(("Memory size set to " MALI_GP_SUBSYSTEM_NAME " core should be zero.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if ( NULL == resource->description ) - { - MALI_PRINT_ERROR(("A " MALI_GP_SUBSYSTEM_NAME " core needs a unique description field")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Create a new core object */ - core = (mali_core_renderunit*) _mali_osk_malloc(sizeof(*core)); - if ( NULL == core ) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Variables set to be able to open and register the core */ - core->subsystem = &subsystem_maligp ; - core->registers_base_addr = resource->base ; - core->size = MALIGP2_REGISTER_ADDRESS_SPACE_SIZE ; - core->description = resource->description; - core->irq_nr = resource->irq ; -#if USING_MMU - core->mmu_id = resource->mmu_id; - core->mmu = NULL; -#endif -#if USING_MALI_PMM - /* Set up core's PMM id */ - core->pmm_id = MALI_PMM_CORE_GP; -#endif - - err = mali_core_renderunit_init( core ); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to initialize renderunit\n")); - goto exit_on_error0; - } - - /* Map the new core object, setting: core->registers_mapped */ - err = mali_core_renderunit_map_registers(core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error1; - - /* Check that the register mapping of the core works. - Return 0 if maligp core is present and accessible. */ - if (mali_benchmark) { - core->core_version = MALI_GP_PRODUCT_ID << 16; - } else { - core->core_version = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VERSION); - } - - err = maligp_core_version_legal(core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error2; - - /* Reset the core. Put the core into a state where it can start to render. */ - maligp_reset(core); - - /* Registering IRQ, init the work_queue_irq_handle */ - /* Adding this core as an available renderunit in the subsystem. */ - err = mali_core_subsystem_register_renderunit(&subsystem_maligp, core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error2; - -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Initial Register settings:\n")); - maligp_print_regs(4, core); -#endif - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_renderunit_create\n") ) ; - - MALI_SUCCESS; - -exit_on_error2: - mali_core_renderunit_unmap_registers(core); -exit_on_error1: - mali_core_renderunit_term(core); -exit_on_error0: - _mali_osk_free( core ) ; - MALI_PRINT_ERROR(("Renderunit NOT created.")); - MALI_ERROR((_mali_osk_errcode_t)err); -} - -#if USING_MMU -/* Used currently only for signalling when MMU has a pagefault */ -static void maligp_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - mali_core_subsystem_broadcast_notification(&subsystem_maligp, message, data); -} -#endif - -#ifdef DEBUG -static void maligp_print_regs(int debug_level, mali_core_renderunit *core) -{ - if (debug_level <= mali_debug_level) - { - MALI_DEBUG_PRINT(1, (" VS 0x%08X 0x%08X, PLBU 0x%08X 0x%08X ALLOC 0x%08X 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_END_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_END_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - MALI_DEBUG_PRINT(1, (" IntRaw 0x%08X IntMask 0x%08X, Status 0x%02X Ver: 0x%08X \n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_MASK), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VERSION))); - - MALI_DEBUG_PRINT(1, (" PERF_CNT Enbl:%d %d Src: %02d %02d VAL: 0x%08X 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE))); - - MALI_DEBUG_PRINT(1, (" VS_START 0x%08X PLBU_START 0x%08X AXI_ERR 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR_READ), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBCL_START_ADDR_READ), - mali_core_renderunit_register_read(core, MALIGP2_CONTR_AXI_BUS_ERROR_STAT))); - } -} -#endif - -static _mali_osk_errcode_t maligp_core_version_legal( mali_core_renderunit *core ) -{ - u32 mali_type; - - mali_type = core->core_version >> 16; - -#if defined(USING_MALI400) - if ( MALI400_GP_PRODUCT_ID != mali_type && MALI300_GP_PRODUCT_ID != mali_type ) -#else - if ( MALI_GP_PRODUCT_ID != mali_type ) -#endif - { - MALI_PRINT_ERROR(("Error: reading this from maligp version register: 0x%x\n", core->core_version)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - MALI_DEBUG_PRINT(3, ("Mali GP: core_version_legal: Reads correct mali version: %d\n", core->core_version )) ; - MALI_SUCCESS; -} - -static void subsystem_maligp_renderunit_stop_bus(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); -} - -static void maligp_reset( mali_core_renderunit *core ) -{ - if (!mali_benchmark) { - maligp_raw_reset(core); - maligp_initialize_registers_mgmt(core); - } -} - - -static void maligp_reset_hard( mali_core_renderunit *core ) -{ - const int reset_finished_loop_count = 15; - const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW; - const u32 reset_invalid_value = 0xC0FFE000; - const u32 reset_check_value = 0xC01A0000; - const u32 reset_default_value = 0; - int i; - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_invalid_value); - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET); - - for (i = 0; i < reset_finished_loop_count; i++) - { - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_check_value); - if (reset_check_value == mali_core_renderunit_register_read(core, reset_wait_target_register)) - { - MALI_DEBUG_PRINT(5, ("Reset loop exiting after %d iterations\n", i)); - break; - } - } - - if (i == reset_finished_loop_count) - { - MALI_DEBUG_PRINT(1, ("The reset loop didn't work\n")); - } - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_default_value); /* set it back to the default */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - - -} - -static void maligp_raw_reset( mali_core_renderunit *core ) -{ - int i; - const int request_loop_count = 20; - - MALI_DEBUG_PRINT(4, ("Mali GP: maligp_raw_reset: %s\n", core->description)) ; - if (mali_benchmark) return; - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ - -#if defined(USING_MALI200) - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) break; - _mali_osk_time_ubusydelay(10); - } - - MALI_DEBUG_PRINT_IF(1, request_loop_count == i, ("Mali GP: Bus was never stopped during core reset\n")); - - if (request_loop_count==i) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - MALI_DEBUG_PRINT(1, ("Mali GP: Forcing MMU bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow GP to stop its bus, system failure, unable to recover\n")); - return; - } - - /* the bus was stopped OK, complete the reset */ - /* use the hard reset routine to do the actual reset */ - maligp_reset_hard(core); - -#elif defined(USING_MALI400) - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & /*Bitwise OR*/ - MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) break; - _mali_osk_time_ubusydelay(10); - } - - if ( request_loop_count==i ) - { -#if USING_MMU - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - MALI_DEBUG_PRINT(1, ("Mali GP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow GP to stop its bus, system failure, unable to recover\n")); - } - else - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - } - -#else -#error "no supported mali core defined" -#endif -} - -/* Sets the registers on maligp according to the const default_mgmt_regs array. */ -static void maligp_initialize_registers_mgmt(mali_core_renderunit *core ) -{ - int i; - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_initialize_registers_mgmt: %s\n", core->description)) ; - for(i=0 ; i< (sizeof(default_mgmt_regs)/sizeof(*default_mgmt_regs)) ; ++i) - { - mali_core_renderunit_register_write_relaxed(core, default_mgmt_regs[i].address, default_mgmt_regs[i].value); - } - _mali_osk_write_mem_barrier(); -} - - -/* Start this job on this core. Return MALI_TRUE if the job was started. */ -static _mali_osk_errcode_t subsystem_maligp_start_job(mali_core_job * job, mali_core_renderunit * core) -{ - maligp_job *jobgp; - u32 startcmd; - /* The local extended version of the general structs */ - jobgp = _MALI_OSK_CONTAINER_OF(job, maligp_job, embedded_core_job); - - startcmd = 0; - if ( jobgp->user_input.frame_registers[0] != jobgp->user_input.frame_registers[1] ) - { - startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS; - } - - if ( jobgp->user_input.frame_registers[2] != jobgp->user_input.frame_registers[3] ) - { - startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU; - } - - if(0 == startcmd) - { - MALI_DEBUG_PRINT(4, ("Mali GP: Job: 0x%08x WILL NOT START SINCE JOB HAS ILLEGAL ADDRESSES\n", - (u32)jobgp->user_input.user_job_ptr)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Registers Start\n")); - maligp_print_regs(4, core); -#endif - - - mali_core_renderunit_register_write_array( - core, - MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, - &(jobgp->user_input.frame_registers[0]), - sizeof(jobgp->user_input.frame_registers)/sizeof(jobgp->user_input.frame_registers[0])); - -#if MALI_TRACEPOINTS_ENABLED - jobgp->user_input.perf_counter_flag = 0; - - if( counter_table[7] != 0xFFFFFFFF ) { - jobgp->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE; - jobgp->user_input.perf_counter_src0 = counter_table[7]; - } - if( counter_table[8] != 0xFFFFFFFF ) { - jobgp->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE; - jobgp->user_input.perf_counter_src1 = counter_table[8]; - } -#endif - - /* This selects which performance counters we are reading */ - if ( 0 != jobgp->user_input.perf_counter_flag ) - { - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, - jobgp->user_input.perf_counter_src0); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, - jobgp->user_input.perf_counter_src1); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - -#if defined(USING_MALI400_L2_CACHE) - if ( jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - int force_reset = ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET ) ? 1 : 0; - u32 src0 = 0; - u32 src1 = 0; - - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE ) - { - src0 = jobgp->user_input.perf_counter_l2_src0; - } - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE ) - { - src1 = jobgp->user_input.perf_counter_l2_src1; - } - - mali_kernel_l2_cache_set_perf_counters(src0, src1, force_reset); /* will activate and possibly reset counters */ - - /* Now, retrieve the current values, so we can substract them when the job has completed */ - mali_kernel_l2_cache_get_perf_counters(&jobgp->perf_counter_l2_src0, - &jobgp->perf_counter_l2_val0, - &jobgp->perf_counter_l2_src1, - &jobgp->perf_counter_l2_val1); - } -#endif - } - - if ( 0 == (jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)) - { - /* extended progress checking can be enabled */ - - jobgp->have_extended_progress_checking = 1; - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, - MALIGP2_REG_VAL_PERF_CNT1_SRC_NUMBER_OF_VERTICES_PROCESSED - ); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - - subsystem_flush_mapped_mem_cache(); - - MALI_DEBUG_PRINT(4, ("Mali GP: STARTING GP WITH CMD: 0x%x\n", startcmd)); -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_started); -#endif - - /* This is the command that starts the Core */ - mali_core_renderunit_register_write(core, - MALIGP2_REG_ADDR_MGMT_CMD, - startcmd); - _mali_osk_write_mem_barrier(); - - pr_debug("SPI_GPU_GP Start\n"); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, - jobgp->user_input.frame_builder_id, jobgp->user_input.flush_id, 0, 0, 0); - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), jobgp->pid, jobgp->tid, 0, 0, 0); -#endif - - MALI_SUCCESS; -} - -/* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */ - -static u32 subsystem_maligp_irq_handler_upper_half(mali_core_renderunit * core) -{ - u32 irq_readout; - - if (mali_benchmark) { - return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */ - } - - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_STAT); - - MALI_DEBUG_PRINT(5, ("Mali GP: IRQ: %04x\n", irq_readout)) ; - - if ( MALIGP2_REG_VAL_IRQ_MASK_NONE != irq_readout ) - { - /* Mask out all IRQs from this core until IRQ is handled */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_NONE); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); -#endif - - /* We do need to handle this in a bottom half, return 1 */ - return 1; - } - return 0; -} - -/* This function should check if the interrupt indicates that job was finished. -If so it should update the job-struct, reset the core registers, and return MALI_TRUE, . -If the job is still working after this function it should return MALI_FALSE. -The function must also enable the bits in the interrupt mask for the core. -Called by the bottom half interrupt function. */ -static int subsystem_maligp_irq_handler_bottom_half(mali_core_renderunit* core) -{ - mali_core_job * job; - maligp_job * jobgp; - u32 irq_readout; - u32 core_status; - u32 vscl; - u32 plbcl; - - job = core->current_job; - - if (mali_benchmark) { - MALI_DEBUG_PRINT(3, ("MaliGP: Job: Benchmark\n") ); - irq_readout = MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST; - core_status = 0; - } else { - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALIGP2_REG_VAL_IRQ_MASK_USED; - core_status = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS); - } - - if (NULL == job) - { - MALI_DEBUG_ASSERT(CORE_IDLE==core->state); - if ( 0 != irq_readout ) - { - MALI_PRINT_ERROR(("Interrupt from a core not running a job. IRQ: 0x%04x Status: 0x%04x", irq_readout, core_status)); - } - return JOB_STATUS_END_UNKNOWN_ERR; - } - MALI_DEBUG_ASSERT(CORE_IDLE!=core->state); - - jobgp = GET_JOBGP2_PTR(job); - - jobgp->heap_current_addr = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR); - - vscl = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR); - plbcl = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR); - - MALI_DEBUG_PRINT(3, ("Mali GP: Job: 0x%08x IRQ RECEIVED Rawstat: 0x%x Status: 0x%x\n", - (u32)jobgp->user_input.user_job_ptr, irq_readout , core_status )) ; - - jobgp->irq_status |= irq_readout; - jobgp->status_reg_on_stop = core_status; - - if ( 0 != jobgp->is_stalled_waiting_for_more_memory ) - { - /* Readback the performance counters */ - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { - jobgp->perf_counter0 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - jobgp->perf_counter1 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(7, jobgp->perf_counter0); - _mali_profiling_add_counter(8, jobgp->perf_counter1); -#endif - } - -#if defined(USING_MALI400_L2_CACHE) - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (jobgp->perf_counter_l2_src0 == src0) - { - jobgp->perf_counter_l2_val0 = val0 - jobgp->perf_counter_l2_val0; - } - else - { - jobgp->perf_counter_l2_val0 = 0; - } - - if (jobgp->perf_counter_l2_src1 == src1) - { - jobgp->perf_counter_l2_val1 = val1 - jobgp->perf_counter_l2_val1; - } - else - { - jobgp->perf_counter_l2_val1 = 0; - } - } -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_DEBUG_PRINT(2, ("Mali GP: Job aborted - userspace would not provide more heap memory.\n")); -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_OOM; /* Core is ready for more jobs.*/ - } - /* finished ? */ - else if (0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE)) - { -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Registers On job end:\n")); - maligp_print_regs(4, core); -#endif - MALI_DEBUG_PRINT_IF(5, irq_readout & 0x04, ("OOM when done, ignoring (reg.current = 0x%x, reg.end = 0x%x)\n", - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - - - if (0 != jobgp->user_input.perf_counter_flag ) - { - /* Readback the performance counters */ - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { - jobgp->perf_counter0 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - jobgp->perf_counter1 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(7, jobgp->perf_counter0); - _mali_profiling_add_counter(8, jobgp->perf_counter1); -#endif - } - -#if defined(USING_MALI400_L2_CACHE) - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (jobgp->perf_counter_l2_src0 == src0) - { - jobgp->perf_counter_l2_val0 = val0 - jobgp->perf_counter_l2_val0; - } - else - { - jobgp->perf_counter_l2_val0 = 0; - } - - if (jobgp->perf_counter_l2_src1 == src1) - { - jobgp->perf_counter_l2_val1 = val1 - jobgp->perf_counter_l2_val1; - } - else - { - jobgp->perf_counter_l2_val1 = 0; - } - } -#endif - } - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), - jobgp->perf_counter0, jobgp->perf_counter1, - jobgp->user_input.perf_counter_src0 | (jobgp->user_input.perf_counter_src1 << 8) -#if defined(USING_MALI400_L2_CACHE) - | (jobgp->user_input.perf_counter_l2_src0 << 16) | (jobgp->user_input.perf_counter_l2_src1 << 24), - jobgp->perf_counter_l2_val0, - jobgp->perf_counter_l2_val1 -#else - ,0, 0 -#endif - ); -#endif - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - pr_debug("SPI_GPU_GP Idle\n"); - return JOB_STATUS_END_SUCCESS; /* core idle */ - } - /* sw watchdog timeout handling or time to do hang checking ? */ - else if ( - (CORE_WATCHDOG_TIMEOUT == core->state) || - ( - (CORE_HANG_CHECK_TIMEOUT == core->state) && - ( - (jobgp->have_extended_progress_checking ? (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE) == jobgp->vertices) : 1/*TRUE*/) && - ((core_status & MALIGP2_REG_VAL_STATUS_VS_ACTIVE) ? (vscl == jobgp->last_vscl) : 1/*TRUE*/) && - ((core_status & MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE) ? (plbcl == jobgp->last_plbcl) : 1/*TRUE*/) - ) - ) - ) - { - /* no progress detected, killed by the watchdog */ - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_PRINT( ("Mali GP: SW-Timeout.\n")); - if (core_status & MALIGP2_REG_VAL_STATUS_VS_ACTIVE) MALI_DEBUG_PRINT(1, ("vscl current = 0x%x last = 0x%x\n", (void*)vscl, (void*)jobgp->last_vscl)); - if (core_status & MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE) MALI_DEBUG_PRINT(1, ("plbcl current = 0x%x last = 0x%x\n", (void*)plbcl, (void*)jobgp->last_plbcl)); - if (jobgp->have_extended_progress_checking) MALI_DEBUG_PRINT(1, ("vertices processed = %d, last = %d\n", mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE), - jobgp->vertices)); -#ifdef DEBUG - maligp_print_regs(2, core); -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - MALI_PANIC("%s Watchdog timeout\n", MALI_GP_SUBSYSTEM_NAME); - return JOB_STATUS_END_HANG; - } - /* if hang timeout checking was enabled and we detected progress, will be fall down to this check */ - /* check for PLBU OOM before the hang check to avoid the race condition of the hw wd trigging while waiting for us to handle the OOM interrupt */ - else if ( 0 != (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM)) - { - mali_core_session *session; - _mali_osk_notification_t *notific; - _mali_uk_gp_job_suspended_s * suspended_job; - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - session = job->session; - - MALI_DEBUG_PRINT(4, ("OOM, new heap requested by GP\n")); - MALI_DEBUG_PRINT(4, ("Status when OOM: current = 0x%x, end = 0x%x\n", - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - - notific = _mali_osk_notification_create( - - _MALI_NOTIFICATION_GP_STALLED, - sizeof( _mali_uk_gp_job_suspended_s ) - ); - if ( NULL == notific) - { - MALI_PRINT_ERROR( ("Mali GP: Could not get notification object\n")) ; - return JOB_STATUS_END_OOM; /* Core is ready for more jobs.*/ - } - - core->state = CORE_WORKING; - jobgp->is_stalled_waiting_for_more_memory = 1; - suspended_job = (_mali_uk_gp_job_suspended_s *)notific->result_buffer; /* this is ok - result_buffer was malloc'd */ - - suspended_job->user_job_ptr = jobgp->user_input.user_job_ptr; - suspended_job->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY ; - suspended_job->cookie = (u32) core; - last_gp_core_cookie = core; - - _mali_osk_notification_queue_send( session->notification_queue, notific); - -#ifdef DEBUG - maligp_print_regs(4, core); -#endif - - /* stop all active timers */ - _mali_osk_timer_del( core->timer); - _mali_osk_timer_del( core->timer_hang_detection); - MALI_DEBUG_PRINT(4, ("Mali GP: PLBU heap empty, sending memory request to userspace\n")); - /* save to watchdog_jiffies what was remaining WD timeout value when OOM was triggered */ - job->watchdog_jiffies = (long)job->watchdog_jiffies - (long)_mali_osk_time_tickcount(); - /* reuse core->timer as the userspace response timeout handler */ - _mali_osk_timer_add( core->timer, _mali_osk_time_mstoticks(1000) ); /* wait max 1 sec for userspace to respond */ - return JOB_STATUS_CONTINUE_RUN; /* The core is NOT available for new jobs. */ - } - /* hw watchdog is reporting a new hang or an existing progress-during-hang check passed? */ - else if ((CORE_HANG_CHECK_TIMEOUT == core->state) || (irq_readout & jobgp->active_mask & MALIGP2_REG_VAL_IRQ_HANG)) - { - /* check interval in ms */ - u32 timeout = mali_core_hang_check_timeout_get(); - MALI_DEBUG_PRINT(3, ("Mali GP: HW/SW Watchdog triggered, checking for progress in %d ms\n", timeout)); - core->state = CORE_WORKING; - - /* save state for the progress checking */ - jobgp->last_vscl = vscl; - jobgp->last_plbcl = plbcl; - if (jobgp->have_extended_progress_checking) - { - jobgp->vertices = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - } - /* hw watchdog triggered, set up a progress checker every HANGCHECK ms */ - _mali_osk_timer_add( core->timer_hang_detection, _mali_osk_time_mstoticks(timeout)); - jobgp->active_mask &= ~MALIGP2_REG_VAL_IRQ_HANG; /* ignore the hw watchdog from now on */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* not finihsed */ } - /* no errors, but still working */ - else if ( ( 0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ERROR)) && - ( 0 != (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE )) - ) - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - return JOB_STATUS_CONTINUE_RUN; - } - /* Else there must be some error */ - else - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_PRINT( ("Mali GP: Core crashed? *IRQ: 0x%x Status: 0x%x\n", irq_readout, core_status )); - #ifdef DEBUG - MALI_DEBUG_PRINT(1, ("Mali GP: Registers Before reset:\n")); - maligp_print_regs(1, core); - #endif -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_UNKNOWN_ERR; - } -} - - -/* This function is called from the ioctl function and should return a mali_core_job pointer -to a created mali_core_job object with the data given from userspace */ -static _mali_osk_errcode_t subsystem_maligp_get_new_job_from_user(struct mali_core_session * session, void * argument) -{ - maligp_job *jobgp; - mali_core_job *job = NULL; - mali_core_job *previous_replaced_job; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_uk_gp_start_job_s * user_ptr_job_input; - - user_ptr_job_input = (_mali_uk_gp_start_job_s *)argument; - - MALI_CHECK_NON_NULL(jobgp = (maligp_job *) _mali_osk_calloc(1, sizeof(maligp_job)), _MALI_OSK_ERR_FAULT); - - /* Copy the job data from the U/K interface */ - if ( NULL == _mali_osk_memcpy(&jobgp->user_input, user_ptr_job_input, sizeof(_mali_uk_gp_start_job_s) ) ) - { - MALI_PRINT_ERROR( ("Mali GP: Could not copy data from U/K interface.\n")) ; - err = _MALI_OSK_ERR_FAULT; - goto function_exit; - } - - MALI_DEBUG_PRINT(3, ("Mali GP: subsystem_maligp_get_new_job_from_user 0x%x\n", (void*)jobgp->user_input.user_job_ptr)); - - MALI_DEBUG_PRINT(3, ("Mali GP: Job Regs: 0x%08X 0x%08X, 0x%08X 0x%08X 0x%08X 0x%08X\n", - jobgp->user_input.frame_registers[0], - jobgp->user_input.frame_registers[1], - jobgp->user_input.frame_registers[2], - jobgp->user_input.frame_registers[3], - jobgp->user_input.frame_registers[4], - jobgp->user_input.frame_registers[5]) ); - - - job = GET_JOB_EMBEDDED_PTR(jobgp); - - job->session = session; - job->flags = MALI_UK_START_JOB_FLAG_DEFAULT; /* Current flags only make sence for PP jobs */ - job_priority_set(job, jobgp->user_input.priority); - job_watchdog_set(job, jobgp->user_input.watchdog_msecs ); - jobgp->heap_current_addr = jobgp->user_input.frame_registers[4]; - - job->abort_id = jobgp->user_input.abort_id; - - jobgp->is_stalled_waiting_for_more_memory = 0; - -#if MALI_TIMELINE_PROFILING_ENABLED - jobgp->pid = _mali_osk_get_pid(); - jobgp->tid = _mali_osk_get_tid(); -#endif - - if (mali_job_queue_full(session)) - { - /* Cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - goto function_exit; - } - - /* We now know that we have a job, and a slot to put it in */ - - jobgp->active_mask = MALIGP2_REG_VAL_IRQ_MASK_USED; - - /* Allocating User Return Data */ - jobgp->notification_obj = _mali_osk_notification_create( - _MALI_NOTIFICATION_GP_FINISHED, - sizeof(_mali_uk_gp_job_finished_s) ); - - if ( NULL == jobgp->notification_obj ) - { - MALI_PRINT_ERROR( ("Mali GP: Could not get notification_obj.\n")) ; - err = _MALI_OSK_ERR_NOMEM; - goto function_exit; - } - - _MALI_OSK_INIT_LIST_HEAD( &(job->list) ) ; - - MALI_DEBUG_PRINT(4, ("Mali GP: Job: 0x%08x INPUT from user.\n", (u32)jobgp->user_input.user_job_ptr)) ; - - /* This should not happen since we have the checking of priority above */ - err = mali_core_session_add_job(session, job, &previous_replaced_job); - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_PRINT_ERROR( ("Mali GP: Internal error\n")) ; - /* Cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - _mali_osk_notification_delete( jobgp->notification_obj ); - goto function_exit; - } - - /* If MALI_TRUE: This session had a job with lower priority which were removed. - This replaced job is given back to userspace. */ - if ( NULL != previous_replaced_job ) - { - maligp_job *previous_replaced_jobgp; - - previous_replaced_jobgp = GET_JOBGP2_PTR(previous_replaced_job); - - MALI_DEBUG_PRINT(4, ("Mali GP: Replacing job: 0x%08x\n", (u32)previous_replaced_jobgp->user_input.user_job_ptr)) ; - - /* Copy to the input data (which also is output data) the - pointer to the job that were replaced, so that the userspace - driver can put this job in the front of its job-queue */ - user_ptr_job_input->returned_user_job_ptr = previous_replaced_jobgp->user_input.user_job_ptr; - - /** @note failure to 'copy to user' at this point must not free jobgp, - * and so no transaction rollback required in the U/K interface */ - - /* This does not cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED; - MALI_DEBUG_PRINT(5, ("subsystem_maligp_get_new_job_from_user: Job added, prev returned\n")) ; - } - else - { - /* This does not cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED; - MALI_DEBUG_PRINT(5, ("subsystem_maligp_get_new_job_from_user: Job added\n")) ; - } - -function_exit: - if ( _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE == user_ptr_job_input->status - || _MALI_OSK_ERR_OK != err ) - { - _mali_osk_free(jobgp); - } -#if MALI_STATE_TRACKING - if (_MALI_UK_START_JOB_STARTED==user_ptr_job_input->status) - { - if(job) - { - job->job_nr=_mali_osk_atomic_inc_return(&session->jobs_received); - } - } -#endif - - MALI_ERROR(err); -} - - -static _mali_osk_errcode_t subsystem_maligp_suspend_response(struct mali_core_session * session, void * argument) -{ - mali_core_renderunit *core; - maligp_job *jobgp; - mali_core_job *job; - - _mali_uk_gp_suspend_response_s * suspend_response; - - MALI_DEBUG_PRINT(5, ("subsystem_maligp_suspend_response\n")); - - suspend_response = (_mali_uk_gp_suspend_response_s *)argument; - - /* We read job data from User */ - /* On a single mali_gp system we can only have one Stalled GP, - and therefore one stalled request with a cookie. This checks - that we get the correct cookie */ - if ( last_gp_core_cookie != (mali_core_renderunit *)suspend_response->cookie ) - { - MALI_DEBUG_PRINT(2, ("Mali GP: Got an illegal cookie from Userspace.\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - core = (mali_core_renderunit *)suspend_response->cookie; - last_gp_core_cookie = NULL; - job = core->current_job; - jobgp = GET_JOBGP2_PTR(job); - - switch( suspend_response->code ) - { - case _MALIGP_JOB_RESUME_WITH_NEW_HEAP : - MALI_DEBUG_PRINT(5, ("MALIGP_JOB_RESUME_WITH_NEW_HEAP jiffies: %li\n", _mali_osk_time_tickcount())); - MALI_DEBUG_PRINT(4, ("New Heap addr 0x%08x - 0x%08x\n", suspend_response->arguments[0], suspend_response->arguments[1])); - - jobgp->is_stalled_waiting_for_more_memory = 0; - job->watchdog_jiffies += _mali_osk_time_tickcount(); /* convert to absolute time again */ - _mali_osk_timer_mod( core->timer, job->watchdog_jiffies); /* update the timer */ - - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | MALIGP2_REG_VAL_IRQ_HANG)); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - mali_core_renderunit_register_write_relaxed(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, suspend_response->arguments[0]); - mali_core_renderunit_register_write_relaxed(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, suspend_response->arguments[1]); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); - _mali_osk_write_mem_barrier(); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); -#endif - - MALI_DEBUG_PRINT(4, ("GP resumed with new heap\n")); - - break; - - case _MALIGP_JOB_ABORT: - MALI_DEBUG_PRINT(3, ("MALIGP_JOB_ABORT on heap extend request\n")); - _mali_osk_irq_schedulework( core->irq ); - break; - - default: - MALI_PRINT_ERROR(("Wrong Suspend response from userspace\n")); - } - MALI_SUCCESS; -} - -/* This function is called from the ioctl function and should write the necessary data -to userspace telling which job was finished and the status and debuginfo for this job. -The function must also free and cleanup the input job object. */ -static void subsystem_maligp_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status ) -{ - maligp_job *jobgp; - _mali_uk_gp_job_finished_s * job_out; - _mali_uk_gp_start_job_s* job_input; - mali_core_session *session; - - - jobgp = _MALI_OSK_CONTAINER_OF(job, maligp_job, embedded_core_job); - job_out = (_mali_uk_gp_job_finished_s *)jobgp->notification_obj->result_buffer; /* OK - this should've been malloc'd */ - job_input= &(jobgp->user_input); - session = job->session; - - MALI_DEBUG_PRINT(5, ("Mali GP: Job: 0x%08x OUTPUT to user. Runtime: %d us, irq readout %x\n", - (u32)jobgp->user_input.user_job_ptr, - job->render_time_usecs, - jobgp->irq_status)) ; - - _mali_osk_memset(job_out, 0 , sizeof(_mali_uk_gp_job_finished_s)); - - job_out->user_job_ptr = job_input->user_job_ptr; - - switch( end_status ) - { - case JOB_STATUS_CONTINUE_RUN: - case JOB_STATUS_END_SUCCESS: - case JOB_STATUS_END_OOM: - case JOB_STATUS_END_ABORT: - case JOB_STATUS_END_TIMEOUT_SW: - case JOB_STATUS_END_HANG: - case JOB_STATUS_END_SEG_FAULT: - case JOB_STATUS_END_ILLEGAL_JOB: - case JOB_STATUS_END_UNKNOWN_ERR: - case JOB_STATUS_END_SHUTDOWN: - case JOB_STATUS_END_SYSTEM_UNUSABLE: - job_out->status = (mali_subsystem_job_end_code) end_status; - break; - default: - job_out->status = JOB_STATUS_END_UNKNOWN_ERR ; - } - - job_out->irq_status = jobgp->irq_status; - job_out->status_reg_on_stop = jobgp->status_reg_on_stop; - job_out->vscl_stop_addr = 0; - job_out->plbcl_stop_addr = 0; - job_out->heap_current_addr = jobgp->heap_current_addr; - job_out->perf_counter0 = jobgp->perf_counter0; - job_out->perf_counter1 = jobgp->perf_counter1; - job_out->perf_counter_src0 = jobgp->user_input.perf_counter_src0 ; - job_out->perf_counter_src1 = jobgp->user_input.perf_counter_src1 ; - job_out->render_time = job->render_time_usecs; -#if defined(USING_MALI400_L2_CACHE) - job_out->perf_counter_l2_src0 = jobgp->perf_counter_l2_src0; - job_out->perf_counter_l2_src1 = jobgp->perf_counter_l2_src1; - job_out->perf_counter_l2_val0 = jobgp->perf_counter_l2_val0; - job_out->perf_counter_l2_val1 = jobgp->perf_counter_l2_val1; -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&session->jobs_returned); -#endif - _mali_osk_notification_queue_send( session->notification_queue, jobgp->notification_obj); - jobgp->notification_obj = NULL; - - _mali_osk_free(jobgp); - - last_gp_core_cookie = NULL; -} - -static void subsystem_maligp_renderunit_delete(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Mali GP: maligp_renderunit_delete\n")); - _mali_osk_free(core); -} - -static void subsystem_maligp_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style) -{ - MALI_DEBUG_PRINT(5, ("Mali GP: renderunit_reset_core\n")); - - switch (style) - { - case MALI_CORE_RESET_STYLE_RUNABLE: - maligp_reset(core); - break; - case MALI_CORE_RESET_STYLE_DISABLE: - maligp_raw_reset(core); /* do the raw reset */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* then disable the IRQs */ - break; - case MALI_CORE_RESET_STYLE_HARD: - maligp_reset_hard(core); - maligp_initialize_registers_mgmt(core); - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown reset type %d\n", style)); - break; - } -} - -static void subsystem_maligp_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core , MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); - mali_core_renderunit_register_write(core , MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_CMD_FORCE_HANG ); - _mali_osk_mem_barrier(); -} - -static _mali_osk_errcode_t subsystem_maligp_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core) -{ - u32 irq_readout; - - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_STAT); - - if ( MALIGP2_REG_VAL_IRQ_FORCE_HANG & irq_readout ) - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -_mali_osk_errcode_t _mali_ukk_gp_start_job( _mali_uk_gp_start_job_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_start_job(session, args); -} - -_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_number_of_cores_get(session, &args->number_of_cores); -} - -_mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_core_version_get(session, &args->version); -} - -_mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_suspend_response(session, args); -} - -void _mali_ukk_gp_abort_job( _mali_uk_gp_abort_job_s * args) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - if (NULL == args->ctx) return; - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - if (NULL == session) return; - mali_core_subsystem_ioctl_abort_job(session, args->abort_id); - -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t maligp_signal_power_up( mali_bool queue_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali GP: signal power up core - queue_only: %d\n", queue_only )); - - return( mali_core_subsystem_signal_power_up( &subsystem_maligp, 0, queue_only ) ); -} - -_mali_osk_errcode_t maligp_signal_power_down( mali_bool immediate_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali GP: signal power down core - immediate_only: %d\n", immediate_only )); - - return( mali_core_subsystem_signal_power_down( &subsystem_maligp, 0, immediate_only ) ); -} - -#endif - -#if MALI_STATE_TRACKING -u32 maligp_subsystem_dump_state(char *buf, u32 size) -{ - return mali_core_renderunit_dump_state(&subsystem_maligp, buf, size); -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c b/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c deleted file mode 100644 index 0f5ebd0..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -//added for SPI -#include <linux/kernel.h> - -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_core.h" -#include "regs/mali_200_regs.h" -#include "mali_kernel_rendercore.h" -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#ifdef USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" /* Needed for mali_kernel_mmu_force_bus_reset() */ -#endif - -#include "mali_osk_list.h" - -#if defined(USING_MALI200) -#define MALI_PP_SUBSYSTEM_NAME "Mali200" -#define MALI_PP_CORE_TYPE _MALI_200 -#elif defined(USING_MALI400) -#define MALI_PP_SUBSYSTEM_NAME "Mali-400 PP" -#define MALI_PP_CORE_TYPE _MALI_400_PP -#else -#error "No supported mali core defined" -#endif - -#define GET_JOB_EMBEDDED_PTR(job) (&((job)->embedded_core_job)) -#define GET_JOB200_PTR(job_extern) _MALI_OSK_CONTAINER_OF(job_extern, mali200_job, embedded_core_job) - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_mali200_id = -1; - -/* Describing a mali200 job settings */ -typedef struct mali200_job -{ - /* The general job struct common for all mali cores */ - mali_core_job embedded_core_job; - _mali_uk_pp_start_job_s user_input; - - u32 irq_status; - u32 perf_counter0; - u32 perf_counter1; - u32 last_tile_list_addr; /* Neccessary to continue a stopped job */ - - u32 active_mask; - - /* The data we will return back to the user */ - _mali_osk_notification_t *notification_obj; - -#if defined(USING_MALI400_L2_CACHE) - u32 perf_counter_l2_src0; - u32 perf_counter_l2_src1; - u32 perf_counter_l2_val0; - u32 perf_counter_l2_val1; - u32 perf_counter_l2_val0_raw; - u32 perf_counter_l2_val1_raw; -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - u32 pid; - u32 tid; -#endif -} mali200_job; - - -/*Functions Exposed to the General External System through - funciont pointers.*/ - -static _mali_osk_errcode_t mali200_subsystem_startup(mali_kernel_subsystem_identifier id); -#if USING_MMU -static _mali_osk_errcode_t mali200_subsystem_mmu_connect(mali_kernel_subsystem_identifier id); -#endif -static void mali200_subsystem_terminate(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t mali200_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); -static void mali200_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); -static _mali_osk_errcode_t mali200_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t mali200_renderunit_create(_mali_osk_resource_t * resource); -#if USING_MMU -static void mali200_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif -#if MALI_STATE_TRACKING -u32 mali200_subsystem_dump_state(char *buf, u32 size); -#endif - -/* Internal support functions */ -static _mali_osk_errcode_t mali200_core_version_legal( mali_core_renderunit *core ); -static void mali200_reset(mali_core_renderunit *core); -static void mali200_reset_hard(struct mali_core_renderunit * core); -static void mali200_raw_reset(mali_core_renderunit * core); -static void mali200_initialize_registers_mgmt(mali_core_renderunit *core ); - -/* Functions exposed to mali_core system through functionpointers - in the subsystem struct. */ -static _mali_osk_errcode_t subsystem_mali200_start_job(mali_core_job * job, mali_core_renderunit * core); -static _mali_osk_errcode_t subsystem_mali200_get_new_job_from_user(struct mali_core_session * session, void * argument); -static void subsystem_mali200_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status); -static void subsystem_mali200_renderunit_delete(mali_core_renderunit * core); -static void subsystem_mali200_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style); -static void subsystem_mali200_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_mali200_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core); - -static void subsystem_mali200_renderunit_stop_bus(struct mali_core_renderunit* core); -static u32 subsystem_mali200_irq_handler_upper_half(struct mali_core_renderunit * core); -static int subsystem_mali200_irq_handler_bottom_half(struct mali_core_renderunit* core); - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ - -struct mali_kernel_subsystem mali_subsystem_mali200= -{ - mali200_subsystem_startup, /* startup */ - NULL, /*mali200_subsystem_terminate,*/ /* shutdown */ -#if USING_MMU - mali200_subsystem_mmu_connect, /* load_complete */ -#else - NULL, -#endif - mali200_subsystem_core_system_info_fill, /* system_info_fill */ - mali200_subsystem_session_begin, /* session_begin */ - mali200_subsystem_session_end, /* session_end */ -#if USING_MMU - mali200_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - mali200_subsystem_dump_state, /* dump_state */ -#endif -} ; - -static mali_core_subsystem subsystem_mali200 ; - -static _mali_osk_errcode_t mali200_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem * subsystem; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_startup\n") ) ; - - mali_subsystem_mali200_id = id; - - /* All values get 0 as default */ - _mali_osk_memset(&subsystem_mali200, 0, sizeof(subsystem_mali200)); - - subsystem = &subsystem_mali200; - subsystem->start_job = &subsystem_mali200_start_job; - subsystem->irq_handler_upper_half = &subsystem_mali200_irq_handler_upper_half; - subsystem->irq_handler_bottom_half = &subsystem_mali200_irq_handler_bottom_half; - subsystem->get_new_job_from_user = &subsystem_mali200_get_new_job_from_user; - subsystem->return_job_to_user = &subsystem_mali200_return_job_to_user; - subsystem->renderunit_delete = &subsystem_mali200_renderunit_delete; - subsystem->reset_core = &subsystem_mali200_renderunit_reset_core; - subsystem->stop_bus = &subsystem_mali200_renderunit_stop_bus; - subsystem->probe_core_irq_trigger = &subsystem_mali200_renderunit_probe_core_irq_trigger; - subsystem->probe_core_irq_acknowledge = &subsystem_mali200_renderunit_probe_core_irq_finished; - - /* Setting variables in the general core part of the subsystem.*/ - subsystem->name = MALI_PP_SUBSYSTEM_NAME; - subsystem->core_type = MALI_PP_CORE_TYPE; - subsystem->id = id; - - /* Initiates the rest of the general core part of the subsystem */ - MALI_CHECK_NO_ERROR(mali_core_subsystem_init( subsystem )); - - /* This will register the function for adding MALI200 cores to the subsystem */ -#if defined(USING_MALI200) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI200, mali200_renderunit_create)); -#endif -#if defined(USING_MALI400) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI400PP, mali200_renderunit_create)); -#endif - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_startup\n") ) ; - - MALI_SUCCESS; -} - -#if USING_MMU -static _mali_osk_errcode_t mali200_subsystem_mmu_connect(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem_attach_mmu(&subsystem_mali200); - MALI_SUCCESS; /* OK */ -} -#endif - -static void mali200_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_terminate\n") ) ; - mali_core_subsystem_cleanup(&subsystem_mali200); -} - -static _mali_osk_errcode_t mali200_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_session_begin\n") ) ; - MALI_CHECK_NON_NULL(session = _mali_osk_malloc( sizeof(mali_core_session) ), _MALI_OSK_ERR_NOMEM); - - _mali_osk_memset(session, 0, sizeof(*session) ); - *slot = (mali_kernel_subsystem_session_slot)session; - - session->subsystem = &subsystem_mali200; - - session->notification_queue = queue; - -#if USING_MMU - session->mmu_session = mali_session_data; -#endif - - mali_core_session_begin(session); - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_session_begin\n") ) ; - - MALI_SUCCESS; -} - -static void mali200_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_session_end\n") ) ; - if ( NULL==slot || NULL==*slot) - { - MALI_PRINT_ERROR(("Input slot==NULL")); - return; - } - session = (mali_core_session*) *slot; - mali_core_session_close(session); - - _mali_osk_free(session); - *slot = NULL; - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_session_end\n") ) ; -} - -/** - * We fill in info about all the cores we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali200_subsystem_core_system_info_fill(_mali_system_info* info) -{ - return mali_core_subsystem_system_info_fill(&subsystem_mali200, info); -} - - -static _mali_osk_errcode_t mali200_renderunit_create(_mali_osk_resource_t * resource) -{ - mali_core_renderunit *core; - _mali_osk_errcode_t err; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_renderunit_create\n") ) ; - /* Checking that the resource settings are correct */ -#if defined(USING_MALI200) - if(MALI200 != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#elif defined(USING_MALI400) - if(MALI400PP != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - if ( 0 != resource->size ) - { - MALI_PRINT_ERROR(("Memory size set to " MALI_PP_SUBSYSTEM_NAME " core should be zero.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if ( NULL == resource->description ) - { - MALI_PRINT_ERROR(("A " MALI_PP_SUBSYSTEM_NAME " core needs a unique description field")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Create a new core object */ - core = (mali_core_renderunit*) _mali_osk_malloc(sizeof(*core)); - if ( NULL == core ) - { - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* Variables set to be able to open and register the core */ - core->subsystem = &subsystem_mali200 ; - core->registers_base_addr = resource->base ; - core->size = MALI200_REG_SIZEOF_REGISTER_BANK ; - core->irq_nr = resource->irq ; - core->description = resource->description; -#if USING_MMU - core->mmu_id = resource->mmu_id; - core->mmu = NULL; -#endif -#if USING_MALI_PMM - /* Set up core's PMM id */ - switch( subsystem_mali200.number_of_cores ) - { - case 0: - core->pmm_id = MALI_PMM_CORE_PP0; - break; - case 1: - core->pmm_id = MALI_PMM_CORE_PP1; - break; - case 2: - core->pmm_id = MALI_PMM_CORE_PP2; - break; - case 3: - core->pmm_id = MALI_PMM_CORE_PP3; - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown supported core for PMM\n")); - err = _MALI_OSK_ERR_FAULT; - goto exit_on_error0; - } -#endif - - err = mali_core_renderunit_init( core ); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to initialize renderunit\n")); - goto exit_on_error0; - } - - /* Map the new core object, setting: core->registers_mapped */ - err = mali_core_renderunit_map_registers(core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to map register\n")); - goto exit_on_error1; - } - - /* Check that the register mapping of the core works. - Return 0 if Mali PP core is present and accessible. */ - if (mali_benchmark) { -#if defined(USING_MALI200) - core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 5 /* Fake Mali200-r0p5 */; -#elif defined(USING_MALI400) - core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 0x0101 /* Fake Mali400-r1p1 */; -#else -#error "No supported mali core defined" -#endif - } else { - core->core_version = mali_core_renderunit_register_read( - core, - MALI200_REG_ADDR_MGMT_VERSION); - } - - err = mali200_core_version_legal(core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Invalid core\n")); - goto exit_on_error2; - } - - /* Reset the core. Put the core into a state where it can start to render. */ - mali200_reset(core); - - /* Registering IRQ, init the work_queue_irq_handle */ - /* Adding this core as an available renderunit in the subsystem. */ - err = mali_core_subsystem_register_renderunit(&subsystem_mali200, core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to register with core\n")); - goto exit_on_error2; - } - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_renderunit_create\n") ) ; - - MALI_SUCCESS; - -exit_on_error2: - mali_core_renderunit_unmap_registers(core); -exit_on_error1: - mali_core_renderunit_term(core); -exit_on_error0: - _mali_osk_free( core ) ; - MALI_PRINT_ERROR(("Renderunit NOT created.")); - MALI_ERROR(err); -} - -#if USING_MMU -/* Used currently only for signalling when MMU has a pagefault */ -static void mali200_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - mali_core_subsystem_broadcast_notification(&subsystem_mali200, message, data); -} -#endif - -static _mali_osk_errcode_t mali200_core_version_legal( mali_core_renderunit *core ) -{ - u32 mali_type; - - mali_type = core->core_version >> 16; -#if defined(USING_MALI400) - /* Mali300 and Mali400 is compatible, accept either core. */ - if (MALI400_PP_PRODUCT_ID != mali_type && MALI300_PP_PRODUCT_ID != mali_type) -#else - if (MALI_PP_PRODUCT_ID != mali_type) -#endif - { - MALI_PRINT_ERROR(("Error: reading this from " MALI_PP_SUBSYSTEM_NAME " version register: 0x%x\n", core->core_version)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - MALI_DEBUG_PRINT(3, ("Mali PP: core_version_legal: Reads correct mali version: %d\n", mali_type) ) ; - MALI_SUCCESS; -} - -static void subsystem_mali200_renderunit_stop_bus(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); -} - -static void mali200_raw_reset( mali_core_renderunit *core ) -{ - int i; - const int request_loop_count = 20; - - MALI_DEBUG_PRINT(4, ("Mali PP: mali200_raw_reset: %s\n", core->description)); - if (mali_benchmark) return; - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable IRQs */ - -#if defined(USING_MALI200) - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) break; - _mali_osk_time_ubusydelay(10); - } - - MALI_DEBUG_PRINT_IF(1, request_loop_count == i, ("Mali PP: Bus was never stopped during core reset\n")); - - - if (request_loop_count==i) - { -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow PP to stop its bus, system failure, unable to recover\n")); - return; - } - - /* use the hard reset routine to do the actual reset */ - mali200_reset_hard(core); - -#elif defined(USING_MALI400) - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI400PP_REG_VAL_IRQ_RESET_COMPLETED); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) break; - _mali_osk_time_ubusydelay(10); - } - - if (request_loop_count==i) - { -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow PP to stop its bus, system failure, unable to recover\n")); - return; - } - else - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); - -#else -#error "no supported mali core defined" -#endif -} - -static void mali200_reset( mali_core_renderunit *core ) -{ - if (!mali_benchmark) { - mali200_raw_reset(core); - mali200_initialize_registers_mgmt(core); - } -} - -/* Sets the registers on mali200 according to the const default_mgmt_regs array. */ -static void mali200_initialize_registers_mgmt(mali_core_renderunit *core ) -{ - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_initialize_registers_mgmt: %s\n", core->description)) ; - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); -} - -/* Start this job on this core. Return MALI_TRUE if the job was started. */ -static _mali_osk_errcode_t subsystem_mali200_start_job(mali_core_job * job, mali_core_renderunit * core) -{ - mali200_job *job200; - - /* The local extended version of the general structs */ - job200 = _MALI_OSK_CONTAINER_OF(job, mali200_job, embedded_core_job); - - if ( (0 == job200->user_input.frame_registers[0]) || - (0 == job200->user_input.frame_registers[1]) ) - { - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x WILL NOT START SINCE JOB HAS ILLEGAL ADDRESSES\n", - (u32)job200->user_input.user_job_ptr)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x START_RENDER Tile_list: 0x%08x\n", - (u32)job200->user_input.user_job_ptr, - job200->user_input.frame_registers[0])); - MALI_DEBUG_PRINT(6, ("Mali PP: RSW base addr: 0x%08x Vertex base addr: 0x%08x\n", - job200->user_input.frame_registers[1], job200->user_input.frame_registers[2])); - - /* Frame registers. Copy from mem to physical registers */ - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_FRAME, - &(job200->user_input.frame_registers[0]), - MALI200_NUM_REGS_FRAME); - - /* Write Back unit 0. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb0_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB0, - &(job200->user_input.wb0_registers[0]), - MALI200_NUM_REGS_WBx); - } - - /* Write Back unit 1. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb1_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB1, - &(job200->user_input.wb1_registers[0]), - MALI200_NUM_REGS_WBx); - } - - /* Write Back unit 2. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb2_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB2, - &(job200->user_input.wb2_registers[0]), - MALI200_NUM_REGS_WBx); - } - -#if MALI_TRACEPOINTS_ENABLED - { - int counter = ((core->core_number)*2)+9; /* magic numbers for FP0 are 9 & 10 */ - - //printk("FP core->number = %d\n", core->core_number); - //TODO we are using magic numbers again... these are from gator_events_mali.c - job200->user_input.perf_counter_flag = 0; - - if( counter>=9 && counter<=16) { - - if( counter_table[counter] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE; - job200->user_input.perf_counter_src0 = counter_table[counter]; - } - if( counter_table[counter+1] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE; - job200->user_input.perf_counter_src1 = counter_table[counter+1]; - } - - } else { - MALI_DEBUG_PRINT(2, ("core->core_number out of the range (0-3) (%d)\n", core->core_number)); - } - } -#if defined(USING_MALI400_L2_CACHE) - if( counter_table[5] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE | _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET; - job200->user_input.perf_counter_l2_src0 = counter_table[5]; - } - if( counter_table[6] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE | _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET; - job200->user_input.perf_counter_l2_src1 = counter_table[6]; - } -#endif -#endif - - /* This selects which performance counters we are reading */ - if ( 0 != job200->user_input.perf_counter_flag ) - { - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, - MALI200_REG_VAL_PERF_CNT_ENABLE); - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, - job200->user_input.perf_counter_src0); - - } - - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALI200_REG_VAL_PERF_CNT_ENABLE); - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, - job200->user_input.perf_counter_src1); - - } - -#if defined(USING_MALI400_L2_CACHE) - if ( job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - int force_reset = ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET ) ? 1 : 0; - u32 src0 = 0; - u32 src1 = 0; - - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE ) - { - src0 = job200->user_input.perf_counter_l2_src0; - } - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE ) - { - src1 = job200->user_input.perf_counter_l2_src1; - } - - mali_kernel_l2_cache_set_perf_counters(src0, src1, force_reset); /* will activate and possibly reset counters */ - - /* Now, retrieve the current values, so we can substract them when the job has completed */ - mali_kernel_l2_cache_get_perf_counters(&job200->perf_counter_l2_src0, - &job200->perf_counter_l2_val0, - &job200->perf_counter_l2_src1, - &job200->perf_counter_l2_val1); - } -#endif - } - - subsystem_flush_mapped_mem_cache(); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_started); -#endif - - /* This is the command that starts the Core */ - mali_core_renderunit_register_write( - core, - MALI200_REG_ADDR_MGMT_CTRL_MGMT, - MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); - _mali_osk_write_mem_barrier(); - - - pr_debug("SPI_GPU_PP%u Start\n", core->core_number); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, job200->user_input.frame_builder_id, job200->user_input.flush_id, 0, 0, 0); - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), job200->pid, job200->tid, -#if defined(USING_MALI400_L2_CACHE) - (job200->user_input.perf_counter_l2_src0 << 16) | (job200->user_input.perf_counter_l2_src1 << 24), - job200->perf_counter_l2_val0, job200->perf_counter_l2_val1 -#else - 0, 0, 0 -#endif - ); -#endif - - MALI_SUCCESS; -} - -static u32 subsystem_mali200_irq_handler_upper_half(mali_core_renderunit * core) -{ - u32 irq_readout; - - if (mali_benchmark) { - return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */ - } - - MALI_DEBUG_PRINT(5, ("Mali PP: subsystem_mali200_irq_handler_upper_half: %s\n", core->description)) ; - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS); - - if ( MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout ) - { - /* Mask out all IRQs from this core until IRQ is handled */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); -#endif - - return 1; - } - return 0; -} - -static int subsystem_mali200_irq_handler_bottom_half(struct mali_core_renderunit* core) -{ - u32 irq_readout; - u32 current_tile_addr; - u32 core_status; - mali_core_job * job; - mali200_job * job200; - - job = core->current_job; - job200 = GET_JOB200_PTR(job); - - - if (mali_benchmark) { - irq_readout = MALI200_REG_VAL_IRQ_END_OF_FRAME; - current_tile_addr = 0; - core_status = 0; - } else { - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED; - current_tile_addr = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR); - core_status = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS); - } - - if (NULL == job) - { - MALI_DEBUG_ASSERT(CORE_IDLE==core->state); - if ( 0 != irq_readout ) - { - MALI_PRINT_ERROR(("Interrupt from a core not running a job. IRQ: 0x%04x Status: 0x%04x", irq_readout, core_status)); - } - return JOB_STATUS_END_UNKNOWN_ERR; - } - MALI_DEBUG_ASSERT(CORE_IDLE!=core->state); - - job200->irq_status |= irq_readout; - - MALI_DEBUG_PRINT_IF( 3, ( 0 != irq_readout ), - ("Mali PP: Job: 0x%08x IRQ RECEIVED Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n", - (u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status)); - - if ( MALI200_REG_VAL_IRQ_END_OF_FRAME & irq_readout) - { -#if defined(USING_MALI200) - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FLUSH_CACHES); -#endif - - if (0 != job200->user_input.perf_counter_flag ) - { - if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - unsigned int counter = (core->core_number * 2) + 9; -#endif - - job200->perf_counter0 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - job200->perf_counter1 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - _mali_profiling_add_counter(counter, job200->perf_counter0); - _mali_profiling_add_counter(counter + 1, job200->perf_counter1); -#endif - - } - -#if defined(USING_MALI400_L2_CACHE) - if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (job200->perf_counter_l2_src0 == src0) - { - job200->perf_counter_l2_val0_raw = val0; - job200->perf_counter_l2_val0 = val0 - job200->perf_counter_l2_val0; - } - else - { - job200->perf_counter_l2_val0_raw = 0; - job200->perf_counter_l2_val0 = 0; - } - - if (job200->perf_counter_l2_src1 == src1) - { - job200->perf_counter_l2_val1_raw = val1; - job200->perf_counter_l2_val1 = val1 - job200->perf_counter_l2_val1; - } - else - { - job200->perf_counter_l2_val1_raw = 0; - job200->perf_counter_l2_val1 = 0; - } - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(5, val0); - _mali_profiling_add_counter(6, val1); -#endif - } -#endif - - } - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), - job200->perf_counter0, job200->perf_counter1, - job200->user_input.perf_counter_src0 | (job200->user_input.perf_counter_src1 << 8) -#if defined(USING_MALI400_L2_CACHE) - | (job200->user_input.perf_counter_l2_src0 << 16) | (job200->user_input.perf_counter_l2_src1 << 24), - job200->perf_counter_l2_val0, job200->perf_counter_l2_val1 -#else - , 0, 0 -#endif - ); -#endif - - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - - pr_debug("SPI_GPU_PP%u Idle\n", core->core_number); - - return JOB_STATUS_END_SUCCESS; /* reschedule */ - } - /* Overall SW watchdog timeout or (time to do hang checking and progress detected)? */ - else if ( - (CORE_WATCHDOG_TIMEOUT == core->state) || - ((CORE_HANG_CHECK_TIMEOUT == core->state) && (current_tile_addr == job200->last_tile_list_addr)) - ) - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */ -#endif - /* no progress detected, killed by the watchdog */ - MALI_PRINT( ("M200: SW-Timeout Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x.\n", irq_readout ,current_tile_addr ,core_status) ); - /* In this case will the system outside cleanup and reset the core */ - - MALI_PANIC("%s Watchdog timeout (rawstat: 0x%x tile_addr: 0x%x status: 0x%x)\n", MALI_PP_SUBSYSTEM_NAME, irq_readout, current_tile_addr, core_status); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - - return JOB_STATUS_END_HANG; - } - /* HW watchdog triggered or an existing hang check passed? */ - else if ((CORE_HANG_CHECK_TIMEOUT == core->state) || (irq_readout & job200->active_mask & MALI200_REG_VAL_IRQ_HANG)) - { - /* check interval in ms */ - u32 timeout = mali_core_hang_check_timeout_get(); - MALI_PRINT( ("M200: HW/SW Watchdog triggered, checking for progress in %d ms\n", timeout)); - job200->last_tile_list_addr = current_tile_addr; - /* hw watchdog triggered, set up a progress checker every HANGCHECK ms */ - _mali_osk_timer_add(core->timer_hang_detection, _mali_osk_time_mstoticks(timeout)); - job200->active_mask &= ~MALI200_REG_VAL_IRQ_HANG; /* ignore the hw watchdoig from now on */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout & ~MALI200_REG_VAL_IRQ_HANG); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* not finished */ - } - /* No irq pending, core still busy */ - else if ((0 == (irq_readout & MALI200_REG_VAL_IRQ_MASK_USED)) && ( 0 != (core_status & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE))) - { - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* Not finished */ - } - else - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */ -#endif - - MALI_PRINT( ("Mali PP: Job: 0x%08x CRASH? Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n", - (u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status) ) ; - - if (irq_readout & MALI200_REG_VAL_IRQ_BUS_ERROR) - { - u32 bus_error = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS); - - MALI_PRINT(("Bus error status: 0x%08X\n", bus_error)); - MALI_DEBUG_PRINT_IF(1, (bus_error & 0x01), ("Bus write error from id 0x%02x\n", (bus_error>>2) & 0x0F)); - MALI_DEBUG_PRINT_IF(1, (bus_error & 0x02), ("Bus read error from id 0x%02x\n", (bus_error>>6) & 0x0F)); - MALI_DEBUG_PRINT_IF(1, (0 == (bus_error & 0x03)), ("Bus error but neither read or write was set as the error reason\n")); - (void)bus_error; - } - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_UNKNOWN_ERR; /* reschedule */ - } -} - - -/* This function is called from the ioctl function and should return a mali_core_job pointer -to a created mali_core_job object with the data given from userspace */ -static _mali_osk_errcode_t subsystem_mali200_get_new_job_from_user(struct mali_core_session * session, void * argument) -{ - mali200_job *job200; - mali_core_job *job = NULL; - mali_core_job *previous_replaced_job; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_uk_pp_start_job_s * user_ptr_job_input; - - user_ptr_job_input = (_mali_uk_pp_start_job_s *)argument; - - MALI_CHECK_NON_NULL(job200 = (mali200_job *) _mali_osk_malloc(sizeof(mali200_job)), _MALI_OSK_ERR_NOMEM); - _mali_osk_memset(job200, 0 , sizeof(mali200_job) ); - - /* We read job data from Userspace pointer */ - if ( NULL == _mali_osk_memcpy((void*)&job200->user_input, user_ptr_job_input, sizeof(job200->user_input)) ) - { - MALI_PRINT_ERROR( ("Mali PP: Could not copy data from U/K interface.\n")) ; - err = _MALI_OSK_ERR_FAULT; - goto function_exit; - } - - MALI_DEBUG_PRINT(5, ("Mali PP: subsystem_mali200_get_new_job_from_user 0x%x\n", (void*)job200->user_input.user_job_ptr)); - - MALI_DEBUG_PRINT(5, ("Mali PP: Frameregs: 0x%x 0x%x 0x%x Writeback[1] 0x%x, Pri:%d; Watchd:%d\n", - job200->user_input.frame_registers[0], job200->user_input.frame_registers[1], job200->user_input.frame_registers[2], - job200->user_input.wb0_registers[1], job200->user_input.priority, - job200->user_input.watchdog_msecs)); - - if ( job200->user_input.perf_counter_flag) - { -#if defined(USING_MALI400_L2_CACHE) - MALI_DEBUG_PRINT(5, ("Mali PP: Performance counters: flag:0x%x src0:0x%x src1:0x%x l2_src0:0x%x l2_src1:0x%x\n", - job200->user_input.perf_counter_flag, - job200->user_input.perf_counter_src0, - job200->user_input.perf_counter_src1, - job200->user_input.perf_counter_l2_src0, - job200->user_input.perf_counter_l2_src1)); -#else - MALI_DEBUG_PRINT(5, ("Mali PP: Performance counters: flag:0x%x src0:0x%x src1:0x%x\n", - job200->user_input.perf_counter_flag, - job200->user_input.perf_counter_src0, - job200->user_input.perf_counter_src1)); -#endif - } - - job = GET_JOB_EMBEDDED_PTR(job200); - - job->session = session; - job->flags = user_ptr_job_input->flags; - job_priority_set(job, job200->user_input.priority); - job_watchdog_set(job, job200->user_input.watchdog_msecs ); - -#if MALI_TIMELINE_PROFILING_ENABLED - job200->pid = _mali_osk_get_pid(); - job200->tid = _mali_osk_get_tid(); -#endif - - job->abort_id = job200->user_input.abort_id; - if (mali_job_queue_full(session)) - { - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - goto function_exit; - } - - /* We now know that we has a job, and a empty session slot to put it in */ - - job200->active_mask = MALI200_REG_VAL_IRQ_MASK_USED; - - /* Allocating User Return Data */ - job200->notification_obj = _mali_osk_notification_create( - _MALI_NOTIFICATION_PP_FINISHED, - sizeof(_mali_uk_pp_job_finished_s) ); - - if ( NULL == job200->notification_obj ) - { - MALI_PRINT_ERROR( ("Mali PP: Could not get notification_obj.\n")) ; - err = _MALI_OSK_ERR_NOMEM; - goto function_exit; - } - - _MALI_OSK_INIT_LIST_HEAD( &(job->list) ) ; - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x INPUT from user.\n", (u32)job200->user_input.user_job_ptr)) ; - - /* This should not happen since we have the checking of priority above */ - if ( _MALI_OSK_ERR_OK != mali_core_session_add_job(session, job, &previous_replaced_job)) - { - MALI_PRINT_ERROR( ("Mali PP: Internal error\n")) ; - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - _mali_osk_notification_delete( job200->notification_obj ); - goto function_exit; - } - - /* If MALI_TRUE: This session had a job with lower priority which were removed. - This replaced job is given back to userspace. */ - if ( NULL != previous_replaced_job ) - { - mali200_job *previous_replaced_job200; - - previous_replaced_job200 = GET_JOB200_PTR(previous_replaced_job); - - MALI_DEBUG_PRINT(4, ("Mali PP: Replacing job: 0x%08x\n", (u32)previous_replaced_job200->user_input.user_job_ptr)) ; - - /* Copy to the input data (which also is output data) the - pointer to the job that were replaced, so that the userspace - driver can put this job in the front of its job-queue */ - - user_ptr_job_input->returned_user_job_ptr = previous_replaced_job200->user_input.user_job_ptr; - - /** @note failure to 'copy to user' at this point must not free job200, - * and so no transaction rollback required in the U/K interface */ - - /* This does not cause job200 to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED; - MALI_DEBUG_PRINT(5, ("subsystem_mali200_get_new_job_from_user: Job added, prev returned\n")) ; - } - else - { - /* This does not cause job200 to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED; - MALI_DEBUG_PRINT(5, ("subsystem_mali200_get_new_job_from_user: Job added\n")) ; - } - -function_exit: - if (_MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE == user_ptr_job_input->status - || _MALI_OSK_ERR_OK != err ) - { - _mali_osk_free(job200); - } -#if MALI_STATE_TRACKING - if (_MALI_UK_START_JOB_STARTED==user_ptr_job_input->status) - { - if(job) - { - job->job_nr=_mali_osk_atomic_inc_return(&session->jobs_received); - } - } -#endif - - MALI_ERROR(err); -} - -/* This function is called from the ioctl function and should write the necessary data -to userspace telling which job was finished and the status and debuginfo for this job. -The function must also free and cleanup the input job object. */ -static void subsystem_mali200_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status) -{ - mali200_job *job200; - _mali_uk_pp_job_finished_s * job_out; - _mali_uk_pp_start_job_s * job_input; - mali_core_session *session; - - if (NULL == job) - { - MALI_DEBUG_PRINT(1, ("subsystem_mali200_return_job_to_user received a NULL ptr\n")); - return; - } - - job200 = _MALI_OSK_CONTAINER_OF(job, mali200_job, embedded_core_job); - - if (NULL == job200->notification_obj) - { - MALI_DEBUG_PRINT(1, ("Found job200 with NULL notification object, abandoning userspace sending\n")); - return; - } - - job_out = job200->notification_obj->result_buffer; - job_input= &(job200->user_input); - session = job->session; - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x OUTPUT to user. Runtime: %dus\n", - (u32)job200->user_input.user_job_ptr, - job->render_time_usecs)) ; - - _mali_osk_memset(job_out, 0 , sizeof(_mali_uk_pp_job_finished_s)); - - job_out->user_job_ptr = job_input->user_job_ptr; - - switch( end_status ) - { - case JOB_STATUS_CONTINUE_RUN: - case JOB_STATUS_END_SUCCESS: - case JOB_STATUS_END_OOM: - case JOB_STATUS_END_ABORT: - case JOB_STATUS_END_TIMEOUT_SW: - case JOB_STATUS_END_HANG: - case JOB_STATUS_END_SEG_FAULT: - case JOB_STATUS_END_ILLEGAL_JOB: - case JOB_STATUS_END_UNKNOWN_ERR: - case JOB_STATUS_END_SHUTDOWN: - case JOB_STATUS_END_SYSTEM_UNUSABLE: - job_out->status = (mali_subsystem_job_end_code) end_status; - break; - - default: - job_out->status = JOB_STATUS_END_UNKNOWN_ERR ; - } - job_out->irq_status = job200->irq_status; - job_out->perf_counter0 = job200->perf_counter0; - job_out->perf_counter1 = job200->perf_counter1; - job_out->render_time = job->render_time_usecs; - -#if defined(USING_MALI400_L2_CACHE) - job_out->perf_counter_l2_src0 = job200->perf_counter_l2_src0; - job_out->perf_counter_l2_src1 = job200->perf_counter_l2_src1; - job_out->perf_counter_l2_val0 = job200->perf_counter_l2_val0; - job_out->perf_counter_l2_val1 = job200->perf_counter_l2_val1; - job_out->perf_counter_l2_val0_raw = job200->perf_counter_l2_val0_raw; - job_out->perf_counter_l2_val1_raw = job200->perf_counter_l2_val1_raw; -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&session->jobs_returned); -#endif - _mali_osk_notification_queue_send( session->notification_queue, job200->notification_obj); - job200->notification_obj = NULL; - - _mali_osk_free(job200); -} - -static void subsystem_mali200_renderunit_delete(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Mali PP: mali200_renderunit_delete\n")); - _mali_osk_free(core); -} - -static void mali200_reset_hard(struct mali_core_renderunit * core) -{ - const int reset_finished_loop_count = 15; - const u32 reset_wait_target_register = MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW; - const u32 reset_invalid_value = 0xC0FFE000; - const u32 reset_check_value = 0xC01A0000; - const u32 reset_default_value = 0; - int i; - - MALI_DEBUG_PRINT(5, ("subsystem_mali200_renderunit_reset_core_hard called for core %s\n", core->description)); - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_invalid_value); - - mali_core_renderunit_register_write( - core, - MALI200_REG_ADDR_MGMT_CTRL_MGMT, - MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET); - - for (i = 0; i < reset_finished_loop_count; i++) - { - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_check_value); - if (reset_check_value == mali_core_renderunit_register_read(core, reset_wait_target_register)) - { - MALI_DEBUG_PRINT(5, ("Reset loop exiting after %d iterations\n", i)); - break; - } - _mali_osk_time_ubusydelay(10); - } - - if (i == reset_finished_loop_count) - { - MALI_DEBUG_PRINT(1, ("The reset loop didn't work\n")); - } - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_default_value); /* set it back to the default */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); -} - -static void subsystem_mali200_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style) -{ - MALI_DEBUG_PRINT(5, ("Mali PP: renderunit_reset_core\n")); - - switch (style) - { - case MALI_CORE_RESET_STYLE_RUNABLE: - mali200_reset(core); - break; - case MALI_CORE_RESET_STYLE_DISABLE: - mali200_raw_reset(core); /* do the raw reset */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* then disable the IRQs */ - break; - case MALI_CORE_RESET_STYLE_HARD: - mali200_reset_hard(core); - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown reset type %d\n", style)); - } -} - -static void subsystem_mali200_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); -} - -static _mali_osk_errcode_t subsystem_mali200_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core) -{ - u32 irq_readout; - - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS); - - if ( MALI200_REG_VAL_IRQ_FORCE_HANG & irq_readout ) - { - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -_mali_osk_errcode_t _mali_ukk_pp_start_job( _mali_uk_pp_start_job_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_start_job(session, args); -} - -_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_number_of_cores_get(session, &args->number_of_cores); -} - -_mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_core_version_get(session, &args->version); -} - -void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s * args) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - if (NULL == args->ctx) return; - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - if (NULL == session) return; - mali_core_subsystem_ioctl_abort_job(session, args->abort_id); - -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t malipp_signal_power_up( u32 core_num, mali_bool queue_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali PP: signal power up core: %d - queue_only: %d\n", core_num, queue_only )); - - return( mali_core_subsystem_signal_power_up( &subsystem_mali200, core_num, queue_only ) ); -} - -_mali_osk_errcode_t malipp_signal_power_down( u32 core_num, mali_bool immediate_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali PP: signal power down core: %d - immediate_only: %d\n", core_num, immediate_only )); - - return( mali_core_subsystem_signal_power_down( &subsystem_mali200, core_num, immediate_only ) ); -} - -#endif - -#if MALI_STATE_TRACKING -u32 mali200_subsystem_dump_state(char *buf, u32 size) -{ - return mali_core_renderunit_dump_state(&subsystem_mali200, buf, size); -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_common.h b/drivers/media/video/samsung/mali/common/mali_kernel_common.h index ab6f143..b354f92 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_common.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 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. @@ -28,7 +28,6 @@ #define MALI_PANIC(fmt, args...) #endif - /* The file include several useful macros for error checking, debugging and printing. * - MALI_PRINTF(...) Do not use this function: Will be included in Release builds. * - MALI_DEBUG_PRINT(nr, (X) ) Prints the second argument if nr<=MALI_DEBUG_LEVEL. @@ -129,7 +128,9 @@ } while (0) #ifdef DEBUG +#ifndef mali_debug_level extern int mali_debug_level; +#endif #define MALI_DEBUG_CODE(code) code #define MALI_DEBUG_PRINT(level, args) do { \ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_core.c b/drivers/media/video/samsung/mali/common/mali_kernel_core.c index be1889d..0155dfc 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_core.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -8,344 +8,805 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "mali_kernel_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_session_manager.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_gp.h" +#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_kernel_rendercore.h" -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.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_gp.h" +#include "mali_pp.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_cluster.h" +#include "mali_group.h" +#include "mali_pm.h" +#include "mali_pmu.h" +#include "mali_scheduler.h" +#ifdef CONFIG_MALI400_GPU_UTILIZATION +#include "mali_kernel_utilization.h" +#endif +#include "mali_l2_cache.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" #endif -#if USING_MALI_PMM -#include "mali_pmm.h" -#endif /* USING_MALI_PMM */ - -/* platform specific set up */ -#include "mali_platform.h" - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_core_id = -1; /** Pointer to table of resource definitions available to the Mali driver. * _mali_osk_resources_init() sets up the pointer to this table. */ static _mali_osk_resource_t *arch_configuration = NULL; +/** Start profiling from module load? */ +int mali_boot_profiling = 0; + /** Number of resources initialized by _mali_osk_resources_init() */ static u32 num_resources; -static _mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources ); - -static _mali_osk_errcode_t initialize_subsystems(void); -static void terminate_subsystems(void); - -static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id); -static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); +static _mali_product_id_t global_product_id = _MALI_PRODUCT_ID_UNKNOWN; +static u32 global_gpu_base_address = 0; +static u32 global_gpu_major_version = 0; +static u32 global_gpu_minor_version = 0; static _mali_osk_errcode_t build_system_info(void); static void cleanup_system_info(_mali_system_info *cleanup); -/** - * @brief handler for MEM_VALIDATION resources - * - * This resource handler is common to all memory systems. It provides a default - * means for validating requests to map in external memory via - * _mali_ukk_map_external_mem. In addition, if _mali_ukk_va_to_pa is - * implemented, then _mali_ukk_va_to_pa can make use of this MEM_VALIDATION - * resource. - * - * MEM_VALIDATION also provide a CPU physical to Mali physical address - * translation, for use by _mali_ukk_map_external_mem. - * - * @note MEM_VALIDATION resources are only to handle simple cases where a - * certain physical address range is allowed to be mapped in by any process, - * e.g. a framebuffer at a fixed location. If the implementor has more complex - * mapping requirements, then they must either: - * - implement their own memory validation function - * - or, integrate with UMP. - * - * @param resource The resource to handle (type MEM_VALIDATION) - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource); - -/* MEM_VALIDATION handler state */ -typedef struct -{ - u32 phys_base; /**< Mali physical base of the memory, page aligned */ - u32 size; /**< size in bytes of the memory, multiple of page size */ - s32 cpu_usage_adjust; /**< Offset to add to Mali Physical address to obtain CPU physical address */ -} _mali_mem_validation_t; +/* system info variables */ +static _mali_osk_lock_t *system_info_lock = NULL; +static _mali_system_info *system_info = NULL; +static u32 system_info_size = 0; +static u32 first_pp_offset = 0; -#define INVALID_MEM 0xffffffff +#define HANG_CHECK_MSECS_DEFAULT 500 /* 500 ms */ +#define WATCHDOG_MSECS_DEFAULT 4000 /* 4 s */ -static _mali_mem_validation_t mem_validator = { INVALID_MEM, INVALID_MEM, -1 }; +/* timer related */ +int mali_max_job_runtime = WATCHDOG_MSECS_DEFAULT; +int mali_hang_check_interval = HANG_CHECK_MSECS_DEFAULT; -static struct mali_kernel_subsystem mali_subsystem_core = +static _mali_osk_resource_t *mali_find_resource(_mali_osk_resource_type_t type, u32 offset) { - mali_kernel_subsystem_core_setup, /* startup */ - mali_kernel_subsystem_core_cleanup, /* shutdown */ - NULL, /* load_complete */ - mali_kernel_subsystem_core_system_info_fill, /* system_info_fill */ - mali_kernel_subsystem_core_session_begin, /* session_begin */ - NULL, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; + int i; + u32 addr = global_gpu_base_address + offset; -static struct mali_kernel_subsystem * subsystems[] = -{ + for (i = 0; i < num_resources; i++) + { + if (type == arch_configuration[i].type && arch_configuration[i].base == addr) + { + return &(arch_configuration[i]); + } + } -#if USING_MALI_PMM - /* The PMM must be initialized before any cores - including L2 cache */ - &mali_subsystem_pmm, -#endif + return NULL; +} - /* always included */ - &mali_subsystem_memory, +static u32 mali_count_resources(_mali_osk_resource_type_t type) +{ + int i; + u32 retval = 0; - /* The rendercore subsystem must be initialized before any subsystem based on the - * rendercores is started e.g. mali_subsystem_mali200 and mali_subsystem_gp2 */ - &mali_subsystem_rendercore, + for (i = 0; i < num_resources; i++) + { + if (type == arch_configuration[i].type) + { + retval++; + } + } - /* add reference to the subsystem */ - &mali_subsystem_mali200, + return retval; +} - /* add reference to the subsystem */ - &mali_subsystem_gp2, -#if defined USING_MALI400_L2_CACHE - &mali_subsystem_l2_cache, -#endif +static _mali_osk_errcode_t mali_parse_gpu_base_and_first_pp_offset_address(void) +{ + int i; + _mali_osk_resource_t *first_gp_resource = NULL; + _mali_osk_resource_t *first_pp_resource = NULL; + + for (i = 0; i < num_resources; i++) + { + if (MALI_GP == arch_configuration[i].type) + { + if (NULL == first_gp_resource || first_gp_resource->base > arch_configuration[i].base) + { + first_gp_resource = &(arch_configuration[i]); + } + } + if (MALI_PP == arch_configuration[i].type) + { + if (NULL == first_pp_resource || first_pp_resource->base > arch_configuration[i].base) + { + first_pp_resource = &(arch_configuration[i]); + } + } + } - /* always included */ - /* NOTE Keep the core entry at the tail of the list */ - &mali_subsystem_core -}; + if (NULL == first_gp_resource || NULL == first_pp_resource) + { + MALI_PRINT_ERROR(("No GP+PP core specified in config file\n")); + return _MALI_OSK_ERR_FAULT; + } -#define SUBSYSTEMS_COUNT ( sizeof(subsystems) / sizeof(subsystems[0]) ) + if (first_gp_resource->base < first_pp_resource->base) + { + /* GP is first, so we are dealing with Mali-300, Mali-400 or Mali-450 */ + global_gpu_base_address = first_gp_resource->base; + first_pp_offset = 0x8000; + } + else + { + /* PP is first, so we are dealing with Mali-200 */ + global_gpu_base_address = first_pp_resource->base; + first_pp_offset = 0x0; + } + MALI_SUCCESS; +} -/* Pointers to this type available as incomplete struct in mali_kernel_session_manager.h */ -struct mali_session_data +static _mali_osk_errcode_t mali_parse_product_info(void) { - void * subsystem_data[SUBSYSTEMS_COUNT]; - _mali_osk_notification_queue_t * ioctl_queue; -}; + _mali_osk_resource_t *first_pp_resource = NULL; -static mali_kernel_resource_registrator resource_handler[RESOURCE_TYPE_COUNT] = { NULL, }; + /* Find the first PP core */ + first_pp_resource = mali_find_resource(MALI_PP, first_pp_offset); + if (NULL != 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); + if (NULL != group) + { + /*struct mali_pp_core *pp_core = mali_pp_create(first_pp_resource, group, 0);*/ + struct mali_pp_core *pp_core = mali_pp_create(first_pp_resource, group); + if (NULL != pp_core) + { + u32 pp_version = mali_pp_core_get_version(pp_core); + mali_pp_delete(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)); + 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; + default: + MALI_DEBUG_PRINT(2, ("Found unknown Mali GPU 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")); + } -/* system info variables */ -static _mali_osk_lock_t *system_info_lock = NULL; -static _mali_system_info * system_info = NULL; -static u32 system_info_size = 0; + return _MALI_OSK_ERR_FAULT; +} -/* is called from OS specific driver entry point */ -_mali_osk_errcode_t mali_kernel_constructor( void ) +static void mali_delete_clusters(void) { - _mali_osk_errcode_t err; - - err = mali_platform_init(); - if (_MALI_OSK_ERR_OK != err) goto error1; + u32 i; + u32 number_of_clusters = mali_cluster_get_glob_num_clusters(); - err = _mali_osk_init(); - if (_MALI_OSK_ERR_OK != err) goto error2; + for (i = 0; i < number_of_clusters; i++) + { + mali_cluster_delete(mali_cluster_get_global_cluster(i)); + } +} - MALI_DEBUG_PRINT(2, ("\n")); - MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION)); - MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__)); - MALI_DEBUG_PRINT(2, ("Svn revision: %s\n", SVN_REV_STRING)); +static _mali_osk_errcode_t mali_create_cluster(_mali_osk_resource_t *resource) +{ + if (NULL != resource) + { + struct mali_l2_cache_core *l2_cache; - err = initialize_subsystems(); - if (_MALI_OSK_ERR_OK != err) goto error3; + if (mali_l2_cache_core_get_glob_num_l2_cores() >= mali_l2_cache_core_get_max_num_l2_cores()) + { + MALI_PRINT_ERROR(("Found too many L2 cache core objects, max %u is supported\n", mali_l2_cache_core_get_max_num_l2_cores())); + return _MALI_OSK_ERR_FAULT; + } - MALI_PRINT(("Mali device driver %s loaded\n", SVN_REV_STRING)); + MALI_DEBUG_PRINT(3, ("Found L2 cache %s, starting new cluster\n", resource->description)); - MALI_SUCCESS; + /*l2_cache = mali_l2_cache_create(resource, global_num_l2_cache_cores);*/ + l2_cache = mali_l2_cache_create(resource); + if (NULL == l2_cache) + { + MALI_PRINT_ERROR(("Failed to create L2 cache object\n")); + return _MALI_OSK_ERR_FAULT; + } -error3: - MALI_PRINT(("Mali subsystems failed\n")); - _mali_osk_term(); -error2: - MALI_PRINT(("Mali device driver init failed\n")); - if (_MALI_OSK_ERR_OK != mali_platform_deinit()) + if (NULL == mali_cluster_create(l2_cache)) + { + MALI_PRINT_ERROR(("Failed to create cluster object\n")); + mali_l2_cache_delete(l2_cache); + return _MALI_OSK_ERR_FAULT; + } + } + else { - MALI_PRINT(("Failed to deinit platform\n")); + mali_cluster_create(NULL); + if (NULL == mali_cluster_get_global_cluster(0)) + { + MALI_PRINT_ERROR(("Failed to create cluster object\n")); + return _MALI_OSK_ERR_FAULT; + } } -error1: - MALI_PRINT(("Failed to init platform\n")); - MALI_ERROR(err); + + MALI_DEBUG_PRINT(3, ("Created cluster object\n")); + return _MALI_OSK_ERR_OK; } -/* is called from OS specific driver exit point */ -void mali_kernel_destructor( void ) +static _mali_osk_errcode_t mali_parse_config_cluster(void) { - MALI_DEBUG_PRINT(2, ("\n")); - MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION)); -#if USING_MALI_PMM - malipmm_force_powerup(); -#endif - terminate_subsystems(); /* subsystems are responsible for their registered resources */ - _mali_osk_term(); - - if (_MALI_OSK_ERR_OK != mali_platform_deinit()) + if (_MALI_PRODUCT_ID_MALI200 == global_product_id) { - MALI_PRINT(("Failed to deinit platform\n")); + /* Create dummy cluster without L2 cache */ + return mali_create_cluster(NULL); } - MALI_DEBUG_PRINT(2, ("Module unloaded.\n")); -} + else if (_MALI_PRODUCT_ID_MALI300 == global_product_id || _MALI_PRODUCT_ID_MALI400 == global_product_id) + { + _mali_osk_resource_t *l2_resource = mali_find_resource(MALI_L2, 0x1000); + if (NULL == l2_resource) + { + MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache in config file\n")); + return _MALI_OSK_ERR_FAULT; + } -_mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources ) -{ - _mali_osk_resource_t *arch_resource = *arch_configuration; - u32 i; -#if USING_MALI_PMM - u32 is_pmu_first_resource = 1; -#endif /* USING_MALI_PMM */ - - /* loop over arch configuration */ - for (i = 0; i < num_resources; ++i, arch_resource++) - { - if ( (arch_resource->type >= RESOURCE_TYPE_FIRST) && - (arch_resource->type < RESOURCE_TYPE_COUNT) && - (NULL != resource_handler[arch_resource->type]) - ) - { -#if USING_MALI_PMM - if((arch_resource->type != PMU) && (is_pmu_first_resource == 1)) + return mali_create_cluster(l2_resource); + } + else if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + /* + * 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 */ + l2_gp_resource = mali_find_resource(MALI_L2, 0x10000); + if (NULL != l2_gp_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for GP\n")); + ret = mali_create_cluster(l2_gp_resource); + if (_MALI_OSK_ERR_OK != ret) { - _mali_osk_resource_t mali_pmu_virtual_resource; - mali_pmu_virtual_resource.type = PMU; - mali_pmu_virtual_resource.description = "Virtual PMU"; - mali_pmu_virtual_resource.base = 0x00000000; - mali_pmu_virtual_resource.cpu_usage_adjust = 0; - mali_pmu_virtual_resource.size = 0; - mali_pmu_virtual_resource.irq = 0; - mali_pmu_virtual_resource.flags = 0; - mali_pmu_virtual_resource.mmu_id = 0; - mali_pmu_virtual_resource.alloc_order = 0; - MALI_CHECK_NO_ERROR(resource_handler[mali_pmu_virtual_resource.type](&mali_pmu_virtual_resource)); + return ret; } - is_pmu_first_resource = 0; -#endif /* USING_MALI_PMM */ + } + else + { + MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for GP in config file\n")); + return _MALI_OSK_ERR_FAULT; + } - MALI_CHECK_NO_ERROR(resource_handler[arch_resource->type](arch_resource)); - /* the subsystem shutdown process will release all the resources already registered */ + /* Make cluster for first PP core group */ + l2_pp_grp0_resource = mali_find_resource(MALI_L2, 0x1000); + if (NULL != l2_pp_grp0_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for PP group 0\n")); + ret = mali_create_cluster(l2_pp_grp0_resource); + if (_MALI_OSK_ERR_OK != ret) + { + return ret; + } } else { - MALI_DEBUG_PRINT(1, ("No handler installed for resource %s, type %d\n", arch_resource->description, arch_resource->type)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + 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 */ + l2_pp_grp1_resource = mali_find_resource(MALI_L2, 0x11000); + if (NULL != l2_pp_grp1_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for PP group 0\n")); + ret = mali_create_cluster(l2_pp_grp1_resource); + if (_MALI_OSK_ERR_OK != ret) + { + return ret; + } } } - MALI_SUCCESS; + return _MALI_OSK_ERR_OK; } -static _mali_osk_errcode_t initialize_subsystems(void) +static _mali_osk_errcode_t mali_create_group(struct mali_cluster *cluster, + _mali_osk_resource_t *resource_mmu, + _mali_osk_resource_t *resource_gp, + _mali_osk_resource_t *resource_pp) { - int i, j; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; /* default error code */ + struct mali_mmu_core *mmu; + struct mali_group *group; + struct mali_pp_core *pp; - MALI_CHECK_NON_NULL(system_info_lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0 ), _MALI_OSK_ERR_FAULT); + MALI_DEBUG_PRINT(3, ("Starting new group for MMU %s\n", resource_mmu->description)); - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + /* Create the MMU object */ + mmu = mali_mmu_create(resource_mmu); + if (NULL == mmu) { - if (NULL != subsystems[i]->startup) + MALI_PRINT_ERROR(("Failed to create MMU object\n")); + return _MALI_OSK_ERR_FAULT; + } + + /* Create the group object */ + group = mali_group_create(cluster, mmu); + if (NULL == group) + { + MALI_PRINT_ERROR(("Failed to create group object for MMU %s\n", resource_mmu->description)); + mali_mmu_delete(mmu); + return _MALI_OSK_ERR_FAULT; + } + + /* Set pointer back to group in mmu.*/ + mali_mmu_set_group(mmu, group); + + /* Add this group to current cluster */ + mali_cluster_add_group(cluster, group); + + if (NULL != resource_gp) + { + /* Create the GP core object inside this group */ + /* global_gp_core = mali_gp_create(resource_gp, group); */ + if (NULL == mali_gp_create(resource_gp, group)) { - /* the subsystem has a startup function defined */ - err = subsystems[i]->startup(i); /* the subsystem identifier is the offset in our subsystems array */ - if (_MALI_OSK_ERR_OK != err) goto cleanup; + /* 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")); + return _MALI_OSK_ERR_FAULT; } + + /* Add GP object to this group */ + MALI_DEBUG_PRINT(3, ("Adding GP %s to group\n", resource_gp->description)); + mali_group_add_gp_core(group, mali_gp_get_global_gp_core()); } - for (j = 0; j < (int)SUBSYSTEMS_COUNT; ++j) + if (NULL != resource_pp) { - if (NULL != subsystems[j]->load_complete) + /* Create the PP core object inside this group */ + pp = mali_pp_create(resource_pp, group); + + if (NULL == pp) { - /* the subsystem has a load_complete function defined */ - err = subsystems[j]->load_complete(j); - if (_MALI_OSK_ERR_OK != err) goto cleanup; + /* 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")); + return _MALI_OSK_ERR_FAULT; } + + /* Add PP object to this group */ + MALI_DEBUG_PRINT(3, ("Adding PP %s to group\n", resource_pp->description)); + mali_group_add_pp_core(group, pp); } - /* All systems loaded and resources registered */ - /* Build system info */ - if (_MALI_OSK_ERR_OK != build_system_info()) goto cleanup; + return _MALI_OSK_ERR_OK; +} + +static _mali_osk_errcode_t mali_parse_config_groups(void) +{ + if (_MALI_PRODUCT_ID_MALI200 == global_product_id) + { + _mali_osk_resource_t *resource_gp; + _mali_osk_resource_t *resource_pp; + _mali_osk_resource_t *resource_mmu; + + MALI_DEBUG_ASSERT(1 == mali_cluster_get_glob_num_clusters()); - MALI_SUCCESS; /* all ok */ + resource_gp = mali_find_resource(MALI_GP, 0x02000); + resource_pp = mali_find_resource(MALI_PP, 0x00000); + resource_mmu = mali_find_resource(MMU, 0x03000); -cleanup: - /* i is index of subsystem which failed to start, all indices before that has to be shut down */ - for (i = i - 1; i >= 0; --i) + if (NULL == resource_mmu || NULL == resource_gp || NULL == resource_pp) + { + /* Missing mandatory core(s) */ + return _MALI_OSK_ERR_FAULT; + } + + /*return mali_create_group(global_clusters[0], resource_mmu, resource_gp, resource_pp);*/ + return mali_create_group(mali_cluster_get_global_cluster(0), resource_mmu, resource_gp, resource_pp); + } + else if (_MALI_PRODUCT_ID_MALI300 == global_product_id || + _MALI_PRODUCT_ID_MALI400 == global_product_id || + _MALI_PRODUCT_ID_MALI450 == global_product_id) { - /* the subsystem identifier is the offset in our subsystems array */ - /* Call possible shutdown notficiation functions */ - if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i); + _mali_osk_errcode_t err; + 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[mali_pp_get_max_num_pp_cores()]; + _mali_osk_resource_t *resource_pp_mmu[mali_pp_get_max_num_pp_cores()]; + u32 max_num_pp_cores = mali_pp_get_max_num_pp_cores(); + + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + /* Mali-450 has separate L2s for GP, and PP core group(s) */ + cluster_id_pp_grp0 = 1; + cluster_id_pp_grp1 = 2; + } + + resource_gp = mali_find_resource(MALI_GP, 0x00000); + resource_gp_mmu = mali_find_resource(MMU, 0x03000); + resource_pp[0] = mali_find_resource(MALI_PP, 0x08000); + resource_pp[1] = mali_find_resource(MALI_PP, 0x0A000); + resource_pp[2] = mali_find_resource(MALI_PP, 0x0C000); + resource_pp[3] = mali_find_resource(MALI_PP, 0x0E000); + resource_pp[4] = mali_find_resource(MALI_PP, 0x28000); + resource_pp[5] = mali_find_resource(MALI_PP, 0x2A000); + resource_pp[6] = mali_find_resource(MALI_PP, 0x2C000); + resource_pp[7] = mali_find_resource(MALI_PP, 0x2E000); + resource_pp_mmu[0] = mali_find_resource(MMU, 0x04000); + resource_pp_mmu[1] = mali_find_resource(MMU, 0x05000); + resource_pp_mmu[2] = mali_find_resource(MMU, 0x06000); + resource_pp_mmu[3] = mali_find_resource(MMU, 0x07000); + resource_pp_mmu[4] = mali_find_resource(MMU, 0x1C000); + resource_pp_mmu[5] = mali_find_resource(MMU, 0x1D000); + resource_pp_mmu[6] = mali_find_resource(MMU, 0x1E000); + resource_pp_mmu[7] = mali_find_resource(MMU, 0x1F000); + + if (NULL == resource_gp || NULL == resource_gp_mmu || NULL == resource_pp[0] || NULL == resource_pp_mmu[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 (0x%08X, 0x%08X, 0x%08X, 0x%08X)\n", + resource_gp, resource_gp_mmu, resource_pp[0], resource_pp_mmu[0])); + return _MALI_OSK_ERR_FAULT; + } + + MALI_DEBUG_ASSERT(1 <= mali_cluster_get_glob_num_clusters()); + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_gp), resource_gp_mmu, resource_gp, NULL); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + + /* Create group for first (and mandatory) PP core */ + MALI_DEBUG_ASSERT(mali_cluster_get_glob_num_clusters() >= (cluster_id_pp_grp0 + 1)); /* >= 1 on Mali-300 and Mali-400, >= 2 on Mali-450 */ + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp0), resource_pp_mmu[0], NULL, resource_pp[0]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + + /* 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 (NULL != resource_pp[i]) + { + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp0), resource_pp_mmu[i], NULL, resource_pp[i]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + } + } + + /* Create groups for cores in the second PP core group */ + for (i = 4; i < max_num_pp_cores; i++) /* Second half of the PP cores belong to second core group */ + { + if (NULL != resource_pp[i]) + { + MALI_DEBUG_ASSERT(mali_cluster_get_glob_num_clusters() >= 2); /* Only Mali-450 have more than 4 PPs, and these cores belong to second core group */ + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp1), resource_pp_mmu[i], NULL, resource_pp[i]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + } + } } - _mali_osk_lock_term( system_info_lock ); - MALI_ERROR(err); /* err is what the module which failed its startup returned, or the default */ + return _MALI_OSK_ERR_OK; } -static void terminate_subsystems(void) +static _mali_osk_errcode_t mali_parse_config_pmu(void) { - int i; - /* shut down subsystems in reverse order from startup */ - for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i) + _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; + _mali_osk_resource_t *resource_pmu; + u32 number_of_pp_cores; + u32 number_of_l2_caches; + + resource_pmu = mali_find_resource(PMU, 0x02000); + number_of_pp_cores = mali_count_resources(MALI_PP); + number_of_l2_caches = mali_count_resources(MALI_L2); + + if (NULL != resource_pmu) { - /* the subsystem identifier is the offset in our subsystems array */ - if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i); + if (NULL == mali_pmu_create(resource_pmu, number_of_pp_cores, number_of_l2_caches)) + { + err = _MALI_OSK_ERR_FAULT; + } } - if (system_info_lock) _mali_osk_lock_term( system_info_lock ); - - /* Free _mali_system_info struct */ - cleanup_system_info(system_info); + return err; } -void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data) +static _mali_osk_errcode_t mali_parse_config_memory(void) { int i; + _mali_osk_errcode_t ret; - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + for(i = 0; i < num_resources; i++) { - if (NULL != subsystems[i]->broadcast_notification) + switch(arch_configuration[i].type) { - subsystems[i]->broadcast_notification(message, data); + case OS_MEMORY: + ret = mali_memory_core_resource_os_memory(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register OS_MEMORY\n")); + mali_memory_terminate(); + return ret; + } + break; + case MEMORY: + ret = mali_memory_core_resource_dedicated_memory(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register MEMORY\n")); + mali_memory_terminate(); + return ret; + } + break; + case MEM_VALIDATION: + ret = mali_mem_validation_add_range(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register MEM_VALIDATION\n")); + mali_memory_terminate(); + return ret; + } + break; + default: + break; } } + return _MALI_OSK_ERR_OK; } -static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id) +_mali_osk_errcode_t mali_initialize_subsystems(void) { - mali_subsystem_core_id = id; + _mali_osk_errcode_t err; + mali_bool is_pmu_enabled; - /* Register our own resources */ - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MEM_VALIDATION, mali_kernel_core_resource_mem_validation)); + MALI_CHECK_NON_NULL(system_info_lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0 ), _MALI_OSK_ERR_FAULT); - /* parse the arch resource definition and tell all the subsystems */ - /* this is why the core subsystem has to be specified last in the subsystem array */ - MALI_CHECK_NO_ERROR(_mali_osk_resources_init(&arch_configuration, &num_resources)); + err = mali_session_initialize(); + if (_MALI_OSK_ERR_OK != err) goto session_init_failed; - MALI_CHECK_NO_ERROR(register_resources(&arch_configuration, num_resources)); +#if MALI_TIMELINE_PROFILING_ENABLED + err = _mali_osk_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE); + if (_MALI_OSK_ERR_OK != err) + { + /* No biggie if we wheren't able to initialize the profiling */ + MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n")); + } +#endif - /* resource parsing succeeded and the subsystem have corretly accepted their resources */ - MALI_SUCCESS; + /* Build dummy system info. Will be removed in the future. */ + err = build_system_info(); + if (_MALI_OSK_ERR_OK != err) goto build_system_info_failed; + + /* Get data from config.h */ + err = _mali_osk_resources_init(&arch_configuration, &num_resources); + if (_MALI_OSK_ERR_OK != err) goto osk_resources_init_failed; + + /* Initialize driver subsystems */ + err = mali_memory_initialize(); + if (_MALI_OSK_ERR_OK != err) goto memory_init_failed; + + /* Configure memory early. Memory allocation needed for mali_mmu_initialize. */ + err = mali_parse_config_memory(); + if (_MALI_OSK_ERR_OK != err) goto parse_memory_config_failed; + + /* Parsing the GPU base address and first pp offset */ + err = mali_parse_gpu_base_and_first_pp_offset_address(); + if (_MALI_OSK_ERR_OK != err) goto parse_gpu_base_address_failed; + + /* Initialize the MALI PMU */ + err = mali_parse_config_pmu(); + if (_MALI_OSK_ERR_OK != err) goto parse_pmu_config_failed; + + is_pmu_enabled = mali_pmu_get_global_pmu_core() != NULL ? MALI_TRUE : MALI_FALSE; + + /* Initialize the power management module */ + err = mali_pm_initialize(); + if (_MALI_OSK_ERR_OK != err) goto pm_init_failed; + + /* Make sure the power stays on for the rest of this function */ + mali_pm_always_on(MALI_TRUE); + + /* Detect which Mali GPU we are dealing with */ + err = mali_parse_product_info(); + if (_MALI_OSK_ERR_OK != err) goto product_info_parsing_failed; + + /* The global_product_id is now populated with the correct Mali GPU */ + + /* Initialize MMU module */ + err = mali_mmu_initialize(); + if (_MALI_OSK_ERR_OK != err) goto mmu_init_failed; + + /* Initialize the DLBU module for Mali-450 */ + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + err = mali_dlbu_initialize(); + if (_MALI_OSK_ERR_OK != err) goto dlbu_init_failed; + } + + /* Start configuring the actual Mali hardware. */ + err = mali_parse_config_cluster(); + if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; + err = mali_parse_config_groups(); + if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; + + /* Initialize the schedulers */ + err = mali_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto scheduler_init_failed; + err = mali_gp_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto gp_scheduler_init_failed; + err = mali_pp_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto pp_scheduler_init_failed; + +#ifdef CONFIG_MALI400_GPU_UTILIZATION + /* Initialize the GPU utilization tracking */ + err = mali_utilization_init(); + if (_MALI_OSK_ERR_OK != err) goto utilization_init_failed; +#endif + + /* We no longer need to stay */ + mali_pm_always_on(MALI_FALSE); + MALI_SUCCESS; /* all ok */ + + /* Error handling */ +#ifdef CONFIG_MALI400_GPU_UTILIZATION +utilization_init_failed: + mali_pp_scheduler_terminate(); +#endif +pp_scheduler_init_failed: + mali_gp_scheduler_terminate(); +gp_scheduler_init_failed: + mali_scheduler_terminate(); +scheduler_init_failed: +config_parsing_failed: + mali_delete_clusters(); /* Delete clusters even if config parsing failed. */ + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + mali_dlbu_terminate(); + } +dlbu_init_failed: + mali_mmu_terminate(); +mmu_init_failed: + /* Nothing to roll back */ +product_info_parsing_failed: + mali_pm_terminate(); +pm_init_failed: + if (is_pmu_enabled) + { + mali_pmu_delete(mali_pmu_get_global_pmu_core()); + } +parse_pmu_config_failed: +parse_gpu_base_address_failed: +parse_memory_config_failed: + mali_memory_terminate(); +memory_init_failed: + _mali_osk_resources_term(&arch_configuration, num_resources); +osk_resources_init_failed: + cleanup_system_info(system_info); +build_system_info_failed: +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_term(); +#endif + mali_session_terminate(); +session_init_failed: + return err; +} + +void mali_terminate_subsystems(void) +{ + struct mali_pmu_core *pmu; + MALI_DEBUG_PRINT(2, ("terminate_subsystems() called\n")); + + /* shut down subsystems in reverse order from startup */ + + mali_pm_always_on(MALI_TRUE); /* Mali will be powered off once PM subsystem terminates */ + +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_term(); +#endif + + mali_pp_scheduler_terminate(); + mali_gp_scheduler_terminate(); + mali_scheduler_terminate(); + + mali_delete_clusters(); /* Delete clusters even if config parsing failed. */ + + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + mali_dlbu_terminate(); + } + + mali_mmu_terminate(); + + pmu = mali_pmu_get_global_pmu_core(); + if (NULL != pmu) + { + mali_pmu_delete(pmu); + } + + mali_pm_terminate(); + + mali_memory_terminate(); + + _mali_osk_resources_term(&arch_configuration, num_resources); + + cleanup_system_info(system_info); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_term(); +#endif + + mali_session_terminate(); + + if (NULL != system_info_lock) + { + _mali_osk_lock_term( system_info_lock ); + } +} + +_mali_product_id_t mali_kernel_core_get_product_id(void) +{ + return global_product_id; } -static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id) +void mali_kernel_core_wakeup(void) { - _mali_osk_resources_term(&arch_configuration, num_resources); + u32 i; + u32 glob_num_clusters = mali_cluster_get_glob_num_clusters(); + struct mali_cluster *cluster; + + for (i = 0; i < glob_num_clusters; i++) + { + cluster = mali_cluster_get_global_cluster(i); + mali_cluster_reset(cluster); + } } static void cleanup_system_info(_mali_system_info *cleanup) @@ -373,11 +834,10 @@ static void cleanup_system_info(_mali_system_info *cleanup) _mali_osk_free(cleanup); } +/* Build a dummy system info struct. User space still need this. */ static _mali_osk_errcode_t build_system_info(void) { - unsigned int i; - int err = _MALI_OSK_ERR_FAULT; - _mali_system_info * new_info, * cleanup; + _mali_system_info * new_info; _mali_core_info * current_core; _mali_mem_info * current_mem; u32 new_size = 0; @@ -387,19 +847,25 @@ static _mali_osk_errcode_t build_system_info(void) _mali_osk_memset(new_info, 0, sizeof(_mali_system_info)); - /* if an error happens during any of the system_info_fill calls cleanup the new info structs */ - cleanup = new_info; + /* fill in the info */ + new_info->has_mmu = 1; + new_info->drivermode = _MALI_DRIVER_MODE_NORMAL; - /* ask each subsystems to fill in their info */ - for (i = 0; i < SUBSYSTEMS_COUNT; ++i) + new_info->core_info = NULL; /* Not used by user space */ + + new_info->mem_info = _mali_osk_calloc(1, sizeof(_mali_mem_info)); + if(NULL == new_info->mem_info) { - if (NULL != subsystems[i]->system_info_fill) - { - err = subsystems[i]->system_info_fill(new_info); - if (_MALI_OSK_ERR_OK != err) goto error_exit; - } + _mali_osk_free(new_info); + return _MALI_OSK_ERR_NOMEM; } + new_info->mem_info->size = 1024 * 1024 * 1024; /* 1GiB */ + new_info->mem_info->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE; + new_info->mem_info->maximum_order_supported = 30; + new_info->mem_info->identifier = 0; + new_info->mem_info->next = NULL; + /* building succeeded, calculate the size */ /* size needed of the system info struct itself */ @@ -420,8 +886,6 @@ static _mali_osk_errcode_t build_system_info(void) /* lock system info access so a user wont't get a corrupted version */ _mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW ); - /* cleanup the old one */ - cleanup = system_info; /* set new info */ system_info = new_info; system_info_size = new_size; @@ -430,25 +894,15 @@ static _mali_osk_errcode_t build_system_info(void) _mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW ); /* ok result */ - err = _MALI_OSK_ERR_OK; - - /* we share the cleanup routine with the error case */ -error_exit: - if (NULL == cleanup) MALI_ERROR((_mali_osk_errcode_t)err); /* no cleanup needed, return what err contains */ - - /* cleanup */ - cleanup_system_info(cleanup); - - /* return whatever err is, we could end up here in both the error and success cases */ - MALI_ERROR((_mali_osk_errcode_t)err); + return _MALI_OSK_ERR_OK; } _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ) { - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - /* check compatability */ + /* check compatability */ if ( args->version == _MALI_UK_API_VERSION ) { args->compatible = 1; @@ -461,14 +915,14 @@ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args args->version = _MALI_UK_API_VERSION; /* report our version */ /* success regardless of being compatible or not */ - MALI_SUCCESS; + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_get_system_info_size(_mali_uk_get_system_info_size_s *args) { - MALI_DEBUG_ASSERT_POINTER(args); - args->size = system_info_size; - MALI_SUCCESS; + MALI_DEBUG_ASSERT_POINTER(args); + args->size = system_info_size; + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args ) @@ -477,12 +931,12 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args _mali_mem_info * current_mem; _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; void * current_write_pos, ** current_patch_pos; - u32 adjust_ptr_base; + u32 adjust_ptr_base; /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS); /* lock the system info */ _mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW ); @@ -491,20 +945,20 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args if (args->size < system_info_size) goto exit_when_locked; /* we build a copy of system_info in the user space buffer specified by the user and - * patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may - * indicate a different base address for patching the pointers (normally the - * address of the provided system_info buffer would be used). This is helpful when - * the system_info buffer needs to get copied to user space and the pointers need - * to be in user space. - */ - if (0 == args->ukk_private) - { - adjust_ptr_base = (u32)args->system_info; - } - else - { - adjust_ptr_base = args->ukk_private; - } + * patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may + * indicate a different base address for patching the pointers (normally the + * address of the provided system_info buffer would be used). This is helpful when + * the system_info buffer needs to get copied to user space and the pointers need + * to be in user space. + */ + if (0 == args->ukk_private) + { + adjust_ptr_base = (u32)args->system_info; + } + else + { + adjust_ptr_base = args->ukk_private; + } /* copy each struct into the buffer, and update its pointers */ current_write_pos = (void *)args->system_info; @@ -557,56 +1011,56 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args err = _MALI_OSK_ERR_OK; exit_when_locked: _mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW ); - MALI_ERROR(err); + MALI_ERROR(err); } _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; + _mali_osk_notification_t *notification; + _mali_osk_notification_queue_t *queue; - /* check input */ + /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id); + queue = ((struct mali_session_data *)args->ctx)->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; + args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS; MALI_SUCCESS; } - /* receive a notification, might sleep */ + /* 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 */ - } + 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); + 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 ); - MALI_SUCCESS; /* all ok */ + MALI_SUCCESS; /* 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; + _mali_osk_notification_queue_t *queue; - /* check input */ + /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id); + queue = ((struct mali_session_data *)args->ctx)->ioctl_queue; /* if the queue does not exist we're currently shutting down */ if (NULL == queue) @@ -618,294 +1072,115 @@ _mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *a notification = _mali_osk_notification_create(args->type, 0); if ( NULL == notification) { - MALI_PRINT_ERROR( ("Failed to create notification object\n")) ; + MALI_PRINT_ERROR( ("Failed to create notification object\n")); return _MALI_OSK_ERR_NOMEM; } _mali_osk_notification_queue_send(queue, notification); - MALI_SUCCESS; /* all ok */ -} - -static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info) -{ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - info->drivermode = _MALI_DRIVER_MODE_NORMAL; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - MALI_CHECK_NON_NULL(slot, _MALI_OSK_ERR_INVALID_ARGS); - *slot = queue; - MALI_SUCCESS; -} - -/* MEM_VALIDATION resource handler */ -static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource) -{ - /* Check that no other MEM_VALIDATION resources exist */ - MALI_CHECK( ((u32)-1) == mem_validator.phys_base, _MALI_OSK_ERR_FAULT ); - - /* Check restrictions on page alignment */ - MALI_CHECK( 0 == (resource->base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == (resource->size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == (resource->cpu_usage_adjust & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - - mem_validator.phys_base = resource->base; - mem_validator.size = resource->size; - mem_validator.cpu_usage_adjust = resource->cpu_usage_adjust; - MALI_DEBUG_PRINT( 2, ("Memory Validator '%s' installed for Mali physical address base==0x%08X, size==0x%08X, cpu_adjust==0x%08X\n", - resource->description, mem_validator.phys_base, mem_validator.size, mem_validator.cpu_usage_adjust )); - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size ) -{ - u32 mali_phys_base; - - mali_phys_base = *phys_base - mem_validator.cpu_usage_adjust; - - MALI_CHECK( 0 == ( mali_phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - - MALI_CHECK_NO_ERROR( mali_kernel_core_validate_mali_phys_range( mali_phys_base, size ) ); - - *phys_base = mali_phys_base; - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size ) -{ - MALI_CHECK_GOTO( 0 == ( phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), failure ); - MALI_CHECK_GOTO( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), failure ); - - if ( phys_base >= mem_validator.phys_base - && (phys_base + size) >= mem_validator.phys_base - && phys_base <= (mem_validator.phys_base + mem_validator.size) - && (phys_base + size) <= (mem_validator.phys_base + mem_validator.size) ) - { - MALI_SUCCESS; - } - - failure: - MALI_PRINTF( ("*******************************************************************************\n") ); - MALI_PRINTF( ("MALI PHYSICAL RANGE VALIDATION ERROR!\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("We failed to validate a Mali-Physical range that the user-side wished to map in\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("It is likely that the user-side wished to do Direct Rendering, but a suitable\n") ); - MALI_PRINTF( ("address range validation mechanism has not been correctly setup\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_base, size) ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("Please refer to the ARM Mali Software Integration Guide for more information.\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("*******************************************************************************\n") ); - - MALI_ERROR( _MALI_OSK_ERR_FAULT ); -} - - -_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler) -{ - MALI_CHECK(type < RESOURCE_TYPE_COUNT, _MALI_OSK_ERR_INVALID_ARGS); - MALI_DEBUG_ASSERT(NULL == resource_handler[type]); /* A handler for resource already exists */ - resource_handler[type] = handler; - MALI_SUCCESS; -} - -void * mali_kernel_session_manager_slot_get(struct mali_session_data * session_data, int id) -{ - MALI_DEBUG_ASSERT_POINTER(session_data); - if(id >= SUBSYSTEMS_COUNT) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: id %d out of range\n", id)); return NULL; } - - if (NULL == session_data) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: got NULL session data\n")); return NULL; } - return session_data->subsystem_data[id]; + MALI_SUCCESS; /* all ok */ } _mali_osk_errcode_t _mali_ukk_open(void **context) { - int i; - _mali_osk_errcode_t err; - struct mali_session_data * session_data; + struct mali_session_data *session_data; /* allocated struct to track this session */ - session_data = (struct mali_session_data *)_mali_osk_malloc(sizeof(struct mali_session_data)); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM); + session_data = (struct mali_session_data *)_mali_osk_calloc(1, sizeof(struct mali_session_data)); + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM); - _mali_osk_memset(session_data->subsystem_data, 0, sizeof(session_data->subsystem_data)); + MALI_DEBUG_PRINT(2, ("Session starting\n")); /* create a response queue for this session */ session_data->ioctl_queue = _mali_osk_notification_queue_init(); if (NULL == session_data->ioctl_queue) { _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - MALI_DEBUG_PRINT(3, ("Session starting\n")); - - /* call session_begin on all subsystems */ - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + session_data->page_directory = mali_mmu_pagedir_alloc(); + if (NULL == session_data->page_directory) { - if (NULL != subsystems[i]->session_begin) - { - /* subsystem has a session_begin */ - err = subsystems[i]->session_begin(session_data, &session_data->subsystem_data[i], session_data->ioctl_queue); - MALI_CHECK_GOTO(err == _MALI_OSK_ERR_OK, cleanup); - } + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - *context = (void*)session_data; + if (_MALI_OSK_ERR_OK != mali_mmu_pagedir_map(session_data->page_directory, MALI_DLB_VIRT_ADDR, _MALI_OSK_MALI_PAGE_SIZE)) + { + MALI_PRINT_ERROR(("Failed to map DLB page into session\n")); + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } - MALI_DEBUG_PRINT(3, ("Session started\n")); - MALI_SUCCESS; + if (0 != mali_dlbu_phys_addr) + { + mali_mmu_pagedir_update(session_data->page_directory, MALI_DLB_VIRT_ADDR, mali_dlbu_phys_addr, _MALI_OSK_MALI_PAGE_SIZE); + } -cleanup: - MALI_DEBUG_PRINT(2, ("Session startup failed\n")); - /* i is index of subsystem which failed session begin, all indices before that has to be ended */ - /* end subsystem sessions in the reverse order they where started in */ - for (i = i - 1; i >= 0; --i) + if (_MALI_OSK_ERR_OK != mali_memory_session_begin(session_data)) { - if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]); + mali_mmu_pagedir_free(session_data->page_directory); + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - _mali_osk_notification_queue_term(session_data->ioctl_queue); - _mali_osk_free(session_data); + *context = (void*)session_data; - /* return what the subsystem which failed session start returned */ - MALI_ERROR(err); + /* Add session to the list of all sessions. */ + mali_session_add(session_data); + + MALI_DEBUG_PRINT(3, ("Session started\n")); + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_close(void **context) { - int i; - struct mali_session_data * session_data; + struct mali_session_data *session; + MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); + session = (struct mali_session_data *)*context; - MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); + MALI_DEBUG_PRINT(3, ("Session ending\n")); - session_data = (struct mali_session_data *)*context; + /* Remove session from list of all sessions. */ + mali_session_remove(session); - MALI_DEBUG_PRINT(2, ("Session ending\n")); + /* Abort queued and running jobs */ + mali_gp_scheduler_abort_session(session); + mali_pp_scheduler_abort_session(session); - /* end subsystem sessions in the reverse order they where started in */ - for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i) - { - if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]); - } + /* 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_flush_workqueue(NULL); - _mali_osk_notification_queue_term(session_data->ioctl_queue); - _mali_osk_free(session_data); + /* Free remaining memory allocated to this session */ + mali_memory_session_end(session); - *context = NULL; + /* Free session data structures */ + mali_mmu_pagedir_free(session->page_directory); + _mali_osk_notification_queue_term(session->ioctl_queue); + _mali_osk_free(session); - MALI_DEBUG_PRINT(2, ("Session has ended\n")); - - MALI_SUCCESS; -} + *context = NULL; -#if USING_MALI_PMM - -_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only ) -{ - switch( core ) - { - case MALI_PMM_CORE_GP: - MALI_CHECK_NO_ERROR(maligp_signal_power_up(queue_only)); - break; -#if defined USING_MALI400_L2_CACHE - case MALI_PMM_CORE_L2: - if( !queue_only ) - { - /* Enable L2 cache due to power up */ - mali_kernel_l2_cache_do_enable(); + MALI_DEBUG_PRINT(2, ("Session has ended\n")); - /* Invalidate the cache on power up */ - MALI_DEBUG_PRINT(5, ("L2 Cache: Invalidate all\n")); - MALI_CHECK_NO_ERROR(mali_kernel_l2_cache_invalidate_all()); - } - break; -#endif - case MALI_PMM_CORE_PP0: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(0, queue_only)); - break; - case MALI_PMM_CORE_PP1: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(1, queue_only)); - break; - case MALI_PMM_CORE_PP2: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(2, queue_only)); - break; - case MALI_PMM_CORE_PP3: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(3, queue_only)); - break; - default: - /* Unknown core */ - MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power up: %d\n", core) ); - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); - } - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only ) -{ - switch( core ) - { - case MALI_PMM_CORE_GP: - MALI_CHECK_NO_ERROR(maligp_signal_power_down(immediate_only)); - break; -#if defined USING_MALI400_L2_CACHE - case MALI_PMM_CORE_L2: - /* Nothing to do */ - break; -#endif - case MALI_PMM_CORE_PP0: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(0, immediate_only)); - break; - case MALI_PMM_CORE_PP1: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(1, immediate_only)); - break; - case MALI_PMM_CORE_PP2: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(2, immediate_only)); - break; - case MALI_PMM_CORE_PP3: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(3, immediate_only)); - break; - default: - /* Unknown core */ - MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power down: %d\n", core) ); - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); - } - MALI_SUCCESS; } -#endif - - #if MALI_STATE_TRACKING u32 _mali_kernel_core_dump_state(char* buf, u32 size) { - int i, n; - char *original_buf = buf; - for (i = 0; i < SUBSYSTEMS_COUNT; ++i) - { - if (NULL != subsystems[i]->dump_state) - { - n = subsystems[i]->dump_state(buf, size); - size -= n; - buf += n; - } - } -#if USING_MALI_PMM - n = mali_pmm_dump_os_thread_state(buf, size); - size -= n; - buf += n; -#endif - /* Return number of bytes written to buf */ - return (u32)(buf - original_buf); + int n = 0; /* Number of bytes written to buf */ + + n += mali_gp_scheduler_dump_state(buf + n, size - n); + n += mali_pp_scheduler_dump_state(buf + n, size - n); + + return n; } #endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_core.h b/drivers/media/video/samsung/mali/common/mali_kernel_core.h index 715c1cd..d424c48 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_core.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_core.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -13,122 +13,27 @@ #include "mali_osk.h" -#if USING_MALI_PMM -#include "mali_ukk.h" -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#endif +extern int mali_hang_check_interval; +extern int mali_max_job_runtime; -_mali_osk_errcode_t mali_kernel_constructor( void ); -void mali_kernel_destructor( void ); +typedef enum +{ + _MALI_PRODUCT_ID_UNKNOWN, + _MALI_PRODUCT_ID_MALI200, + _MALI_PRODUCT_ID_MALI300, + _MALI_PRODUCT_ID_MALI400, + _MALI_PRODUCT_ID_MALI450, +} _mali_product_id_t; -/** - * @brief Tranlate CPU physical to Mali physical addresses. - * - * This function is used to convert CPU physical addresses to Mali Physical - * addresses, such that _mali_ukk_map_external_mem may be used to map them - * into Mali. This will be used by _mali_ukk_va_to_mali_pa. - * - * This function only supports physically contiguous regions. - * - * A default implementation is provided, which uses a registered MEM_VALIDATION - * resource to do a static translation. Only an address range which will lie - * in the range specified by MEM_VALIDATION will be successfully translated. - * - * If a more complex, or non-static translation is required, then the - * implementor has the following options: - * - Rewrite this function to provide such a translation - * - Integrate the provider of the memory with UMP. - * - * @param[in,out] phys_base pointer to the page-aligned base address of the - * physical range to be translated - * - * @param[in] size size of the address range to be translated, which must be a - * multiple of the physical page size. - * - * @return on success, _MALI_OSK_ERR_OK and *phys_base is translated. If the - * cpu physical address range is not in the valid range, then a suitable - * _mali_osk_errcode_t error. - * - */ -_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size ); - - -/** - * @brief Validate a Mali physical address range. - * - * This function is used to ensure that an address range passed to - * _mali_ukk_map_external_mem is allowed to be mapped into Mali. - * - * This function only supports physically contiguous regions. - * - * A default implementation is provided, which uses a registered MEM_VALIDATION - * resource to do a static translation. Only an address range which will lie - * in the range specified by MEM_VALIDATION will be successfully validated. - * - * If a more complex, or non-static validation is required, then the - * implementor has the following options: - * - Rewrite this function to provide such a validation - * - Integrate the provider of the memory with UMP. - * - * @param phys_base page-aligned base address of the Mali physical range to be - * validated. - * - * @param size size of the address range to be validated, which must be a - * multiple of the physical page size. - * - * @return _MALI_OSK_ERR_OK if the Mali physical range is valid. Otherwise, a - * suitable _mali_osk_errcode_t error. - * - */ -_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size ); +_mali_osk_errcode_t mali_initialize_subsystems(void); -#if USING_MALI_PMM -/** - * @brief Signal a power up on a Mali core. - * - * This function flags a core as powered up. - * For PP and GP cores it calls functions that move the core from a power off - * queue into the idle queue ready to run jobs. It also tries to schedule any - * pending jobs to run on it. - * - * This function will fail if the core is not powered off - either running or - * already idle. - * - * @param core The PMM core id to power up. - * @param queue_only When MALI_TRUE only re-queue the core - do not reset. - * - * @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a - * suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only ); - -/** - * @brief Signal a power down on a Mali core. - * - * This function flags a core as powered down. - * For PP and GP cores it calls functions that move the core from an idle - * queue into the power off queue. - * - * This function will fail if the core is not idle - either running or - * already powered down. - * - * @param core The PMM core id to power up. - * @param immediate_only Do not set the core to pending power down if it can't - * power down immediately - * - * @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a - * suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only ); +void mali_terminate_subsystems(void); -#endif +void mali_kernel_core_wakeup(void); -/** - * Flag to indicate whether or not mali_benchmark is turned on. - */ -extern int mali_benchmark; +_mali_product_id_t mali_kernel_core_get_product_id(void); +u32 _mali_kernel_core_dump_state(char* buf, u32 size); #endif /* __MALI_KERNEL_CORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c index 8b2a97d..b9f05ca 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 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. @@ -40,11 +40,7 @@ mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int m map->table = descriptor_table_alloc(init_entries); if (NULL != map->table) { -#if !USING_MMU - map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 20); -#else - map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 116); -#endif + map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP); if (NULL != map->lock) { _mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */ @@ -151,15 +147,20 @@ _mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, i MALI_ERROR(result); } -void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor) +void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor) { + void *old_value = NULL; + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { + old_value = map->table->mappings[descriptor]; map->table->mappings[descriptor] = NULL; _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage); } _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW); + + return old_value; } static mali_descriptor_table * descriptor_table_alloc(int count) diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h index 745be92..82ed94d 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 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. @@ -93,7 +93,9 @@ void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void ( * For the descriptor to be reused it has to be freed * @param map The map to free the descriptor from * @param descriptor The descriptor ID to free + * + * @return old value of descriptor mapping */ -void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor); +void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor); #endif /* __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_gp.h b/drivers/media/video/samsung/mali/common/mali_kernel_gp.h deleted file mode 100644 index efd3b43..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_gp.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_KERNEL_GP2_H__ -#define __MALI_KERNEL_GP2_H__ - -extern struct mali_kernel_subsystem mali_subsystem_gp2; - -#if USING_MALI_PMM -_mali_osk_errcode_t maligp_signal_power_up( mali_bool queue_only ); -_mali_osk_errcode_t maligp_signal_power_down( mali_bool immediate_only ); -#endif - -#endif /* __MALI_KERNEL_GP2_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c b/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c deleted file mode 100644 index e4d4ab1..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (C) 2010 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_osk.h" -#include "mali_osk_list.h" - -#include "mali_kernel_core.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_subsystem.h" -#include "regs/mali_200_regs.h" -#include "mali_kernel_rendercore.h" -#include "mali_kernel_l2_cache.h" - -/** - * Size of the Mali L2 cache registers in bytes - */ -#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30 - -/** - * Mali L2 cache register numbers - * Used in the register read/write routines. - * See the hardware documentation for more information about each register - */ -typedef enum mali_l2_cache_register { - MALI400_L2_CACHE_REGISTER_STATUS = 0x0002, - /*unused = 0x0003 */ - MALI400_L2_CACHE_REGISTER_COMMAND = 0x0004, /**< Misc cache commands, e.g. clear */ - MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0005, - MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0006, /**< Limit of outstanding read requests */ - MALI400_L2_CACHE_REGISTER_ENABLE = 0x0007, /**< Enable misc cache features */ - MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0008, - MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0009, - MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x000A, - MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x000B, -} mali_l2_cache_register; - - -/** - * Mali L2 cache commands - * These are the commands that can be sent to the Mali L2 cache unit - */ -typedef enum mali_l2_cache_command -{ - MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */ - /* Read HW TRM carefully before adding/using other commands than the clear above */ -} mali_l2_cache_command; - -/** - * Mali L2 cache commands - * These are the commands that can be sent to the Mali L2 cache unit - */ -typedef enum mali_l2_cache_enable -{ - MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */ - MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */ - MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */ -} mali_l2_cache_enable; - -/** - * Mali L2 cache status bits - */ -typedef enum mali_l2_cache_status -{ - MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */ - MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */ -} mali_l2_cache_status; - - -/** - * Definition of the L2 cache core struct - * Used to track a L2 cache unit in the system. - * Contains information about the mapping of the registers - */ -typedef struct mali_kernel_l2_cache_core -{ - unsigned long base; /**< Physical address of the registers */ - mali_io_address mapped_registers; /**< Virtual mapping of the registers */ - u32 mapping_size; /**< Size of registers in bytes */ - _mali_osk_list_t list; /**< Used to link multiple cache cores into a list */ - _mali_osk_lock_t *lock; /**< Serialize all L2 cache commands */ -} mali_kernel_l2_cache_core; - - -#define MALI400_L2_MAX_READS_DEFAULT 0x1C - -int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT; - - -/** - * Mali L2 cache subsystem startup function - * Called by the driver core when the driver is loaded. - * - * @param id Identifier assigned by the core to the L2 cache subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id); - -/** - * Mali L2 cache subsystem shutdown function - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the L2 cache subsystem - */ -static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id); - -/** - * L2 cache subsystem complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * @param id Identifier assigned by the core to the L2 cache subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id); - -/** - * Mali L2 cache subsystem's notification handler for a Mali L2 cache resource instances. - * Registered with the core during startup. - * Called by the core for each Mali L2 cache described in the active architecture's config.h file. - * @param resource The resource to handle (type MALI400L2) - * @return 0 if the Mali L2 cache was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource); - -/** - * Write to a L2 cache register - * Writes the given value to the specified register - * @param unit The L2 cache to write to - * @param reg The register to write to - * @param val The value to write to the register - */ -static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val); - - - -/** - * Invalidate specified L2 cache - * @param cache The L2 cache to invalidate - * @return 0 if Mali L2 cache was successfully invalidated, otherwise error - */ -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache); - - -/* - The fixed Mali L2 cache system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_l2_cache = -{ - mali_l2_cache_initialize, /**< startup */ - NULL, /*mali_l2_cache_terminate,*/ /**< shutdown */ - mali_l2_cache_load_complete, /**< load_complete */ - NULL, /**< system_info_fill */ - NULL, /**< session_begin */ - NULL, /**< session_end */ - NULL, /**< broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /**< dump_state */ -#endif -}; - - - -static _MALI_OSK_LIST_HEAD(caches_head); - - - - -/* called during module init */ -static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id) -{ - _mali_osk_errcode_t err; - - MALI_IGNORE( id ); - - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system initializing\n")); - - _MALI_OSK_INIT_LIST_HEAD(&caches_head); - - /* This will register the function for adding Mali L2 cache cores to the subsystem */ - err = _mali_kernel_core_register_resource_handler(MALI400L2, mali_l2_cache_core_create); - - MALI_ERROR(err); -} - - - -/* called if/when our module is unloaded */ -static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system terminating\n")); - - /* loop over all L2 cache units and shut them down */ - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list ) - { - /* reset to defaults */ - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT); - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT); - - /* remove from the list of cacges on the system */ - _mali_osk_list_del( &cache->list ); - - /* release resources */ - _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers ); - _mali_osk_mem_unreqregion( cache->base, cache->mapping_size ); - _mali_osk_lock_term( cache->lock ); - _mali_osk_free( cache ); - - #if USING_MALI_PMM - /* Unregister the L2 cache with the PMM */ - malipmm_core_unregister( MALI_PMM_CORE_L2 ); - #endif - } -} - -static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT ; - mali_kernel_l2_cache_core * cache = NULL; - - MALI_DEBUG_PRINT(2, ( "Creating Mali L2 cache: %s\n", resource->description)); - -#if USING_MALI_PMM - /* Register the L2 cache with the PMM */ - err = malipmm_core_register( MALI_PMM_CORE_L2 ); - if( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT(1, ( "Failed to register L2 cache unit with PMM")); - return err; - } -#endif - - err = _mali_osk_mem_reqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE, resource->description); - - MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup_requestmem_failed); - - /* Reset error that might be passed out */ - err = _MALI_OSK_ERR_FAULT; - - cache = _mali_osk_malloc(sizeof(mali_kernel_l2_cache_core)); - - MALI_CHECK_GOTO( NULL != cache, err_cleanup); - - cache->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 104 ); - - MALI_CHECK_GOTO( NULL != cache->lock, err_cleanup); - - /* basic setup */ - _MALI_OSK_INIT_LIST_HEAD(&cache->list); - - cache->base = resource->base; - cache->mapping_size = MALI400_L2_CACHE_REGISTERS_SIZE; - - /* map the registers */ - cache->mapped_registers = _mali_osk_mem_mapioregion( cache->base, cache->mapping_size, resource->description ); - - MALI_CHECK_GOTO( NULL != cache->mapped_registers, err_cleanup); - - /* Invalidate cache (just to keep it in a known state at startup) */ - err = mali_kernel_l2_cache_invalidate_all_cache(cache); - - MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup); - - /* add to our list of L2 caches */ - _mali_osk_list_add( &cache->list, &caches_head ); - - MALI_SUCCESS; - -err_cleanup: - /* This cleanup used when resources have been requested successfully */ - - if ( NULL != cache ) - { - if (NULL != cache->mapped_registers) - { - _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to map Mali L2 cache registers at 0x%08lX\n", cache->base)); - } - - if( NULL != cache->lock ) - { - _mali_osk_lock_term( cache->lock ); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to allocate a lock for handling a L2 cache unit")); - } - - _mali_osk_free( cache ); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to allocate memory for handling a L2 cache unit")); - } - - /* A call is to request region, so this must always be reversed */ - _mali_osk_mem_unreqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE); -#if USING_MALI_PMM - malipmm_core_unregister( MALI_PMM_CORE_L2 ); -#endif - return err; - -err_cleanup_requestmem_failed: - MALI_DEBUG_PRINT(1, ("Failed to request Mali L2 cache '%s' register address space at (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI400_L2_CACHE_REGISTERS_SIZE - 1) ); -#if USING_MALI_PMM - malipmm_core_unregister( MALI_PMM_CORE_L2 ); -#endif - return err; - -} - - -static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val) -{ - _mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val); -} - - -static u32 mali_l2_cache_register_read(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg) -{ - return _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32)); -} - -void mali_kernel_l2_cache_do_enable(void) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and enable them*/ - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE); - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads); - } -} - - -static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_kernel_l2_cache_do_enable(); - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system load complete\n")); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_l2_cache_send_command(mali_kernel_l2_cache_core *cache, u32 reg, u32 val) -{ - int i = 0; - const int loop_count = 100000; - - /* - * Grab lock in order to send commands to the L2 cache in a serialized fashion. - * The L2 cache will ignore commands if it is busy. - */ - _mali_osk_lock_wait(cache->lock, _MALI_OSK_LOCKMODE_RW); - - /* First, wait for L2 cache command handler to go idle */ - - for (i = 0; i < loop_count; i++) - { - if (!(_mali_osk_mem_ioread32(cache->mapped_registers , (u32)MALI400_L2_CACHE_REGISTER_STATUS * sizeof(u32)) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY)) - { - break; - } - } - - if (i == loop_count) - { - _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n")); - MALI_ERROR( _MALI_OSK_ERR_FAULT ); - } - - /* then issue the command */ - mali_l2_cache_register_write(cache, reg, val); - - _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW); - MALI_SUCCESS; -} - - -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache) -{ - return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); -} - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and invalidate them */ - - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_all_cache(cache) ); - } - - MALI_SUCCESS; -} - - -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page_cache(mali_kernel_l2_cache_core *cache, u32 page) -{ - return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, page); -} - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and invalidate them */ - - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_page_cache(cache, page) ); - } - - MALI_SUCCESS; -} - - -void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - int reset0 = force_reset; - int reset1 = force_reset; - MALI_DEBUG_CODE( - int changed0 = 0; - int changed1 = 0; - ) - - /* loop over all L2 cache units and activate the counters on them */ - _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0); - u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1); - - if (src0 != cur_src0) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, src0); - MALI_DEBUG_CODE(changed0 = 1;) - reset0 = 1; - } - - if (src1 != cur_src1) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, src1); - MALI_DEBUG_CODE(changed1 = 1;) - reset1 = 1; - } - - if (reset0) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0, 0); - } - - if (reset1) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1, 0); - } - - MALI_DEBUG_PRINT(5, ("L2 cache counters set: SRC0=%u, CHANGED0=%d, RESET0=%d, SRC1=%u, CHANGED1=%d, RESET1=%d\n", - src0, changed0, reset0, - src1, changed1, reset1)); - } -} - - -void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - int first_time = 1; - *src0 = 0; - *src1 = 0; - *val0 = 0; - *val1 = 0; - - /* loop over all L2 cache units and read the counters */ - _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0); - u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1); - u32 cur_val0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0); - u32 cur_val1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); - - MALI_DEBUG_PRINT(5, ("L2 cache counters get: SRC0=%u, VAL0=%u, SRC1=%u, VAL1=%u\n", cur_src0, cur_val0, cur_src1, cur_val1)); - - /* Only update the counter source once, with the value from the first L2 cache unit. */ - if (first_time) - { - *src0 = cur_src0; - *src1 = cur_src1; - first_time = 0; - } - - /* Bail out if the L2 cache units have different counters set. */ - if (*src0 == cur_src0 && *src1 == cur_src1) - { - *val0 += cur_val0; - *val1 += cur_val1; - } - else - { - MALI_DEBUG_PRINT(1, ("Warning: Mali L2 caches has different performance counters set, not retrieving data\n")); - } - } -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h b/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h deleted file mode 100644 index 8c12b50..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_KERNEL_L2_CACHE_H__ -#define __MALI_KERNEL_L2_CACHE_H__ - -#include "mali_osk.h" -#include "mali_kernel_subsystem.h" -extern struct mali_kernel_subsystem mali_subsystem_l2_cache; - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void); -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page); - -void mali_kernel_l2_cache_do_enable(void); -void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset); -void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1); - -#endif /* __MALI_KERNEL_L2_CACHE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c deleted file mode 100644 index e378f03..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c +++ /dev/null @@ -1,1427 +0,0 @@ -/* - * Copyright (C) 2010 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_core.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_descriptor_mapping.h" -#include "mali_kernel_session_manager.h" - -/* kernel side OS functions and user-kernel interface */ -#include "mali_osk.h" -#include "mali_osk_mali.h" -#include "mali_osk_list.h" -#include "mali_ukk.h" - -#ifdef _MALI_OSK_SPECIFIC_INDIRECT_MMAP -#include "mali_osk_indir_mmap.h" -#endif - -#error Support for non-MMU builds is no longer supported and is planned for removal. - -/** - * Minimum memory allocation size - */ -#define MIN_BLOCK_SIZE (1024*1024UL) - -/** - * Per-session memory descriptor mapping table sizes - */ -#define MALI_MEM_DESCRIPTORS_INIT 64 -#define MALI_MEM_DESCRIPTORS_MAX 4096 - -/** - * Enum uses to store multiple fields in one u32 to keep the memory block struct small - */ -enum MISC_SHIFT { MISC_SHIFT_FREE = 0, MISC_SHIFT_ORDER = 1, MISC_SHIFT_TOPLEVEL = 6 }; -enum MISC_MASK { MISC_MASK_FREE = 0x01, MISC_MASK_ORDER = 0x1F, MISC_MASK_TOPLEVEL = 0x1F }; - -/* forward declaration of the block struct */ -struct mali_memory_block; - -/** - * Definition of memory bank type. - * Represents a memory bank (separate address space) - * Each bank keeps track of its block usage. - * A buddy system used to track the usage -*/ -typedef struct mali_memory_bank -{ - _mali_osk_list_t list; /* links multiple banks together */ - _mali_osk_lock_t *lock; - u32 base_addr; /* Mali seen address of bank */ - u32 cpu_usage_adjust; /* Adjustment factor for what the CPU sees */ - u32 size; /* the effective size */ - u32 real_size; /* the real size of the bank, as given by to the subsystem */ - int min_order; - int max_order; - struct mali_memory_block * blocklist; - _mali_osk_list_t *freelist; - _mali_osk_atomic_t num_active_allocations; - u32 used_for_flags; - u32 alloc_order; /**< Order in which the bank will be used for allocations */ - const char *name; /**< Descriptive name of the bank */ -} mali_memory_bank; - -/** - * Definition of the memory block type - * Represents a memory block, which is the smallest memory unit operated on. - * A block keeps info about its mapping, if in use by a user process - */ -typedef struct mali_memory_block -{ - _mali_osk_list_t link; /* used for freelist and process usage list*/ - mali_memory_bank * bank; /* the bank it belongs to */ - void __user * mapping; /* possible user space mapping of this block */ - u32 misc; /* used while a block is free to track the number blocks it represents */ - int descriptor; - u32 mmap_cookie; /**< necessary for interaction with _mali_ukk_mem_mmap/munmap */ -} mali_memory_block; - -/** - * Defintion of the type used to represent memory used by a session. - * Containts the head of the list of memory currently in use by a session. - */ -typedef struct memory_session -{ - _mali_osk_lock_t *lock; - _mali_osk_list_t memory_head; /* List of the memory blocks used by this session. */ - mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ -} memory_session; - -/* - Subsystem interface implementation -*/ -/** - * Buddy block memory subsystem startup function - * Called by the driver core when the driver is loaded. - * Registers the memory systems ioctl handler, resource handlers and memory map function with the core. - * - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id); - -/** - * Buddy block memory subsystem shutdown function - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the memory subsystem - */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id); - -/** - * Buddy block memory load complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * Reports on the memory resources registered - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id); - - -/** - * Buddy block memory subsystem session begin notification - * Called by the core when a new session to the driver is started. - * Creates a memory session object and sets it as the subsystem slot data for this session - * @param slot Pointer to the slot to use for storing per-session data - * @param queue The user space event sink - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - -/** - * Buddy block memory subsystem session end notification - * Called by the core when a session to the driver has ended. - * Cleans up per session data, which includes checking and fixing memory leaks - * - * @param slot Pointer to the slot to use for storing per-session data - */ -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - -/** - * Buddy block memory subsystem system info filler - * Called by the core when a system info update is needed - * We fill in info about all the memory types we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info); - -/* our registered resource handlers */ -/** - * Buddy block memory subsystem's notification handler for MEMORY resource instances. - * Registered with the core during startup. - * Called by the core for each memory bank described in the active architecture's config.h file. - * Requests memory region ownership and calls backend. - * @param resource The resource to handle (type MEMORY) - * @return 0 if the memory was claimed and accepted, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_memory(_mali_osk_resource_t * resource); - -/** - * Buddy block memory subsystem's notification handler for MMU resource instances. - * Registered with the core during startup. - * Called by the core for each mmu described in the active architecture's config.h file. - * @param resource The resource to handle (type MMU) - * @return 0 if the MMU was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource); - -/** - * Buddy block memory subsystem's notification handler for FPGA_FRAMEWORK resource instances. - * Registered with the core during startup. - * Called by the core for each fpga framework described in the active architecture's config.h file. - * @param resource The resource to handle (type FPGA_FRAMEWORK) - * @return 0 if the FPGA framework was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource); - -/* ioctl command implementations */ -/** - * Buddy block memory subsystem's handler for MALI_IOC_MEM_GET_BIG_BLOCK ioctl - * Called by the generic ioctl handler when the MALI_IOC_MEM_GET_BIG_BLOCK command is received. - * Finds an available memory block and maps into the current process' address space. - * @param ukk_private private word for use by the User/Kernel interface - * @param session_data Pointer to the per-session object which will track the memory usage - * @param argument The argument from the user. A pointer to an struct mali_dd_get_big_block in user space - * @return Zero if successful, a standard Linux error value value on error (a negative value) - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ); - -/** - * Buddy block memory subsystem's handler for MALI_IOC_MEM_FREE_BIG_BLOCK ioctl - * Called by the generic ioctl handler when the MALI_IOC_MEM_FREE_BIG_BLOCK command is received. - * Unmaps the memory from the process' address space and marks the block as free. - * @param session_data Pointer to the per-session object which tracks the memory usage - * @param argument The argument from the user. A pointer to an struct mali_dd_get_big_block in user space - * @return Zero if successful, a standard Linux error value value on error (a negative value) - */ - -/* this static version allows us to make use of it while holding the memory_session lock. - * This is required for the session_end code */ -static _mali_osk_errcode_t _mali_ukk_free_big_block_internal( struct mali_session_data * mali_session_data, memory_session * session_data, _mali_uk_free_big_block_s *args); - -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); - -/** - * Buddy block memory subsystem's memory bank registration routine - * Called when a MEMORY resource has been found. - * The memory region has already been reserved for use by this driver. - * Create a bank object to represent this region and initialize its slots. - * @note Can only be called in an module atomic scope, i.e. during module init since no locking is performed - * @param phys_base Physical base address of this bank - * @param cpu_usage_adjust Adjustment factor for CPU seen address - * @param size Size of the bank in bytes - * @param flags Memory type bits - * @param alloc_order Order in which the bank will be used for allocations - * @param name descriptive name of the bank - * @return Zero on success, negative on error - */ -static int mali_memory_bank_register(u32 phys_base, u32 cpu_usage_adjust, u32 size, u32 flags, u32 alloc_order, const char *name); - -/** - * Get a block of mali memory of at least the given size and of the given type - * This is the backend for get_big_block. - * @param type_id The type id of memory requested. - * @param minimum_size The size requested - * @return Pointer to a block on success, NULL on failure - */ -static mali_memory_block * mali_memory_block_get(u32 type_id, u32 minimum_size); - -/** - * Get the mali seen address of the memory described by the block - * @param block The memory block to return the address of - * @return The mali seen address of the memory block - */ -MALI_STATIC_INLINE u32 block_mali_addr_get(mali_memory_block * block); - -/** - * Get the cpu seen address of the memory described by the block - * The cpu_usage_adjust will be used to change the mali seen phys address - * @param block The memory block to return the address of - * @return The mali seen address of the memory block - */ -MALI_STATIC_INLINE u32 block_cpu_addr_get(mali_memory_block * block); - -/** - * Get the size of the memory described by the given block - * @param block The memory block to return the size of - * @return The size of the memory block described by the object - */ -MALI_STATIC_INLINE u32 block_size_get(mali_memory_block * block); - -/** - * Get the user space accessible mapping the memory described by the given memory block - * Returns a pointer in user space to the memory, if one has been created. - * @param block The memory block to return the mapping of - * @return User space pointer to cpu accessible memory or NULL if not mapped - */ -MALI_STATIC_INLINE void __user * block_mapping_get(mali_memory_block * block); - -/** - * Set the user space accessible mapping the memory described by the given memory block. - * Sets the stored pointer to user space for the memory described by this block. - * @param block The memory block to set mapping info for - * @param ptr User space pointer to cpu accessible memory or NULL if not mapped - */ -MALI_STATIC_INLINE void block_mapping_set(mali_memory_block * block, void __user * ptr); - -/** - * Get the cookie for use with _mali_ukk_mem_munmap(). - * @param block The memory block to get the cookie from - * @return the cookie. A return of 0 is still a valid cookie. - */ -MALI_STATIC_INLINE u32 block_mmap_cookie_get(mali_memory_block * block); - -/** - * Set the cookie returned via _mali_ukk_mem_mmap(). - * @param block The memory block to set the cookie for - * @param cookie the cookie - */ -MALI_STATIC_INLINE void block_mmap_cookie_set(mali_memory_block * block, u32 cookie); - - -/** - * Get a memory block's free status - * @param block The block to get the state of - */ -MALI_STATIC_INLINE u32 get_block_free(mali_memory_block * block); - -/** - * Set a memory block's free status - * @param block The block to set the state for - * @param state The state to set - */ -MALI_STATIC_INLINE void set_block_free(mali_memory_block * block, int state); - -/** - * Set a memory block's order - * @param block The block to set the order for - * @param order The order to set - */ -MALI_STATIC_INLINE void set_block_order(mali_memory_block * block, u32 order); - -/** - * Get a memory block's order - * @param block The block to get the order for - * @return The order this block exists on - */ -MALI_STATIC_INLINE u32 get_block_order(mali_memory_block * block); - -/** - * Tag a block as being a toplevel block. - * A toplevel block has no buddy and no parent - * @param block The block to tag as being toplevel - */ -MALI_STATIC_INLINE void set_block_toplevel(mali_memory_block * block, u32 level); - -/** - * Check if a block is a toplevel block - * @param block The block to check - * @return 1 if toplevel, 0 else - */ -MALI_STATIC_INLINE u32 get_block_toplevel(mali_memory_block * block); - -/** - * Checks if the given block is a buddy at the given order and that it's free - * @param block The block to check - * @param order The order to check against - * @return 0 if not valid, else 1 - */ -MALI_STATIC_INLINE int block_is_valid_buddy(mali_memory_block * block, int order); - -/* - The buddy system uses the following rules to quickly find a blocks buddy - and parent (block representing this block at a higher order level): - - Given a block with index i the blocks buddy is at index i ^ ( 1 << order) - - Given a block with index i the blocks parent is at i & ~(1 << order) -*/ - -/** - * Get a blocks buddy - * @param block The block to find the buddy for - * @param order The order to operate on - * @return Pointer to the buddy block - */ -MALI_STATIC_INLINE mali_memory_block * block_get_buddy(mali_memory_block * block, u32 order); - -/** - * Get a blocks parent - * @param block The block to find the parent for - * @param order The order to operate on - * @return Pointer to the parent block - */ -MALI_STATIC_INLINE mali_memory_block * block_get_parent(mali_memory_block * block, u32 order); - -/** - * Release mali memory - * Backend for free_big_block. - * Will release the mali memory described by the given block struct. - * @param block Memory block to free - */ -static void block_release(mali_memory_block * block); - -/* end interface implementation */ - -/** - * List of all the memory banks registerd with the subsystem. - * Access to this list is NOT synchronized since it's only - * written to during module init and termination. - */ -static _MALI_OSK_LIST_HEAD(memory_banks_list); - -/* - The buddy memory system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_memory = -{ - mali_memory_core_initialize, /* startup */ - NULL, /*mali_memory_core_terminate,*/ /* shutdown */ - mali_memory_core_load_complete, /* load_complete */ - mali_memory_core_system_info_fill, /* system_info_fill */ - mali_memory_core_session_begin, /* session_begin */ - mali_memory_core_session_end, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_memory_id = -1; - -/* called during module init */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id) -{ - _MALI_OSK_INIT_LIST_HEAD(&memory_banks_list); - - mali_subsystem_memory_id = id; - - /* register our handlers */ - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MEMORY, mali_memory_core_resource_memory)); - - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MMU, mali_memory_core_resource_mmu)); - - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(FPGA_FRAMEWORK, mali_memory_core_resource_fpga)); - - MALI_SUCCESS; -} - -/* called if/when our module is unloaded */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id) -{ - mali_memory_bank * bank, *temp; - - /* loop over all memory banks to free them */ - /* we use the safe version since we delete the current bank in the body */ - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - MALI_DEBUG_CODE(int usage_count = _mali_osk_atomic_read(&bank->num_active_allocations)); - /* - Report leaked memory - If this happens we have a bug in our session cleanup code. - */ - MALI_DEBUG_PRINT_IF(1, 0 != usage_count, ("%d allocation(s) from memory bank at 0x%X still in use\n", usage_count, bank->base_addr)); - - _mali_osk_atomic_term(&bank->num_active_allocations); - - _mali_osk_lock_term(bank->lock); - - /* unlink from bank list */ - _mali_osk_list_del(&bank->list); - - /* release kernel resources used by the bank */ - _mali_osk_mem_unreqregion(bank->base_addr, bank->real_size); - - /* remove all resources used to represent this bank*/ - _mali_osk_free(bank->freelist); - _mali_osk_free(bank->blocklist); - - /* destroy the bank object itself */ - _mali_osk_free(bank); - } - - /* No need to de-initialize mali_subsystem_memory_id - it could only be - * re-initialized to the same value */ -} - -/* load_complete handler */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_memory_bank * bank, *temp; - - MALI_DEBUG_PRINT( 1, ("Mali memory allocators will be used in this order of preference (lowest number first) :\n")); - - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - if ( NULL != bank->name ) - { - MALI_DEBUG_PRINT( 1, ("\t%d: %s\n", bank->alloc_order, bank->name) ); - } - else - { - MALI_DEBUG_PRINT( 1, ("\t%d: (UNNAMED ALLOCATOR)\n", bank->alloc_order ) ); - } - } - MALI_SUCCESS; -} - -MALI_STATIC_INLINE u32 order_needed_for_size(u32 size, struct mali_memory_bank * bank) -{ - u32 order = 0; - - if (0 < size) - { - for ( order = sizeof(u32)*8 - 1; ((1UL<<order) & size) == 0; --order) - /* nothing */; - - /* check if size is pow2, if not we need increment order by one */ - if (0 != (size & ((1UL<<order)-1))) ++order; - } - - if ((NULL != bank) && (order < bank->min_order)) order = bank->min_order; - /* Not capped to max order, that doesn't make sense */ - - return order; -} - -MALI_STATIC_INLINE u32 maximum_order_which_fits(u32 size) -{ - u32 order = 0; - u32 powsize = 1; - while (powsize < size) - { - powsize <<= 1; - if (powsize > size) break; - order++; - } - - return order; -} - -/* called for new MEMORY resources */ -static _mali_osk_errcode_t mali_memory_bank_register(u32 phys_base, u32 cpu_usage_adjust, u32 size, u32 flags, u32 alloc_order, const char *name) -{ - /* no locking performed due to function contract */ - int i; - u32 left, offset; - mali_memory_bank * bank; - mali_memory_bank * bank_enum, *temp; - - _mali_osk_errcode_t err; - - /* Only a multiple of MIN_BLOCK_SIZE is usable */ - u32 usable_size = size & ~(MIN_BLOCK_SIZE - 1); - - /* handle zero sized banks and bank smaller than the fixed block size */ - if (0 == usable_size) - { - MALI_PRINT(("Usable size == 0\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - /* warn for banks not a muliple of the block size */ - MALI_DEBUG_PRINT_IF(1, usable_size != size, ("Memory bank @ 0x%X not a multiple of minimum block size. %d bytes wasted\n", phys_base, size - usable_size)); - - /* check against previous registrations */ - MALI_DEBUG_CODE( - { - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - /* duplicate ? */ - if (bank->base_addr == phys_base) - { - MALI_PRINT(("Duplicate registration of a memory bank at 0x%X detected\n", phys_base)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - /* overlapping ? */ - else if ( - ( (phys_base > bank->base_addr) && (phys_base < (bank->base_addr + bank->real_size)) ) || - ( (phys_base + size) > bank->base_addr && ((phys_base + size) < (bank->base_addr + bank->real_size)) ) - ) - { - MALI_PRINT(("Overlapping memory blocks found. Memory at 0x%X overlaps with memory at 0x%X size 0x%X\n", bank->base_addr, phys_base, size)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - } - } - ); - - /* create an object to represent this memory bank */ - MALI_CHECK_NON_NULL(bank = (mali_memory_bank*)_mali_osk_malloc(sizeof(mali_memory_bank)), _MALI_OSK_ERR_NOMEM); - - /* init the fields */ - _MALI_OSK_INIT_LIST_HEAD(&bank->list); - bank->base_addr = phys_base; - bank->cpu_usage_adjust = cpu_usage_adjust; - bank->size = usable_size; - bank->real_size = size; - bank->alloc_order = alloc_order; - bank->name = name; - - err = _mali_osk_atomic_init(&bank->num_active_allocations, 0); - if (err != _MALI_OSK_ERR_OK) - { - _mali_osk_free(bank); - MALI_ERROR(err); - } - - bank->used_for_flags = flags; - bank->min_order = order_needed_for_size(MIN_BLOCK_SIZE, NULL); - bank->max_order = maximum_order_which_fits(usable_size); - bank->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0); - if (NULL == bank->lock) - { - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - bank->blocklist = _mali_osk_calloc(1, sizeof(struct mali_memory_block) * (usable_size / MIN_BLOCK_SIZE)); - if (NULL == bank->blocklist) - { - _mali_osk_lock_term(bank->lock); - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - for (i = 0; i < (usable_size / MIN_BLOCK_SIZE); i++) - { - bank->blocklist[i].bank = bank; - } - - bank->freelist = _mali_osk_calloc(1, sizeof(_mali_osk_list_t) * (bank->max_order - bank->min_order + 1)); - if (NULL == bank->freelist) - { - _mali_osk_lock_term(bank->lock); - _mali_osk_free(bank->blocklist); - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - for (i = 0; i < (bank->max_order - bank->min_order + 1); i++) _MALI_OSK_INIT_LIST_HEAD(&bank->freelist[i]); - - /* init slot info */ - for (offset = 0, left = usable_size; offset < (usable_size / MIN_BLOCK_SIZE); /* updated inside the body */) - { - u32 block_order; - mali_memory_block * block; - - /* the maximum order which fits in the remaining area */ - block_order = maximum_order_which_fits(left); - - /* find the block pointer */ - block = &bank->blocklist[offset]; - - /* tag the block as being toplevel */ - set_block_toplevel(block, block_order); - - /* tag it as being free */ - set_block_free(block, 1); - - /* set the order */ - set_block_order(block, block_order); - - _mali_osk_list_addtail(&block->link, bank->freelist + (block_order - bank->min_order)); - - left -= (1 << block_order); - offset += ((1 << block_order) / MIN_BLOCK_SIZE); - } - - /* add bank to list of banks on the system */ - _MALI_OSK_LIST_FOREACHENTRY( bank_enum, temp, &memory_banks_list, mali_memory_bank, list ) - { - if ( bank_enum->alloc_order >= alloc_order ) - { - /* Found insertion point - our item must go before this one */ - break; - } - } - _mali_osk_list_addtail(&bank->list, &bank_enum->list); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_memory_mmu_register(u32 type, u32 phys_base) -{ - /* not supported */ - return _MALI_OSK_ERR_INVALID_FUNC; -} - -void mali_memory_mmu_unregister(u32 phys_base) -{ - /* not supported */ - return; -} - -static mali_memory_block * mali_memory_block_get(u32 type_id, u32 minimum_size) -{ - mali_memory_bank * bank; - mali_memory_block * block = NULL; - u32 requested_order, current_order; - - /* input validation */ - if (0 == minimum_size) - { - /* bad size */ - MALI_DEBUG_PRINT(2, ("Zero size block requested by mali_memory_block_get\n")); - return NULL; - } - - bank = (mali_memory_bank*)type_id; - - requested_order = order_needed_for_size(minimum_size, bank); - - MALI_DEBUG_PRINT(4, ("For size %d we need order %d (%d)\n", minimum_size, requested_order, 1 << requested_order)); - - _mali_osk_lock_wait(bank->lock, _MALI_OSK_LOCKMODE_RW); - /* ! critical section begin */ - - MALI_DEBUG_PRINT(7, ("Bank 0x%x locked\n", bank)); - - for (current_order = requested_order; current_order <= bank->max_order; ++current_order) - { - _mali_osk_list_t * list = bank->freelist + (current_order - bank->min_order); - MALI_DEBUG_PRINT(7, ("Checking freelist 0x%x for order %d\n", list, current_order)); - if (0 != _mali_osk_list_empty(list)) continue; /* empty list */ - - MALI_DEBUG_PRINT(7, ("Found an entry on the freelist for order %d\n", current_order)); - - - block = _MALI_OSK_LIST_ENTRY(list->next, mali_memory_block, link); - _mali_osk_list_delinit(&block->link); - - while (current_order > requested_order) - { - mali_memory_block * buddy_block; - MALI_DEBUG_PRINT(7, ("Splitting block 0x%x\n", block)); - current_order--; - list--; - buddy_block = block_get_buddy(block, current_order - bank->min_order); - set_block_order(buddy_block, current_order); - set_block_free(buddy_block, 1); - _mali_osk_list_add(&buddy_block->link, list); - } - - set_block_order(block, current_order); - set_block_free(block, 0); - - /* update usage count */ - _mali_osk_atomic_inc(&bank->num_active_allocations); - - break; - } - - /* ! critical section end */ - _mali_osk_lock_signal(bank->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(7, ("Lock released for bank 0x%x\n", bank)); - - MALI_DEBUG_PRINT_IF(7, NULL != block, ("Block 0x%x allocated\n", block)); - - return block; -} - - -static void block_release(mali_memory_block * block) -{ - mali_memory_bank * bank; - u32 current_order; - - if (NULL == block) return; - - bank = block->bank; - - /* we're manipulating the free list, so we need to lock it */ - _mali_osk_lock_wait(bank->lock, _MALI_OSK_LOCKMODE_RW); - /* ! critical section begin */ - - set_block_free(block, 1); - current_order = get_block_order(block); - - while (current_order <= bank->max_order) - { - mali_memory_block * buddy_block; - buddy_block = block_get_buddy(block, current_order - bank->min_order); - if (!block_is_valid_buddy(buddy_block, current_order)) break; - _mali_osk_list_delinit(&buddy_block->link); /* remove from free list */ - /* clear tracked data in both blocks */ - set_block_order(block, 0); - set_block_free(block, 0); - set_block_order(buddy_block, 0); - set_block_free(buddy_block, 0); - /* make the parent control the new state */ - block = block_get_parent(block, current_order - bank->min_order); - set_block_order(block, current_order + 1); /* merged has a higher order */ - set_block_free(block, 1); /* mark it as free */ - current_order++; - if (get_block_toplevel(block) == current_order) break; /* stop the merge if we've arrived at a toplevel block */ - } - - _mali_osk_list_add(&block->link, &bank->freelist[current_order - bank->min_order]); - - /* update bank usage statistics */ - _mali_osk_atomic_dec(&block->bank->num_active_allocations); - - /* !critical section end */ - _mali_osk_lock_signal(bank->lock, _MALI_OSK_LOCKMODE_RW); - - return; -} - -MALI_STATIC_INLINE u32 block_get_offset(mali_memory_block * block) -{ - return block - block->bank->blocklist; -} - -MALI_STATIC_INLINE u32 block_mali_addr_get(mali_memory_block * block) -{ - if (NULL != block) return block->bank->base_addr + MIN_BLOCK_SIZE * block_get_offset(block); - else return 0; -} - -MALI_STATIC_INLINE u32 block_cpu_addr_get(mali_memory_block * block) -{ - if (NULL != block) return (block->bank->base_addr + MIN_BLOCK_SIZE * block_get_offset(block)) + block->bank->cpu_usage_adjust; - else return 0; -} - -MALI_STATIC_INLINE u32 block_size_get(mali_memory_block * block) -{ - if (NULL != block) return 1 << get_block_order(block); - else return 0; -} - -MALI_STATIC_INLINE void __user * block_mapping_get(mali_memory_block * block) -{ - if (NULL != block) return block->mapping; - else return NULL; -} - -MALI_STATIC_INLINE void block_mapping_set(mali_memory_block * block, void __user * ptr) -{ - if (NULL != block) block->mapping = ptr; -} - -MALI_STATIC_INLINE u32 block_mmap_cookie_get(mali_memory_block * block) -{ - if (NULL != block) return block->mmap_cookie; - else return 0; -} - -/** - * Set the cookie returned via _mali_ukk_mem_mmap(). - * @param block The memory block to set the cookie for - * @param cookie the cookie - */ -MALI_STATIC_INLINE void block_mmap_cookie_set(mali_memory_block * block, u32 cookie) -{ - if (NULL != block) block->mmap_cookie = cookie; -} - - -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - memory_session * session_data; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (NULL != *slot) - { - MALI_DEBUG_PRINT(1, ("The slot given to memory session begin already contains data")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - /* create the session data object */ - MALI_CHECK_NON_NULL(session_data = _mali_osk_malloc(sizeof(memory_session)), _MALI_OSK_ERR_NOMEM); - - /* create descriptor mapping table */ - session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); - - if (NULL == session_data->descriptor_mapping) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _MALI_OSK_INIT_LIST_HEAD(&session_data->memory_head); /* no memory in use */ - session_data->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0); - if (NULL == session_data->lock) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - *slot = session_data; /* slot will point to our data object */ - - MALI_SUCCESS; -} - -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - memory_session * session_data; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - return; - } - - if (NULL == *slot) - { - MALI_DEBUG_PRINT(1, ("NULL memory_session found in current session object")); - return; - } - - _mali_osk_lock_wait(((memory_session*)*slot)->lock, _MALI_OSK_LOCKMODE_RW); - session_data = (memory_session *)*slot; - /* clear our slot */ - *slot = NULL; - - /* - First free all memory still being used. - This can happen if the caller has leaked memory or - the application has crashed forcing an auto-session end. - */ - if (0 == _mali_osk_list_empty(&session_data->memory_head)) - { - mali_memory_block * block, * temp; - MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); - - /* use the _safe version since fre_big_block removes the active block from the list we're iterating */ - _MALI_OSK_LIST_FOREACHENTRY(block, temp, &session_data->memory_head, mali_memory_block, link) - { - _mali_osk_errcode_t err; - _mali_uk_free_big_block_s uk_args; - - MALI_DEBUG_PRINT(4, ("Freeing block 0x%x with mali address 0x%x size %d mapped in user space at 0x%x\n", - block, - (void*)block_mali_addr_get(block), - block_size_get(block), - block_mapping_get(block)) - ); - - /* free the block */ - /** @note manual type safety check-point */ - uk_args.ctx = mali_session_data; - uk_args.cookie = (u32)block->descriptor; - err = _mali_ukk_free_big_block_internal( mali_session_data, session_data, &uk_args ); - - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT_ERROR(("_mali_ukk_free_big_block_internal() failed during session termination on block with cookie==0x%X\n", - uk_args.cookie) - ); - } - } - } - - if (NULL != session_data->descriptor_mapping) - { - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - session_data->descriptor_mapping = NULL; - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_term(session_data->lock); - - /* free the session data object */ - _mali_osk_free(session_data); - - return; -} - -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info) -{ - mali_memory_bank * bank, *temp; - _mali_mem_info **mem_info_tail; - - /* check input */ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - /* make sure we won't leak any memory. It could also be that it's an uninitialized variable, but that would be a bug in the caller */ - MALI_DEBUG_ASSERT(NULL == info->mem_info); - - mem_info_tail = &info->mem_info; - - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - _mali_mem_info * mem_info; - - mem_info = (_mali_mem_info *)_mali_osk_calloc(1, sizeof(_mali_mem_info)); - if (NULL == mem_info) return _MALI_OSK_ERR_NOMEM; /* memory already allocated will be freed by the caller */ - - /* set info */ - mem_info->size = bank->size; - mem_info->flags = (_mali_bus_usage)bank->used_for_flags; - mem_info->maximum_order_supported = bank->max_order; - mem_info->identifier = (u32)bank; - - /* add to system info linked list */ - (*mem_info_tail) = mem_info; - mem_info_tail = &mem_info->next; - } - - /* all OK */ - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_memory(_mali_osk_resource_t * resource) -{ - _mali_osk_errcode_t err; - - /* Request ownership of the memory */ - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) - { - MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* call backend */ - err = mali_memory_bank_register(resource->base, resource->cpu_usage_adjust, resource->size, resource->flags, resource->alloc_order, resource->description); - if (_MALI_OSK_ERR_OK != err) - { - /* if backend refused the memory we have to release the region again */ - MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); - _mali_osk_mem_unreqregion(resource->base, resource->size); - MALI_ERROR(err); - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource) -{ - /* Not supported by the fixed block memory system */ - MALI_DEBUG_PRINT(1, ("MMU resource not supported by non-MMU driver!\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_FUNC); -} - -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource) -{ - mali_io_address mapping; - - MALI_DEBUG_PRINT(5, ("FPGA framework '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + sizeof(u32) * 2 - 1 - )); - - mapping = _mali_osk_mem_mapioregion(resource->base + 0x1000, sizeof(u32) * 2, "fpga framework"); - if (mapping) - { - u32 data; - data = _mali_osk_mem_ioread32(mapping, 0); - MALI_DEBUG_PRINT(2, ("FPGA framwork '%s' @ 0x%08X:\n", resource->description, resource->base)); - MALI_DEBUG_PRINT(2, ("\tBitfile date: %d%02d%02d_%02d%02d\n", - (data >> 20), - (data >> 16) & 0xF, - (data >> 11) & 0x1F, - (data >> 6) & 0x1F, - (data >> 0) & 0x3F)); - data = _mali_osk_mem_ioread32(mapping, sizeof(u32)); - MALI_DEBUG_PRINT(2, ("\tBitfile SCCS rev: %d\n", data)); - - _mali_osk_mem_unmapioregion(resource->base + 0x1000, sizeof(u32) *2, mapping); - } - else MALI_DEBUG_PRINT(1, ("Failed to access FPGA framwork '%s' @ 0x%08X\n", resource->description, resource->base)); - - MALI_SUCCESS; -} - -/* static _mali_osk_errcode_t get_big_block(void * ukk_private, struct mali_session_data * mali_session_data, void __user * argument) */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ) -{ - _mali_uk_mem_mmap_s args_mmap = {0, }; - int md; - mali_memory_block * block; - _mali_osk_errcode_t err; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER( args ); - - MALI_DEBUG_ASSERT_POINTER( args->ctx ); - - /** @note manual type safety check-point */ - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (!args->type_id) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* at least min block size */ - if (MIN_BLOCK_SIZE > args->minimum_size_requested) args->minimum_size_requested = MIN_BLOCK_SIZE; - - /* perform the actual allocation */ - block = mali_memory_block_get(args->type_id, args->minimum_size_requested); - if ( NULL == block ) - { - /* no memory available with requested type_id */ - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, block, &md)) - { - block_release(block); - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - block->descriptor = md; - - - /* fill in response */ - args->mali_address = block_mali_addr_get(block); - args->block_size = block_size_get(block); - args->cookie = (u32)md; - args->flags = block->bank->used_for_flags; - - /* map the block into the process' address space */ - - /** @note manual type safety check-point */ - args_mmap.ukk_private = (void *)args->ukk_private; - args_mmap.ctx = args->ctx; - args_mmap.size = args->block_size; - args_mmap.phys_addr = block_cpu_addr_get(block); - -#ifndef _MALI_OSK_SPECIFIC_INDIRECT_MMAP - err = _mali_ukk_mem_mmap( &args_mmap ); -#else - err = _mali_osk_specific_indirect_mmap( &args_mmap ); -#endif - - /* check if the mapping failed */ - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT(1, ("Memory mapping failed 0x%x\n", args->cpuptr)); - /* mapping failed */ - - /* remove descriptor entry */ - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - - /* free the mali memory */ - block_release(block); - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - return err; - } - - args->cpuptr = args_mmap.mapping; - block_mmap_cookie_set(block, args_mmap.cookie); - block_mapping_set(block, args->cpuptr); - - MALI_DEBUG_PRINT(2, ("Mali memory 0x%x (size %d) mapped in process memory space at 0x%x\n", (void*)args->mali_address, args->block_size, args->cpuptr)); - - /* track memory in use for the session */ - _mali_osk_list_addtail(&block->link, &session_data->memory_head); - - /* memory assigned to the session, memory mapped into the process' view */ - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_SUCCESS; -} - -/* Internal code that assumes the memory session lock is held */ -static _mali_osk_errcode_t _mali_ukk_free_big_block_internal( struct mali_session_data * mali_session_data, memory_session * session_data, _mali_uk_free_big_block_s *args) -{ - mali_memory_block * block = NULL; - _mali_osk_errcode_t err; - _mali_uk_mem_munmap_s args_munmap = {0,}; - - MALI_DEBUG_ASSERT_POINTER( mali_session_data ); - MALI_DEBUG_ASSERT_POINTER( session_data ); - MALI_DEBUG_ASSERT_POINTER( args ); - - err = mali_descriptor_mapping_get(session_data->descriptor_mapping, (int)args->cookie, (void**)&block); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release memory pages\n", (int)args->cookie)); - MALI_ERROR(err); - } - - MALI_DEBUG_ASSERT_POINTER(block); - - MALI_DEBUG_PRINT(4, ("Asked to free block 0x%x with mali address 0x%x size %d mapped in user space at 0x%x\n", - block, - (void*)block_mali_addr_get(block), - block_size_get(block), - block_mapping_get(block)) - ); - - /** @note manual type safety check-point */ - args_munmap.ctx = (void*)mali_session_data; - args_munmap.mapping = block_mapping_get( block ); - args_munmap.size = block_size_get( block ); - args_munmap.cookie = block_mmap_cookie_get( block ); - -#ifndef _MALI_OSK_SPECIFIC_INDIRECT_MMAP - _mali_ukk_mem_munmap( &args_munmap ); -#else - _mali_osk_specific_indirect_munmap( &args_munmap ); -#endif - - MALI_DEBUG_PRINT(6, ("Session data 0x%x, lock 0x%x\n", session_data, &session_data->lock)); - - /* unlink from session usage list */ - MALI_DEBUG_PRINT(5, ("unlink from session usage list\n")); - _mali_osk_list_delinit(&block->link); - - /* remove descriptor entry */ - mali_descriptor_mapping_free(session_data->descriptor_mapping, (int)args->cookie); - - /* free the mali memory */ - block_release(block); - MALI_DEBUG_PRINT(5, ("Block freed\n")); - - MALI_SUCCESS; -} - -/* static _mali_osk_errcode_t free_big_block( struct mali_session_data * mali_session_data, void __user * argument) */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ) -{ - _mali_osk_errcode_t err; - struct mali_session_data * mali_session_data; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER( args ); - - MALI_DEBUG_ASSERT_POINTER( args->ctx ); - - /** @note manual type safety check-point */ - mali_session_data = (struct mali_session_data *)args->ctx; - - /* Must always verify this, since these are provided by the user */ - MALI_CHECK_NON_NULL(mali_session_data, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - /** @note this has been separated out so that the session_end handler can call this while it has the memory_session lock held */ - err = _mali_ukk_free_big_block_internal( mali_session_data, session_data, args ); - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - return err; -} - -MALI_STATIC_INLINE u32 get_block_free(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_FREE) & MISC_MASK_FREE; -} - -MALI_STATIC_INLINE void set_block_free(mali_memory_block * block, int state) -{ - if (state) block->misc |= (MISC_MASK_FREE << MISC_SHIFT_FREE); - else block->misc &= ~(MISC_MASK_FREE << MISC_SHIFT_FREE); -} - -MALI_STATIC_INLINE void set_block_order(mali_memory_block * block, u32 order) -{ - block->misc &= ~(MISC_MASK_ORDER << MISC_SHIFT_ORDER); - block->misc |= ((order & MISC_MASK_ORDER) << MISC_SHIFT_ORDER); -} - -MALI_STATIC_INLINE u32 get_block_order(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_ORDER) & MISC_MASK_ORDER; -} - -MALI_STATIC_INLINE void set_block_toplevel(mali_memory_block * block, u32 level) -{ - block->misc |= ((level & MISC_MASK_TOPLEVEL) << MISC_SHIFT_TOPLEVEL); -} - -MALI_STATIC_INLINE u32 get_block_toplevel(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_TOPLEVEL) & MISC_MASK_TOPLEVEL; -} - -MALI_STATIC_INLINE int block_is_valid_buddy(mali_memory_block * block, int order) -{ - if (get_block_free(block) && (get_block_order(block) == order)) return 1; - else return 0; -} - -MALI_STATIC_INLINE mali_memory_block * block_get_buddy(mali_memory_block * block, u32 order) -{ - return block + ( (block_get_offset(block) ^ (1 << order)) - block_get_offset(block)); -} - -MALI_STATIC_INLINE mali_memory_block * block_get_parent(mali_memory_block * block, u32 order) -{ - return block + ((block_get_offset(block) & ~(1 << order)) - block_get_offset(block)); -} - -/* This handler registered to mali_mmap for non-MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) -{ - _mali_osk_errcode_t ret; - struct mali_session_data * mali_session_data; - mali_memory_allocation * descriptor; - memory_session * session_data; - - /* validate input */ - if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - /* Unpack arguments */ - mali_session_data = (struct mali_session_data *)args->ctx; - - if (NULL == mali_session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: mali_session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - MALI_DEBUG_ASSERT( mali_subsystem_memory_id >= 0 ); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - /* validate input */ - if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } - - descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); - if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - - descriptor->size = args->size; - descriptor->mali_address = args->phys_addr; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; - - ret = _mali_osk_mem_mapregion_init( descriptor ); - if ( _MALI_OSK_ERR_OK != ret ) - { - MALI_DEBUG_PRINT(3, ("_mali_osk_mem_mapregion_init() failed\n")); - _mali_osk_free(descriptor); - MALI_ERROR(ret); - } - - ret = _mali_osk_mem_mapregion_map( descriptor, 0, &descriptor->mali_address, descriptor->size ); - if ( _MALI_OSK_ERR_OK != ret ) - { - MALI_DEBUG_PRINT(3, ("_mali_osk_mem_mapregion_map() failed\n")); - _mali_osk_mem_mapregion_term( descriptor ); - _mali_osk_free(descriptor); - MALI_ERROR(ret); - } - - args->mapping = descriptor->mapping; - - /** - * @note we do not require use of mali_descriptor_mapping here: - * the cookie gets stored in the mali_memory_block struct, which itself is - * protected by mali_descriptor_mapping, and so this cookie never leaves - * kernel space (on any OS). - * - * In the MMU case, we must use a mali_descriptor_mapping, since on _some_ - * OSs, the cookie leaves kernel space. - */ - args->cookie = (u32)descriptor; - MALI_SUCCESS; -} - -/* This handler registered to mali_munmap for non-MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) -{ - mali_memory_allocation * descriptor; - - /** see note in _mali_ukk_mem_mmap() - no need to use descriptor mapping */ - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /* args->mapping and args->size are also discarded. They are only necessary for certain do_munmap implementations. However, they could be used to check the descriptor at this point. */ - _mali_osk_mem_mapregion_unmap( descriptor, 0, descriptor->size, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_mem_mapregion_term( descriptor ); - - _mali_osk_free(descriptor); - - return _MALI_OSK_ERR_OK; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c deleted file mode 100644 index c993ad5..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c +++ /dev/null @@ -1,3157 +0,0 @@ -/* - * Copyright (C) 2010 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_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_ioctl.h" -#include "mali_kernel_descriptor_mapping.h" -#include "mali_kernel_mem_mmu.h" -#include "mali_kernel_memory_engine.h" -#include "mali_block_allocator.h" -#include "mali_kernel_mem_os.h" -#include "mali_kernel_session_manager.h" -#include "mali_kernel_core.h" -#include "mali_kernel_rendercore.h" - -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -#include "ump_kernel_interface.h" -#endif - -/* kernel side OS functions and user-kernel interface */ -#include "mali_osk.h" -#include "mali_osk_mali.h" -#include "mali_ukk.h" -#include "mali_osk_bitops.h" -#include "mali_osk_list.h" - -/** - * Size of the MMU registers in bytes - */ -#define MALI_MMU_REGISTERS_SIZE 0x24 - -/** - * Size of an MMU page in bytes - */ -#define MALI_MMU_PAGE_SIZE 0x1000 - -/** - * Page directory index from address - * Calculates the page directory index from the given address - */ -#define MALI_MMU_PDE_ENTRY(address) (((address)>>22) & 0x03FF) - -/** - * Page table index from address - * Calculates the page table index from the given address - */ -#define MALI_MMU_PTE_ENTRY(address) (((address)>>12) & 0x03FF) - -/** - * Extract the memory address from an PDE/PTE entry - */ -#define MALI_MMU_ENTRY_ADDRESS(value) ((value) & 0xFFFFFC00) - -/** - * Calculate memory address from PDE and PTE - */ -#define MALI_MMU_ADDRESS(pde, pte) (((pde)<<22) | ((pte)<<12)) - -/** - * Linux kernel version has marked SA_SHIRQ as deprecated, IRQF_SHARED should be used. - * This is to handle older kernels which haven't done this swap. - */ -#ifndef IRQF_SHARED -#define IRQF_SHARED SA_SHIRQ -#endif /* IRQF_SHARED */ - -/** - * Per-session memory descriptor mapping table sizes - */ -#define MALI_MEM_DESCRIPTORS_INIT 64 -#define MALI_MEM_DESCRIPTORS_MAX 65536 - -/** - * Used to disallow more than one core to run a MMU at the same time - * - * @note This value is hardwired into some systems' configuration files, - * which \em might not be a header file (e.g. some external data configuration - * file). Therefore, if this value is modified, its occurance must be - * \b manually checked for in the entire driver source tree. - */ -#define MALI_MMU_DISALLOW_PARALLELL_WORK_OF_MALI_CORES 1 - -#define MALI_INVALID_PAGE ((u32)(~0)) - -/** - * - */ -typedef enum mali_mmu_entry_flags -{ - MALI_MMU_FLAGS_PRESENT = 0x01, - MALI_MMU_FLAGS_READ_PERMISSION = 0x02, - MALI_MMU_FLAGS_WRITE_PERMISSION = 0x04, - MALI_MMU_FLAGS_MASK = 0x07 -} mali_mmu_entry_flags; - -/** - * MMU register numbers - * Used in the register read/write routines. - * See the hardware documentation for more information about each register - */ -typedef enum mali_mmu_register { - MALI_MMU_REGISTER_DTE_ADDR = 0x0000, /**< Current Page Directory Pointer */ - MALI_MMU_REGISTER_STATUS = 0x0001, /**< Status of the MMU */ - MALI_MMU_REGISTER_COMMAND = 0x0002, /**< Command register, used to control the MMU */ - MALI_MMU_REGISTER_PAGE_FAULT_ADDR = 0x0003, /**< Logical address of the last page fault */ - MALI_MMU_REGISTER_ZAP_ONE_LINE = 0x004, /**< Used to invalidate the mapping of a single page from the MMU */ - MALI_MMU_REGISTER_INT_RAWSTAT = 0x0005, /**< Raw interrupt status, all interrupts visible */ - MALI_MMU_REGISTER_INT_CLEAR = 0x0006, /**< Indicate to the MMU that the interrupt has been received */ - MALI_MMU_REGISTER_INT_MASK = 0x0007, /**< Enable/disable types of interrupts */ - MALI_MMU_REGISTER_INT_STATUS = 0x0008 /**< Interrupt status based on the mask */ -} mali_mmu_register; - -/** - * MMU interrupt register bits - * Each cause of the interrupt is reported - * through the (raw) interrupt status registers. - * Multiple interrupts can be pending, so multiple bits - * can be set at once. - */ -typedef enum mali_mmu_interrupt -{ - MALI_MMU_INTERRUPT_PAGE_FAULT = 0x01, /**< A page fault occured */ - MALI_MMU_INTERRUPT_READ_BUS_ERROR = 0x02 /**< A bus read error occured */ -} mali_mmu_interrupt; - -/** - * MMU commands - * These are the commands that can be sent - * to the MMU unit. - */ -typedef enum mali_mmu_command -{ - MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */ - MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */ - MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**< Enable stall on page fault */ - MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */ - MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */ - MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */ - MALI_MMU_COMMAND_SOFT_RESET = 0x06 /**< Reset the MMU back to power-on settings */ -} mali_mmu_command; - -typedef enum mali_mmu_status_bits -{ - MALI_MMU_STATUS_BIT_PAGING_ENABLED = 1 << 0, - MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE = 1 << 1, - MALI_MMU_STATUS_BIT_STALL_ACTIVE = 1 << 2, - MALI_MMU_STATUS_BIT_IDLE = 1 << 3, - MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY = 1 << 4, - MALI_MMU_STATUS_BIT_PAGE_FAULT_IS_WRITE = 1 << 5, -} mali_mmu_status_bits; - -/** - * Defintion of the type used to represent memory used by a session. - * Containts the pointer to the huge user space virtual memory area - * used to access the Mali memory. - */ -typedef struct memory_session -{ - _mali_osk_lock_t *lock; /**< Lock protecting the vm manipulation */ - - u32 mali_base_address; /**< Mali virtual memory area used by this session */ - mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ - - u32 page_directory; /**< Physical address of the memory session's page directory */ - - mali_io_address page_directory_mapped; /**< Pointer to the mapped version of the page directory into the kernel's address space */ - mali_io_address page_entries_mapped[1024]; /**< Pointers to the page tables which exists in the page directory mapped into the kernel's address space */ - u32 page_entries_usage_count[1024]; /**< Tracks usage count of the page table pages, so they can be releases on the last reference */ - - _mali_osk_list_t active_mmus; /**< The MMUs in this session, in increasing order of ID (so we can lock them in the correct order when necessary) */ - _mali_osk_list_t memory_head; /**< Track all the memory allocated in this session, for freeing on abnormal termination */ -} memory_session; - -typedef struct mali_kernel_memory_mmu_idle_callback -{ - _mali_osk_list_t link; - void (*callback)(void*); - void * callback_argument; -} mali_kernel_memory_mmu_idle_callback; - -/** - * Definition of the MMU struct - * Used to track a MMU unit in the system. - * Contains information about the mapping of the registers - */ -typedef struct mali_kernel_memory_mmu -{ - int id; /**< ID of the MMU, no duplicate IDs may exist on the system */ - const char * description; /**< Description text received from the resource manager to help identify the resource for people */ - int irq_nr; /**< IRQ number */ - u32 base; /**< Physical address of the registers */ - mali_io_address mapped_registers; /**< Virtual mapping of the registers */ - u32 mapping_size; /**< Size of registers in bytes */ - _mali_osk_list_t list; /**< Used to link multiple MMU's into a list */ - _mali_osk_irq_t *irq; - u32 flags; /**< Used to store if there is something special with this mmu. */ - - _mali_osk_lock_t *lock; /**< Lock protecting access to the usage fields */ - /* usage fields */ - memory_session * active_session; /**< Active session, NULL if no session is active */ - u32 usage_count; /**< Number of nested activations of the active session */ - _mali_osk_list_t callbacks; /**< Callback registered for MMU idle notification */ - void *core; - - int in_page_fault_handler; - - _mali_osk_list_t session_link; -} mali_kernel_memory_mmu; - -typedef struct dedicated_memory_info -{ - u32 base; - u32 size; - struct dedicated_memory_info * next; -} dedicated_memory_info; - -/* types used for external_memory and ump_memory physical memory allocators, which are using the mali_allocation_engine */ -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -typedef struct ump_mem_allocation -{ - mali_allocation_engine * engine; - mali_memory_allocation * descriptor; - u32 initial_offset; - u32 size_allocated; - ump_dd_handle ump_mem; -} ump_mem_allocation ; -#endif - -typedef struct external_mem_allocation -{ - mali_allocation_engine * engine; - mali_memory_allocation * descriptor; - u32 initial_offset; - u32 size; -} external_mem_allocation; - -/* - Subsystem interface implementation -*/ -/** - * Fixed block memory subsystem startup function. - * Called by the driver core when the driver is loaded. - * Registers the memory systems ioctl handler, resource handlers and memory map function with the core. - * - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id); - -/** - * Fixed block memory subsystem shutdown function. - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the memory subsystem - */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id); - -/** - * MMU Memory load complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * Builds the memory overall memory list - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id); - -/** - * Fixed block memory subsystem session begin notification - * Called by the core when a new session to the driver is started. - * Creates a memory session object and sets it as the subsystem slot data for this session - * @param slot Pointer to the slot to use for storing per-session data - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - -/** - * Fixed block memory subsystem session end notification - * Called by the core when a session to the driver has ended. - * Cleans up per session data, which includes checking and fixing memory leaks - * - * @param slot Pointer to the slot to use for storing per-session data - */ -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - -/** - * Fixed block memory subsystem system info filler - * Called by the core when a system info update is needed - * We fill in info about all the memory types we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info); - -/* our registered resource handlers */ - -/** - * Fixed block memory subsystem's notification handler for MMU resource instances. - * Registered with the core during startup. - * Called by the core for each mmu described in the active architecture's config.h file. - * @param resource The resource to handle (type MMU) - * @return 0 if the MMU was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource); - -/** - * Fixed block memory subsystem's notification handler for FPGA_FRAMEWORK resource instances. - * Registered with the core during startup. - * Called by the core for each fpga framework described in the active architecture's config.h file. - * @param resource The resource to handle (type FPGA_FRAMEWORK) - * @return 0 if the FPGA framework was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource); - - -static _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource); -static _mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource); - -/** - * @brief Internal function for unmapping memory - * - * Worker function for unmapping memory from a user-process. We assume that the - * session/descriptor's lock was obtained before entry. For example, the - * wrapper _mali_ukk_mem_munmap() will lock the descriptor, then call this - * function to do the actual unmapping. mali_memory_core_session_end() could - * also call this directly (depending on compilation options), having locked - * the descriptor. - * - * This function will fail if it is unable to put the MMU in stall mode (which - * might be the case if a page fault is also being processed). - * - * @param args see _mali_uk_mem_munmap_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ); - -/** - * The MMU interrupt handler - * Upper half of the MMU interrupt processing. - * Called by the kernel when the MMU has triggered an interrupt. - * The interrupt function supports IRQ sharing. So it'll probe the MMU in question - * @param irq The irq number (not used) - * @param dev_id Points to the MMU object being handled - * @param regs Registers of interrupted process (not used) - * @return Standard Linux interrupt result. - * Subset used by the driver is IRQ_HANDLED processed - * IRQ_NONE Not processed - */ -static _mali_osk_errcode_t mali_kernel_memory_mmu_interrupt_handler_upper_half(void * data); - -/** - * The MMU reset hander - * Bottom half of the MMU interrupt processing for page faults and bus errors - * @param work The item to operate on, NULL in our case - */ -static void mali_kernel_memory_mmu_interrupt_handler_bottom_half ( void *data ); - -/** - * Read MMU register value - * Reads the contents of the specified register. - * @param unit The MMU to read from - * @param reg The register to read - * @return The contents of the register - */ -static u32 mali_mmu_register_read(mali_kernel_memory_mmu * unit, mali_mmu_register reg); - -/** - * Write to a MMU register - * Writes the given value to the specified register - * @param unit The MMU to write to - * @param reg The register to write to - * @param val The value to write to the register - */ -static void mali_mmu_register_write(mali_kernel_memory_mmu * unit, mali_mmu_register reg, u32 val); - -/** - * Issues the reset command to the MMU and waits for HW to be ready again - * @param mmu The MMU to reset - */ -static void mali_mmu_raw_reset(mali_kernel_memory_mmu * mmu); - -/** - * Issues the enable paging command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - */ -static void mali_mmu_enable_paging(mali_kernel_memory_mmu * mmu); - -/** - * Issues the enable stall command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out) - */ -static mali_bool mali_mmu_enable_stall(mali_kernel_memory_mmu * mmu); - -/** - * Issues the disable stall command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - */ -static void mali_mmu_disable_stall(mali_kernel_memory_mmu * mmu); - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -static void ump_memory_release(void * ctx, void * handle); -static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); -#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0*/ - - -static void external_memory_release(void * ctx, void * handle); -static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); - - - - -/* nop functions */ - -/* mali address manager needs to allocate page tables on allocate, write to page table(s) on map, write to page table(s) and release page tables on release */ -static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor); /* validates the range, allocates memory for the page tables if needed */ -static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size); -static void mali_address_manager_release(mali_memory_allocation * descriptor); - -static void mali_mmu_activate_address_space(mali_kernel_memory_mmu * mmu, u32 page_directory); - -_mali_osk_errcode_t mali_mmu_page_table_cache_create(void); -void mali_mmu_page_table_cache_destroy(void); - -_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping); -void mali_mmu_release_table_page(u32 pa); - -static _mali_osk_errcode_t mali_allocate_empty_page_directory(void); - -static void mali_free_empty_page_directory(void); - -static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data); - -static _mali_osk_errcode_t mali_allocate_fault_flush_pages(void); - -static void mali_free_fault_flush_pages(void); - -static void mali_mmu_probe_irq_trigger(mali_kernel_memory_mmu * mmu); -static _mali_osk_errcode_t mali_mmu_probe_irq_acknowledge(mali_kernel_memory_mmu * mmu); - -/* MMU variables */ - -typedef struct mali_mmu_page_table_allocation -{ - _mali_osk_list_t list; - u32 * usage_map; - u32 usage_count; - u32 num_pages; - mali_page_table_block pages; -} mali_mmu_page_table_allocation; - -typedef struct mali_mmu_page_table_allocations -{ - _mali_osk_lock_t *lock; - _mali_osk_list_t partial; - _mali_osk_list_t full; - /* we never hold on to a empty allocation */ -} mali_mmu_page_table_allocations; - -/* Head of the list of MMUs */ -static _MALI_OSK_LIST_HEAD(mmu_head); - -/* the mmu page table cache */ -static struct mali_mmu_page_table_allocations page_table_cache; - -/* page fault queue flush helper pages - * note that the mapping pointers are currently unused outside of the initialization functions */ -static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_page_directory_mapping = NULL; -static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_page_table_mapping = NULL; -static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_data_page_mapping = NULL; - -/* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */ -static u32 mali_empty_page_directory = MALI_INVALID_PAGE; - -/* - The fixed memory system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_memory = -{ - mali_memory_core_initialize, /* startup */ - NULL, /*mali_memory_core_terminate,*/ /* shutdown */ - mali_memory_core_load_complete, /* load_complete */ - mali_memory_core_system_info_fill, /* system_info_fill */ - mali_memory_core_session_begin, /* session_begin */ - mali_memory_core_session_end, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; - -static mali_kernel_mem_address_manager mali_address_manager = -{ - mali_address_manager_allocate, /* allocate */ - mali_address_manager_release, /* release */ - mali_address_manager_map, /* map_physical */ - NULL /* unmap_physical not present*/ -}; - -static mali_kernel_mem_address_manager process_address_manager = -{ - _mali_osk_mem_mapregion_init, /* allocate */ - _mali_osk_mem_mapregion_term, /* release */ - _mali_osk_mem_mapregion_map, /* map_physical */ - _mali_osk_mem_mapregion_unmap /* unmap_physical */ -}; - -static mali_allocation_engine memory_engine = NULL; -static mali_physical_memory_allocator * physical_memory_allocators = NULL; - -static dedicated_memory_info * mem_region_registrations = NULL; - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_memory_id = (mali_kernel_subsystem_identifier)-1; - -/* called during module init */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(2, ("MMU memory system initializing\n")); - - /* save our subsystem id for later for use in slot lookup during session activation */ - mali_subsystem_memory_id = id; - - _MALI_OSK_INIT_LIST_HEAD(&mmu_head); - - MALI_CHECK_NO_ERROR( mali_mmu_page_table_cache_create() ); - - /* register our handlers */ - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(MMU, mali_memory_core_resource_mmu) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(FPGA_FRAMEWORK, mali_memory_core_resource_fpga) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(MEMORY, mali_memory_core_resource_dedicated_memory) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(OS_MEMORY, mali_memory_core_resource_os_memory) ); - - memory_engine = mali_allocation_engine_create(&mali_address_manager, &process_address_manager); - MALI_CHECK_NON_NULL( memory_engine, _MALI_OSK_ERR_FAULT); - - MALI_SUCCESS; -} - -/* called if/when our module is unloaded */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id) -{ - mali_kernel_memory_mmu * mmu, *temp_mmu; - - MALI_DEBUG_PRINT(2, ("MMU memory system terminating\n")); - - /* loop over all MMU units and shut them down */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - /* reset to defaults */ - mali_mmu_raw_reset(mmu); - - /* unregister the irq */ - _mali_osk_irq_term(mmu->irq); - - /* remove from the list of MMU's on the system */ - _mali_osk_list_del(&mmu->list); - - /* release resources */ - _mali_osk_mem_unmapioregion(mmu->base, mmu->mapping_size, mmu->mapped_registers); - _mali_osk_mem_unreqregion(mmu->base, mmu->mapping_size); - _mali_osk_lock_term(mmu->lock); - _mali_osk_free(mmu); - } - - /* free global helper pages */ - mali_free_empty_page_directory(); - mali_free_fault_flush_pages(); - - /* destroy the page table cache before shutting down backends in case we have a page table leak to report */ - mali_mmu_page_table_cache_destroy(); - - while ( NULL != mem_region_registrations) - { - dedicated_memory_info * m; - m = mem_region_registrations; - mem_region_registrations = m->next; - _mali_osk_mem_unreqregion(m->base, m->size); - _mali_osk_free(m); - } - - while ( NULL != physical_memory_allocators) - { - mali_physical_memory_allocator * m; - m = physical_memory_allocators; - physical_memory_allocators = m->next; - m->destroy(m); - } - - if (NULL != memory_engine) - { - mali_allocation_engine_destroy(memory_engine); - memory_engine = NULL; - } - -} - -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - memory_session * session_data; - _mali_osk_errcode_t err; - int i; - mali_io_address pd_mapped; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (NULL != *slot) - { - MALI_DEBUG_PRINT(1, ("The slot given to memory session begin already contains data")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_DEBUG_PRINT(2, ("MMU session begin\n")); - - /* create the session data object */ - session_data = _mali_osk_calloc(1, sizeof(memory_session)); - MALI_CHECK_NON_NULL( session_data, _MALI_OSK_ERR_NOMEM ); - - /* create descriptor mapping table */ - session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); - - if (NULL == session_data->descriptor_mapping) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - err = mali_mmu_get_table_page(&session_data->page_directory, &pd_mapped); - - session_data->page_directory_mapped = pd_mapped; - if (_MALI_OSK_ERR_OK != err) - { - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - _mali_osk_free(session_data); - MALI_ERROR(err); - } - MALI_DEBUG_ASSERT_POINTER( session_data->page_directory_mapped ); - - MALI_DEBUG_PRINT(2, ("Page directory for session 0x%x placed at physical address 0x%08X\n", mali_session_data, session_data->page_directory)); - - for (i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) - { - /* mark each page table as not present */ - _mali_osk_mem_iowrite32_relaxed(session_data->page_directory_mapped, sizeof(u32) * i, 0); - } - _mali_osk_write_mem_barrier(); - - /* page_table_mapped[] is already set to NULL by _mali_osk_calloc call */ - - _MALI_OSK_INIT_LIST_HEAD(&session_data->active_mmus); - session_data->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 128); - if (NULL == session_data->lock) - { - mali_mmu_release_table_page(session_data->page_directory); - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Init the session's memory allocation list */ - _MALI_OSK_INIT_LIST_HEAD( &session_data->memory_head ); - - *slot = session_data; /* slot will point to our data object */ - MALI_DEBUG_PRINT(2, ("MMU session begin: success\n")); - MALI_SUCCESS; -} - -static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target) -{ - mali_memory_allocation * descriptor; - - descriptor = (mali_memory_allocation*)map_target; - - MALI_DEBUG_PRINT(1, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target)); - MALI_DEBUG_ASSERT(descriptor); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - _mali_osk_free(descriptor); -} - -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - memory_session * session_data; - int i; - const int num_page_table_entries = sizeof(session_data->page_entries_mapped) / sizeof(session_data->page_entries_mapped[0]); - - MALI_DEBUG_PRINT(2, ("MMU session end\n")); - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - return; - } - - session_data = (memory_session *)*slot; - - if (NULL == session_data) - { - MALI_DEBUG_PRINT(1, ("No session data found during session end\n")); - return; - } - /* Lock the session so we can modify the memory list */ - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - /* Noninterruptable spinlock type, so must always have locked. Checking should've been done in OSK function. */ - -#ifndef MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP -#if _MALI_OSK_SPECIFIC_INDIRECT_MMAP -#error Indirect MMAP specified, but UKK does not have implicit MMAP cleanup. Current implementation does not handle this. -#else - - /* Free all memory engine allocations */ - if (0 == _mali_osk_list_empty(&session_data->memory_head)) - { - mali_memory_allocation *descriptor; - mali_memory_allocation *temp; - _mali_uk_mem_munmap_s unmap_args; - - MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); - - unmap_args.ctx = mali_session_data; - - /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */ - _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->memory_head, mali_memory_allocation, list) - { - MALI_DEBUG_PRINT(4, ("Freeing block with mali address 0x%x size %d mapped in user space at 0x%x\n", - descriptor->mali_address, descriptor->size, descriptor->size, descriptor->mapping) - ); - /* ASSERT that the descriptor's lock references the correct thing */ - MALI_DEBUG_ASSERT( descriptor->lock == session_data->lock ); - /* Therefore, we have already locked the descriptor */ - - unmap_args.size = descriptor->size; - unmap_args.mapping = descriptor->mapping; - unmap_args.cookie = (u32)descriptor; - - /* - * This removes the descriptor from the list, and frees the descriptor - * - * Does not handle the _MALI_OSK_SPECIFIC_INDIRECT_MMAP case, since - * the only OS we are aware of that requires indirect MMAP also has - * implicit mmap cleanup. - */ - _mali_ukk_mem_munmap_internal( &unmap_args ); - } - } - - /* Assert that we really did free everything */ - MALI_DEBUG_ASSERT( _mali_osk_list_empty(&session_data->memory_head) ); -#endif /* _MALI_OSK_SPECIFIC_INDIRECT_MMAP */ -#endif /* MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP */ - - if (NULL != session_data->descriptor_mapping) - { - mali_descriptor_mapping_call_for_each(session_data->descriptor_mapping, descriptor_table_cleanup_callback); - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - session_data->descriptor_mapping = NULL; - } - - for (i = 0; i < num_page_table_entries; i++) - { - /* free PTE memory */ - if (session_data->page_directory_mapped && (_mali_osk_mem_ioread32(session_data->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT)) - { - mali_mmu_release_table_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); - } - } - - if (MALI_INVALID_PAGE != session_data->page_directory) - { - mali_mmu_release_table_page(session_data->page_directory); - session_data->page_directory = MALI_INVALID_PAGE; - } - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - /** - * @note Could the VMA close handler mean that we use the session data after it was freed? - * In which case, would need to refcount the session data, and free on VMA close - */ - - /* Free the lock */ - _mali_osk_lock_term( session_data->lock ); - /* free the session data object */ - _mali_osk_free(session_data); - - /* clear our slot */ - *slot = NULL; - - return; -} - -static _mali_osk_errcode_t mali_allocate_empty_page_directory(void) -{ - _mali_osk_errcode_t err; - mali_io_address mapping; - - MALI_CHECK_NO_ERROR(mali_mmu_get_table_page(&mali_empty_page_directory, &mapping)); - - MALI_DEBUG_ASSERT_POINTER( mapping ); - - err = fill_page(mapping, 0); - if (_MALI_OSK_ERR_OK != err) - { - mali_mmu_release_table_page(mali_empty_page_directory); - mali_empty_page_directory = MALI_INVALID_PAGE; - } - return err; -} - -static void mali_free_empty_page_directory(void) -{ - if (MALI_INVALID_PAGE != mali_empty_page_directory) - { - mali_mmu_release_table_page(mali_empty_page_directory); - mali_empty_page_directory = MALI_INVALID_PAGE; - } -} - -static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data) -{ - int i; - MALI_DEBUG_ASSERT_POINTER( mapping ); - - for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) - { - _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data); - } - _mali_osk_mem_barrier(); - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_allocate_fault_flush_pages(void) -{ - _mali_osk_errcode_t err; - - err = mali_mmu_get_table_page(&mali_page_fault_flush_data_page, &mali_page_fault_flush_data_page_mapping); - if (_MALI_OSK_ERR_OK == err) - { - err = mali_mmu_get_table_page(&mali_page_fault_flush_page_table, &mali_page_fault_flush_page_table_mapping); - if (_MALI_OSK_ERR_OK == err) - { - err = mali_mmu_get_table_page(&mali_page_fault_flush_page_directory, &mali_page_fault_flush_page_directory_mapping); - if (_MALI_OSK_ERR_OK == err) - { - fill_page(mali_page_fault_flush_data_page_mapping, 0); - fill_page(mali_page_fault_flush_page_table_mapping, mali_page_fault_flush_data_page | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); - fill_page(mali_page_fault_flush_page_directory_mapping, mali_page_fault_flush_page_table | MALI_MMU_FLAGS_PRESENT); - MALI_SUCCESS; - } - mali_mmu_release_table_page(mali_page_fault_flush_page_table); - mali_page_fault_flush_page_table = MALI_INVALID_PAGE; - mali_page_fault_flush_page_table_mapping = NULL; - } - mali_mmu_release_table_page(mali_page_fault_flush_data_page); - mali_page_fault_flush_data_page = MALI_INVALID_PAGE; - mali_page_fault_flush_data_page_mapping = NULL; - } - MALI_ERROR(err); -} - -static void mali_free_fault_flush_pages(void) -{ - if (MALI_INVALID_PAGE != mali_page_fault_flush_page_directory) - { - mali_mmu_release_table_page(mali_page_fault_flush_page_directory); - mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; - } - - if (MALI_INVALID_PAGE != mali_page_fault_flush_page_table) - { - mali_mmu_release_table_page(mali_page_fault_flush_page_table); - mali_page_fault_flush_page_table = MALI_INVALID_PAGE; - } - - if (MALI_INVALID_PAGE != mali_page_fault_flush_data_page) - { - mali_mmu_release_table_page(mali_page_fault_flush_data_page); - mali_page_fault_flush_data_page = MALI_INVALID_PAGE; - } -} - -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_kernel_memory_mmu * mmu, * temp_mmu; - - /* Report the allocators */ - mali_allocation_engine_report_allocators( physical_memory_allocators ); - - /* allocate the helper pages */ - MALI_CHECK_NO_ERROR( mali_allocate_empty_page_directory() ); - if (_MALI_OSK_ERR_OK != mali_allocate_fault_flush_pages()) - { - mali_free_empty_page_directory(); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* activate the empty page directory on all MMU's */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); - mali_mmu_enable_paging(mmu); - } - - MALI_DEBUG_PRINT(4, ("MMUs activated\n")); - /* the MMU system is now active */ - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info) -{ - _mali_mem_info * mem_info; - - /* Make sure we won't leak any memory. It could also be that it's an - * uninitialized variable, but the caller should have zeroed the - * variable. */ - MALI_DEBUG_ASSERT(NULL == info->mem_info); - - info->has_mmu = 1; - - mem_info = _mali_osk_calloc(1,sizeof(_mali_mem_info)); - MALI_CHECK_NON_NULL( mem_info, _MALI_OSK_ERR_NOMEM ); - - mem_info->size = 2048UL * 1024UL * 1024UL; - mem_info->maximum_order_supported = 30; - mem_info->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE; - mem_info->identifier = 0; - - info->mem_info = mem_info; - - /* all OK */ - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource) -{ - mali_kernel_memory_mmu * mmu; - - MALI_DEBUG_PRINT(4, ("MMU '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1 - )); - - if (NULL != mali_memory_core_mmu_lookup(resource->mmu_id)) - { - MALI_DEBUG_PRINT(1, ("Duplicate MMU ids found. The id %d is already in use\n", resource->mmu_id)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, MALI_MMU_REGISTERS_SIZE, resource->description)) - { - /* specified addresses are already in used by another driver / the kernel */ - MALI_DEBUG_PRINT( - 1, ("Failed to request MMU '%s' register address space at (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1 - )); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mmu = _mali_osk_calloc(1, sizeof(mali_kernel_memory_mmu)); - - if (NULL == mmu) - { - MALI_DEBUG_PRINT(1, ("Failed to allocate memory for handling a MMU unit")); - _mali_osk_mem_unreqregion(resource->base, MALI_MMU_REGISTERS_SIZE); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* basic setup */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->list); - - mmu->id = resource->mmu_id; - mmu->irq_nr = resource->irq; - mmu->flags = resource->flags; - mmu->base = resource->base; - mmu->mapping_size = MALI_MMU_REGISTERS_SIZE; - mmu->description = resource->description; /* no need to copy */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->callbacks); - _MALI_OSK_INIT_LIST_HEAD(&mmu->session_link); - mmu->in_page_fault_handler = 0; - - mmu->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 127-mmu->id); - if (NULL == mmu->lock) - { - MALI_DEBUG_PRINT(1, ("Failed to create mmu lock\n")); - _mali_osk_mem_unreqregion(mmu->base, mmu->mapping_size); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* map the registers */ - mmu->mapped_registers = _mali_osk_mem_mapioregion( mmu->base, mmu->mapping_size, mmu->description ); - if (NULL == mmu->mapped_registers) - { - /* failed to map the registers */ - MALI_DEBUG_PRINT(1, ("Failed to map MMU registers at 0x%08X\n", mmu->base)); - _mali_osk_lock_term(mmu->lock); - _mali_osk_mem_unreqregion(mmu->base, MALI_MMU_REGISTERS_SIZE); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(4, ("MMU '%s' @ (0x%08X - 0x%08X) mapped to 0x%08X\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1, mmu->mapped_registers - )); - - /* setup MMU interrupt mask */ - /* set all values to known defaults */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - /* setup MMU page directory pointer */ - /* The mali_page_directory pointer is guaranteed to be 4kb aligned because we've used get_zeroed_page to accquire it */ - /* convert the kernel virtual address into a physical address and set */ - - /* add to our list of MMU's */ - _mali_osk_list_addtail(&mmu->list, &mmu_head); - - mmu->irq = _mali_osk_irq_init( - mmu->irq_nr, - mali_kernel_memory_mmu_interrupt_handler_upper_half, - mali_kernel_memory_mmu_interrupt_handler_bottom_half, - (_mali_osk_irq_trigger_t)mali_mmu_probe_irq_trigger, - (_mali_osk_irq_ack_t)mali_mmu_probe_irq_acknowledge, - mmu, - "mali_mmu_irq_handlers" - ); - if (NULL == mmu->irq) - { - _mali_osk_list_del(&mmu->list); - _mali_osk_lock_term(mmu->lock); - _mali_osk_mem_unmapioregion( mmu->base, mmu->mapping_size, mmu->mapped_registers ); - _mali_osk_mem_unreqregion(resource->base, MALI_MMU_REGISTERS_SIZE); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* set to a known state */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - - MALI_DEBUG_PRINT(2, ("MMU registered\n")); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource) -{ - mali_io_address mapping; - - MALI_DEBUG_PRINT(5, ("FPGA framework '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + sizeof(u32) * 2 - 1 - )); - - mapping = _mali_osk_mem_mapioregion(resource->base + 0x1000, sizeof(u32) * 2, "fpga framework"); - if (mapping) - { - MALI_DEBUG_CODE(u32 data = ) - _mali_osk_mem_ioread32(mapping, 0); - MALI_DEBUG_PRINT(2, ("FPGA framwork '%s' @ 0x%08X:\n", resource->description, resource->base)); - MALI_DEBUG_PRINT(2, ("\tBitfile date: %d%02d%02d_%02d%02d\n", - (data >> 20), - (data >> 16) & 0xF, - (data >> 11) & 0x1F, - (data >> 6) & 0x1F, - (data >> 0) & 0x3F)); - MALI_DEBUG_CODE(data = ) - _mali_osk_mem_ioread32(mapping, sizeof(u32)); - MALI_DEBUG_PRINT(2, ("\tBitfile SCCS rev: %d\n", data)); - - _mali_osk_mem_unmapioregion(resource->base + 0x1000, sizeof(u32) *2, mapping); - } - else MALI_DEBUG_PRINT(1, ("Failed to access FPGA framwork '%s' @ 0x%08X\n", resource->description, resource->base)); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource) -{ - mali_physical_memory_allocator * allocator; - mali_physical_memory_allocator ** next_allocator_list; - - u32 alloc_order = resource->alloc_order; - - allocator = mali_os_allocator_create(resource->size, resource->cpu_usage_adjust, resource->description); - if (NULL == allocator) - { - MALI_DEBUG_PRINT(1, ("Failed to create OS memory allocator\n")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - allocator->alloc_order = alloc_order; - - /* link in the allocator: insertion into ordered list - * resources of the same alloc_order will be Last-in-first */ - next_allocator_list = &physical_memory_allocators; - - while ( NULL != *next_allocator_list && - (*next_allocator_list)->alloc_order < alloc_order ) - { - next_allocator_list = &((*next_allocator_list)->next); - } - - allocator->next = (*next_allocator_list); - (*next_allocator_list) = allocator; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource) -{ - mali_physical_memory_allocator * allocator; - mali_physical_memory_allocator ** next_allocator_list; - dedicated_memory_info * cleanup_data; - - u32 alloc_order = resource->alloc_order; - - /* do the lowlevel linux operation first */ - - /* Request ownership of the memory */ - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) - { - MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* create generic block allocator object to handle it */ - allocator = mali_block_allocator_create(resource->base, resource->cpu_usage_adjust, resource->size, resource->description ); - - if (NULL == allocator) - { - MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); - _mali_osk_mem_unreqregion(resource->base, resource->size); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* save lowlevel cleanup info */ - allocator->alloc_order = alloc_order; - - cleanup_data = _mali_osk_malloc(sizeof(dedicated_memory_info)); - - if (NULL == cleanup_data) - { - _mali_osk_mem_unreqregion(resource->base, resource->size); - allocator->destroy(allocator); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - cleanup_data->base = resource->base; - cleanup_data->size = resource->size; - - cleanup_data->next = mem_region_registrations; - mem_region_registrations = cleanup_data; - - /* link in the allocator: insertion into ordered list - * resources of the same alloc_order will be Last-in-first */ - next_allocator_list = &physical_memory_allocators; - - while ( NULL != *next_allocator_list && - (*next_allocator_list)->alloc_order < alloc_order ) - { - next_allocator_list = &((*next_allocator_list)->next); - } - - allocator->next = (*next_allocator_list); - (*next_allocator_list) = allocator; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_memory_mmu_interrupt_handler_upper_half(void * data) -{ - mali_kernel_memory_mmu * mmu; - u32 int_stat; - mali_core_renderunit *core; - - if (mali_benchmark) MALI_SUCCESS; - - mmu = (mali_kernel_memory_mmu *)data; - - MALI_DEBUG_ASSERT_POINTER(mmu); - - /* Pointer to core holding this MMU */ - core = (mali_core_renderunit *)mmu->core; - if(core && (CORE_OFF == core->state)) - { - MALI_SUCCESS; - } - - - /* check if it was our device which caused the interrupt (we could be sharing the IRQ line) */ - int_stat = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_STATUS); - if (0 == int_stat) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); /* no bits set, we are sharing the IRQ line and someone else caused the interrupt */ - } - - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, 0); - - mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - - if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) - { - _mali_osk_irq_schedulework(mmu->irq); - } - if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) - { - /* clear interrupt flag */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); - /* reenable it */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_MASK) | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - } - - MALI_SUCCESS; -} - - -static void mali_kernel_mmu_bus_reset(mali_kernel_memory_mmu * mmu) -{ - -#if defined(USING_MALI200) - int i; - const int replay_buffer_check_interval = 10; /* must be below 1000 */ - const int replay_buffer_max_number_of_checks = 100; -#endif - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - /* add an extra reference while handling the page fault */ - mmu->usage_count++; - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(4, ("Sending stop bus request to cores\n")); - /* request to stop the bus, but don't wait for it to actually stop */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES, (u32)mmu); - -#if defined(USING_MALI200) - /* no new request will come from any of the connected cores from now - * we must now flush the playback buffer for any requests queued already - */ - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(4, ("Switching to the special page fault flush page directory\n")); - /* don't use the mali_mmu_activate_address_space function here as we can't stall the MMU */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_page_fault_flush_page_directory); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - /* resume the MMU */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE); - /* the MMU will now play back all the requests, all going to our special page fault flush data page */ - - /* just to be safe, check that the playback buffer is empty before continuing */ - if (!mali_benchmark) { - for (i = 0; i < replay_buffer_max_number_of_checks; i++) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY) break; - _mali_osk_time_ubusydelay(replay_buffer_check_interval); - } - - MALI_DEBUG_PRINT_IF(1, i == replay_buffer_max_number_of_checks, ("MMU: %s: Failed to flush replay buffer on page fault\n", mmu->description)); - MALI_DEBUG_PRINT(1, ("Replay playback took %ld usec\n", i * replay_buffer_check_interval)); - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - -#endif - /* notify all subsystems that the core should be reset once the bus is actually stopped */ - MALI_DEBUG_PRINT(4,("Sending job abort command to subsystems\n")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS, (u32)mmu); - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* reprogram the MMU */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); /* no session is active, so just activate the empty page directory */ - mali_mmu_enable_paging(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* release the extra address space reference, will schedule */ - mali_memory_core_mmu_release_address_space_reference(mmu); - - /* resume normal operation */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP3_CONTINUE_JOB_HANDLING, (u32)mmu); - MALI_DEBUG_PRINT(4, ("Page fault handling complete\n")); -} - -static void mali_mmu_raw_reset(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_SOFT_RESET); - - if (!mali_benchmark) - { - int i; - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_DTE_ADDR) == 0) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Reset request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -static void mali_mmu_enable_paging(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING); - - if (!mali_benchmark) - { - int i; - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Enable paging request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -static mali_bool mali_mmu_enable_stall(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 999; - int i; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL); - - if (!mali_benchmark) - { - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_STALL_ACTIVE) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Enable stall request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - if (max_loop_count == i) - { - return MALI_FALSE; - } - } - - return MALI_TRUE; -} - -static void mali_mmu_disable_stall(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - int i; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL); - - if (!mali_benchmark) - { - for (i = 0; i < max_loop_count; ++i) - { - if ((mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_STALL_ACTIVE) == 0) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Disable stall request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -void mali_kernel_mmu_reset(void * input_mmu) -{ - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(input_mmu); - mmu = (mali_kernel_memory_mmu *)input_mmu; - - MALI_DEBUG_PRINT(4, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->description)); - - if ( 0 != mmu->in_page_fault_handler) - { - /* This is possible if the bus can never be stopped for some reason */ - MALI_PRINT_ERROR(("Stopping the Memory bus not possible. Mali reset could not be performed.")); - return; - } - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); /* no session is active, so just activate the empty page directory */ - mali_mmu_enable_paging(mmu); - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - -} - -void mali_kernel_mmu_force_bus_reset(void * input_mmu) -{ - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(input_mmu); - mmu = (mali_kernel_memory_mmu *)input_mmu; - if ( 0 != mmu->in_page_fault_handler) - { - /* This is possible if the bus can never be stopped for some reason */ - MALI_PRINT_ERROR(("Stopping the Memory bus not possible. Mali reset could not be performed.")); - return; - } - MALI_DEBUG_PRINT(1, ("Mali MMU: Force_bus_reset.\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, 0); - mali_kernel_mmu_bus_reset(mmu); -} - - -static void mali_kernel_memory_mmu_interrupt_handler_bottom_half(void * data) -{ - mali_kernel_memory_mmu * mmu; - u32 raw, fault_address, status; - mali_core_renderunit *core; - - MALI_DEBUG_PRINT(1, ("mali_kernel_memory_mmu_interrupt_handler_bottom_half\n")); - if (NULL == data) - { - MALI_PRINT_ERROR(("MMU IRQ work queue: NULL argument")); - return; /* Error */ - } - mmu = (mali_kernel_memory_mmu*)data; - - MALI_DEBUG_PRINT(4, ("Locking subsystems\n")); - /* lock all subsystems */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP0_LOCK_SUBSYSTEM, (u32)mmu); - - /* Pointer to core holding this MMU */ - core = (mali_core_renderunit *)mmu->core; - - if(CORE_OFF == core->state) - { - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - return; - } - - raw = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_RAWSTAT); - status = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - - if ( (0==(raw & MALI_MMU_INTERRUPT_PAGE_FAULT)) && (0==(status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) ) - { - MALI_DEBUG_PRINT(1, ("MMU: Page fault bottom half: No Irq found.\n")); - MALI_DEBUG_PRINT(4, ("Unlocking subsystems")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - return; - } - - mmu->in_page_fault_handler = 1; - - fault_address = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_PAGE_FAULT_ADDR); - MALI_PRINT(("Page fault detected at 0x%x from bus id %d of type %s on %s\n", - (void*)fault_address, - (status >> 6) & 0x1F, - (status & 32) ? "write" : "read", - mmu->description) - ); - - if (NULL == mmu->active_session) - { - MALI_PRINT(("Spurious memory access detected from MMU %s\n", mmu->description)); - } - else - { - MALI_PRINT(("Active page directory at 0x%08X\n", mmu->active_session->page_directory)); - MALI_PRINT(("Info from page table for VA 0x%x:\n", (void*)fault_address)); - MALI_PRINT(("DTE entry: PTE at 0x%x marked as %s\n", - (void*)(_mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, - MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK), - _mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, - MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT ? "present" : "not present" - )); - - if (_mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT) - { - mali_io_address pte; - u32 data; - pte = mmu->active_session->page_entries_mapped[MALI_MMU_PDE_ENTRY(fault_address)]; - data = _mali_osk_mem_ioread32(pte, MALI_MMU_PTE_ENTRY(fault_address) * sizeof(u32)); - MALI_PRINT(("PTE entry: Page at 0x%x, %s %s %s\n", - (void*)(data & ~MALI_MMU_FLAGS_MASK), - data & MALI_MMU_FLAGS_PRESENT ? "present" : "not present", - data & MALI_MMU_FLAGS_READ_PERMISSION ? "readable" : "", - data & MALI_MMU_FLAGS_WRITE_PERMISSION ? "writable" : "" - )); - } - else - { - MALI_PRINT(("PTE entry: Not present\n")); - } - } - - - mali_kernel_mmu_bus_reset(mmu); - - mmu->in_page_fault_handler = 0; - - /* unlock all subsystems */ - MALI_DEBUG_PRINT(4, ("Unlocking subsystems")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - -} - - -static u32 mali_mmu_register_read(mali_kernel_memory_mmu * unit, mali_mmu_register reg) -{ - u32 val; - - if (mali_benchmark) return 0; - - val = _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32)); - - MALI_DEBUG_PRINT(6, ("mali_mmu_register_read addr:0x%04X val:0x%08x\n", (u32)reg * sizeof(u32),val)); - - return val; -} - -static void mali_mmu_register_write(mali_kernel_memory_mmu * unit, mali_mmu_register reg, u32 val) -{ - if (mali_benchmark) return; - - MALI_DEBUG_PRINT(6, ("mali_mmu_register_write addr:0x%04X val:0x%08x\n", (u32)reg * sizeof(u32), val)); - - _mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val); -} - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) -{ - ump_dd_handle ump_mem; - u32 nr_blocks; - u32 i; - ump_dd_physical_block * ump_blocks; - ump_mem_allocation *ret_allocation; - - MALI_DEBUG_ASSERT_POINTER(ctx); - MALI_DEBUG_ASSERT_POINTER(engine); - MALI_DEBUG_ASSERT_POINTER(descriptor); - MALI_DEBUG_ASSERT_POINTER(alloc_info); - - ret_allocation = _mali_osk_malloc( sizeof( ump_mem_allocation ) ); - if ( NULL==ret_allocation ) return MALI_MEM_ALLOC_INTERNAL_FAILURE; - - ump_mem = (ump_dd_handle)ctx; - - MALI_DEBUG_PRINT(4, ("In ump_memory_commit\n")); - - nr_blocks = ump_dd_phys_block_count_get(ump_mem); - - MALI_DEBUG_PRINT(4, ("Have %d blocks\n", nr_blocks)); - - if (nr_blocks == 0) - { - MALI_DEBUG_PRINT(1, ("No block count\n")); - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks ); - if ( NULL==ump_blocks ) - { - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks)) - { - _mali_osk_free(ump_blocks); - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - /* Store away the initial offset for unmapping purposes */ - ret_allocation->initial_offset = *offset; - - for(i=0; i<nr_blocks; ++i) - { - MALI_DEBUG_PRINT(4, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size)); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[i].addr , 0, ump_blocks[i].size )) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); - - /* unmap all previous blocks (if any) */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_free(ump_blocks); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += ump_blocks[i].size; - } - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - /* Map in an extra virtual guard page at the end of the VMA */ - MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[0].addr , 0, _MALI_OSK_MALI_PAGE_SIZE )) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); - - /* unmap all previous blocks (if any) */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_free(ump_blocks); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += _MALI_OSK_MALI_PAGE_SIZE; - } - - _mali_osk_free( ump_blocks ); - - ret_allocation->engine = engine; - ret_allocation->descriptor = descriptor; - ret_allocation->ump_mem = ump_mem; - ret_allocation->size_allocated = *offset - ret_allocation->initial_offset; - - alloc_info->ctx = NULL; - alloc_info->handle = ret_allocation; - alloc_info->next = NULL; - alloc_info->release = ump_memory_release; - - return MALI_MEM_ALLOC_FINISHED; -} - -static void ump_memory_release(void * ctx, void * handle) -{ - ump_dd_handle ump_mem; - ump_mem_allocation *allocation; - - allocation = (ump_mem_allocation *)handle; - - MALI_DEBUG_ASSERT_POINTER( allocation ); - - ump_mem = allocation->ump_mem; - - MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID!=ump_mem); - - /* At present, this is a no-op. But, it allows the mali_address_manager to - * do unmapping of a subrange in future. */ - mali_allocation_engine_unmap_physical( allocation->engine, - allocation->descriptor, - allocation->initial_offset, - allocation->size_allocated, - (_mali_osk_mem_mapregion_flags_t)0 - ); - _mali_osk_free( allocation ); - - - ump_dd_reference_release(ump_mem) ; - return; -} - -_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ) -{ - ump_dd_handle ump_mem; - mali_physical_memory_allocator external_memory_allocator; - memory_session * session_data; - mali_memory_allocation * descriptor; - int md; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - /* check arguments */ - /* NULL might be a valid Mali address */ - if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - /* size must be a multiple of the system page size */ - if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - MALI_DEBUG_PRINT(3, - ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n", - args->secure_id, args->mali_address, args->size)); - - ump_mem = ump_dd_handle_create_from_secure_id( (int)args->secure_id ) ; - - if ( UMP_DD_HANDLE_INVALID==ump_mem ) MALI_ERROR(_MALI_OSK_ERR_FAULT); - - descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); - if (NULL == descriptor) - { - ump_dd_reference_release(ump_mem); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - descriptor->size = args->size; - descriptor->mapping = NULL; - descriptor->mali_address = args->mali_address; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ - descriptor->lock = session_data->lock; - if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) - { - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; - } - _mali_osk_list_init( &descriptor->list ); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) - { - ump_dd_reference_release(ump_mem); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - external_memory_allocator.allocate = ump_memory_commit; - external_memory_allocator.allocate_page_table_block = NULL; - external_memory_allocator.ctx = ump_mem; - external_memory_allocator.name = "UMP Memory"; - external_memory_allocator.next = NULL; - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - ump_dd_reference_release(ump_mem); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - args->cookie = md; - - MALI_DEBUG_PRINT(5,("Returning from UMP attach\n")); - - /* All OK */ - MALI_SUCCESS; -} - - -_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ) -{ - mali_memory_allocation * descriptor; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); - - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - _mali_osk_free(descriptor); - - MALI_SUCCESS; - -} -#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 */ - - -static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) -{ - u32 * data; - external_mem_allocation * ret_allocation; - - MALI_DEBUG_ASSERT_POINTER(ctx); - MALI_DEBUG_ASSERT_POINTER(engine); - MALI_DEBUG_ASSERT_POINTER(descriptor); - MALI_DEBUG_ASSERT_POINTER(alloc_info); - - ret_allocation = _mali_osk_malloc( sizeof(external_mem_allocation) ); - - if ( NULL == ret_allocation ) - { - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - data = (u32*)ctx; - - ret_allocation->engine = engine; - ret_allocation->descriptor = descriptor; - ret_allocation->initial_offset = *offset; - - alloc_info->ctx = NULL; - alloc_info->handle = ret_allocation; - alloc_info->next = NULL; - alloc_info->release = external_memory_release; - - MALI_DEBUG_PRINT(3, ("External map: mapping phys 0x%08X at mali virtual address 0x%08X staring at offset 0x%08X length 0x%08X\n", data[0], descriptor->mali_address, *offset, data[1])); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, data[1])) - { - MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += data[1]; - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - /* Map in an extra virtual guard page at the end of the VMA */ - MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, _MALI_OSK_MALI_PAGE_SIZE)) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); - - /* unmap what we previously mapped */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += _MALI_OSK_MALI_PAGE_SIZE; - } - - ret_allocation->size = *offset - ret_allocation->initial_offset; - - return MALI_MEM_ALLOC_FINISHED; -} - -static void external_memory_release(void * ctx, void * handle) -{ - external_mem_allocation * allocation; - - allocation = (external_mem_allocation *) handle; - MALI_DEBUG_ASSERT_POINTER( allocation ); - - /* At present, this is a no-op. But, it allows the mali_address_manager to - * do unmapping of a subrange in future. */ - - mali_allocation_engine_unmap_physical( allocation->engine, - allocation->descriptor, - allocation->initial_offset, - allocation->size, - (_mali_osk_mem_mapregion_flags_t)0 - ); - - _mali_osk_free( allocation ); - - return; -} - -_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) -{ - mali_physical_memory_allocator external_memory_allocator; - memory_session * session_data; - u32 info[2]; - mali_memory_allocation * descriptor; - int md; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - external_memory_allocator.allocate = external_memory_commit; - external_memory_allocator.allocate_page_table_block = NULL; - external_memory_allocator.ctx = &info[0]; - external_memory_allocator.name = "External Memory"; - external_memory_allocator.next = NULL; - - /* check arguments */ - /* NULL might be a valid Mali address */ - if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - /* size must be a multiple of the system page size */ - if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - MALI_DEBUG_PRINT(3, - ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n", - (void*)args->phys_addr, - (void*)(args->phys_addr + args->size -1), - (void*)args->mali_address) - ); - - /* Validate the mali physical range */ - MALI_CHECK_NO_ERROR( mali_kernel_core_validate_mali_phys_range( args->phys_addr, args->size ) ); - - info[0] = args->phys_addr; - info[1] = args->size; - - descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); - if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - descriptor->size = args->size; - descriptor->mapping = NULL; - descriptor->mali_address = args->mali_address; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ - descriptor->lock = session_data->lock; - if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) - { - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; - } - _mali_osk_list_init( &descriptor->list ); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) - { - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - args->cookie = md; - - MALI_DEBUG_PRINT(5,("Returning from range_map_external_memory\n")); - - /* All OK */ - MALI_SUCCESS; -} - - -_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) -{ - mali_memory_allocation * descriptor; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); - - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - _mali_osk_free(descriptor); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) -{ - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */ - args->mali_address_base = 1 * 1024 * 1024 * 1024UL; /* staring at 1GB, causing this layout: (0-1GB unused)(1GB-3G usage by Mali)(3G-4G unused) */ - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) -{ - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_mmu_page_table_cache_create(void) -{ - page_table_cache.lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 110); - MALI_CHECK_NON_NULL( page_table_cache.lock, _MALI_OSK_ERR_FAULT ); - _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.partial); - _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.full); - MALI_SUCCESS; -} - -void mali_mmu_page_table_cache_destroy(void) -{ - mali_mmu_page_table_allocation * alloc, *temp; - - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.partial, mali_mmu_page_table_allocation, list) - { - MALI_DEBUG_PRINT_IF(1, 0 != alloc->usage_count, ("Destroying page table cache while pages are tagged as in use. %d allocations still marked as in use.\n", alloc->usage_count)); - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - - MALI_DEBUG_PRINT_IF(1, 0 == _mali_osk_list_empty(&page_table_cache.full), ("Page table cache full list contains one or more elements \n")); - - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.full, mali_mmu_page_table_allocation, list) - { - MALI_DEBUG_PRINT(1, ("Destroy alloc 0x%08X with usage count %d\n", (u32)alloc, alloc->usage_count)); - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - - _mali_osk_lock_term(page_table_cache.lock); -} - -_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping) -{ - _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - if (0 == _mali_osk_list_empty(&page_table_cache.partial)) - { - mali_mmu_page_table_allocation * alloc = _MALI_OSK_LIST_ENTRY(page_table_cache.partial.next, mali_mmu_page_table_allocation, list); - int page_number = _mali_osk_find_first_zero_bit(alloc->usage_map, alloc->num_pages); - MALI_DEBUG_PRINT(6, ("Partial page table allocation found, using page offset %d\n", page_number)); - _mali_osk_set_nonatomic_bit(page_number, alloc->usage_map); - alloc->usage_count++; - if (alloc->num_pages == alloc->usage_count) - { - /* full, move alloc to full list*/ - _mali_osk_list_move(&alloc->list, &page_table_cache.full); - } - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - *table_page = (MALI_MMU_PAGE_SIZE * page_number) + alloc->pages.phys_base; - *mapping = (mali_io_address)((MALI_MMU_PAGE_SIZE * page_number) + (u32)alloc->pages.mapping); - MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); - MALI_SUCCESS; - } - else - { - mali_mmu_page_table_allocation * alloc; - /* no free pages, allocate a new one */ - - alloc = (mali_mmu_page_table_allocation *)_mali_osk_calloc(1, sizeof(mali_mmu_page_table_allocation)); - if (NULL == alloc) - { - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _MALI_OSK_INIT_LIST_HEAD(&alloc->list); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_page_tables(memory_engine, &alloc->pages, physical_memory_allocators)) - { - MALI_DEBUG_PRINT(1, ("No more memory for page tables\n")); - _mali_osk_free(alloc); - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - *mapping = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* create the usage map */ - alloc->num_pages = alloc->pages.size / MALI_MMU_PAGE_SIZE; - alloc->usage_count = 1; - MALI_DEBUG_PRINT(3, ("New page table cache expansion, %d pages in new cache allocation\n", alloc->num_pages)); - alloc->usage_map = _mali_osk_calloc(1, ((alloc->num_pages + BITS_PER_LONG - 1) & ~(BITS_PER_LONG-1) / BITS_PER_LONG) * sizeof(unsigned long)); - if (NULL == alloc->usage_map) - { - MALI_DEBUG_PRINT(1, ("Failed to allocate memory to describe MMU page table cache usage\n")); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc); - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - *mapping = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* clear memory allocation */ - fill_page(alloc->pages.mapping, 0); - - _mali_osk_set_nonatomic_bit(0, alloc->usage_map); - - if (alloc->num_pages > 1) - { - _mali_osk_list_add(&alloc->list, &page_table_cache.partial); - } - else - { - _mali_osk_list_add(&alloc->list, &page_table_cache.full); - } - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = alloc->pages.phys_base; /* return the first page */ - *mapping = alloc->pages.mapping; /* Mapping for first page */ - MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); - MALI_SUCCESS; - } -} - -void mali_mmu_release_table_page(u32 pa) -{ - mali_mmu_page_table_allocation * alloc, * temp_alloc; - - MALI_DEBUG_PRINT_IF(1, pa & 4095, ("Bad page address 0x%x given to mali_mmu_release_table_page\n", (void*)pa)); - - MALI_DEBUG_PRINT(4, ("Releasing table page 0x%08X to the cache\n", pa)); - - _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - /* find the entry this address belongs to */ - /* first check the partial list */ - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.partial, mali_mmu_page_table_allocation, list) - { - u32 start = alloc->pages.phys_base; - u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; - if (pa >= start && pa <= last) - { - MALI_DEBUG_ASSERT(0 != _mali_osk_test_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map)); - _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); - alloc->usage_count--; - - _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); - - if (0 == alloc->usage_count) - { - /* empty, release whole page alloc */ - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("(partial list)Released table page 0x%08X to the cache\n", pa)); - return; - } - } - - /* the check the full list */ - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.full, mali_mmu_page_table_allocation, list) - { - u32 start = alloc->pages.phys_base; - u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; - if (pa >= start && pa <= last) - { - _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); - alloc->usage_count--; - - _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); - - - if (0 == alloc->usage_count) - { - /* empty, release whole page alloc */ - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - else - { - /* transfer to partial list */ - _mali_osk_list_move(&alloc->list, &page_table_cache.partial); - } - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("(full list)Released table page 0x%08X to the cache\n", pa)); - return; - } - } - - MALI_DEBUG_PRINT(1, ("pa 0x%x not found in the page table cache\n", (void*)pa)); - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); -} - -void* mali_memory_core_mmu_lookup(u32 id) -{ - mali_kernel_memory_mmu * mmu, * temp_mmu; - - /* find an MMU with a matching id */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - if (id == mmu->id) return mmu; - } - - /* not found */ - return NULL; -} - -void mali_memory_core_mmu_owner(void *core, void *mmu_ptr) -{ - mali_kernel_memory_mmu *mmu; - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - MALI_DEBUG_ASSERT_POINTER(core); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - mmu->core = core; -} - -void mali_mmu_activate_address_space(mali_kernel_memory_mmu * mmu, u32 page_directory) -{ - mali_mmu_enable_stall(mmu); /* this might fail, but changing the DTE address and ZAP should work anyway... */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, page_directory); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); -} - -_mali_osk_errcode_t mali_memory_core_mmu_activate_page_table(void* mmu_ptr, struct mali_session_data * mali_session_data, void(*callback)(void*), void * callback_argument) -{ - memory_session * requested_memory_session; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - mali_kernel_memory_mmu * mmu; - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - MALI_DEBUG_ASSERT_POINTER(mali_session_data); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - MALI_DEBUG_PRINT(4, ("Asked to activate page table for session 0x%x on MMU %s\n", mali_session_data, mmu->description)); - requested_memory_session = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - MALI_DEBUG_PRINT(5, ("Session 0x%x looked up as using memory session 0x%x\n", mali_session_data, requested_memory_session)); - - MALI_DEBUG_ASSERT_POINTER(requested_memory_session); - - MALI_DEBUG_PRINT(7, ("Taking locks\n")); - - _mali_osk_lock_wait(requested_memory_session->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - if (0 == mmu->usage_count) - { - /* no session currently active, activate the requested session */ - MALI_DEBUG_ASSERT(NULL == mmu->active_session); - mmu->active_session = requested_memory_session; - mmu->usage_count = 1; - MALI_DEBUG_PRINT(4, ("MMU idle, activating page directory 0x%08X on MMU %s\n", requested_memory_session->page_directory, mmu->description)); - mali_mmu_activate_address_space(mmu, requested_memory_session->page_directory); - { - /* Insert mmu into the right place in the active_mmus list so that - * it is still sorted. The list must be sorted by ID so we can get - * the mutexes in the right order in - * _mali_ukk_mem_munmap_internal(). - */ - _mali_osk_list_t *entry; - for (entry = requested_memory_session->active_mmus.next; - entry != &requested_memory_session->active_mmus; - entry = entry->next) - { - mali_kernel_memory_mmu *temp = _MALI_OSK_LIST_ENTRY(entry, mali_kernel_memory_mmu, session_link); - if (mmu->id < temp->id) - break; - } - /* If we broke out, then 'entry' points to the list node of the - * first mmu with a greater ID; otherwise, it points to - * active_mmus. We want to add *before* this node. - */ - _mali_osk_list_addtail(&mmu->session_link, entry); - } - err = _MALI_OSK_ERR_OK; - } - - /* Allow two cores to run in parallel if they come from the same session */ - else if ( - (mmu->in_page_fault_handler == 0) && - (requested_memory_session == mmu->active_session ) && - (0==(MALI_MMU_DISALLOW_PARALLELL_WORK_OF_MALI_CORES & mmu->flags)) - ) - { - /* nested activation detected, just update the reference count */ - MALI_DEBUG_PRINT(4, ("Nested activation detected, %d previous activations found\n", mmu->usage_count)); - mmu->usage_count++; - err = _MALI_OSK_ERR_OK; - } - - else if (NULL != callback) - { - /* can't activate right now, notify caller on idle via callback */ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp_callback_object; - int found = 0; - - MALI_DEBUG_PRINT(3, ("The MMU is busy and is using a different address space, callback given\n")); - /* check for existing registration */ - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp_callback_object, &mmu->callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - if (callback_object->callback == callback) - { - found = 1; - break; - } - } - - if (found) - { - MALI_DEBUG_PRINT(5, ("Duplicate callback registration found, ignoring\n")); - /* callback already registered */ - err = _MALI_OSK_ERR_BUSY; - } - else - { - MALI_DEBUG_PRINT(5,("New callback, registering\n")); - /* register the new callback */ - callback_object = _mali_osk_malloc(sizeof(mali_kernel_memory_mmu_idle_callback)); - if (NULL != callback_object) - { - MALI_DEBUG_PRINT(7,("Callback struct setup\n")); - callback_object->callback = callback; - callback_object->callback_argument = callback_argument; - _mali_osk_list_addtail(&callback_object->link, &mmu->callbacks); - err = _MALI_OSK_ERR_BUSY; - } - } - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_signal(requested_memory_session->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_ERROR(err); -} - -void mali_memory_core_mmu_release_address_space_reference(void* mmu_ptr) -{ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp; - mali_kernel_memory_mmu * mmu; - memory_session * session; - - _MALI_OSK_LIST_HEAD(callbacks); - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - session = mmu->active_session; - - /* support that we handle spurious page faults */ - if (NULL != session) - { - _mali_osk_lock_wait(session->lock, _MALI_OSK_LOCKMODE_RW); - } - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("Deactivation of address space on MMU %s, %d references exists\n", mmu->description, mmu->usage_count)); - MALI_DEBUG_ASSERT(0 != mmu->usage_count); - mmu->usage_count--; - if (0 != mmu->usage_count) - { - MALI_DEBUG_PRINT(4, ("MMU still in use by this address space, %d references still exists\n", mmu->usage_count)); - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - /* support that we handle spurious page faults */ - if (NULL != session) - { - _mali_osk_lock_signal(session->lock, _MALI_OSK_LOCKMODE_RW); - } - return; - } - - MALI_DEBUG_PRINT(4, ("Activating the empty page directory on %s\n", mmu->description)); - - /* last reference gone, deactivate current address space */ - mali_mmu_activate_address_space(mmu, mali_empty_page_directory); - - /* unlink from session */ - _mali_osk_list_delinit(&mmu->session_link); - /* remove the active session pointer */ - mmu->active_session = NULL; - - /* Notify all registered callbacks. - * We have to be clever here: - * We must call the callbacks with the spinlock unlocked and - * the callback list emptied to allow them to re-register. - * So we make a copy of the list, clears the list and then later call the callbacks on the local copy - */ - /* copy list */ - _MALI_OSK_INIT_LIST_HEAD(&callbacks); - _mali_osk_list_splice(&mmu->callbacks, &callbacks); - /* clear the original, allowing new registrations during the callback */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->callbacks); - - /* end of mmu manipulation, so safe to unlock */ - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* then finally remove the (possible) session lock, supporting that no session was active (spurious page fault handling) */ - if (NULL != session) - { - _mali_osk_lock_signal(session->lock, _MALI_OSK_LOCKMODE_RW); - } - - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp, &callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - MALI_DEBUG_ASSERT_POINTER(callback_object->callback); - (callback_object->callback)(callback_object->callback_argument); - _mali_osk_list_del(&callback_object->link); - _mali_osk_free(callback_object); - } -} - -void mali_memory_core_mmu_unregister_callback(void* mmu_ptr, void(*callback)(void*)) -{ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp_callback_object; - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - - MALI_DEBUG_ASSERT_POINTER(callback); - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp_callback_object, &mmu->callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - MALI_DEBUG_ASSERT_POINTER(callback_object->callback); - if (callback_object->callback == callback) - { - _mali_osk_list_del(&callback_object->link); - _mali_osk_free(callback_object); - break; - } - } - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); -} - -static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor) -{ - /* allocate page tables, if needed */ - int i; - const int first_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address); - int last_pde_idx; - memory_session * session_data; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; - int page_dir_updated = 0; -#endif - - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - last_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address + _MALI_OSK_MALI_PAGE_SIZE + descriptor->size - 1); - } - else - { - last_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address + descriptor->size - 1); - } - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - MALI_DEBUG_PRINT(4, ("allocating page tables for Mali virtual address space 0x%08X to 0x%08X\n", descriptor->mali_address, descriptor->mali_address + descriptor->size - 1)); - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * We have active MMUs, so we are probably in the process of alocating more memory for a suspended GP job (PLBU heap) - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page directory - * from the L2 cache if we add new page directory entries (PDEs) to the page directory. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - if ( 0 == (_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT) ) - { - u32 pte_phys; - mali_io_address pte_mapped; - _mali_osk_errcode_t err; - - /* allocate a new page table */ - MALI_DEBUG_ASSERT(0 == session_data->page_entries_usage_count[i]); - MALI_DEBUG_ASSERT(NULL == session_data->page_entries_mapped[i]); - - err = mali_mmu_get_table_page(&pte_phys, &pte_mapped); - if (_MALI_OSK_ERR_OK == err) - { - session_data->page_entries_mapped[i] = pte_mapped; - MALI_DEBUG_ASSERT_POINTER( session_data->page_entries_mapped[i] ); - - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), pte_phys | MALI_MMU_FLAGS_PRESENT); /* mark page table as present */ - - /* update usage count */ - session_data->page_entries_usage_count[i]++; -#if defined USING_MALI400_L2_CACHE - page_dir_updated = 1; -#endif - continue; /* continue loop */ - } - - MALI_DEBUG_PRINT(1, ("Page table alloc failed\n")); - break; /* abort loop, failed to allocate one or more page tables */ - } - else - { - session_data->page_entries_usage_count[i]++; - } - } - - if (i <= last_pde_idx) - { - /* one or more pages could not be allocated, release reference count for the ones we added one for */ - /* adjust for the one which caused the for loop to be aborted */ - i--; - - while (i >= first_pde_idx) - { - MALI_DEBUG_ASSERT(0 != session_data->page_entries_usage_count[i]); - session_data->page_entries_usage_count[i]--; - if (0 == session_data->page_entries_usage_count[i]) - { - /* last reference removed */ - mali_mmu_release_table_page(MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)))); - session_data->page_entries_mapped[i] = NULL; - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); /* mark as not present in the page directory */ - } - i--; - } - - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus && 1 == page_dir_updated) - { - /* - * We have updated the page directory and have an active MMU using it, so invalidate it in the Mali L2 cache. - */ - mali_kernel_l2_cache_invalidate_page(session_data->page_directory); - } -#endif - - /* all OK */ - MALI_SUCCESS; -} - -static void mali_address_manager_release(mali_memory_allocation * descriptor) -{ - int first_pde_idx; - int last_pde_idx; - memory_session * session_data; - u32 mali_address; - u32 mali_address_end; - u32 left; - int i; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; - int page_dir_updated = 0; -#endif - - MALI_DEBUG_ASSERT_POINTER(descriptor); - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - MALI_DEBUG_ASSERT_POINTER(session_data->page_directory_mapped); - - mali_address = descriptor->mali_address; - mali_address_end = descriptor->mali_address + descriptor->size; - left = descriptor->size; - - first_pde_idx = MALI_MMU_PDE_ENTRY(mali_address); - last_pde_idx = MALI_MMU_PDE_ENTRY(mali_address_end - 1); - - MALI_DEBUG_PRINT(3, ("Zapping Mali MMU table for address 0x%08X size 0x%08X\n", mali_address, left)); - MALI_DEBUG_PRINT(4, ("Zapping PDE %d through %d\n", first_pde_idx, last_pde_idx)); - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page tables - * from the L2 cache to ensure that the memory is unmapped. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - int size_inside_pte = left < 0x400000 ? left : 0x400000; - const int first_pte_idx = MALI_MMU_PTE_ENTRY(mali_address); - int last_pte_idx = MALI_MMU_PTE_ENTRY(mali_address + size_inside_pte - 1); - - if (last_pte_idx < first_pte_idx) - { - /* The last_pte_idx is into the next PTE, crop it to fit into this */ - last_pte_idx = 1023; /* 1024 PTE entries, so 1023 is the last one */ - size_inside_pte = MALI_MMU_ADDRESS(i + 1, 0) - mali_address; - } - - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped[i]); - MALI_DEBUG_ASSERT(0 != session_data->page_entries_usage_count[i]); - MALI_DEBUG_PRINT(4, ("PDE %d: zapping entries %d through %d, address 0x%08X, size 0x%08X, left 0x%08X (page table at 0x%08X)\n", - i, first_pte_idx, last_pte_idx, mali_address, size_inside_pte, left, - MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32))))); - - session_data->page_entries_usage_count[i]--; - - if (0 == session_data->page_entries_usage_count[i]) - { - MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n")); - /* last reference removed, no need to zero out each PTE */ - mali_mmu_release_table_page(MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)))); - session_data->page_entries_mapped[i] = NULL; - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); /* mark as not present in the page directory */ -#if defined USING_MALI400_L2_CACHE - page_dir_updated = 1; -#endif - } - else - { - int j; - - for (j = first_pte_idx; j <= last_pte_idx; j++) - { - _mali_osk_mem_iowrite32(session_data->page_entries_mapped[i], j * sizeof(u32), 0); - } - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus) - { - /* Invalidate the page we've just modified */ - mali_kernel_l2_cache_invalidate_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - } -#endif - } - left -= size_inside_pte; - mali_address += size_inside_pte; - } - -#if defined USING_MALI400_L2_CACHE - if ((1 == page_dir_updated) && (1== has_active_mmus)) - { - /* The page directory was also updated */ - mali_kernel_l2_cache_invalidate_page(session_data->page_directory); - } -#endif -} - -static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size) -{ - memory_session * session_data; - u32 mali_address; - u32 mali_address_end; - u32 current_phys_addr; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; -#endif - - MALI_DEBUG_ASSERT_POINTER(descriptor); - - MALI_DEBUG_ASSERT_POINTER( phys_addr ); - - current_phys_addr = *phys_addr; - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - mali_address = descriptor->mali_address + offset; - mali_address_end = descriptor->mali_address + offset + size; - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * We have active MMUs, so we are probably in the process of alocating more memory for a suspended GP job (PLBU heap) - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page tables - * from the L2 cache when we have allocated more heap memory. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - MALI_DEBUG_PRINT(6, ("Mali map: mapping 0x%08X to Mali address 0x%08X length 0x%08X\n", current_phys_addr, mali_address, size)); - - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped); - - for ( ; mali_address < mali_address_end; mali_address += MALI_MMU_PAGE_SIZE, current_phys_addr += MALI_MMU_PAGE_SIZE) - { - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]); - _mali_osk_mem_iowrite32_relaxed(session_data->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)], MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32), current_phys_addr | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); - } - _mali_osk_write_mem_barrier(); - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus) - { - int i; - const int first_pde_idx = MALI_MMU_PDE_ENTRY(mali_address); - const int last_pde_idx = MALI_MMU_PDE_ENTRY(mali_address_end - 1); - - /* - * Invalidate the updated page table(s), incase they have been used for something - * else since last job start (invalidation of entire Mali L2 cache) - */ - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - mali_kernel_l2_cache_invalidate_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - } - } -#endif - - MALI_SUCCESS; -} - -/* This handler registered to mali_mmap for MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) -{ - struct mali_session_data * mali_session_data; - mali_memory_allocation * descriptor; - memory_session * session_data; - - /* validate input */ - if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - /* Unpack arguments */ - mali_session_data = (struct mali_session_data *)args->ctx; - - if (NULL == mali_session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: mali_session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - MALI_DEBUG_ASSERT( mali_subsystem_memory_id >= 0 ); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - /* validate input */ - if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } - - descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); - if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - - descriptor->size = args->size; - descriptor->mali_address = args->phys_addr; - descriptor->mali_addr_mapping_info = (void*)session_data; - - descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; - descriptor->lock = session_data->lock; - _mali_osk_list_init( &descriptor->list ); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (0 == mali_allocation_engine_allocate_memory(memory_engine, descriptor, physical_memory_allocators, &session_data->memory_head)) - { - mali_kernel_memory_mmu * mmu, * temp_mmu; - - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - /* no need to lock the MMU as we own it already */ - MALI_DEBUG_PRINT(5, ("Zapping the cache of mmu %s as it's using the page table we have updated\n", mmu->description)); - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - mali_mmu_enable_stall(mmu); /* this might fail, but ZAP should work anyway... */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - /* All ok, write out any information generated from this call */ - args->mapping = descriptor->mapping; - args->cookie = (u32)descriptor; - - MALI_DEBUG_PRINT(7, ("MMAP OK\n")); - /* All done */ - MALI_SUCCESS; - } - else - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - /* OOM, but not a fatal error */ - MALI_DEBUG_PRINT(4, ("Memory allocation failure, OOM\n")); - _mali_osk_free(descriptor); - /* Linux will free the CPU address allocation, userspace client the Mali address allocation */ - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -} - -static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ) -{ - memory_session * session_data; - mali_kernel_memory_mmu * mmu, * temp_mmu; - mali_memory_allocation * descriptor; - - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /** @note args->context unused; we use the memory_session from the cookie */ - /* args->mapping and args->size are also discarded. They are only necessary - for certain do_munmap implementations. However, they could be used to check the - descriptor at this point. */ - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - /* Stall the MMU(s) which is using the address space we're operating on. - * Note that active_mmus must be sorted in order of ID to avoid a mutex - * ordering violation. - */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - u32 status; - status = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - if ( MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE == (status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) { - MALI_DEBUG_PRINT(2, ("Stopped stall attempt for mmu with id %d since it is in page fault mode.\n", mmu->id)); - continue; - } - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* - * If we're unable to stall, then make sure we tell our caller that, - * the caller should then release the session lock for a while, - * then this function again. - * This function will fail if we're in page fault mode, and to get - * out of page fault mode, the page fault handler must be able to - * take the session lock. - */ - if (!mali_mmu_enable_stall(mmu)) - { - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_BUSY; - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - /* This function also removes the memory from the session's memory list */ - mali_allocation_engine_release_memory(memory_engine, descriptor); - _mali_osk_free(descriptor); - - /* any L2 maintenance was done during mali_allocation_engine_release_memory */ - /* the session is locked, so the active mmu list should be the same */ - /* zap the TLB and resume operation */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - return _MALI_OSK_ERR_OK; -} - -/* Handler for unmapping memory for MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) -{ - mali_memory_allocation * descriptor; - _mali_osk_lock_t *descriptor_lock; - _mali_osk_errcode_t err; - - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /** @note args->context unused; we use the memory_session from the cookie */ - /* args->mapping and args->size are also discarded. They are only necessary - for certain do_munmap implementations. However, they could be used to check the - descriptor at this point. */ - - MALI_DEBUG_ASSERT_POINTER((memory_session*)descriptor->mali_addr_mapping_info); - - descriptor_lock = descriptor->lock; /* should point to the session data lock... */ - - err = _MALI_OSK_ERR_BUSY; - while (err == _MALI_OSK_ERR_BUSY) - { - if (descriptor_lock) - { - _mali_osk_lock_wait( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); - } - - err = _mali_ukk_mem_munmap_internal( args ); - - if (descriptor_lock) - { - _mali_osk_lock_signal( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); - } - - if (err == _MALI_OSK_ERR_BUSY) - { - /* - * Reason for this; - * We where unable to stall the MMU, probably because we are in page fault handling. - * Sleep for a while with the session lock released, then try again. - * Abnormal termination of programs with running Mali jobs is a normal reason for this. - */ - _mali_osk_time_ubusydelay(10); - } - } - - return err; -} - -/* Is called when the rendercore wants the mmu to give an interrupt */ -static void mali_mmu_probe_irq_trigger(mali_kernel_memory_mmu * mmu) -{ - MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_trigger\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR); -} - -/* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */ -static _mali_osk_errcode_t mali_mmu_probe_irq_acknowledge(mali_kernel_memory_mmu * mmu) -{ - u32 int_stat; - - int_stat = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_STATUS); - - MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat)); - if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) - { - MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); - } - else MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n")); - - if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) - { - MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); - } - else MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n")); - - if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) == - (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) - { - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -struct dump_info -{ - u32 buffer_left; - u32 register_writes_size; - u32 page_table_dump_size; - u32 *buffer; -}; - -static _mali_osk_errcode_t writereg(u32 where, u32 what, const char * comment, struct dump_info * info, int dump_to_serial) -{ - if (dump_to_serial) MALI_DEBUG_PRINT(1, ("writereg %08X %08X # %s\n", where, what, comment)); - - if (NULL != info) - { - info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */ - - if (NULL != info->buffer) - { - /* check that we have enough space */ - if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - *info->buffer = where; - info->buffer++; - - *info->buffer = what; - info->buffer++; - - info->buffer_left -= sizeof(u32)*2; - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info, int dump_to_serial) -{ - if (dump_to_serial) - { - int i; - for (i = 0; i < 256; i++) - { - MALI_DEBUG_PRINT(1, ("%08X: %08X %08X %08X %08X\n", phys_addr + 16*i, _mali_osk_mem_ioread32(page, (i*4 + 0) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 1) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 2) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 3) * sizeof(u32)))); - - } - } - - if (NULL != info) - { - /* 4096 for the page and 4 bytes for the address */ - const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4; - const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE; - const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4; - - info->page_table_dump_size += dump_size_in_bytes; - - if (NULL != info->buffer) - { - if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - *info->buffer = phys_addr; - info->buffer++; - - _mali_osk_memcpy(info->buffer, page, page_size_in_bytes); - info->buffer += page_size_in_elements; - - info->buffer_left -= dump_size_in_bytes; - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_mmu_page_table(memory_session * session_data, struct dump_info * info) -{ - MALI_DEBUG_ASSERT_POINTER(session_data); - MALI_DEBUG_ASSERT_POINTER(info); - - if (NULL != session_data->page_directory_mapped) - { - int i; - - MALI_CHECK_NO_ERROR( - dump_page(session_data->page_directory_mapped, session_data->page_directory, info, 0) - ); - - for (i = 0; i < 1024; i++) - { - if (NULL != session_data->page_entries_mapped[i]) - { - MALI_CHECK_NO_ERROR( - dump_page(session_data->page_entries_mapped[i], _mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info, 0) - ); - } - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_mmu_registers(memory_session * session_data, struct dump_info * info) -{ - MALI_CHECK_NO_ERROR(writereg(0x00000000, session_data->page_directory, "set the page directory address", info, 0)); - MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info, 0)); - MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info, 0)); - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) -{ - struct dump_info info = { 0, 0, 0, NULL }; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data, &info)); - MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data, &info)); - args->size = info.register_writes_size + info.page_table_dump_size; - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) -{ - struct dump_info info = { 0, 0, 0, NULL }; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - info.buffer_left = args->size; - info.buffer = args->buffer; - - args->register_writes = info.buffer; - MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data, &info)); - - args->page_table_dump = info.buffer; - MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data, &info)); - - args->register_writes_size = info.register_writes_size; - args->page_table_dump_size = info.page_table_dump_size; - - MALI_SUCCESS; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -u32 _mali_ukk_report_memory_usage(void) -{ - return mali_allocation_engine_memory_usage(physical_memory_allocators); -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h b/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h deleted file mode 100644 index 6a110d0..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_KERNEL_MEM_MMU_H__ -#define __MALI_KERNEL_MEM_MMU_H__ - -#include "mali_kernel_session_manager.h" - -/** - * Lookup a MMU core by ID. - * @param id ID of the MMU to find - * @return NULL if ID not found or valid, non-NULL if a core was found. - */ -void* mali_memory_core_mmu_lookup(u32 id); - -/** - * Set the core pointer of MMU to core owner of MMU - * - * @param core Core holding this MMU - * @param mmu_ptr The MMU whose core pointer needs set to core holding the MMU - * - */ -void mali_memory_core_mmu_owner(void *core, void *mmu_ptr); - -/** - * Activate a user session with its address space on the given MMU. - * If the session can't be activated due to that the MMU is busy and - * a callback pointer is given, the callback will be called once the MMU becomes idle. - * If the same callback pointer is registered multiple time it will only be called once. - * Nested activations are supported. - * Each call must be matched by a call to @see mali_memory_core_mmu_release_address_space_reference - * - * @param mmu The MMU to activate the address space on - * @param mali_session_data The user session object which address space to activate - * @param callback Pointer to the function to call when the MMU becomes idle - * @param callback_arg Argument given to the callback - * @return 0 if the address space was activated, -EBUSY if the MMU was busy, -EFAULT in all other cases. - */ -int mali_memory_core_mmu_activate_page_table(void* mmu_ptr, struct mali_session_data * mali_session_data, void(*callback)(void*), void * callback_argument); - -/** - * Release a reference to the current active address space. - * Once the last reference is released any callback(s) registered will be called before the function returns - * - * @note Caution must be shown calling this function with locks held due to that callback can be called - * @param mmu The mmu to release a reference to the active address space of - */ -void mali_memory_core_mmu_release_address_space_reference(void* mmu); - -/** - * Soft reset of MMU - needed after power up - * - * @param mmu_ptr The MMU pointer registered with the relevant core - */ -void mali_kernel_mmu_reset(void * mmu_ptr); - -void mali_kernel_mmu_force_bus_reset(void * mmu_ptr); - -/** - * Unregister a previously registered callback. - * @param mmu The MMU to unregister the callback on - * @param callback The function to unregister - */ -void mali_memory_core_mmu_unregister_callback(void* mmu, void(*callback)(void*)); - - - -#endif /* __MALI_KERNEL_MEM_MMU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c index 324fcab..7462a6d 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -65,19 +65,19 @@ mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u3 info->num_pages_allocated = 0; info->cpu_usage_adjust = cpu_usage_adjust; - info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, 106); - if (NULL != info->mutex) - { - allocator->allocate = os_allocator_allocate; - allocator->allocate_page_table_block = os_allocator_allocate_page_table_block; - allocator->destroy = os_allocator_destroy; + info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_MEM_INFO); + if (NULL != info->mutex) + { + allocator->allocate = os_allocator_allocate; + allocator->allocate_page_table_block = os_allocator_allocate_page_table_block; + allocator->destroy = os_allocator_destroy; allocator->stat = os_allocator_stat; - allocator->ctx = info; + allocator->ctx = info; allocator->name = name; - return allocator; - } - _mali_osk_free(info); + return allocator; + } + _mali_osk_free(info); } _mali_osk_free(allocator); } @@ -132,7 +132,7 @@ static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, m allocation->num_pages = ((left + _MALI_OSK_CPU_PAGE_SIZE - 1) & ~(_MALI_OSK_CPU_PAGE_SIZE - 1)) >> _MALI_OSK_CPU_PAGE_ORDER; MALI_DEBUG_PRINT(6, ("Allocating page array of size %d bytes\n", allocation->num_pages * sizeof(struct page*))); - while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max) && _mali_osk_mem_check_allocated(os_mem_max_usage)) + while (left > 0) { err = mali_allocation_engine_map_physical(engine, descriptor, *offset, MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, info->cpu_usage_adjust, _MALI_OSK_CPU_PAGE_SIZE); if ( _MALI_OSK_ERR_OK != err) @@ -243,7 +243,7 @@ static void os_allocator_release(void * ctx, void * handle) static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block) { - int allocation_order = 11; /* _MALI_OSK_CPU_PAGE_SIZE << 6 */ + int allocation_order = 11; /* _MALI_OSK_CPU_PAGE_SIZE << 11 */ void *virt = NULL; u32 size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order; os_allocator * info; diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c index ff105a4..1377560 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -161,13 +161,28 @@ _mali_osk_errcode_t mali_allocation_engine_allocate_memory(mali_allocation_engin void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) { + mali_allocation_engine_release_pt1_mali_pagetables_unmap(mem_engine, descriptor); + mali_allocation_engine_release_pt2_physical_memory_free(mem_engine, descriptor); +} + +void mali_allocation_engine_release_pt1_mali_pagetables_unmap(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) +{ memory_engine * engine = (memory_engine*)mem_engine; - mali_physical_memory_allocation * active_allocation_tracker; MALI_DEBUG_ASSERT_POINTER(engine); MALI_DEBUG_ASSERT_POINTER(descriptor); - /* Determine whether we need to remove this from a tracking list */ + /* Calling: mali_address_manager_release() */ + /* This function is allowed to be called several times, and it only does the release on the first call. */ + engine->mali_address->release(descriptor); +} + +void mali_allocation_engine_release_pt2_physical_memory_free(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) +{ + memory_engine * engine = (memory_engine*)mem_engine; + mali_physical_memory_allocation * active_allocation_tracker; + + /* Remove this from a tracking list in session_data->memory_head */ if ( ! _mali_osk_list_empty( &descriptor->list ) ) { _mali_osk_list_del( &descriptor->list ); @@ -175,8 +190,6 @@ void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, ma MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; ) } - engine->mali_address->release(descriptor); - active_allocation_tracker = &descriptor->physical_allocation; while (NULL != active_allocation_tracker) { @@ -199,7 +212,6 @@ void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, ma } } - _mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size) { _mali_osk_errcode_t err; @@ -244,7 +256,7 @@ _mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine m } } - MALI_DEBUG_PRINT(4, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset)); + MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset)); /* Mali address manager must use the physical address - no point in asking * it to allocate another one for us */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h index 0173c78..cda74c3 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -136,6 +136,9 @@ void mali_allocation_engine_destroy(mali_allocation_engine engine); int mali_allocation_engine_allocate_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_provider, _mali_osk_list_t *tracking_list ); void mali_allocation_engine_release_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor); +void mali_allocation_engine_release_pt1_mali_pagetables_unmap(mali_allocation_engine engine, mali_memory_allocation * descriptor); +void mali_allocation_engine_release_pt2_physical_memory_free(mali_allocation_engine engine, mali_memory_allocation * descriptor); + int mali_allocation_engine_map_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size); void mali_allocation_engine_unmap_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t unmap_flags); diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_pp.h b/drivers/media/video/samsung/mali/common/mali_kernel_pp.h deleted file mode 100644 index 8cf7bf7..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_pp.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_KERNEL_PP_H__ -#define __MALI_KERNEL_PP_H__ - -extern struct mali_kernel_subsystem mali_subsystem_mali200; - -#if USING_MALI_PMM -_mali_osk_errcode_t malipp_signal_power_up( u32 core_num, mali_bool queue_only ); -_mali_osk_errcode_t malipp_signal_power_down( u32 core_num, mali_bool immediate_only ); -#endif - -#endif /* __MALI_KERNEL_PP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.c b/drivers/media/video/samsung/mali/common/mali_kernel_profiling.c deleted file mode 100644 index ca04b5f..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (C) 2010 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_osk.h" -#include "mali_osk_mali.h" -#include "mali_ukk.h" -#include "mali_timestamp.h" -#include "mali_kernel_profiling.h" -#include "mali_linux_trace.h" - -typedef struct mali_profiling_entry -{ - u64 timestamp; - u32 event_id; - u32 data[5]; -} mali_profiling_entry; - - -typedef enum mali_profiling_state -{ - MALI_PROFILING_STATE_UNINITIALIZED, - MALI_PROFILING_STATE_IDLE, - MALI_PROFILING_STATE_RUNNING, - MALI_PROFILING_STATE_RETURN, -} mali_profiling_state; - - -static _mali_osk_lock_t *lock = NULL; -static mali_profiling_state prof_state = MALI_PROFILING_STATE_UNINITIALIZED; -static mali_profiling_entry* profile_entries = NULL; -static u32 profile_entry_count = 0; -static _mali_osk_atomic_t profile_insert_index; -static _mali_osk_atomic_t profile_entries_written; -static mali_bool mali_profiling_default_enable = MALI_FALSE; - -_mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start) -{ - profile_entries = NULL; - profile_entry_count = 0; - _mali_osk_atomic_init(&profile_insert_index, 0); - _mali_osk_atomic_init(&profile_entries_written, 0); - - lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 ); - if (NULL == lock) - { - return _MALI_OSK_ERR_FAULT; - } - - prof_state = MALI_PROFILING_STATE_IDLE; - - if (MALI_TRUE == auto_start) - { - u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* Use maximum buffer size */ - - mali_profiling_default_enable = MALI_TRUE; /* save this so user space can query this on their startup */ - if (_MALI_OSK_ERR_OK != _mali_profiling_start(&limit)) - { - return _MALI_OSK_ERR_FAULT; - } - } - - return _MALI_OSK_ERR_OK; -} - -void _mali_profiling_term(void) -{ - prof_state = MALI_PROFILING_STATE_UNINITIALIZED; - - /* wait for all elements to be completely inserted into array */ - while (_mali_osk_atomic_read(&profile_insert_index) != _mali_osk_atomic_read(&profile_entries_written)) - { - /* do nothing */; - } - - if (NULL != profile_entries) - { - _mali_osk_vfree(profile_entries); - profile_entries = NULL; - } - - if (NULL != lock) - { - _mali_osk_lock_term(lock); - lock = NULL; - } -} - -inline _mali_osk_errcode_t _mali_profiling_start(u32 * limit) -{ - _mali_osk_errcode_t ret; - - mali_profiling_entry *new_profile_entries = _mali_osk_valloc(*limit * sizeof(mali_profiling_entry)); - - if(NULL == new_profile_entries) - { - return _MALI_OSK_ERR_NOMEM; - } - - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (prof_state != MALI_PROFILING_STATE_IDLE) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_vfree(new_profile_entries); - return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ - } - - if (*limit > MALI_PROFILING_MAX_BUFFER_ENTRIES) - { - *limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; - } - - profile_entries = new_profile_entries; - profile_entry_count = *limit; - - ret = _mali_timestamp_reset(); - - if (ret == _MALI_OSK_ERR_OK) - { - prof_state = MALI_PROFILING_STATE_RUNNING; - } - else - { - _mali_osk_vfree(profile_entries); - profile_entries = NULL; - } - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return ret; -} - -inline void _mali_profiling_add_counter(u32 event_id, u32 data0) -{ -#if MALI_TRACEPOINTS_ENABLED - _mali_osk_profiling_add_counter(event_id, data0); -#endif -} - -inline _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4) -{ - u32 cur_index = _mali_osk_atomic_inc_return(&profile_insert_index) - 1; - -#if MALI_TRACEPOINTS_ENABLED - _mali_osk_profiling_add_event(event_id, data0); -#endif - - if (prof_state != MALI_PROFILING_STATE_RUNNING || cur_index >= profile_entry_count) - { - /* - * Not in recording mode, or buffer is full - * Decrement index again, and early out - */ - _mali_osk_atomic_dec(&profile_insert_index); - return _MALI_OSK_ERR_FAULT; - } - - profile_entries[cur_index].timestamp = _mali_timestamp_get(); - profile_entries[cur_index].event_id = event_id; - profile_entries[cur_index].data[0] = data0; - profile_entries[cur_index].data[1] = data1; - profile_entries[cur_index].data[2] = data2; - profile_entries[cur_index].data[3] = data3; - profile_entries[cur_index].data[4] = data4; - - _mali_osk_atomic_inc(&profile_entries_written); - - return _MALI_OSK_ERR_OK; -} - -#if MALI_TRACEPOINTS_ENABLED -/* - * The following code uses a bunch of magic numbers taken from the userspace - * side of the DDK; they are re-used here verbatim. They are taken from the - * file mali_instrumented_counter_types.h. - */ -#define MALI_GLES_COUNTER_OFFSET 1000 -#define MALI_VG_COUNTER_OFFSET 2000 -#define MALI_EGL_COUNTER_OFFSET 3000 -#define MALI_SHARED_COUNTER_OFFSET 4000 - -/* These offsets are derived from the gator driver; see gator_events_mali.c. */ -#define GATOR_EGL_COUNTER_OFFSET 17 -#define GATOR_GLES_COUNTER_OFFSET 18 - -_mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args) -{ - /* Convert the DDK counter ID to what gator expects */ - unsigned int gator_counter_value = 0; - - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (args->id >= MALI_EGL_COUNTER_OFFSET && args->id <= MALI_SHARED_COUNTER_OFFSET) - { - gator_counter_value = (args->id - MALI_EGL_COUNTER_OFFSET) + GATOR_EGL_COUNTER_OFFSET; - } - else if (args->id >= MALI_GLES_COUNTER_OFFSET && args->id <= MALI_VG_COUNTER_OFFSET) - { - gator_counter_value = (args->id - MALI_GLES_COUNTER_OFFSET) + GATOR_GLES_COUNTER_OFFSET; - } - else - { - /* Pass it straight through; gator will ignore it anyway. */ - gator_counter_value = args->id; - } - - trace_mali_sw_counter(gator_counter_value, args->value); - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - - return _MALI_OSK_ERR_OK; -} -#endif - -inline _mali_osk_errcode_t _mali_profiling_stop(u32 * count) -{ - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (prof_state != MALI_PROFILING_STATE_RUNNING) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ - } - - /* go into return state (user to retreive events), no more events will be added after this */ - prof_state = MALI_PROFILING_STATE_RETURN; - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - - /* wait for all elements to be completely inserted into array */ - while (_mali_osk_atomic_read(&profile_insert_index) != _mali_osk_atomic_read(&profile_entries_written)) - { - /* do nothing */; - } - - *count = _mali_osk_atomic_read(&profile_insert_index); - - return _MALI_OSK_ERR_OK; -} - -inline u32 _mali_profiling_get_count(void) -{ - u32 retval = 0; - - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - if (prof_state == MALI_PROFILING_STATE_RETURN) - { - retval = _mali_osk_atomic_read(&profile_entries_written); - } - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - - return retval; -} - -inline _mali_osk_errcode_t _mali_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) -{ - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (prof_state != MALI_PROFILING_STATE_RETURN) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ - } - - if (index >= _mali_osk_atomic_read(&profile_entries_written)) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_FAULT; - } - - *timestamp = profile_entries[index].timestamp; - *event_id = profile_entries[index].event_id; - data[0] = profile_entries[index].data[0]; - data[1] = profile_entries[index].data[1]; - data[2] = profile_entries[index].data[2]; - data[3] = profile_entries[index].data[3]; - data[4] = profile_entries[index].data[4]; - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_OK; -} - -inline _mali_osk_errcode_t _mali_profiling_clear(void) -{ - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (prof_state != MALI_PROFILING_STATE_RETURN) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ - } - - prof_state = MALI_PROFILING_STATE_IDLE; - profile_entry_count = 0; - _mali_osk_atomic_init(&profile_insert_index, 0); - _mali_osk_atomic_init(&profile_entries_written, 0); - if (NULL != profile_entries) - { - _mali_osk_vfree(profile_entries); - profile_entries = NULL; - } - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_OK; -} - -mali_bool _mali_profiling_is_recording(void) -{ - return prof_state == MALI_PROFILING_STATE_RUNNING ? MALI_TRUE : MALI_FALSE; -} - -mali_bool _mali_profiling_have_recording(void) -{ - return prof_state == MALI_PROFILING_STATE_RETURN ? MALI_TRUE : MALI_FALSE; -} - -void _mali_profiling_set_default_enable_state(mali_bool enable) -{ - mali_profiling_default_enable = enable; -} - -mali_bool _mali_profiling_get_default_enable_state(void) -{ - return mali_profiling_default_enable; -} - -_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args) -{ - return _mali_profiling_start(&args->limit); -} - -_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args) -{ - /* Always add process and thread identificator in the first two data elements for events from user space */ - return _mali_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]); -} - -_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args) -{ - return _mali_profiling_stop(&args->count); -} - -_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args) -{ - return _mali_profiling_get_event(args->index, &args->timestamp, &args->event_id, args->data); -} - -_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args) -{ - return _mali_profiling_clear(); -} - -_mali_osk_errcode_t _mali_ukk_profiling_get_config(_mali_uk_profiling_get_config_s *args) -{ - args->enable_events = mali_profiling_default_enable; - return _MALI_OSK_ERR_OK; -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c b/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c deleted file mode 100644 index cfc5ec1..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c +++ /dev/null @@ -1,2031 +0,0 @@ -/* - * Copyright (C) 2010 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_kernel_core.h" -#include "mali_osk.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_rendercore.h" -#include "mali_osk_list.h" -#if MALI_GPU_UTILIZATION -#include "mali_kernel_utilization.h" -#endif -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" -#endif /* USING_MMU */ -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif /* USING_MALI400_L2_CACHE */ - -#define HANG_CHECK_MSECS_MIN 100 -#define HANG_CHECK_MSECS_MAX 2000 /* 2 secs */ -#define HANG_CHECK_MSECS_DEFAULT 500 /* 500 ms */ - -#define WATCHDOG_MSECS_MIN (10*HANG_CHECK_MSECS_MIN) -#define WATCHDOG_MSECS_MAX 3600000 /* 1 hour */ -#define WATCHDOG_MSECS_DEFAULT 4000 /* 4 secs */ - -/* max value that will be converted from jiffies to micro seconds and written to job->render_time_usecs */ -#define JOB_MAX_JIFFIES 100000 - -int mali_hang_check_interval = HANG_CHECK_MSECS_DEFAULT; -int mali_max_job_runtime = WATCHDOG_MSECS_DEFAULT; - -#if MALI_TIMELINE_PROFILING_ENABLED -int mali_boot_profiling = 0; -#endif - -#ifdef MALI_REBOOTNOTIFIER -extern _mali_osk_atomic_t mali_shutdown_state; -#endif - -/* Subsystem entrypoints: */ -static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id); -static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id); -#if USING_MMU -static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif - - -static void mali_core_subsystem_cleanup_all_renderunits(struct mali_core_subsystem* subsys); -static void mali_core_subsystem_move_core_set_idle(struct mali_core_renderunit *core); - -static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem); -static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session); - -static void find_and_abort(mali_core_session* session, u32 abort_id); - -static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core); -#if USING_MMU -static void mali_core_subsystem_callback_schedule_wrapper(void* sub); -#endif -static void mali_core_subsystem_schedule(mali_core_subsystem*subsystem); -static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status); - -static void mali_core_renderunit_irq_handler_remove(struct mali_core_renderunit *core); - -static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data); -static void mali_core_irq_handler_bottom_half ( void *data ); - -#if USING_MMU -static void lock_subsystem(struct mali_core_subsystem * subsys); -static void unlock_subsystem(struct mali_core_subsystem * subsys); -#endif - - -/** - * This will be one of the subsystems in the array of subsystems: - * static struct mali_kernel_subsystem * subsystems[]; - * found in file: mali_kernel_core.c - * - * This subsystem is necessary for operations common to all rendercore - * subsystems. For example, mali_subsystem_mali200 and mali_subsystem_gp2 may - * share a mutex when RENDERCORES_USE_GLOBAL_MUTEX is non-zero. - */ -struct mali_kernel_subsystem mali_subsystem_rendercore= -{ - rendercore_subsystem_startup, /* startup */ - NULL, /*rendercore_subsystem_terminate,*/ /* shutdown */ - NULL, /* load_complete */ - NULL, /* system_info_fill */ - NULL, /* session_begin */ - NULL, /* session_end */ -#if USING_MMU - rendercore_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -} ; - -static _mali_osk_lock_t *rendercores_global_mutex = NULL; -static u32 rendercores_global_mutex_is_held = 0; -static u32 rendercores_global_mutex_owner = 0; - -/** The 'dummy' rendercore subsystem to allow global subsystem mutex to be - * locked for all subsystems that extend the ''rendercore'' */ -static mali_core_subsystem rendercore_dummy_subsystem = {0,}; - -/* - * Rendercore Subsystem functions. - * - * These are exposed by mali_subsystem_rendercore - */ - -/** - * @brief Initialize the Rendercore subsystem. - * - * This must be called before any other subsystem that extends the - * ''rendercore'' may be initialized. For example, this must be called before - * the following functions: - * - mali200_subsystem_startup(), from mali_subsystem_mali200 - * - maligp_subsystem_startup(), from mali_subsystem_gp2 - * - * @note This function is separate from mali_core_subsystem_init(). They - * are related, in that mali_core_subsystem_init() may use the structures - * initialized by rendercore_subsystem_startup() - */ -static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - rendercores_global_mutex_is_held = 0; - rendercores_global_mutex = _mali_osk_lock_init( - (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED), - 0, 129); - - if (NULL == rendercores_global_mutex) - { - MALI_PRINT_ERROR(("Failed: _mali_osk_lock_init\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - rendercore_dummy_subsystem.name = "Rendercore Global Subsystem"; /* On the constant pool, do not free */ - rendercore_dummy_subsystem.magic_nr = SUBSYSTEM_MAGIC_NR; /* To please the Subsystem Mutex code */ - -#if MALI_GPU_UTILIZATION - if (mali_utilization_init() != _MALI_OSK_ERR_OK) - { - _mali_osk_lock_term(rendercores_global_mutex); - rendercores_global_mutex = NULL; - MALI_PRINT_ERROR(("Failed: mali_utilization_init\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - if (_mali_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE) != _MALI_OSK_ERR_OK) - { - /* No biggie if we wheren't able to initialize the profiling */ - MALI_PRINT_ERROR(("Rendercore: Failed to initialize profiling, feature will be unavailable\n")) ; - } -#endif - - MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex initialized\n")) ; - MALI_SUCCESS; -} - -/** - * @brief Terminate the Rendercore subsystem. - * - * This must only be called \b after any other subsystem that extends the - * ''rendercore'' has been terminated. For example, this must be called \b after - * the following functions: - * - mali200_subsystem_terminate(), from mali_subsystem_mali200 - * - maligp_subsystem_terminate(), from mali_subsystem_gp2 - * - * @note This function is separate from mali_core_subsystem_cleanup(), though, - * the subsystems that extend ''rendercore'' must still call - * mali_core_subsystem_cleanup() when they terminate. - */ -static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - /* Catch double-terminate */ - MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_term(); -#endif - -#if MALI_GPU_UTILIZATION - mali_utilization_term(); -#endif - - rendercore_dummy_subsystem.name = NULL; /* The original string was on the constant pool, do not free */ - rendercore_dummy_subsystem.magic_nr = 0; - - /* ASSERT that no-one's holding this */ - MALI_DEBUG_PRINT_ASSERT( 0 == rendercores_global_mutex_is_held, - ("Rendercores' Global Mutex was held at termination time. Have the subsystems that extend ''rendercore'' been terminated?\n") ); - - _mali_osk_lock_term( rendercores_global_mutex ); - rendercores_global_mutex = NULL; - - MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex terminated\n")) ; -} - - -#if USING_MMU -/** - * @brief Handle certain Rendercore subsystem broadcast notifications - * - * When RENDERCORES_USE_GLOBAL_MUTEX is non-zero, this handles the following messages: - * - MMU_KILL_STEP0_LOCK_SUBSYSTEM - * - MMU_KILL_STEP4_UNLOCK_SUBSYSTEM - * - * The purpose is to manage the Rendercode Global Mutex, which cannot be - * managed by any system that extends the ''rendercore''. - * - * All other messages must be handled by mali_core_subsystem_broadcast_notification() - * - * - * When RENDERCORES_USE_GLOBAL_MUTEX is 0, this function does nothing. - * Instead, the subsystem that extends the ''rendercore' \b must handle its - * own mutexes - refer to mali_core_subsystem_broadcast_notification(). - * - * Used currently only for signalling when MMU has a pagefault - */ -static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - switch(message) - { - case MMU_KILL_STEP0_LOCK_SUBSYSTEM: - lock_subsystem( &rendercore_dummy_subsystem ); - break; - case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: - unlock_subsystem( &rendercore_dummy_subsystem ); - break; - - case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: - /** FALLTHROUGH */ - case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: - /** FALLTHROUGH */ - case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: - break; - - default: - MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); - break; - } - -} -#endif - -/* - * Functions inherited by the subsystems that extend the ''rendercore''. - */ - -void mali_core_renderunit_timeout_function_hang_detection(void *arg) -{ - mali_bool action = MALI_FALSE; - mali_core_renderunit * core; - - core = (mali_core_renderunit *) arg; - if( !core ) return; - - /* if NOT idle OR NOT powered off OR has TIMED_OUT */ - if ( !((CORE_WATCHDOG_TIMEOUT == core->state ) || (CORE_IDLE== core->state) || (CORE_OFF == core->state)) ) - { - core->state = CORE_HANG_CHECK_TIMEOUT; - action = MALI_TRUE; - } - - if(action) _mali_osk_irq_schedulework(core->irq); -} - - -void mali_core_renderunit_timeout_function(void *arg) -{ - mali_core_renderunit * core; - mali_bool is_watchdog; - - core = (mali_core_renderunit *)arg; - if( !core ) return; - - is_watchdog = MALI_TRUE; - if (mali_benchmark) - { - /* poll based core */ - mali_core_job *job; - job = core->current_job; - if ( (NULL != job) && - (0 != _mali_osk_time_after(job->watchdog_jiffies,_mali_osk_time_tickcount())) - ) - { - core->state = CORE_POLL; - is_watchdog = MALI_FALSE; - } - } - - if (is_watchdog) - { - MALI_DEBUG_PRINT(3, ("SW-Watchdog timeout: Core:%s\n", core->description)); - core->state = CORE_WATCHDOG_TIMEOUT; - } - - _mali_osk_irq_schedulework(core->irq); -} - -/* Used by external renderunit_create<> function */ -_mali_osk_errcode_t mali_core_renderunit_init(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Core: renderunit_init: Core:%s\n", core->description)); - - _MALI_OSK_INIT_LIST_HEAD(&core->list) ; - core->timer = _mali_osk_timer_init(); - if (NULL == core->timer) - { - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init timer\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_timer_setcallback(core->timer, mali_core_renderunit_timeout_function, (void *)core); - - core->timer_hang_detection = _mali_osk_timer_init(); - if (NULL == core->timer_hang_detection) - { - _mali_osk_timer_term(core->timer); - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init hang detection timer\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_timer_setcallback(core->timer_hang_detection, mali_core_renderunit_timeout_function_hang_detection, (void *)core); - -#if USING_MALI_PMM - /* Init no pending power downs */ - core->pend_power_down = MALI_FALSE; - - /* Register the core with the PMM - which powers it up */ - if (_MALI_OSK_ERR_OK != malipmm_core_register( core->pmm_id )) - { - _mali_osk_timer_term(core->timer); - _mali_osk_timer_term(core->timer_hang_detection); - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot register with PMM\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif /* USING_MALI_PMM */ - - core->error_recovery = MALI_FALSE; - core->in_detach_function = MALI_FALSE; - core->state = CORE_IDLE; - core->current_job = NULL; - core->magic_nr = CORE_MAGIC_NR; -#if USING_MMU - core->mmu = NULL; -#endif /* USING_MMU */ - - MALI_SUCCESS; -} - -void mali_core_renderunit_term(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Core: renderunit_term: Core:%s\n", core->description)); - - if (NULL != core->timer) - { - _mali_osk_timer_term(core->timer); - core->timer = NULL; - } - if (NULL != core->timer_hang_detection) - { - _mali_osk_timer_term(core->timer_hang_detection); - core->timer_hang_detection = NULL; - } - -#if USING_MALI_PMM - /* Unregister the core with the PMM */ - malipmm_core_unregister( core->pmm_id ); -#endif -} - -/* Used by external renderunit_create<> function */ -_mali_osk_errcode_t mali_core_renderunit_map_registers(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_map_registers: Core:%s\n", core->description)) ; - if( (0 == core->registers_base_addr) || - (0 == core->size) || - (NULL == core->description) - ) - { - MALI_PRINT_ERROR(("Missing fields in the core structure %u %u 0x%x;\n", core->registers_base_addr, core->size, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(core->registers_base_addr, core->size, core->description)) - { - MALI_PRINT_ERROR(("Could not request register region (0x%08X - 0x%08X) to core: %s\n", - core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - else - { - MALI_DEBUG_PRINT(6, ("Success: request_mem_region: (0x%08X - 0x%08X) Core:%s\n", - core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); - } - - core->registers_mapped = _mali_osk_mem_mapioregion( core->registers_base_addr, core->size, core->description ); - - if ( 0 == core->registers_mapped ) - { - MALI_PRINT_ERROR(("Could not ioremap registers for %s .\n", core->description)); - _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - else - { - MALI_DEBUG_PRINT(6, ("Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) Core:%s\n", - (u32) core->registers_mapped, - ((u32)core->registers_mapped)+ core->size - 1, - core->description)); - } - - MALI_DEBUG_PRINT(4, ("Success: Mapping registers to core: %s\n",core->description)); - - MALI_SUCCESS; -} - -/* Used by external renderunit_create<> function + other places */ -void mali_core_renderunit_unmap_registers(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_unmap_registers: Core:%s\n", core->description)); - if (0 == core->registers_mapped) - { - MALI_PRINT_ERROR(("Trying to unmap register-mapping with NULL from core: %s\n", core->description)); - return; - } - _mali_osk_mem_unmapioregion(core->registers_base_addr, core->size, core->registers_mapped); - core->registers_mapped = 0; - _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); -} - -static void mali_core_renderunit_irq_handler_remove(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_irq_handler_remove: Core:%s\n", core->description)); - _mali_osk_irq_term(core->irq); -} - -mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr) -{ - mali_core_renderunit * core; - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - if (subsys->number_of_cores <= mali_core_nr) - { - MALI_PRINT_ERROR(("Trying to get illegal mali_core_nr: 0x%x for %s", mali_core_nr, subsys->name)); - return NULL; - } - core = (subsys->mali_core_array)[mali_core_nr]; - MALI_DEBUG_PRINT(6, ("Core: renderunit_get_mali_core_nr: Core:%s\n", core->description)); - MALI_CHECK_CORE(core); - return core; -} - -/* Is used by external function: - subsystem_startup<> */ -_mali_osk_errcode_t mali_core_subsystem_init(mali_core_subsystem* new_subsys) -{ - int i; - - /* These function pointers must have been set on before calling this function */ - if ( - ( NULL == new_subsys->name ) || - ( NULL == new_subsys->start_job ) || - ( NULL == new_subsys->irq_handler_upper_half ) || - ( NULL == new_subsys->irq_handler_bottom_half ) || - ( NULL == new_subsys->get_new_job_from_user ) || - ( NULL == new_subsys->return_job_to_user ) - ) - { - MALI_PRINT_ERROR(("Missing functions in subsystem.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(2, ("Core: subsystem_init: %s\n", new_subsys->name)) ; - - /* Catch use-before-initialize/use-after-terminate */ - MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); - - new_subsys->magic_nr = SUBSYSTEM_MAGIC_NR; - - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_idle_head); /* Idle cores of this type */ - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_off_head); /* Powered off cores of this type */ - - /* Linked list for each priority of sessions with a job ready for scheduleing */ - for(i=0; i<PRIORITY_LEVELS; ++i) - { - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->awaiting_sessions_head[i]); - } - - /* Linked list of all sessions connected to this coretype */ - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->all_sessions_head); - - MALI_SUCCESS; -} - -#if USING_MMU -void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys) -{ - u32 i; - mali_core_renderunit * core; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - if ( NULL==core ) break; - core->mmu = mali_memory_core_mmu_lookup(core->mmu_id); - mali_memory_core_mmu_owner(core,core->mmu); - MALI_DEBUG_PRINT(2, ("Attach mmu: 0x%x to core: %s in subsystem: %s\n", core->mmu, core->description, subsys->name)); - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); -} -#endif - -/* This will register an IRQ handler, and add the core to the list of available cores for this subsystem. */ -_mali_osk_errcode_t mali_core_subsystem_register_renderunit(mali_core_subsystem* subsys, mali_core_renderunit * core) -{ - mali_core_renderunit ** mali_core_array; - u32 previous_nr; - u32 previous_size; - u32 new_nr; - u32 new_size; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - - /* If any of these are 0 there is an error */ - if(0 == core->subsystem || - 0 == core->registers_base_addr || - 0 == core->size || - 0 == core->description) - { - MALI_PRINT_ERROR(("Missing fields in the core structure 0x%x 0x%x 0x%x;\n", - core->registers_base_addr, core->size, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_DEBUG_PRINT(3, ("Core: subsystem_register_renderunit: %s\n", core->description)); - - MALI_CHECK_NON_NULL( - core->irq = _mali_osk_irq_init( - core->irq_nr, - mali_core_irq_handler_upper_half, - mali_core_irq_handler_bottom_half, - (_mali_osk_irq_trigger_t)subsys->probe_core_irq_trigger, - (_mali_osk_irq_ack_t)subsys->probe_core_irq_acknowledge, - core, - "mali_core_irq_handlers" - ), - _MALI_OSK_ERR_FAULT - ); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - /* Update which core number this is */ - core->core_number = subsys->number_of_cores; - - /* Update the array of cores in the subsystem. */ - previous_nr = subsys->number_of_cores; - previous_size = sizeof(mali_core_renderunit*)*previous_nr; - new_nr = previous_nr + 1; - new_size = sizeof(mali_core_renderunit*)*new_nr; - - if (0 != previous_nr) - { - if (NULL == subsys->mali_core_array) - { - MALI_PRINT_ERROR(("Internal error")); - goto exit_function; - } - - mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); - if (NULL == mali_core_array ) - { - MALI_PRINT_ERROR(("Out of mem")); - err = _MALI_OSK_ERR_NOMEM; - goto exit_function; - } - _mali_osk_memcpy(mali_core_array, subsys->mali_core_array, previous_size); - _mali_osk_free( subsys->mali_core_array); - MALI_DEBUG_PRINT(5, ("Success: adding a new core to subsystem array %s\n", core->description) ) ; - } - else - { - mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); - if (NULL == mali_core_array ) - { - MALI_PRINT_ERROR(("Out of mem")); - err = _MALI_OSK_ERR_NOMEM; - goto exit_function; - } - MALI_DEBUG_PRINT(6, ("Success: adding first core to subsystem array %s\n", core->description) ) ; - } - subsys->mali_core_array = mali_core_array; - mali_core_array[previous_nr] = core; - - /* Add the core to the list of available cores on the system */ - _mali_osk_list_add(&(core->list), &(subsys->renderunit_idle_head)); - - /* Update total number of cores */ - subsys->number_of_cores = new_nr; - MALI_DEBUG_PRINT(6, ("Success: mali_core_subsystem_register_renderunit %s\n", core->description)); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_SUCCESS; - -exit_function: - mali_core_renderunit_irq_handler_remove(core); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_ERROR(err); -} - - -/** - * Called by the core when a system info update is needed - * We fill in info about all the core types available - * @param subsys Pointer to the core's @a mali_core_subsystem data structure - * @param info Pointer to system info struct to update - * @return _MALI_OSK_ERR_OK on success, or another _mali_osk_errcode_t error code on failure - */ -_mali_osk_errcode_t mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info) -{ - u32 i; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; /* OK if no cores to update info for */ - mali_core_renderunit * core; - _mali_core_info **core_info_nextp; - _mali_core_info * cinfo; - - MALI_DEBUG_PRINT(4, ("mali_core_subsystem_system_info_fill: %s\n", subsys->name) ) ; - - /* check input */ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - core_info_nextp = &(info->core_info); - cinfo = info->core_info; - - while(NULL!=cinfo) - { - core_info_nextp = &(cinfo->next); - cinfo = cinfo->next; - } - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - if ( NULL==core ) - { - err = _MALI_OSK_ERR_FAULT; - goto early_exit; - } - cinfo = (_mali_core_info *)_mali_osk_calloc(1, sizeof(_mali_core_info)); - if ( NULL==cinfo ) - { - err = _MALI_OSK_ERR_NOMEM; - goto early_exit; - } - cinfo->version = core->core_version; - cinfo->type =subsys->core_type; - cinfo->reg_address = core->registers_base_addr; - cinfo->core_nr = i; - cinfo->next = NULL; - /* Writing this address to the previous' *(&next) ptr */ - *core_info_nextp = cinfo; - /* Setting the next_ptr to point to &this->next_ptr */ - core_info_nextp = &(cinfo->next); - } -early_exit: - if ( _MALI_OSK_ERR_OK != err) MALI_PRINT_ERROR(("Error: In mali_core_subsystem_system_info_fill %d\n", err)); - MALI_DEBUG_CODE( - cinfo = info->core_info; - - MALI_DEBUG_PRINT(3, ("Current list of cores\n")); - while( NULL != cinfo ) - { - MALI_DEBUG_PRINT(3, ("Type: 0x%x\n", cinfo->type)); - MALI_DEBUG_PRINT(3, ("Version: 0x%x\n", cinfo->version)); - MALI_DEBUG_PRINT(3, ("Reg_addr: 0x%x\n", cinfo->reg_address)); - MALI_DEBUG_PRINT(3, ("Core_nr: 0x%x\n", cinfo->core_nr)); - MALI_DEBUG_PRINT(3, ("Flags: 0x%x\n", cinfo->flags)); - MALI_DEBUG_PRINT(3, ("*****\n")); - cinfo = cinfo->next; - } - ); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_ERROR(err); -} - - -/* Is used by external function: - subsystem_terminate<> */ -void mali_core_subsystem_cleanup(mali_core_subsystem* subsys) -{ - u32 i; - mali_core_renderunit * core; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - MALI_DEBUG_PRINT(2, ("Core: subsystem_cleanup: %s\n", subsys->name )) ; - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - -#if USING_MMU - if (NULL != core->mmu) - { - /* the MMU is attached in the load_complete callback, which will never be called if the module fails to load, handle that case */ - mali_memory_core_mmu_unregister_callback(core->mmu, mali_core_subsystem_callback_schedule_wrapper); - } -#endif - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - mali_core_renderunit_irq_handler_remove(core); - - /* When a process terminates, all cores running jobs from that process is reset and put to idle. - That means that when the module is unloading (this code) we are guaranteed that all cores are idle. - However: if something (we can't think of) is really wrong, a core may give an interrupt during this - unloading, and we may now in the code have a bottom-half-processing pending from the interrupts - we deregistered above. To be sure that the bottom halves do not access the structures after they - are deallocated we flush the bottom-halves processing here, before the deallocation. */ - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - -#if USING_MALI_PMM - /* Only reset when we are using PMM and the core is not off */ -#if MALI_PMM_NO_PMU - /* We need to reset when there is no PMU - but this will - * cause the register read/write functions to report an - * error (hence the if to check for CORE_OFF below) we - * change state to allow the reset to happen. - */ - core->state = CORE_IDLE; -#endif - if( core->state != CORE_OFF ) - { - subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); - } -#else - /* Always reset the core */ - subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); -#endif - - mali_core_renderunit_unmap_registers(core); - - _mali_osk_list_delinit(&core->list); - - mali_core_renderunit_term(core); - - subsys->renderunit_delete(core); - } - - mali_core_subsystem_cleanup_all_renderunits(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT(6, ("SUCCESS: mali_core_subsystem_cleanup: %s\n", subsys->name )) ; -} - -_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores) -{ - mali_core_subsystem * subsystem; - - subsystem = session->subsystem; - if ( NULL != number_of_cores ) - { - *number_of_cores = subsystem->number_of_cores; - - MALI_DEBUG_PRINT(4, ("Core: ioctl_number_of_cores_get: %s: %u\n", subsystem->name, *number_of_cores) ) ; - } - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data) -{ - mali_core_subsystem * subsystem; - _mali_osk_errcode_t err; - - /* need the subsystem to run callback function */ - subsystem = session->subsystem; - MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - err = subsystem->get_new_job_from_user(session, job_data); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_ERROR(err); -} - - -/* We return the version number to the first core in this subsystem */ -_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit * core0; - u32 nr_return; - - subsystem = session->subsystem; - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - - core0 = mali_core_renderunit_get_mali_core_nr(subsystem, 0); - - if( NULL == core0 ) - { - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - nr_return = core0->core_version; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_DEBUG_PRINT(4, ("Core: ioctl_core_version_get: %s: %u\n", subsystem->name, nr_return )) ; - - *version = nr_return; - - MALI_SUCCESS; -} - -void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id) -{ - find_and_abort(session, id); -} - -static mali_bool job_should_be_aborted(mali_core_job *job, u32 abort_id) -{ - if ( job->abort_id == abort_id ) return MALI_TRUE; - else return MALI_FALSE; -} - -static void find_and_abort(mali_core_session* session, u32 abort_id) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit *core; - mali_core_renderunit *tmp; - mali_core_job *job; - - subsystem = session->subsystem; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - job = mali_job_queue_abort_job(session, abort_id); - if (NULL != job) - { - MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, from the waiting_to_run slot.\n", subsystem->name, abort_id )); - if (mali_job_queue_empty(session)) - { - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - } - subsystem->awaiting_sessions_sum_all_priorities--; - subsystem->return_job_to_user(job , JOB_STATUS_END_ABORT); - } - - _MALI_OSK_LIST_FOREACHENTRY( core, tmp, &session->renderunits_working_head, mali_core_renderunit, list ) - { - job = core->current_job; - if ( (job!=NULL) && (job_should_be_aborted (job, abort_id) ) ) - { - MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, which is currently running on mali.\n", subsystem->name, abort_id )); - if ( core->state==CORE_IDLE ) - { - MALI_PRINT_ERROR(("Aborting core with running job which is idle. Must be something very wrong.")); - goto end_bug; - } - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_ABORT); - } - } -end_bug: - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); -} - - -_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void *argument) -{ - mali_core_subsystem * subsystem; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - - /* need the subsystem to run callback function */ - subsystem = session->subsystem; - MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - if ( NULL != subsystem->suspend_response) - { - MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE start\n")); - err = subsystem->suspend_response(session, argument); - MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE end\n")); - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - return err; -} - - -/* Is used by internal function: - mali_core_subsystem_cleanup<>s */ -/* All cores should be removed before calling this function -Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_cleanup_all_renderunits(mali_core_subsystem* subsys) -{ - int i; - _mali_osk_free(subsys->mali_core_array); - subsys->number_of_cores = 0; - - MALI_DEBUG_PRINT(5, ("Core: subsystem_cleanup_all_renderunits: %s\n", subsys->name) ) ; - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - - if ( ! _mali_osk_list_empty(&(subsys->renderunit_idle_head))) - { - MALI_PRINT_ERROR(("List renderunit_list_idle should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_idle_head)) ; - } - - if ( ! _mali_osk_list_empty(&(subsys->renderunit_off_head))) - { - MALI_PRINT_ERROR(("List renderunit_list_off should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_off_head)) ; - } - - for(i=0; i<PRIORITY_LEVELS; ++i) - { - if ( ! _mali_osk_list_empty(&(subsys->awaiting_sessions_head[i]))) - { - MALI_PRINT_ERROR(("List awaiting_sessions_linkedlist should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->awaiting_sessions_head[i])) ; - subsys->awaiting_sessions_sum_all_priorities = 0; - } - } - - if ( ! _mali_osk_list_empty(&(subsys->all_sessions_head))) - { - MALI_PRINT_ERROR(("List all_sessions_linkedlist should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->all_sessions_head)) ; - } -} - -/* Is used by internal functions: - mali_core_irq_handler_bottom_half<>; - mali_core_subsystem_schedule<>; */ -/* Will release the core.*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_core_set_idle(mali_core_renderunit *core) -{ - mali_core_subsystem *subsystem; -#if USING_MALI_PMM - mali_core_status oldstatus; -#endif - subsystem = core->subsystem; - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(subsystem); - - _mali_osk_timer_del(core->timer); - _mali_osk_timer_del(core->timer_hang_detection); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_idle: %s\n", core->description) ) ; - - core->current_job = NULL ; - -#if USING_MALI_PMM - - oldstatus = core->state; - - if ( !core->pend_power_down ) - { - core->state = CORE_IDLE ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); - } - - if( CORE_OFF != oldstatus ) - { - /* Message that this core is now idle or in fact off */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_FINISHED, - 0 }; - event.data = core->pmm_id; - _mali_ukk_pmm_event_message( &event ); -#if USING_MMU - /* Only free the reference when entering idle state from - * anything other than power off - */ - mali_memory_core_mmu_release_address_space_reference(core->mmu); -#endif /* USING_MMU */ - } - - if( core->pend_power_down ) - { - core->state = CORE_OFF ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); - - /* Done the move from the active queues, so the pending power down can be done */ - core->pend_power_down = MALI_FALSE; - malipmm_core_power_down_okay( core->pmm_id ); - } - -#else /* !USING_MALI_PMM */ - - core->state = CORE_IDLE ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); - -#if USING_MMU - mali_memory_core_mmu_release_address_space_reference(core->mmu); -#endif - -#endif /* USING_MALI_PMM */ -} - -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_set_working(mali_core_renderunit *core, mali_core_job *job) -{ - mali_core_subsystem *subsystem; - mali_core_session *session; - u64 time_now; - - session = job->session; - subsystem = core->subsystem; - - MALI_CHECK_CORE(core); - MALI_CHECK_JOB(job); - MALI_CHECK_SUBSYSTEM(subsystem); - - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_set_working: %s\n", core->description) ) ; - - time_now = _mali_osk_time_get_ns(); - job->start_time = time_now; -#if MALI_GPU_UTILIZATION - mali_utilization_core_start(time_now); -#endif - - core->current_job = job ; - core->state = CORE_WORKING ; - _mali_osk_list_move( &core->list, &session->renderunits_working_head ); - -} - -#if USING_MALI_PMM - -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_core_set_off(mali_core_renderunit *core) -{ - mali_core_subsystem *subsystem; - subsystem = core->subsystem; - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(subsystem); - - /* Cores must be idle before powering off */ - MALI_DEBUG_ASSERT(core->state == CORE_IDLE); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_off: %s\n", core->description) ) ; - - core->current_job = NULL ; - core->state = CORE_OFF ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); -} - -#endif /* USING_MALI_PMM */ - -/* Is used by internal function: - mali_core_subsystem_schedule<>; */ -/* Returns the job with the highest priority for the subsystem. NULL if none*/ -/* Must hold subsystem_mutex before entering this function */ -static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem) -{ - int i; - - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - if ( 0 == subsystem->awaiting_sessions_sum_all_priorities ) - { - MALI_DEBUG_PRINT(5, ("Core: subsystem_get_waiting_job: No awaiting session found\n")); - return NULL; - } - - for( i=0; i<PRIORITY_LEVELS ; ++i) - { - if (!_mali_osk_list_empty(&subsystem->awaiting_sessions_head[i])) - { - return _MALI_OSK_LIST_ENTRY(subsystem->awaiting_sessions_head[i].next, mali_core_session, awaiting_sessions_list); - } - } - - return NULL; -} - -static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session) -{ - mali_core_job *job; - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - job = mali_job_queue_get_job(session); - subsystem->awaiting_sessions_sum_all_priorities--; - - if(mali_job_queue_empty(session)) - { - /* This is the last job, so remove it from the list */ - _mali_osk_list_delinit(&session->awaiting_sessions_list); - } - else - { - if (0 == (job->flags & MALI_UK_START_JOB_FLAG_MORE_JOBS_FOLLOW)) - { - /* There are more jobs, but the follow flag is not set, so let other sessions run their jobs first */ - _mali_osk_list_del(&(session->awaiting_sessions_list)); - _mali_osk_list_addtail(&(session->awaiting_sessions_list), &(subsystem->awaiting_sessions_head[ - session->queue[session->queue_head]->priority])); - } - /* else; keep on list, follow flag is set and there are more jobs in queue for this session */ - } - - MALI_CHECK_JOB(job); - return job; -} - -/* Is used by internal functions: - mali_core_subsystem_schedule<> */ -/* This will start the job on the core. It will also release the core if it did not start.*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core) -{ - mali_core_session *session; - mali_core_subsystem *subsystem; - _mali_osk_errcode_t err; - session = job->session; - subsystem = core->subsystem; - - MALI_CHECK_CORE(core); - MALI_CHECK_JOB(job); - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_CHECK_SESSION(session); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(4, ("Core: job_start_on_core: job=0x%x, session=0x%x, core=%s\n", job, session, core->description)); - - MALI_DEBUG_ASSERT(NULL == core->current_job) ; - MALI_DEBUG_ASSERT(CORE_IDLE == core->state ); - - mali_core_subsystem_move_set_working(core, job); - -#if defined USING_MALI400_L2_CACHE - if (0 == (job->flags & MALI_UK_START_JOB_FLAG_NO_FLUSH)) - { - /* Invalidate the L2 cache */ - if (_MALI_OSK_ERR_OK != mali_kernel_l2_cache_invalidate_all() ) - { - MALI_DEBUG_PRINT(4, ("Core: Clear of L2 failed, return job. System may not be usable for some reason.\n")); - mali_core_subsystem_move_core_set_idle(core); - subsystem->return_job_to_user(job,JOB_STATUS_END_SYSTEM_UNUSABLE ); - return; - } - } -#endif - - /* Tries to start job on the core. Returns MALI_FALSE if the job could not be started */ - err = subsystem->start_job(job, core); - - if ( _MALI_OSK_ERR_OK != err ) - { - /* This will happen only if there is something in the job object - which make it inpossible to start. Like if it require illegal memory.*/ - MALI_DEBUG_PRINT(4, ("Core: start_job failed, return job and putting core back into idle list\n")); - mali_core_subsystem_move_core_set_idle(core); - subsystem->return_job_to_user(job,JOB_STATUS_END_ILLEGAL_JOB ); - } - else - { - u32 delay = _mali_osk_time_mstoticks(job->watchdog_msecs)+1; - job->watchdog_jiffies = _mali_osk_time_tickcount() + delay; - if (mali_benchmark) - { - _mali_osk_timer_add(core->timer, 1); - } - else - { - _mali_osk_timer_add(core->timer, delay); - } - } -} - -#if USING_MMU -static void mali_core_subsystem_callback_schedule_wrapper(void* sub) -{ - mali_core_subsystem * subsystem; - subsystem = (mali_core_subsystem *)sub; - MALI_DEBUG_PRINT(3, ("MMU: Is schedulling subsystem: %s\n", subsystem->name)); - mali_core_subsystem_schedule(subsystem); -} -#endif - -/* Is used by internal function: - mali_core_irq_handler_bottom_half - mali_core_session_add_job -*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_schedule(mali_core_subsystem * subsystem) -{ - mali_core_renderunit *core, *tmp; - mali_core_session *session; - mali_core_job *job; -#ifdef MALI_REBOOTNOTIFIER - if (_mali_osk_atomic_read(&mali_shutdown_state) > 0) { - MALI_DEBUG_PRINT(3, ("Core: mali already under shutdown process!!")) ; - return; - } -#endif - - MALI_DEBUG_PRINT(5, ("Core: subsystem_schedule: %s\n", subsystem->name )) ; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - /* First check that there are sessions with jobs waiting to run */ - if ( 0 == subsystem->awaiting_sessions_sum_all_priorities) - { - MALI_DEBUG_PRINT(6, ("Core: No jobs available for %s\n", subsystem->name) ) ; - return; - } - - /* Returns the session with the highest priority job for the subsystem. NULL if none*/ - session = mali_core_subsystem_get_waiting_session(subsystem); - - if (NULL == session) - { - MALI_DEBUG_PRINT(6, ("Core: Schedule: No runnable job found\n")); - return; - } - - _MALI_OSK_LIST_FOREACHENTRY(core, tmp, &subsystem->renderunit_idle_head, mali_core_renderunit, list) - { -#if USING_MMU - int err = mali_memory_core_mmu_activate_page_table(core->mmu, session->mmu_session, mali_core_subsystem_callback_schedule_wrapper, subsystem); - if (0 == err) - { - /* core points to a core where the MMU page table activation succeeded */ -#endif - /* This will remove the job from queue system */ - job = mali_core_subsystem_release_session_get_job(subsystem, session); - MALI_DEBUG_ASSERT_POINTER(job); - - MALI_DEBUG_PRINT(6, ("Core: Schedule: Got a job 0x%x\n", job)); - -#if USING_MALI_PMM - { - /* Message that there is a job scheduled to run - * NOTE: mali_core_job_start_on_core() can fail to start - * the job for several reasons, but it will move the core - * back to idle which will create the FINISHED message - * so we can still say that the job is SCHEDULED - */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_SCHEDULED, - 0 }; - event.data = core->pmm_id; - _mali_ukk_pmm_event_message( &event ); - } -#endif - /* This will {remove core from freelist AND start the job on the core}*/ - mali_core_job_start_on_core(job, core); - - MALI_DEBUG_PRINT(6, ("Core: Schedule: Job started, done\n")); - return; -#if USING_MMU - } -#endif - } - MALI_DEBUG_PRINT(6, ("Core: Schedule: Could not activate MMU. Scheduelling postponed to MMU, checking next.\n")); - -#if USING_MALI_PMM - { - /* Message that there are jobs to run */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_QUEUED, - 0 }; - if( subsystem->core_type == _MALI_GP2 || subsystem->core_type == _MALI_400_GP ) - { - event.data = MALI_PMM_CORE_GP; - } - else - { - /* Check the PP is supported by the PMM */ - MALI_DEBUG_ASSERT( subsystem->core_type == _MALI_200 || subsystem->core_type == _MALI_400_PP ); - /* We state that all PP cores are scheduled to inform the PMM - * that it may need to power something up! - */ - event.data = MALI_PMM_CORE_PP_ALL; - } - _mali_ukk_pmm_event_message( &event ); - } -#endif /* USING_MALI_PMM */ - -} - -/* Is used by external function: - session_begin<> */ -void mali_core_session_begin(mali_core_session * session) -{ - mali_core_subsystem * subsystem; - int i; - - subsystem = session->subsystem; - if ( NULL == subsystem ) - { - MALI_PRINT_ERROR(("Missing data in struct\n")); - return; - } - MALI_DEBUG_PRINT(2, ("Core: session_begin: for %s\n", session->subsystem->name )) ; - - session->magic_nr = SESSION_MAGIC_NR; - - _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); - - for (i = 0; i < MALI_JOB_QUEUE_SIZE; i++) - { - session->queue[i] = NULL; - } - session->queue_head = 0; - session->queue_tail = 0; - _MALI_OSK_INIT_LIST_HEAD(&session->awaiting_sessions_list); - _MALI_OSK_INIT_LIST_HEAD(&session->all_sessions_list); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - _mali_osk_list_add(&session->all_sessions_list, &session->subsystem->all_sessions_head); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_init(&session->jobs_received, 0); - _mali_osk_atomic_init(&session->jobs_returned, 0); - session->pid = _mali_osk_get_pid(); -#endif - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: session_begin: for %s DONE\n", session->subsystem->name) ) ; -} - -#if USING_MMU -static void mali_core_renderunit_stop_bus(mali_core_renderunit* core) -{ - core->subsystem->stop_bus(core); -} -#endif - -void mali_core_session_close(mali_core_session * session) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit *core; - - subsystem = session->subsystem; - MALI_DEBUG_ASSERT_POINTER(subsystem); - - MALI_DEBUG_PRINT(2, ("Core: session_close: for %s\n", session->subsystem->name) ) ; - - /* We must grab subsystem mutex since the list this session belongs to - is owned by the subsystem */ - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - /* Remove this session from the global sessionlist */ - _mali_osk_list_delinit(&session->all_sessions_list); - - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - - /* Return the potensial waiting job to user */ - while ( !mali_job_queue_empty(session) ) - { - /* Queue not empty */ - mali_core_job *job = mali_job_queue_get_job(session); - subsystem->return_job_to_user( job, JOB_STATUS_END_SHUTDOWN ); - subsystem->awaiting_sessions_sum_all_priorities--; - } - - /* Kill active cores working for this session - freeing their jobs - Since the handling of one core also could stop jobs from another core, there is a while loop */ - while ( ! _mali_osk_list_empty(&session->renderunits_working_head) ) - { - core = _MALI_OSK_LIST_ENTRY(session->renderunits_working_head.next, mali_core_renderunit, list); - MALI_DEBUG_PRINT(3, ("Core: session_close: Core was working: %s\n", core->description )) ; - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_SHUTDOWN ); - } - _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); /* Not necessary - we will _mali_osk_free session*/ - - MALI_DEBUG_PRINT(5, ("Core: session_close: for %s FINISHED\n", session->subsystem->name )) ; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); -} - -/* Must hold subsystem_mutex before entering this function */ -_mali_osk_errcode_t mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return) -{ - mali_core_subsystem * subsystem; - - job->magic_nr = JOB_MAGIC_NR; - MALI_CHECK_SESSION(session); - - subsystem = session->subsystem; - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: session_add_job: for %s\n", subsystem->name )) ; - - /* Setting the default value; No job to return */ - MALI_DEBUG_ASSERT_POINTER(job_return); - *job_return = NULL; - - if (mali_job_queue_empty(session)) - { - /* Add session to the wait list only if it didn't already have a job waiting. */ - _mali_osk_list_addtail( &(session->awaiting_sessions_list), &(subsystem->awaiting_sessions_head[job->priority])); - } - - - if (_MALI_OSK_ERR_OK != mali_job_queue_add_job(session, job)) - { - if (mali_job_queue_empty(session)) - { - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - } - MALI_DEBUG_PRINT(4, ("Core: session_add_job: %s queue is full\n", subsystem->name)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Continue to add the new job as the next job from this session */ - MALI_DEBUG_PRINT(6, ("Core: session_add_job job=0x%x\n", job)); - - subsystem->awaiting_sessions_sum_all_priorities++; - - mali_core_subsystem_schedule(subsystem); - - MALI_DEBUG_PRINT(6, ("Core: session_add_job: for %s FINISHED\n", session->subsystem->name )) ; - - MALI_SUCCESS; -} - -static void mali_core_job_set_run_time(mali_core_job * job, u64 end_time) -{ - u32 time_used_nano_seconds; - - time_used_nano_seconds = end_time - job->start_time; - job->render_time_usecs = time_used_nano_seconds / 1000; -} - -static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status) -{ - mali_core_job * job; - mali_core_subsystem * subsystem; - mali_bool already_in_detach_function; - u64 time_now; - - MALI_DEBUG_ASSERT(CORE_IDLE != core->state); - time_now = _mali_osk_time_get_ns(); - job = core->current_job; - subsystem = core->subsystem; - - /* The reset_core() called some lines below might call this detach - * funtion again. To protect the core object from being modified by - * recursive calls, the in_detach_function would track if it is an recursive call - */ - already_in_detach_function = core->in_detach_function; - - - if ( MALI_FALSE == already_in_detach_function ) - { - core->in_detach_function = MALI_TRUE; - if ( NULL != job ) - { - mali_core_job_set_run_time(job, time_now); - core->current_job = NULL; - } - } - - if (JOB_STATUS_END_SEG_FAULT == end_status) - { - subsystem->reset_core( core, MALI_CORE_RESET_STYLE_HARD ); - } - else - { - subsystem->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); - } - - if ( MALI_FALSE == already_in_detach_function ) - { - if ( CORE_IDLE != core->state ) - { - #if MALI_GPU_UTILIZATION - mali_utilization_core_end(time_now); - #endif - mali_core_subsystem_move_core_set_idle(core); - } - - core->in_detach_function = MALI_FALSE; - - if ( SUBSYSTEM_RESCHEDULE == reschedule ) - { - mali_core_subsystem_schedule(subsystem); - } - if ( NULL != job ) - { - core->subsystem->return_job_to_user(job, end_status); - } - } -} - -#if USING_MMU -/* This function intentionally does not release the semaphore. You must run - stop_bus_for_all_cores(), reset_all_cores_on_mmu() and continue_job_handling() - after calling this function, and then call unlock_subsystem() to release the - semaphore. */ - -static void lock_subsystem(struct mali_core_subsystem * subsys) -{ - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. - - This function only stops cores behind the given MMU, unless "mmu" is NULL, in - which case all cores are stopped. -*/ -static void stop_bus_for_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) -{ - u32 i; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_DEBUG_PRINT(2,("Handling: bus stop %s\n", subsys->name )); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - - /* We stop only cores behind the given MMU, unless MMU is NULL */ - if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; - - if ( CORE_IDLE != core->state ) - { - MALI_DEBUG_PRINT(4, ("Stopping bus on core %s\n", core->description)); - mali_core_renderunit_stop_bus(core); - core->error_recovery = MALI_TRUE; - } - else - { - MALI_DEBUG_PRINT(4,("Core: not active %s\n", core->description )); - } - } - /* Mutex is still being held, to prevent things to happen while we do cleanup */ - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. - - This function only resets cores behind the given MMU, unless "mmu" is NULL, in - which case all cores are reset. -*/ -static void reset_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) -{ - u32 i; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_DEBUG_PRINT(3, ("Handling: reset cores from mmu: 0x%x on %s\n", mmu, subsys->name )); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - - /* We reset only cores behind the given MMU, unless MMU is NULL */ - if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; - - if ( CORE_IDLE != core->state ) - { - MALI_DEBUG_PRINT(4, ("Abort and reset core: %s\n", core->description )); - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_WAIT, JOB_STATUS_END_SEG_FAULT); - } - else - { - MALI_DEBUG_PRINT(4, ("Core: not active %s\n", core->description )); - } - } - MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. */ -static void continue_job_handling(struct mali_core_subsystem * subsys) -{ - u32 i, j; - - MALI_DEBUG_PRINT(3, ("Handling: Continue: %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - core->error_recovery = MALI_FALSE; - } - - i = subsys->number_of_cores; - j = subsys->awaiting_sessions_sum_all_priorities; - - /* Schedule MIN(nr_waiting_jobs , number of cores) times */ - while( i-- && j--) - { - mali_core_subsystem_schedule(subsys); - } - MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* Unlock the subsystem. */ -static void unlock_subsystem(struct mali_core_subsystem * subsys) -{ - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); -} - -void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data) -{ - void * mmu; - mmu = (void*) data; - - switch(message) - { - case MMU_KILL_STEP0_LOCK_SUBSYSTEM: - break; - case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: - stop_bus_for_all_cores_on_mmu(subsys, mmu); - break; - case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: - reset_all_cores_on_mmu(subsys, mmu ); - break; - case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: - continue_job_handling(subsys); - break; - case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: - break; - - default: - MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); - break; - } -} -#endif /* USING_MMU */ - -void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs) -{ - if (watchdog_msecs == 0) job->watchdog_msecs = mali_max_job_runtime; /* use the default */ - else if (watchdog_msecs > WATCHDOG_MSECS_MAX) job->watchdog_msecs = WATCHDOG_MSECS_MAX; /* no larger than max */ - else if (watchdog_msecs < WATCHDOG_MSECS_MIN) job->watchdog_msecs = WATCHDOG_MSECS_MIN; /* not below min */ - else job->watchdog_msecs = watchdog_msecs; -} - -u32 mali_core_hang_check_timeout_get(void) -{ - /* check the value. The user might have set the value outside the allowed range */ - if (mali_hang_check_interval > HANG_CHECK_MSECS_MAX) mali_hang_check_interval = HANG_CHECK_MSECS_MAX; /* cap to max */ - else if (mali_hang_check_interval < HANG_CHECK_MSECS_MIN) mali_hang_check_interval = HANG_CHECK_MSECS_MIN; /* cap to min */ - - /* return the active value */ - return mali_hang_check_interval; -} - -static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data) -{ - mali_core_renderunit *core; - u32 has_pending_irq; - - core = (mali_core_renderunit * )data; - - if(core && (CORE_OFF == core->state)) - { - MALI_SUCCESS; - } - - if ( (NULL == core) || - (NULL == core->subsystem) || - (NULL == core->subsystem->irq_handler_upper_half) ) - { - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(core->subsystem); - - has_pending_irq = core->subsystem->irq_handler_upper_half(core); - - if ( has_pending_irq ) - { - _mali_osk_irq_schedulework( core->irq ) ; - MALI_SUCCESS; - } - - if (mali_benchmark) MALI_SUCCESS; - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -static void mali_core_irq_handler_bottom_half ( void *data ) -{ - mali_core_renderunit *core; - mali_core_subsystem* subsystem; - - mali_subsystem_job_end_code job_status; - - core = (mali_core_renderunit * )data; - - MALI_CHECK_CORE(core); - subsystem = core->subsystem; - MALI_CHECK_SUBSYSTEM(subsystem); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - if ( CORE_IDLE == core->state || CORE_OFF == core->state ) goto end_function; - - MALI_DEBUG_PRINT(5, ("IRQ: handling irq from core %s\n", core->description )) ; - - _mali_osk_cache_flushall(); - - /* This function must also update the job status flag */ - job_status = subsystem->irq_handler_bottom_half( core ); - - /* Retval is nonzero if the job is finished. */ - if ( JOB_STATUS_CONTINUE_RUN != job_status ) - { - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, job_status); - } - else - { - switch ( core->state ) - { - case CORE_WATCHDOG_TIMEOUT: - MALI_DEBUG_PRINT(2, ("Watchdog SW Timeout of job from core: %s\n", core->description )); - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_TIMEOUT_SW ); - break; - - case CORE_POLL: - MALI_DEBUG_PRINT(5, ("Poll core: %s\n", core->description )) ; - core->state = CORE_WORKING; - _mali_osk_timer_add( core->timer, 1); - break; - - default: - MALI_DEBUG_PRINT(4, ("IRQ: The job on the core continue to run: %s\n", core->description )) ; - break; - } - } -end_function: - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); -} - -void subsystem_flush_mapped_mem_cache(void) -{ - _mali_osk_cache_flushall(); - _mali_osk_mem_barrier(); -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only) -{ - mali_core_renderunit * core = NULL; - - MALI_CHECK_SUBSYSTEM(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - /* It is possible that this signal funciton can be called during a driver exit, - * and so the requested core may now be destroyed. (This is due to us not having - * the subsys lock before signalling power down). - * mali_core_renderunit_get_mali_core_nr() will report a Mali ERR because - * the core number is out of range (which is a valid error in other cases). - * So instead we check here (now that we have the subsys lock) and let the - * caller cope with the core get failure and check that the core has - * been unregistered in the PMM as part of its destruction. - */ - if ( subsys->number_of_cores > mali_core_nr ) - { - core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); - } - - if ( NULL == core ) - { - /* Couldn't find the core */ - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: Failed to find core to power down\n") ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - else if ( core->state != CORE_IDLE ) - { - /* When powering down we either set a pending power down flag here so we - * can power down cleanly after the job completes or we don't set the - * flag if we have been asked to only do a power down right now - * In either case, return that the core is busy - */ - if ( !immediate_only ) core->pend_power_down = MALI_TRUE; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 5, ("Core: No idle core to power down\n") ); - MALI_ERROR(_MALI_OSK_ERR_BUSY); - } - - /* Shouldn't have a pending power down flag set */ - MALI_DEBUG_ASSERT( !core->pend_power_down ); - - /* Move core to off queue */ - mali_core_subsystem_move_core_set_off(core); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only) -{ - mali_core_renderunit * core; - - MALI_CHECK_SUBSYSTEM(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); - - if( core == NULL ) - { - /* Couldn't find the core */ - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: Failed to find core to power up\n") ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - else if( core->state != CORE_OFF ) - { - /* This will usually happen because we are trying to cancel a pending power down */ - core->pend_power_down = MALI_FALSE; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: No powered off core to power up (cancelled power down?)\n") ); - MALI_ERROR(_MALI_OSK_ERR_BUSY); - } - - /* Shouldn't have a pending power down set */ - MALI_DEBUG_ASSERT( !core->pend_power_down ); - - /* Move core to idle queue */ - mali_core_subsystem_move_core_set_idle(core); - - if( !queue_only ) - { - /* Reset MMU & core - core must be idle to allow this */ -#if USING_MMU - if ( NULL!=core->mmu ) - { -#if defined(USING_MALI200) - if (core->pmm_id != MALI_PMM_CORE_PP0) - { -#endif - mali_kernel_mmu_reset(core->mmu); -#if defined(USING_MALI200) - } -#endif - - } -#endif /* USING_MMU */ - subsys->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); - } - - /* Need to schedule work to start on this core */ - mali_core_subsystem_schedule(subsys); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - MALI_SUCCESS; -} - -#endif /* USING_MALI_PMM */ - -#if MALI_STATE_TRACKING -u32 mali_core_renderunit_dump_state(mali_core_subsystem* subsystem, char *buf, u32 size) -{ - u32 i, len = 0; - mali_core_renderunit *core; - mali_core_renderunit *tmp_core; - - mali_core_session* session; - mali_core_session* tmp_session; - - if (0 >= size) - { - return 0; - } - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - len += _mali_osk_snprintf(buf + len, size - len, "Subsystem:\n"); - len += _mali_osk_snprintf(buf + len, size - len, " Name: %s\n", subsystem->name); - - for (i = 0; i < subsystem->number_of_cores; i++) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core: #%u\n", - subsystem->mali_core_array[i]->core_number); - len += _mali_osk_snprintf(buf + len, size - len, " Description: %s\n", - subsystem->mali_core_array[i]->description); - switch(subsystem->mali_core_array[i]->state) - { - case CORE_IDLE: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_IDLE\n"); - break; - case CORE_WORKING: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_WORKING\n"); - break; - case CORE_WATCHDOG_TIMEOUT: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_WATCHDOG_TIMEOUT\n"); - break; - case CORE_POLL: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_POLL\n"); - break; - case CORE_HANG_CHECK_TIMEOUT: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_HANG_CHECK_TIMEOUT\n"); - break; - case CORE_OFF: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_OFF\n"); - break; - default: - len += _mali_osk_snprintf(buf + len, size - len, " State: Unknown (0x%X)\n", - subsystem->mali_core_array[i]->state); - break; - } - len += _mali_osk_snprintf(buf + len, size - len, " Current job: 0x%X\n", - (u32)(subsystem->mali_core_array[i]->current_job)); - if (subsystem->mali_core_array[i]->current_job) - { - u64 time_used_nano_seconds; - u32 time_used_micro_seconds; - u64 time_now = _mali_osk_time_get_ns(); - - time_used_nano_seconds = time_now - subsystem->mali_core_array[i]->current_job->start_time; - time_used_micro_seconds = ((u32)(time_used_nano_seconds)) / 1000; - - len += _mali_osk_snprintf(buf + len, size - len, " Current job session: 0x%X\n", - subsystem->mali_core_array[i]->current_job->session); - len += _mali_osk_snprintf(buf + len, size - len, " Current job number: %d\n", - subsystem->mali_core_array[i]->current_job->job_nr); - len += _mali_osk_snprintf(buf + len, size - len, " Current job render_time micro seconds: %d\n", - time_used_micro_seconds ); - len += _mali_osk_snprintf(buf + len, size - len, " Current job start time micro seconds: %d\n", - (u32) (subsystem->mali_core_array[i]->current_job->start_time >>10) ); - } - len += _mali_osk_snprintf(buf + len, size - len, " Core version: 0x%X\n", - subsystem->mali_core_array[i]->core_version); -#if USING_MALI_PMM - len += _mali_osk_snprintf(buf + len, size - len, " PMM id: 0x%X\n", - subsystem->mali_core_array[i]->pmm_id); - len += _mali_osk_snprintf(buf + len, size - len, " Power down requested: %s\n", - subsystem->mali_core_array[i]->pend_power_down ? "TRUE" : "FALSE"); -#endif - } - - len += _mali_osk_snprintf(buf + len, size - len, " Cores on idle list:\n"); - _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_idle_head, mali_core_renderunit, list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core #%u\n", core->core_number); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Cores on off list:\n"); - _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_off_head, mali_core_renderunit, list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core #%u\n", core->core_number); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Connected sessions:\n"); - _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->all_sessions_head, mali_core_session, all_sessions_list) - { - len += _mali_osk_snprintf(buf + len, size - len, - " Session 0x%X:\n", (u32)session); - len += _mali_osk_snprintf(buf + len, size - len, - " Queue depth: %u\n", mali_job_queue_size(session)); - len += _mali_osk_snprintf(buf + len, size - len, - " First waiting job: 0x%p\n", session->queue[session->queue_head]); - len += _mali_osk_snprintf(buf + len, size - len, " Notification queue: %s\n", - _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY"); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs received:%4d\n", _mali_osk_atomic_read(&session->jobs_received)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs started :%4d\n", _mali_osk_atomic_read(&session->jobs_started)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs ended :%4d\n", _mali_osk_atomic_read(&session->jobs_ended)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs returned:%4d\n", _mali_osk_atomic_read(&session->jobs_returned)); - len += _mali_osk_snprintf(buf + len, size - len, " PID: %d\n", session->pid); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Waiting sessions sum all priorities: %u\n", - subsystem->awaiting_sessions_sum_all_priorities); - for (i = 0; i < PRIORITY_LEVELS; i++) - { - len += _mali_osk_snprintf(buf + len, size - len, " Waiting sessions with priority %u:\n", i); - _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->awaiting_sessions_head[i], - mali_core_session, awaiting_sessions_list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Session 0x%X:\n", (u32)session); - len += _mali_osk_snprintf(buf + len, size - len, " Waiting job: 0x%X\n", - (u32)session->queue[session->queue_head]); - len += _mali_osk_snprintf(buf + len, size - len, " Notification queue: %s\n", - _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY"); - } - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); - return len; -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h b/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h deleted file mode 100644 index 5fbe686..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_RENDERCORE_H__ -#define __MALI_RENDERCORE_H__ - -#include "mali_osk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#define PRIORITY_LEVELS 3 -#define PRIORITY_MAX 0 -#define PRIORITY_MIN (PRIORITY_MAX+PRIORITY_LEVELS-1) - -/* This file contains what we need in kernel for all core types. */ - -typedef enum -{ - CORE_IDLE, /**< Core is ready for a new job */ - CORE_WORKING, /**< Core is working on a job */ - CORE_WATCHDOG_TIMEOUT, /**< Core is working but it has timed out */ - CORE_POLL, /**< Poll timer triggered, pending handling */ - CORE_HANG_CHECK_TIMEOUT,/**< Timeout for hang detection */ - CORE_OFF /**< Core is powered off */ -} mali_core_status; - -typedef enum -{ - SUBSYSTEM_RESCHEDULE, - SUBSYSTEM_WAIT -} mali_subsystem_reschedule_option; - -typedef enum -{ - MALI_CORE_RESET_STYLE_RUNABLE, - MALI_CORE_RESET_STYLE_DISABLE, - MALI_CORE_RESET_STYLE_HARD -} mali_core_reset_style; - -typedef enum -{ - JOB_STATUS_CONTINUE_RUN = 0x01, - JOB_STATUS_END_SUCCESS = 1<<(16+0), - JOB_STATUS_END_OOM = 1<<(16+1), - JOB_STATUS_END_ABORT = 1<<(16+2), - JOB_STATUS_END_TIMEOUT_SW = 1<<(16+3), - JOB_STATUS_END_HANG = 1<<(16+4), - JOB_STATUS_END_SEG_FAULT = 1<<(16+5), - JOB_STATUS_END_ILLEGAL_JOB = 1<<(16+6), - JOB_STATUS_END_UNKNOWN_ERR = 1<<(16+7), - JOB_STATUS_END_SHUTDOWN = 1<<(16+8), - JOB_STATUS_END_SYSTEM_UNUSABLE = 1<<(16+9) -} mali_subsystem_job_end_code; - - -struct mali_core_job; -struct mali_core_subsystem; -struct mali_core_renderunit; -struct mali_core_session; - -/* We have one of these subsystems for each core type */ -typedef struct mali_core_subsystem -{ - struct mali_core_renderunit ** mali_core_array; /* An array of all cores of this type */ - u32 number_of_cores; /* Number of cores in this list */ - - _mali_core_type core_type; - - u32 magic_nr; - - _mali_osk_list_t renderunit_idle_head; /* Idle cores of this type */ - _mali_osk_list_t renderunit_off_head; /* Powered off cores of this type */ - - /* Linked list for each priority of sessions with a job ready for scheduelling */ - _mali_osk_list_t awaiting_sessions_head[PRIORITY_LEVELS]; - u32 awaiting_sessions_sum_all_priorities; - - /* Linked list of all sessions connected to this coretype */ - _mali_osk_list_t all_sessions_head; - - /* Linked list of all sessions connected to this coretype */ - struct _mali_osk_notification_queue_t * notification_queue; - - const char * name; - mali_kernel_subsystem_identifier id; - - /**** Functions registered for this core type. Set during mali_core_init ******/ - /* Start this job on this core. Return MALI_TRUE if the job was started. */ - _mali_osk_errcode_t (*start_job)(struct mali_core_job * job, struct mali_core_renderunit * core); - - /* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */ - u32 (*irq_handler_upper_half)(struct mali_core_renderunit * core); - - /* This function should check if the interrupt indicates that job was finished. - If so it should update the job-struct, reset the core registers, and return MALI_TRUE, . - If the job is still working after this function it should return MALI_FALSE. - The function must also enable the bits in the interrupt mask for the core. - Called by the bottom half interrupt function. */ - int (*irq_handler_bottom_half)(struct mali_core_renderunit* core); - - /* This function is called from the ioctl function and should return a mali_core_job pointer - to a created mali_core_job object with the data given from userspace */ - _mali_osk_errcode_t (*get_new_job_from_user)(struct mali_core_session * session, void * argument); - - _mali_osk_errcode_t (*suspend_response)(struct mali_core_session * session, void * argument); - - /* This function is called from the ioctl function and should write the necessary data - to userspace telling which job was finished and the status and debuginfo for this job. - The function must also free and cleanup the input job object. */ - void (*return_job_to_user)(struct mali_core_job * job, mali_subsystem_job_end_code end_status); - - /* Is called when a subsystem shuts down. This function needs to - release internal pointers in the core struct, and free the - core struct before returning. - It is not allowed to write to any registers, since this - unmapping is already done. */ - void (*renderunit_delete)(struct mali_core_renderunit * core); - - /* Is called when we want to abort a job that is running on the core. - This is done if program exits while core is running */ - void (*reset_core)(struct mali_core_renderunit * core, mali_core_reset_style style); - - /* Is called when the rendercore wants the core to give an interrupt */ - void (*probe_core_irq_trigger)(struct mali_core_renderunit* core); - - /* Is called when the irq probe wants the core to acknowledge an interrupt from the hw */ - _mali_osk_errcode_t (*probe_core_irq_acknowledge)(struct mali_core_renderunit* core); - - /* Called when the rendercore want to issue a bus stop request to a core */ - void (*stop_bus)(struct mali_core_renderunit* core); -} mali_core_subsystem; - - -/* Per core data. This must be embedded into each core type internal core info. */ -typedef struct mali_core_renderunit -{ - struct mali_core_subsystem * subsystem; /* The core belongs to this subsystem */ - _mali_osk_list_t list; /* Is always in subsystem->idle_list OR session->renderunits_working */ - mali_core_status state; - mali_bool error_recovery; /* Indicates if the core is waiting for external help to recover (typically the MMU) */ - mali_bool in_detach_function; - struct mali_core_job * current_job; /* Current job being processed on this core ||NULL */ - u32 magic_nr; - _mali_osk_timer_t * timer; - _mali_osk_timer_t * timer_hang_detection; - - mali_io_address registers_mapped; /* IO-mapped pointer to registers */ - u32 registers_base_addr; /* Base addres of the registers */ - u32 size; /* The size of registers_mapped */ - const char * description; /* Description of this core. */ - u32 irq_nr; /* The IRQ nr for this core */ - u32 core_version; -#if USING_MMU - u32 mmu_id; - void * mmu; /* The MMU this rendercore is behind.*/ -#endif -#if USING_MALI_PMM - mali_pmm_core_id pmm_id; /* The PMM core id */ - mali_bool pend_power_down; /* Power down is requested */ -#endif - - u32 core_number; /* 0 for first detected core of this type, 1 for second and so on */ - - _mali_osk_irq_t *irq; -} mali_core_renderunit; - - -#define MALI_JOB_QUEUE_SIZE 8 -/* Per open FILE data. */ -/* You must held subsystem->mutex before any transactions to this datatype. */ -typedef struct mali_core_session -{ - struct mali_core_subsystem * subsystem; /* The session belongs to this subsystem */ - _mali_osk_list_t renderunits_working_head; /* List of renderunits working for this session */ - struct mali_core_job *queue[MALI_JOB_QUEUE_SIZE]; /* The next job from this session to run */ - int queue_head; - int queue_tail; - int queue_size; - - _mali_osk_list_t awaiting_sessions_list; /* Linked list of sessions with jobs, for each priority */ - _mali_osk_list_t all_sessions_list; /* Linked list of all sessions on the system. */ - - _mali_osk_notification_queue_t * notification_queue; /* Messages back to Base in userspace*/ -#if USING_MMU - struct mali_session_data * mmu_session; /* The session associated with the MMU page tables for this core */ -#endif - u32 magic_nr; -#if MALI_STATE_TRACKING - _mali_osk_atomic_t jobs_received; - _mali_osk_atomic_t jobs_started; - _mali_osk_atomic_t jobs_ended; - _mali_osk_atomic_t jobs_returned; - u32 pid; -#endif -} mali_core_session; - -/* This must be embedded into a specific mali_core_job struct */ -/* use this macro to get spesific mali_core_job: container_of(ptr, type, member)*/ -typedef struct mali_core_job -{ - _mali_osk_list_t list; /* Linked list of jobs. Used by struct mali_core_session */ - struct mali_core_session *session; - u32 magic_nr; - u32 priority; - u32 watchdog_msecs; - u32 render_time_usecs ; - u64 start_time; - unsigned long watchdog_jiffies; - u32 abort_id; - u32 job_nr; - _mali_uk_start_job_flags flags; -} mali_core_job; - -MALI_STATIC_INLINE mali_bool mali_job_queue_empty(mali_core_session *session) -{ - if (0 == session->queue_size) - { - return MALI_TRUE; - } - return MALI_FALSE; -} - -MALI_STATIC_INLINE mali_bool mali_job_queue_full(mali_core_session *session) -{ - if (MALI_JOB_QUEUE_SIZE == session->queue_size) - { - return MALI_TRUE; - } - return MALI_FALSE; -} - - -MALI_STATIC_INLINE _mali_osk_errcode_t mali_job_queue_add_job(mali_core_session *session, struct mali_core_job *job) -{ - if (mali_job_queue_full(session)) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - session->queue[session->queue_tail] = job; - session->queue_tail = (session->queue_tail + 1) % MALI_JOB_QUEUE_SIZE; - session->queue_size++; - - MALI_SUCCESS; -} - -MALI_STATIC_INLINE struct mali_core_job *mali_job_queue_get_job(mali_core_session *session) -{ - struct mali_core_job *job; - MALI_DEBUG_ASSERT(!mali_job_queue_empty(session)); - - job = session->queue[session->queue_head]; - - MALI_DEBUG_ASSERT_POINTER(job); - - session->queue[session->queue_head] = NULL; - session->queue_head = (session->queue_head + 1) % MALI_JOB_QUEUE_SIZE; - session->queue_size--; - - return job; -} - -MALI_STATIC_INLINE u32 mali_job_queue_size(mali_core_session *session) -{ - return (u32)(session->queue_size); -} - -MALI_STATIC_INLINE struct mali_core_job *mali_job_queue_abort_job(mali_core_session *session, u32 abort_id) -{ - int i; - int n; - struct mali_core_job *job = NULL; - - for (i = session->queue_head, n = session->queue_size; n > 0; n--, i = (i+1)%MALI_JOB_QUEUE_SIZE) - { - if (session->queue[i]->abort_id == abort_id) - { - /* Remove job from queue */ - job = session->queue[i]; - session->queue[i] = NULL; - - session->queue_size -= 1; - n--; - break; - } - } - if (NULL == job) - { - return NULL; - } - - /* Rearrange queue */ - while (n > 0) - { - int next = (i + 1) % MALI_JOB_QUEUE_SIZE; - session->queue[i] = session->queue[next]; - i = next; - n--; - } - session->queue_tail = i; - - return job; -} - - -/* - * The rendercode subsystem is included in the subsystems[] array. - */ -extern struct mali_kernel_subsystem mali_subsystem_rendercore; - -void subsystem_flush_mapped_mem_cache(void); - - -#define SUBSYSTEM_MAGIC_NR 0xdeadbeef -#define CORE_MAGIC_NR 0xcafebabe -#define SESSION_MAGIC_NR 0xbabe1234 -#define JOB_MAGIC_NR 0x0123abcd - - -#define MALI_CHECK_SUBSYSTEM(subsystem)\ - do { \ - if ( SUBSYSTEM_MAGIC_NR != subsystem->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ - } while (0) - -#define MALI_CHECK_CORE(CORE)\ - do { \ - if ( CORE_MAGIC_NR != CORE->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - -#define MALI_CHECK_SESSION(SESSION)\ - do { \ - if ( SESSION_MAGIC_NR != SESSION->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - -#define MALI_CHECK_JOB(JOB)\ - do { \ - if ( JOB_MAGIC_NR != JOB->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - - -/* Check if job_a has higher priority than job_b */ -MALI_STATIC_INLINE int job_has_higher_priority(mali_core_job * job_a, mali_core_job * job_b) -{ - /* The lowest number has the highest priority */ - return (int) (job_a->priority < job_b->priority); -} - -MALI_STATIC_INLINE void job_priority_set(mali_core_job * job, u32 priority) -{ - if (priority > PRIORITY_MIN) job->priority = PRIORITY_MIN; - else job->priority = priority; -} - -void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs); - -/* For use by const default register settings (e.g. set these after reset) */ -typedef struct register_address_and_value -{ - u32 address; - u32 value; -} register_address_and_value ; - - -/* For use by dynamic default register settings (e.g. set these after reset) */ -typedef struct register_address_and_value_list -{ - _mali_osk_list_t list; - register_address_and_value item; -} register_address_and_value_list ; - -/* Used if the user wants to set a continious block of registers */ -typedef struct register_array_user -{ - u32 entries_in_array; - u32 start_address; - void __user * reg_array; -}register_array_user; - - -#define MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys) \ - do { \ - MALI_DEBUG_PRINT(5, ("MUTEX: GRAB %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - _mali_osk_lock_wait( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \ - MALI_DEBUG_PRINT(5, ("MUTEX: GRABBED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - rendercores_global_mutex_is_held = 1; \ - rendercores_global_mutex_owner = _mali_osk_get_tid(); \ - } while (0) ; - -#define MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys) \ - do { \ - MALI_DEBUG_PRINT(5, ("MUTEX: RELEASE %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - rendercores_global_mutex_is_held = 0; \ - rendercores_global_mutex_owner = 0; \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - _mali_osk_lock_signal( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \ - MALI_DEBUG_PRINT(5, ("MUTEX: RELEASED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - } while (0) ; - - -#define MALI_ASSERT_MUTEX_IS_GRABBED(input_pointer)\ - do { \ - if ( 0 == rendercores_global_mutex_is_held ) MALI_PRINT_ERROR(("ASSERT MUTEX SHOULD BE GRABBED"));\ - if ( SUBSYSTEM_MAGIC_NR != input_pointer->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - if ( rendercores_global_mutex_owner != _mali_osk_get_tid() ) MALI_PRINT_ERROR(("Owner mismatch"));\ - } while (0) - -MALI_STATIC_INLINE _mali_osk_errcode_t mali_core_renderunit_register_rw_check(mali_core_renderunit *core, - u32 relative_address) -{ -#if USING_MALI_PMM - if( core->state == CORE_OFF ) - { - MALI_PRINT_ERROR(("Core is OFF during access: Core: %s Addr: 0x%04X\n", - core->description,relative_address)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - - if (mali_benchmark) MALI_ERROR(_MALI_OSK_ERR_FAULT); - - MALI_DEBUG_CODE(if (relative_address >= core->size) - { - MALI_PRINT_ERROR(("Trying to access illegal register: 0x%04x in core: %s", - relative_address, core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - }) - - MALI_SUCCESS; -} - - -MALI_STATIC_INLINE u32 mali_core_renderunit_register_read(struct mali_core_renderunit *core, u32 relative_address) -{ - u32 read_val; - - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return 0xDEADBEEF; - - read_val = _mali_osk_mem_ioread32(core->registers_mapped, relative_address); - - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, read_val)); - - return read_val; -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_read_array(struct mali_core_renderunit *core, - u32 relative_address, - u32 * result_array, - u32 nr_of_regs) -{ - /* NOTE Do not use burst reads against the registers */ - u32 i; - - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read_array: Core:%s Addr:0x%04X Nr_regs: %u\n", - core->description,relative_address, nr_of_regs)); - - for(i=0; i<nr_of_regs; ++i) - { - result_array[i] = mali_core_renderunit_register_read(core, relative_address + i*4); - } -} - -/* - * Write to a core register, and bypass implied memory barriers. - * - * On some systems, _mali_osk_mem_iowrite32() implies a memory barrier. This - * can be a performance problem when doing many writes in sequence. - * - * When using this function, ensure proper barriers are put in palce. Most - * likely a _mali_osk_mem_barrier() is needed after all related writes are - * completed. - * - */ -MALI_STATIC_INLINE void mali_core_renderunit_register_write_relaxed(mali_core_renderunit *core, - u32 relative_address, - u32 new_val) -{ - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return; - - MALI_DEBUG_PRINT(6, ("mali_core_renderunit_register_write_relaxed: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, new_val)); - - _mali_osk_mem_iowrite32_relaxed(core->registers_mapped, relative_address, new_val); -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_write(struct mali_core_renderunit *core, - u32 relative_address, - u32 new_val) -{ - MALI_DEBUG_PRINT(6, ("mali_core_renderunit_register_write: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, new_val)); - - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return; - - _mali_osk_mem_iowrite32(core->registers_mapped, relative_address, new_val); -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_write_array(struct mali_core_renderunit *core, - u32 relative_address, - u32 * write_array, - u32 nr_of_regs) -{ - u32 i; - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_write_array: Core:%s Addr:0x%04X Nr_regs: %u\n", - core->description,relative_address, nr_of_regs)); - - /* Do not use burst writes against the registers */ - for( i = 0; i< nr_of_regs; i++) - { - mali_core_renderunit_register_write_relaxed(core, relative_address + i*4, write_array[i]); - } -} - -_mali_osk_errcode_t mali_core_renderunit_init(struct mali_core_renderunit * core); -void mali_core_renderunit_term(struct mali_core_renderunit * core); -int mali_core_renderunit_map_registers(struct mali_core_renderunit *core); -void mali_core_renderunit_unmap_registers(struct mali_core_renderunit *core); -int mali_core_renderunit_irq_handler_add(struct mali_core_renderunit *core); -mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr); - -int mali_core_subsystem_init(struct mali_core_subsystem * new_subsys); -#if USING_MMU -void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys); -#endif -int mali_core_subsystem_register_renderunit(struct mali_core_subsystem * subsys, struct mali_core_renderunit * core); -int mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info); -void mali_core_subsystem_cleanup(struct mali_core_subsystem * subsys); -#if USING_MMU -void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data); -#endif -void mali_core_session_begin(mali_core_session *session); -void mali_core_session_close(mali_core_session * session); -int mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return); -u32 mali_core_hang_check_timeout_get(void); - -_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data); -_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores); -_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version); -_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void* argument); -void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id); - -#if USING_MALI_PMM -_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only); -_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only); -#endif - -#if MALI_STATE_TRACKING -u32 mali_core_renderunit_dump_state(mali_core_subsystem* subsystem, char *buf, u32 size); -#endif - -#endif /* __MALI_RENDERCORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h b/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h deleted file mode 100644 index 8f05216..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_kernel_subsystem.h - */ - -#ifndef __MALI_KERNEL_SUBSYSTEM_H__ -#define __MALI_KERNEL_SUBSYSTEM_H__ - -#include "mali_osk.h" -#include "mali_uk_types.h" -#include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" - -/* typedefs of the datatypes used in the hook functions */ -typedef void * mali_kernel_subsystem_session_slot; -typedef int mali_kernel_subsystem_identifier; -typedef _mali_osk_errcode_t (*mali_kernel_resource_registrator)(_mali_osk_resource_t *); - -/** - * Broadcast notification messages - */ -typedef enum mali_core_notification_message -{ - MMU_KILL_STEP0_LOCK_SUBSYSTEM, /**< Request to lock subsystem */ - MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES, /**< Request to stop all buses */ - MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS, /**< Request kill all jobs, and not start more jobs */ - MMU_KILL_STEP3_CONTINUE_JOB_HANDLING, /**< Request to continue with new jobs on all cores */ - MMU_KILL_STEP4_UNLOCK_SUBSYSTEM /**< Request to unlock subsystem */ -} mali_core_notification_message; - -/** - * A function pointer can be NULL if the subsystem isn't interested in the event. - */ -typedef struct mali_kernel_subsystem -{ - /* subsystem control */ - _mali_osk_errcode_t (*startup)(mali_kernel_subsystem_identifier id); /**< Called during module load or system startup*/ - void (*shutdown)(mali_kernel_subsystem_identifier id); /**< Called during module unload or system shutdown */ - - /** - * Called during module load or system startup. - * Called when all subsystems have reported startup OK and all resources where successfully initialized - */ - _mali_osk_errcode_t (*load_complete)(mali_kernel_subsystem_identifier id); - - /* per subsystem handlers */ - _mali_osk_errcode_t (*system_info_fill)(_mali_system_info* info); /**< Fill info into info struct. MUST allocate memory with kmalloc, since it's kfree'd */ - - /* per session handlers */ - /** - * Informs about a new session. - * slot can be used to track per-session per-subsystem data. - * queue can be used to send events to user space. - * _mali_osk_errcode_t error return value. - */ - _mali_osk_errcode_t (*session_begin)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - /** - * Informs that a session is ending - * slot was the same as given during session_begin - */ - void (*session_end)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - - /* Used by subsystems to send messages to each other. This is the receiving end */ - void (*broadcast_notification)(mali_core_notification_message message, u32 data); - -#if MALI_STATE_TRACKING - /** Dump the current state of the subsystem */ - u32 (*dump_state)(char *buf, u32 size); -#endif -} mali_kernel_subsystem; - -/* functions used by the subsystems to interact with the core */ -/** - * Register a resouce handler - * @param type The resoruce type to register a handler for - * @param handler Pointer to the function handling this resource - * @return _MALI_OSK_ERR_OK on success. Otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler); - -/* function used to interact with other subsystems */ -/** - * Broadcast a message - * Sends a message to all subsystems which have registered a broadcast notification handler - * @param message The message to send - * @param data Message specific extra data - */ -void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data); - -#if MALI_STATE_TRACKING -/** - * Tell all subsystems to dump their current state - */ -u32 _mali_kernel_core_dump_state(char *buf, u32 size); -#endif - - -#endif /* __MALI_KERNEL_SUBSYSTEM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c index b43b872..a374dbf 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -27,7 +27,7 @@ static _mali_osk_timer_t *utilization_timer = NULL; static mali_bool timer_running = MALI_FALSE; -static void calculate_gpu_utilization(void *arg) +static void calculate_gpu_utilization(void* arg) { u64 time_now; u64 time_period; @@ -39,7 +39,8 @@ static void calculate_gpu_utilization(void *arg) _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW); - if (accumulated_work_time == 0 && work_start_time == 0) { + if (accumulated_work_time == 0 && work_start_time == 0) + { /* Don't reschedule timer, this will be started if new work arrives */ timer_running = MALI_FALSE; @@ -55,7 +56,8 @@ static void calculate_gpu_utilization(void *arg) time_period = time_now - period_start_time; /* If we are currently busy, update working period up to now */ - if (work_start_time != 0) { + if (work_start_time != 0) + { accumulated_work_time += (time_now - work_start_time); work_start_time = time_now; } @@ -79,10 +81,13 @@ static void calculate_gpu_utilization(void *arg) * (we could do a combination, but we just use one for simplicity, * but the end result should be good enough anyway) */ - if (period_normalized > 0x00FFFFFF) { + if (period_normalized > 0x00FFFFFF) + { /* The divisor is so big that it is safe to shift it down */ period_normalized >>= 8; - } else { + } + else + { /* * The divisor is so small that we can shift up the dividend, without loosing any data. * (dividend is always smaller than the divisor) @@ -99,22 +104,25 @@ static void calculate_gpu_utilization(void *arg) _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT)); + mali_gpu_utilization_handler(utilization); } - - _mali_osk_errcode_t mali_utilization_init(void) { - time_data_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ|_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 ); + time_data_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ | + _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_UTILIZATION); + if (NULL == time_data_lock) + { return _MALI_OSK_ERR_FAULT; - + } _mali_osk_atomic_init(&num_running_cores, 0); utilization_timer = _mali_osk_timer_init(); - if (NULL == utilization_timer) { + if (NULL == utilization_timer) + { _mali_osk_lock_term(time_data_lock); return _MALI_OSK_ERR_FAULT; } @@ -125,7 +133,8 @@ _mali_osk_errcode_t mali_utilization_init(void) void mali_utilization_suspend(void) { - if (NULL != utilization_timer) { + if (NULL != utilization_timer) + { _mali_osk_timer_del(utilization_timer); timer_running = MALI_FALSE; } @@ -133,7 +142,8 @@ void mali_utilization_suspend(void) void mali_utilization_term(void) { - if (NULL != utilization_timer) { + if (NULL != utilization_timer) + { _mali_osk_timer_del(utilization_timer); timer_running = MALI_FALSE; _mali_osk_timer_term(utilization_timer); @@ -145,11 +155,10 @@ void mali_utilization_term(void) _mali_osk_lock_term(time_data_lock); } - - void mali_utilization_core_start(u64 time_now) { - if (_mali_osk_atomic_inc_return(&num_running_cores) == 1) { + if (_mali_osk_atomic_inc_return(&num_running_cores) == 1) + { /* * We went from zero cores working, to one core working, * we now consider the entire GPU for being busy @@ -167,27 +176,26 @@ void mali_utilization_core_start(u64 time_now) } work_start_time = time_now; - - if (timer_running != MALI_TRUE) { + if (timer_running != MALI_TRUE) + { timer_running = MALI_TRUE; period_start_time = work_start_time; /* starting a new period */ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_timer_del(utilization_timer); - _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT)); - } else { + } + else + { _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW); } } } - - void mali_utilization_core_end(u64 time_now) { - if (_mali_osk_atomic_dec_return(&num_running_cores) == 0) { + if (_mali_osk_atomic_dec_return(&num_running_cores) == 0) + { /* * No more cores are working, so accumulate the time we was busy. */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h index c779978..1f60517 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c b/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c index dc39e01..63c9f5b 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011-2012 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. @@ -10,39 +10,41 @@ #include "mali_kernel_common.h" #include "mali_osk.h" -#include "mali_osk_mali.h" #include "mali_ukk.h" -/*#include "mali_timestamp.h"*/ #if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" +#include "mali_osk_profiling.h" #endif _mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args) { _mali_uk_vsync_event event = (_mali_uk_vsync_event)args->event; MALI_IGNORE(event); /* event is not used for release code, and that is OK */ -/* u64 ts = _mali_timestamp_get(); - */ #if MALI_TIMELINE_PROFILING_ENABLED + /* + * Manually generate user space events in kernel space. + * This saves user space from calling kernel space twice in this case. + * We just need to remember to add pid and tid manually. + */ if ( event==_MALI_UK_VSYNC_EVENT_BEGIN_WAIT) { - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SUSPEND | - MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | - MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, - 0, 0, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND | + MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, + _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); } - if ( event==_MALI_UK_VSYNC_EVENT_END_WAIT) + if (event==_MALI_UK_VSYNC_EVENT_END_WAIT) { - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_RESUME | - MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | - MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, - 0, 0, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME | + MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, + _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); } #endif + MALI_DEBUG_PRINT(4, ("Received VSYNC event: %d\n", event)); MALI_SUCCESS; } diff --git a/drivers/media/video/samsung/mali/common/mali_l2_cache.c b/drivers/media/video/samsung/mali/common/mali_l2_cache.c new file mode 100644 index 0000000..aa5cc54 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_l2_cache.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2010-2012 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_osk.h" + +#include "mali_l2_cache.h" +#include "mali_hw_core.h" +#include "mali_pm.h" + +/** + * Size of the Mali L2 cache registers in bytes + */ +#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30 + +#define MALI_MAX_NUMBER_OF_L2_CACHE_CORES 3 + +/** + * Mali L2 cache register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_l2_cache_register { + MALI400_L2_CACHE_REGISTER_STATUS = 0x0008, + /*unused = 0x000C */ + MALI400_L2_CACHE_REGISTER_COMMAND = 0x0010, /**< Misc cache commands, e.g. clear */ + MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0014, + MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0018, /**< Limit of outstanding read requests */ + MALI400_L2_CACHE_REGISTER_ENABLE = 0x001C, /**< Enable misc cache features */ + MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0020, + MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0024, + MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x0028, + MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x002C, +} mali_l2_cache_register; + +/** + * Mali L2 cache commands + * These are the commands that can be sent to the Mali L2 cache unit + */ +typedef enum mali_l2_cache_command +{ + MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */ + /* Read HW TRM carefully before adding/using other commands than the clear above */ +} mali_l2_cache_command; + +/** + * Mali L2 cache commands + * These are the commands that can be sent to the Mali L2 cache unit + */ +typedef enum mali_l2_cache_enable +{ + MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */ + MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */ + MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */ +} mali_l2_cache_enable; + +/** + * Mali L2 cache status bits + */ +typedef enum mali_l2_cache_status +{ + MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */ + MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */ +} mali_l2_cache_status; + +/** + * Definition of the L2 cache core struct + * Used to track a L2 cache unit in the system. + * Contains information about the mapping of the registers + */ +struct mali_l2_cache_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + u32 core_id; /**< Unique core ID */ + _mali_osk_lock_t *command_lock; /**< Serialize all L2 cache commands */ + _mali_osk_lock_t *counter_lock; /**< Synchronize L2 cache counter access */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ +}; + +#define MALI400_L2_MAX_READS_DEFAULT 0x1C + +static struct mali_l2_cache_core *mali_global_l2_cache_cores[MALI_MAX_NUMBER_OF_L2_CACHE_CORES]; +static u32 mali_global_num_l2_cache_cores = 0; + +int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT; + +/* Local helper functions */ +static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val); + + +struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t *resource) +{ + struct mali_l2_cache_core *cache = NULL; + + MALI_DEBUG_PRINT(2, ("Mali L2 cache: Creating Mali L2 cache: %s\n", resource->description)); + + if (mali_global_num_l2_cache_cores >= MALI_MAX_NUMBER_OF_L2_CACHE_CORES) + { + MALI_PRINT_ERROR(("Mali L2 cache: Too many L2 cache core objects created\n")); + return NULL; + } + + cache = _mali_osk_malloc(sizeof(struct mali_l2_cache_core)); + if (NULL != cache) + { + cache->core_id = mali_global_num_l2_cache_cores; + cache->counter_src0 = MALI_HW_CORE_NO_COUNTER; + cache->counter_src1 = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&cache->hw_core, resource, MALI400_L2_CACHE_REGISTERS_SIZE)) + { + cache->command_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, + 0, _MALI_OSK_LOCK_ORDER_L2_COMMAND); + if (NULL != cache->command_lock) + { + cache->counter_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, + 0, _MALI_OSK_LOCK_ORDER_L2_COUNTER); + if (NULL != cache->counter_lock) + { + if (_MALI_OSK_ERR_OK == mali_l2_cache_reset(cache)) + { + mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = cache; + mali_global_num_l2_cache_cores++; + + return cache; + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to reset L2 cache core %s\n", cache->hw_core.description)); + } + + _mali_osk_lock_term(cache->counter_lock); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to create counter lock for L2 cache core %s\n", cache->hw_core.description)); + } + + _mali_osk_lock_term(cache->command_lock); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to create command lock for L2 cache core %s\n", cache->hw_core.description)); + } + + mali_hw_core_delete(&cache->hw_core); + } + + _mali_osk_free(cache); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to allocate memory for L2 cache core\n")); + } + + return NULL; +} + +void mali_l2_cache_delete(struct mali_l2_cache_core *cache) +{ + u32 i; + + /* reset to defaults */ + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT); + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT); + + _mali_osk_lock_term(cache->counter_lock); + _mali_osk_lock_term(cache->command_lock); + mali_hw_core_delete(&cache->hw_core); + + for (i = 0; i < mali_global_num_l2_cache_cores; i++) + { + if (mali_global_l2_cache_cores[i] == cache) + { + mali_global_l2_cache_cores[i] = NULL; + mali_global_num_l2_cache_cores--; + } + } + + _mali_osk_free(cache); +} + +u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache) +{ + return cache->core_id; +} + +mali_bool mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter) +{ + u32 value = 0; /* disabled src */ + + MALI_DEBUG_ASSERT_POINTER(cache); + MALI_DEBUG_ASSERT(counter < (1 << 7)); /* the possible values are 0-127 */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + cache->counter_src0 = counter; + + if (counter != MALI_HW_CORE_NO_COUNTER) + { + value = counter; + } + + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, value); + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + return MALI_TRUE; +} + +mali_bool mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter) +{ + u32 value = 0; /* disabled src */ + + MALI_DEBUG_ASSERT_POINTER(cache); + MALI_DEBUG_ASSERT(counter < (1 << 7)); /* the possible values are 0-127 */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + cache->counter_src1 = counter; + + if (counter != MALI_HW_CORE_NO_COUNTER) + { + value = counter; + } + + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, value); + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + return MALI_TRUE; +} + +u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache) +{ + return cache->counter_src0; +} + +u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache) +{ + return cache->counter_src1; +} + +void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1) +{ + MALI_DEBUG_ASSERT(NULL != src0); + MALI_DEBUG_ASSERT(NULL != value0); + MALI_DEBUG_ASSERT(NULL != src1); + MALI_DEBUG_ASSERT(NULL != value1); + + /* Caller must hold the PM lock and know that we are powered on */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + *src0 = cache->counter_src0; + *src1 = cache->counter_src1; + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + *value0 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0); + } + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + *value1 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); + } + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); +} + +struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index) +{ + if (MALI_MAX_NUMBER_OF_L2_CACHE_CORES > index) + { + return mali_global_l2_cache_cores[index]; + } + + return NULL; +} + +u32 mali_l2_cache_core_get_glob_num_l2_cores(void) +{ + return mali_global_num_l2_cache_cores; +} + +u32 mali_l2_cache_core_get_max_num_l2_cores(void) +{ + return MALI_MAX_NUMBER_OF_L2_CACHE_CORES; +} + +_mali_osk_errcode_t mali_l2_cache_reset(struct mali_l2_cache_core *cache) +{ + /* Invalidate cache (just to keep it in a known state at startup) */ + mali_l2_cache_invalidate_all(cache); + + /* Enable cache */ + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE); + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads); + + /* Restart any performance counters (if enabled) */ + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, cache->counter_src0); + } + + if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER) + { + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, cache->counter_src1); + } + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_l2_cache_invalidate_all(struct mali_l2_cache_core *cache) +{ + return mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); +} + +_mali_osk_errcode_t mali_l2_cache_invalidate_pages(struct mali_l2_cache_core *cache, u32 *pages, u32 num_pages) +{ + u32 i; + _mali_osk_errcode_t ret1, ret = _MALI_OSK_ERR_OK; + + for (i = 0; i < num_pages; i++) + { + ret1 = mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, pages[i]); + if (_MALI_OSK_ERR_OK != ret1) + { + ret = ret1; + } + } + + return ret; +} + +mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache) +{ + /* + * Take PM lock and check power state. + * Returns MALI_TRUE if module is powered on. + * Power state will not change until mali_l2_cache_unlock_power_state() is called. + */ + mali_pm_lock(); + return mali_pm_is_powered_on(); +} + +void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache) +{ + /* Release PM lock */ + mali_pm_unlock(); +} + +/* -------- local helper functions below -------- */ + + +static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val) +{ + int i = 0; + const int loop_count = 100000; + + /* + * Grab lock in order to send commands to the L2 cache in a serialized fashion. + * The L2 cache will ignore commands if it is busy. + */ + _mali_osk_lock_wait(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + + /* First, wait for L2 cache command handler to go idle */ + + for (i = 0; i < loop_count; i++) + { + if (!(mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_STATUS) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY)) + { + break; + } + } + + if (i == loop_count) + { + _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n")); + MALI_ERROR( _MALI_OSK_ERR_FAULT ); + } + + /* then issue the command */ + mali_hw_core_register_write(&cache->hw_core, reg, val); + + _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + + MALI_SUCCESS; +} diff --git a/drivers/media/video/samsung/mali/common/mali_l2_cache.h b/drivers/media/video/samsung/mali/common/mali_l2_cache.h new file mode 100644 index 0000000..5a8e4da --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_l2_cache.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __MALI_KERNEL_L2_CACHE_H__ +#define __MALI_KERNEL_L2_CACHE_H__ + +#include "mali_osk.h" + +struct mali_l2_cache_core; + +_mali_osk_errcode_t mali_l2_cache_initialize(void); +void mali_l2_cache_terminate(void); + +struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t * resource); +void mali_l2_cache_delete(struct mali_l2_cache_core *cache); + +u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache); + +mali_bool mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter); +mali_bool mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter); +u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache); +u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache); +void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1); +struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index); +u32 mali_l2_cache_core_get_glob_num_l2_cores(void); +u32 mali_l2_cache_core_get_max_num_l2_cores(void); + +_mali_osk_errcode_t mali_l2_cache_reset(struct mali_l2_cache_core *cache); + +_mali_osk_errcode_t mali_l2_cache_invalidate_all(struct mali_l2_cache_core *cache); +_mali_osk_errcode_t mali_l2_cache_invalidate_pages(struct mali_l2_cache_core *cache, u32 *pages, u32 num_pages); + +mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache); +void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache); + +#endif /* __MALI_KERNEL_L2_CACHE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mem_validation.c b/drivers/media/video/samsung/mali/common/mali_mem_validation.c new file mode 100644 index 0000000..ea9c428 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mem_validation.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011-2012 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_mem_validation.h" +#include "mali_osk.h" +#include "mali_kernel_common.h" + +#define MALI_INVALID_MEM_ADDR 0xFFFFFFFF + +typedef struct +{ + u32 phys_base; /**< Mali physical base of the memory, page aligned */ + u32 size; /**< size in bytes of the memory, multiple of page size */ +} _mali_mem_validation_t; + +static _mali_mem_validation_t mali_mem_validator = { MALI_INVALID_MEM_ADDR, MALI_INVALID_MEM_ADDR }; + +_mali_osk_errcode_t mali_mem_validation_add_range(const _mali_osk_resource_t *resource) +{ + /* Check that no other MEM_VALIDATION resources exist */ + if (MALI_INVALID_MEM_ADDR != mali_mem_validator.phys_base) + { + MALI_PRINT_ERROR(("Failed to add MEM_VALIDATION resource %s; another range is already specified\n", resource->description)); + return _MALI_OSK_ERR_FAULT; + } + + /* Check restrictions on page alignment */ + if ((0 != (resource->base & (~_MALI_OSK_CPU_PAGE_MASK))) || + (0 != (resource->size & (~_MALI_OSK_CPU_PAGE_MASK)))) + { + MALI_PRINT_ERROR(("Failed to add MEM_VALIDATION resource %s; incorrect alignment\n", resource->description)); + return _MALI_OSK_ERR_FAULT; + } + + mali_mem_validator.phys_base = resource->base; + mali_mem_validator.size = resource->size; + MALI_DEBUG_PRINT(2, ("Memory Validator '%s' installed for Mali physical address base=0x%08X, size=0x%08X\n", + resource->description, mali_mem_validator.phys_base, mali_mem_validator.size)); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) +{ + if (phys_addr < (phys_addr + size)) /* Don't allow overflow (or zero size) */ + { + if ((0 == ( phys_addr & (~_MALI_OSK_CPU_PAGE_MASK))) && + (0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)))) + { + if ((phys_addr >= mali_mem_validator.phys_base) && + ((phys_addr + (size - 1)) >= mali_mem_validator.phys_base) && + (phys_addr <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) && + ((phys_addr + (size - 1)) <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) ) + { + MALI_DEBUG_PRINT(3, ("Accepted range 0x%08X + size 0x%08X (= 0x%08X)\n", phys_addr, size, (phys_addr + size - 1))); + return _MALI_OSK_ERR_OK; + } + } + } + + MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size)); + + return _MALI_OSK_ERR_FAULT; +} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_session_manager.h b/drivers/media/video/samsung/mali/common/mali_mem_validation.h index 8cc41d7..2043b44 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_session_manager.h +++ b/drivers/media/video/samsung/mali/common/mali_mem_validation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011-2012 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. @@ -8,12 +8,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_SESSION_MANAGER_H__ -#define __MALI_KERNEL_SESSION_MANAGER_H__ +#ifndef __MALI_MEM_VALIDATION_H__ +#define __MALI_MEM_VALIDATION_H__ -/* Incomplete struct to pass around pointers to it */ -struct mali_session_data; +#include "mali_osk.h" -void * mali_kernel_session_manager_slot_get(struct mali_session_data * session, int id); +_mali_osk_errcode_t mali_mem_validation_add_range(const _mali_osk_resource_t * resource); +_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size); -#endif /* __MALI_KERNEL_SESSION_MANAGER_H__ */ +#endif /* __MALI_MEM_VALIDATION_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_memory.c b/drivers/media/video/samsung/mali/common/mali_memory.c new file mode 100644 index 0000000..7a11d1a --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_memory.c @@ -0,0 +1,1321 @@ +/* + * Copyright (C) 2010-2012 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_kernel_descriptor_mapping.h" +#include "mali_mem_validation.h" +#include "mali_memory.h" +#include "mali_mmu_page_directory.h" +#include "mali_kernel_memory_engine.h" +#include "mali_block_allocator.h" +#include "mali_kernel_mem_os.h" +#include "mali_session.h" +#include "mali_l2_cache.h" +#include "mali_cluster.h" +#include "mali_group.h" +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +#include "ump_kernel_interface.h" +#endif + +/* kernel side OS functions and user-kernel interface */ +#include "mali_osk.h" +#include "mali_osk_mali.h" +#include "mali_ukk.h" +#include "mali_osk_list.h" +#include "mali_osk_bitops.h" + +/** + * Per-session memory descriptor mapping table sizes + */ +#define MALI_MEM_DESCRIPTORS_INIT 64 +#define MALI_MEM_DESCRIPTORS_MAX 65536 + +typedef struct dedicated_memory_info +{ + u32 base; + u32 size; + struct dedicated_memory_info * next; +} dedicated_memory_info; + +/* types used for external_memory and ump_memory physical memory allocators, which are using the mali_allocation_engine */ +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +typedef struct ump_mem_allocation +{ + mali_allocation_engine * engine; + mali_memory_allocation * descriptor; + u32 initial_offset; + u32 size_allocated; + ump_dd_handle ump_mem; +} ump_mem_allocation ; +#endif + +typedef struct external_mem_allocation +{ + mali_allocation_engine * engine; + mali_memory_allocation * descriptor; + u32 initial_offset; + u32 size; +} external_mem_allocation; + +/** + * @brief Internal function for unmapping memory + * + * Worker function for unmapping memory from a user-process. We assume that the + * session/descriptor's lock was obtained before entry. For example, the + * wrapper _mali_ukk_mem_munmap() will lock the descriptor, then call this + * function to do the actual unmapping. mali_memory_core_session_end() could + * also call this directly (depending on compilation options), having locked + * the descriptor. + * + * This function will fail if it is unable to put the MMU in stall mode (which + * might be the case if a page fault is also being processed). + * + * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h" + * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. + */ +static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ); + +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +static void ump_memory_release(void * ctx, void * handle); +static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); +#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0*/ + + +static void external_memory_release(void * ctx, void * handle); +static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); + + +/* nop functions */ + +/* mali address manager needs to allocate page tables on allocate, write to page table(s) on map, write to page table(s) and release page tables on release */ +static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor); /* validates the range, allocates memory for the page tables if needed */ +static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size); +static void mali_address_manager_release(mali_memory_allocation * descriptor); + +/* MMU variables */ + +typedef struct mali_mmu_page_table_allocation +{ + _mali_osk_list_t list; + u32 * usage_map; + u32 usage_count; + u32 num_pages; + mali_page_table_block pages; +} mali_mmu_page_table_allocation; + +typedef struct mali_mmu_page_table_allocations +{ + _mali_osk_lock_t *lock; + _mali_osk_list_t partial; + _mali_osk_list_t full; + /* we never hold on to a empty allocation */ +} mali_mmu_page_table_allocations; + +static mali_kernel_mem_address_manager mali_address_manager = +{ + mali_address_manager_allocate, /* allocate */ + mali_address_manager_release, /* release */ + mali_address_manager_map, /* map_physical */ + NULL /* unmap_physical not present*/ +}; + +/* the mmu page table cache */ +static struct mali_mmu_page_table_allocations page_table_cache; + + +static mali_kernel_mem_address_manager process_address_manager = +{ + _mali_osk_mem_mapregion_init, /* allocate */ + _mali_osk_mem_mapregion_term, /* release */ + _mali_osk_mem_mapregion_map, /* map_physical */ + _mali_osk_mem_mapregion_unmap /* unmap_physical */ +}; + +static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void); +static void mali_mmu_page_table_cache_destroy(void); + +static mali_allocation_engine memory_engine = NULL; +static mali_physical_memory_allocator * physical_memory_allocators = NULL; + +static dedicated_memory_info * mem_region_registrations = NULL; + +/* called during module init */ +_mali_osk_errcode_t mali_memory_initialize(void) +{ + _mali_osk_errcode_t err; + + MALI_DEBUG_PRINT(2, ("Memory system initializing\n")); + + err = mali_mmu_page_table_cache_create(); + if(_MALI_OSK_ERR_OK != err) + { + MALI_ERROR(err); + } + + memory_engine = mali_allocation_engine_create(&mali_address_manager, &process_address_manager); + MALI_CHECK_NON_NULL( memory_engine, _MALI_OSK_ERR_FAULT); + + MALI_SUCCESS; +} + +/* called if/when our module is unloaded */ +void mali_memory_terminate(void) +{ + MALI_DEBUG_PRINT(2, ("Memory system terminating\n")); + + mali_mmu_page_table_cache_destroy(); + + while ( NULL != mem_region_registrations) + { + dedicated_memory_info * m; + m = mem_region_registrations; + mem_region_registrations = m->next; + _mali_osk_mem_unreqregion(m->base, m->size); + _mali_osk_free(m); + } + + while ( NULL != physical_memory_allocators) + { + mali_physical_memory_allocator * m; + m = physical_memory_allocators; + physical_memory_allocators = m->next; + m->destroy(m); + } + + if (NULL != memory_engine) + { + mali_allocation_engine_destroy(memory_engine); + memory_engine = NULL; + } +} + +_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data) +{ + MALI_DEBUG_PRINT(5, ("Memory session begin\n")); + + /* create descriptor mapping table */ + session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); + + if (NULL == session_data->descriptor_mapping) + { + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + session_data->memory_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_SESSION); + if (NULL == session_data->memory_lock) + { + mali_descriptor_mapping_destroy(session_data->descriptor_mapping); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* Init the session's memory allocation list */ + _MALI_OSK_INIT_LIST_HEAD( &session_data->memory_head ); + + MALI_DEBUG_PRINT(5, ("MMU session begin: success\n")); + MALI_SUCCESS; +} + +static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target) +{ + mali_memory_allocation * descriptor; + + descriptor = (mali_memory_allocation*)map_target; + + MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target)); + MALI_DEBUG_ASSERT(descriptor); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + _mali_osk_free(descriptor); +} + +void mali_memory_session_end(struct mali_session_data *session_data) +{ + MALI_DEBUG_PRINT(3, ("MMU session end\n")); + + if (NULL == session_data) + { + MALI_DEBUG_PRINT(1, ("No session data found during session end\n")); + return; + } + +#ifndef MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP +#if _MALI_OSK_SPECIFIC_INDIRECT_MMAP +#error Indirect MMAP specified, but UKK does not have implicit MMAP cleanup. Current implementation does not handle this. +#else + { + _mali_osk_errcode_t err; + err = _MALI_OSK_ERR_BUSY; + while (err == _MALI_OSK_ERR_BUSY) + { + /* Lock the session so we can modify the memory list */ + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + err = _MALI_OSK_ERR_OK; + + /* Free all memory engine allocations */ + if (0 == _mali_osk_list_empty(&session_data->memory_head)) + { + mali_memory_allocation *descriptor; + mali_memory_allocation *temp; + _mali_uk_mem_munmap_s unmap_args; + + MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); + + unmap_args.ctx = session_data; + + /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */ + _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->memory_head, mali_memory_allocation, list) + { + MALI_DEBUG_PRINT(4, ("Freeing block with mali address 0x%x size %d mapped in user space at 0x%x\n", + descriptor->mali_address, descriptor->size, descriptor->size, descriptor->mapping) + ); + /* ASSERT that the descriptor's lock references the correct thing */ + MALI_DEBUG_ASSERT( descriptor->lock == session_data->memory_lock ); + /* Therefore, we have already locked the descriptor */ + + unmap_args.size = descriptor->size; + unmap_args.mapping = descriptor->mapping; + unmap_args.cookie = (u32)descriptor; + + /* + * This removes the descriptor from the list, and frees the descriptor + * + * Does not handle the _MALI_OSK_SPECIFIC_INDIRECT_MMAP case, since + * the only OS we are aware of that requires indirect MMAP also has + * implicit mmap cleanup. + */ + err = _mali_ukk_mem_munmap_internal( &unmap_args ); + + if (err == _MALI_OSK_ERR_BUSY) + { + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + /* + * Reason for this; + * We where unable to stall the MMU, probably because we are in page fault handling. + * Sleep for a while with the session lock released, then try again. + * Abnormal termination of programs with running Mali jobs is a normal reason for this. + */ + _mali_osk_time_ubusydelay(10); + break; /* Will jump back into: "while (err == _MALI_OSK_ERR_BUSY)" */ + } + } + } + } + /* Assert that we really did free everything */ + MALI_DEBUG_ASSERT( _mali_osk_list_empty(&session_data->memory_head) ); + } +#endif /* _MALI_OSK_SPECIFIC_INDIRECT_MMAP */ +#else + /* Lock the session so we can modify the memory list */ + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); +#endif /* MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP */ + + if (NULL != session_data->descriptor_mapping) + { + mali_descriptor_mapping_call_for_each(session_data->descriptor_mapping, descriptor_table_cleanup_callback); + mali_descriptor_mapping_destroy(session_data->descriptor_mapping); + session_data->descriptor_mapping = NULL; + } + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + /** + * @note Could the VMA close handler mean that we use the session data after it was freed? + * In which case, would need to refcount the session data, and free on VMA close + */ + + /* Free the lock */ + _mali_osk_lock_term( session_data->memory_lock ); + + return; +} + +_mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource) +{ + mali_physical_memory_allocator * allocator; + mali_physical_memory_allocator ** next_allocator_list; + + u32 alloc_order = resource->alloc_order; + + allocator = mali_os_allocator_create(resource->size, resource->cpu_usage_adjust, resource->description); + if (NULL == allocator) + { + MALI_DEBUG_PRINT(1, ("Failed to create OS memory allocator\n")); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + allocator->alloc_order = alloc_order; + + /* link in the allocator: insertion into ordered list + * resources of the same alloc_order will be Last-in-first */ + next_allocator_list = &physical_memory_allocators; + + while (NULL != *next_allocator_list && + (*next_allocator_list)->alloc_order < alloc_order ) + { + next_allocator_list = &((*next_allocator_list)->next); + } + + allocator->next = (*next_allocator_list); + (*next_allocator_list) = allocator; + + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource) +{ + mali_physical_memory_allocator * allocator; + mali_physical_memory_allocator ** next_allocator_list; + dedicated_memory_info * cleanup_data; + + u32 alloc_order = resource->alloc_order; + + /* do the low level linux operation first */ + + /* Request ownership of the memory */ + if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) + { + MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* create generic block allocator object to handle it */ + allocator = mali_block_allocator_create(resource->base, resource->cpu_usage_adjust, resource->size, resource->description ); + + if (NULL == allocator) + { + MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); + _mali_osk_mem_unreqregion(resource->base, resource->size); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* save low level cleanup info */ + allocator->alloc_order = alloc_order; + + cleanup_data = _mali_osk_malloc(sizeof(dedicated_memory_info)); + + if (NULL == cleanup_data) + { + _mali_osk_mem_unreqregion(resource->base, resource->size); + allocator->destroy(allocator); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + cleanup_data->base = resource->base; + cleanup_data->size = resource->size; + + cleanup_data->next = mem_region_registrations; + mem_region_registrations = cleanup_data; + + /* link in the allocator: insertion into ordered list + * resources of the same alloc_order will be Last-in-first */ + next_allocator_list = &physical_memory_allocators; + + while ( NULL != *next_allocator_list && + (*next_allocator_list)->alloc_order < alloc_order ) + { + next_allocator_list = &((*next_allocator_list)->next); + } + + allocator->next = (*next_allocator_list); + (*next_allocator_list) = allocator; + + MALI_SUCCESS; +} + +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) +{ + ump_dd_handle ump_mem; + u32 nr_blocks; + u32 i; + ump_dd_physical_block * ump_blocks; + ump_mem_allocation *ret_allocation; + + MALI_DEBUG_ASSERT_POINTER(ctx); + MALI_DEBUG_ASSERT_POINTER(engine); + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(alloc_info); + + ret_allocation = _mali_osk_malloc( sizeof( ump_mem_allocation ) ); + if ( NULL==ret_allocation ) return MALI_MEM_ALLOC_INTERNAL_FAILURE; + + ump_mem = (ump_dd_handle)ctx; + + MALI_DEBUG_PRINT(4, ("In ump_memory_commit\n")); + + nr_blocks = ump_dd_phys_block_count_get(ump_mem); + + MALI_DEBUG_PRINT(4, ("Have %d blocks\n", nr_blocks)); + + if (nr_blocks == 0) + { + MALI_DEBUG_PRINT(1, ("No block count\n")); + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks ); + if ( NULL==ump_blocks ) + { + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks)) + { + _mali_osk_free(ump_blocks); + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + /* Store away the initial offset for unmapping purposes */ + ret_allocation->initial_offset = *offset; + + for(i=0; i<nr_blocks; ++i) + { + MALI_DEBUG_PRINT(4, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size)); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[i].addr , 0, ump_blocks[i].size )) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); + + /* unmap all previous blocks (if any) */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + + _mali_osk_free(ump_blocks); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += ump_blocks[i].size; + } + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + /* Map in an extra virtual guard page at the end of the VMA */ + MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[0].addr , 0, _MALI_OSK_MALI_PAGE_SIZE )) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); + + /* unmap all previous blocks (if any) */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + + _mali_osk_free(ump_blocks); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += _MALI_OSK_MALI_PAGE_SIZE; + } + + _mali_osk_free( ump_blocks ); + + ret_allocation->engine = engine; + ret_allocation->descriptor = descriptor; + ret_allocation->ump_mem = ump_mem; + ret_allocation->size_allocated = *offset - ret_allocation->initial_offset; + + alloc_info->ctx = NULL; + alloc_info->handle = ret_allocation; + alloc_info->next = NULL; + alloc_info->release = ump_memory_release; + + return MALI_MEM_ALLOC_FINISHED; +} + +static void ump_memory_release(void * ctx, void * handle) +{ + ump_dd_handle ump_mem; + ump_mem_allocation *allocation; + + allocation = (ump_mem_allocation *)handle; + + MALI_DEBUG_ASSERT_POINTER( allocation ); + + ump_mem = allocation->ump_mem; + + MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID!=ump_mem); + + /* At present, this is a no-op. But, it allows the mali_address_manager to + * do unmapping of a subrange in future. */ + mali_allocation_engine_unmap_physical( allocation->engine, + allocation->descriptor, + allocation->initial_offset, + allocation->size_allocated, + (_mali_osk_mem_mapregion_flags_t)0 + ); + _mali_osk_free( allocation ); + + + ump_dd_reference_release(ump_mem) ; + return; +} + +_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ) +{ + ump_dd_handle ump_mem; + mali_physical_memory_allocator external_memory_allocator; + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + int md; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + /* check arguments */ + /* NULL might be a valid Mali address */ + if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + /* size must be a multiple of the system page size */ + if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + MALI_DEBUG_PRINT(3, + ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n", + args->secure_id, args->mali_address, args->size)); + + ump_mem = ump_dd_handle_create_from_secure_id( (int)args->secure_id ) ; + + if ( UMP_DD_HANDLE_INVALID==ump_mem ) MALI_ERROR(_MALI_OSK_ERR_FAULT); + + descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); + if (NULL == descriptor) + { + ump_dd_reference_release(ump_mem); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + descriptor->size = args->size; + descriptor->mapping = NULL; + descriptor->mali_address = args->mali_address; + descriptor->mali_addr_mapping_info = (void*)session_data; + descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ + descriptor->lock = session_data->memory_lock; + if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) + { + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; + } + _mali_osk_list_init( &descriptor->list ); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) + { + ump_dd_reference_release(ump_mem); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + external_memory_allocator.allocate = ump_memory_commit; + external_memory_allocator.allocate_page_table_block = NULL; + external_memory_allocator.ctx = ump_mem; + external_memory_allocator.name = "UMP Memory"; + external_memory_allocator.next = NULL; + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + mali_descriptor_mapping_free(session_data->descriptor_mapping, md); + ump_dd_reference_release(ump_mem); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + args->cookie = md; + + MALI_DEBUG_PRINT(5,("Returning from UMP attach\n")); + + /* All OK */ + MALI_SUCCESS; +} + + +_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ) +{ + mali_memory_allocation * descriptor; + struct mali_session_data *session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) + { + MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + descriptor = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); + + if (NULL != descriptor) + { + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + _mali_osk_free(descriptor); + } + + MALI_SUCCESS; + +} +#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 */ + + +static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) +{ + u32 * data; + external_mem_allocation * ret_allocation; + + MALI_DEBUG_ASSERT_POINTER(ctx); + MALI_DEBUG_ASSERT_POINTER(engine); + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(alloc_info); + + ret_allocation = _mali_osk_malloc( sizeof(external_mem_allocation) ); + + if ( NULL == ret_allocation ) + { + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + data = (u32*)ctx; + + ret_allocation->engine = engine; + ret_allocation->descriptor = descriptor; + ret_allocation->initial_offset = *offset; + + alloc_info->ctx = NULL; + alloc_info->handle = ret_allocation; + alloc_info->next = NULL; + alloc_info->release = external_memory_release; + + MALI_DEBUG_PRINT(5, ("External map: mapping phys 0x%08X at mali virtual address 0x%08X staring at offset 0x%08X length 0x%08X\n", data[0], descriptor->mali_address, *offset, data[1])); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, data[1])) + { + MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += data[1]; + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + /* Map in an extra virtual guard page at the end of the VMA */ + MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, _MALI_OSK_MALI_PAGE_SIZE)) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); + + /* unmap what we previously mapped */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += _MALI_OSK_MALI_PAGE_SIZE; + } + + ret_allocation->size = *offset - ret_allocation->initial_offset; + + return MALI_MEM_ALLOC_FINISHED; +} + +static void external_memory_release(void * ctx, void * handle) +{ + external_mem_allocation * allocation; + + allocation = (external_mem_allocation *) handle; + MALI_DEBUG_ASSERT_POINTER( allocation ); + + /* At present, this is a no-op. But, it allows the mali_address_manager to + * do unmapping of a subrange in future. */ + + mali_allocation_engine_unmap_physical( allocation->engine, + allocation->descriptor, + allocation->initial_offset, + allocation->size, + (_mali_osk_mem_mapregion_flags_t)0 + ); + + _mali_osk_free( allocation ); + + return; +} + +_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) +{ + mali_physical_memory_allocator external_memory_allocator; + struct mali_session_data *session_data; + u32 info[2]; + mali_memory_allocation * descriptor; + int md; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + external_memory_allocator.allocate = external_memory_commit; + external_memory_allocator.allocate_page_table_block = NULL; + external_memory_allocator.ctx = &info[0]; + external_memory_allocator.name = "External Memory"; + external_memory_allocator.next = NULL; + + /* check arguments */ + /* NULL might be a valid Mali address */ + if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + /* size must be a multiple of the system page size */ + if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + MALI_DEBUG_PRINT(3, + ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n", + (void*)args->phys_addr, + (void*)(args->phys_addr + args->size -1), + (void*)args->mali_address) + ); + + /* Validate the mali physical range */ + if (_MALI_OSK_ERR_OK != mali_mem_validation_check(args->phys_addr, args->size)) + { + return _MALI_OSK_ERR_FAULT; + } + + info[0] = args->phys_addr; + info[1] = args->size; + + descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); + if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + descriptor->size = args->size; + descriptor->mapping = NULL; + descriptor->mali_address = args->mali_address; + descriptor->mali_addr_mapping_info = (void*)session_data; + descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ + descriptor->lock = session_data->memory_lock; + if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) + { + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; + } + _mali_osk_list_init( &descriptor->list ); + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) + { + mali_allocation_engine_release_memory(memory_engine, descriptor); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + args->cookie = md; + + MALI_DEBUG_PRINT(5,("Returning from range_map_external_memory\n")); + + /* All OK */ + MALI_SUCCESS; +} + + +_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) +{ + mali_memory_allocation * descriptor; + void* old_value; + struct mali_session_data *session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) + { + MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + old_value = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); + + if (NULL != old_value) + { + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + _mali_osk_free(descriptor); + } + + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */ + args->mali_address_base = 1 * 1024 * 1024 * 1024UL; /* staring at 1GB, causing this layout: (0-1GB unused)(1GB-3G usage by Mali)(3G-4G unused) */ + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_SUCCESS; +} + +static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor) +{ + struct mali_session_data *session_data; + u32 actual_size; + + MALI_DEBUG_ASSERT_POINTER(descriptor); + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + + actual_size = descriptor->size; + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + actual_size += _MALI_OSK_MALI_PAGE_SIZE; + } + + return mali_mmu_pagedir_map(session_data->page_directory, descriptor->mali_address, actual_size); +} + +static void mali_address_manager_release(mali_memory_allocation * descriptor) +{ + const u32 illegal_mali_address = 0xffffffff; + struct mali_session_data *session_data; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /* It is allowed to call this function several times on the same descriptor. + When memory is released we set the illegal_mali_address so we can early out here. */ + if ( illegal_mali_address == descriptor->mali_address) return; + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + mali_mmu_pagedir_unmap(session_data->page_directory, descriptor->mali_address, descriptor->size); + + descriptor->mali_address = illegal_mali_address ; +} + +static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size) +{ + struct mali_session_data *session_data; + u32 mali_address; + + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(phys_addr); + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + MALI_DEBUG_ASSERT_POINTER(session_data); + + mali_address = descriptor->mali_address + offset; + + MALI_DEBUG_PRINT(7, ("Mali map: mapping 0x%08X to Mali address 0x%08X length 0x%08X\n", *phys_addr, mali_address, size)); + + mali_mmu_pagedir_update(session_data->page_directory, mali_address, *phys_addr, size); + + MALI_SUCCESS; +} + +/* This handler registered to mali_mmap for MMU builds */ +_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) +{ + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + + /* validate input */ + if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } + + /* Unpack arguments */ + session_data = (struct mali_session_data *)args->ctx; + + /* validate input */ + if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } + + descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); + if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } + + descriptor->size = args->size; + descriptor->mali_address = args->phys_addr; + descriptor->mali_addr_mapping_info = (void*)session_data; + + descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; + descriptor->lock = session_data->memory_lock; + _mali_osk_list_init( &descriptor->list ); + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (0 == mali_allocation_engine_allocate_memory(memory_engine, descriptor, physical_memory_allocators, &session_data->memory_head)) + { + /* We do not FLUSH nor TLB_ZAP on MMAP, since we do both of those on job start*/ + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + args->mapping = descriptor->mapping; + args->cookie = (u32)descriptor; + + MALI_DEBUG_PRINT(7, ("MMAP OK\n")); + MALI_SUCCESS; + } + else + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + /* OOM, but not a fatal error */ + MALI_DEBUG_PRINT(4, ("Memory allocation failure, OOM\n")); + _mali_osk_free(descriptor); + /* Linux will free the CPU address allocation, userspace client the Mali address allocation */ + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } +} + +static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ) +{ + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + + u32 num_groups = mali_group_get_glob_num_groups(); + struct mali_group *group; + u32 i; + + descriptor = (mali_memory_allocation *)args->cookie; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /** @note args->context unused; we use the memory_session from the cookie */ + /* args->mapping and args->size are also discarded. They are only necessary + for certain do_munmap implementations. However, they could be used to check the + descriptor at this point. */ + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + MALI_DEBUG_ASSERT_POINTER(session_data); + + /* Unmapping the memory from the mali virtual address space. + It is allowed to call this function severeal times, which might happen if zapping below fails. */ + mali_allocation_engine_release_pt1_mali_pagetables_unmap(memory_engine, descriptor); + +#ifdef MALI_UNMAP_FLUSH_ALL_MALI_L2 + { + u32 number_of_clusters = mali_cluster_get_glob_num_clusters(); + for (i = 0; i < number_of_clusters; i++) + { + struct mali_cluster *cluster; + cluster = mali_cluster_get_global_cluster(i); + if( mali_cluster_power_is_enabled_get(cluster) ) + { + mali_cluster_l2_cache_invalidate_all_force(cluster); + } + } + } +#endif + + for (i = 0; i < num_groups; i++) + { + group = mali_group_get_glob_group(i); + mali_group_lock(group); + mali_group_remove_session_if_unused(group, session_data); + if (mali_group_get_session(group) == session_data) + { + /* The Zap also does the stall and disable_stall */ + mali_bool zap_success = mali_mmu_zap_tlb(mali_group_get_mmu(group)); + if (MALI_TRUE != zap_success) + { + MALI_DEBUG_PRINT(2, ("Mali memory unmap failed. Doing pagefault handling.\n")); + mali_group_bottom_half(group, GROUP_EVENT_MMU_PAGE_FAULT); + /* The bottom half will also do the unlock */ + continue; + } + } + mali_group_unlock(group); + } + + /* Removes the descriptor from the session's memory list, releases physical memory, releases descriptor */ + mali_allocation_engine_release_pt2_physical_memory_free(memory_engine, descriptor); + + _mali_osk_free(descriptor); + + return _MALI_OSK_ERR_OK; +} + +/* Handler for unmapping memory for MMU builds */ +_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) +{ + mali_memory_allocation * descriptor; + _mali_osk_lock_t *descriptor_lock; + _mali_osk_errcode_t err; + + descriptor = (mali_memory_allocation *)args->cookie; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /** @note args->context unused; we use the memory_session from the cookie */ + /* args->mapping and args->size are also discarded. They are only necessary + for certain do_munmap implementations. However, they could be used to check the + descriptor at this point. */ + + MALI_DEBUG_ASSERT_POINTER((struct mali_session_data *)descriptor->mali_addr_mapping_info); + + descriptor_lock = descriptor->lock; /* should point to the session data lock... */ + + err = _MALI_OSK_ERR_BUSY; + while (err == _MALI_OSK_ERR_BUSY) + { + if (descriptor_lock) + { + _mali_osk_lock_wait( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); + } + + err = _mali_ukk_mem_munmap_internal( args ); + + if (descriptor_lock) + { + _mali_osk_lock_signal( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); + } + + if (err == _MALI_OSK_ERR_BUSY) + { + /* + * Reason for this; + * We where unable to stall the MMU, probably because we are in page fault handling. + * Sleep for a while with the session lock released, then try again. + * Abnormal termination of programs with running Mali jobs is a normal reason for this. + */ + _mali_osk_time_ubusydelay(10); + } + } + + return err; +} + +u32 _mali_ukk_report_memory_usage(void) +{ + return mali_allocation_engine_memory_usage(physical_memory_allocators); +} + +_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping) +{ + _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + if (0 == _mali_osk_list_empty(&page_table_cache.partial)) + { + mali_mmu_page_table_allocation * alloc = _MALI_OSK_LIST_ENTRY(page_table_cache.partial.next, mali_mmu_page_table_allocation, list); + int page_number = _mali_osk_find_first_zero_bit(alloc->usage_map, alloc->num_pages); + MALI_DEBUG_PRINT(6, ("Partial page table allocation found, using page offset %d\n", page_number)); + _mali_osk_set_nonatomic_bit(page_number, alloc->usage_map); + alloc->usage_count++; + if (alloc->num_pages == alloc->usage_count) + { + /* full, move alloc to full list*/ + _mali_osk_list_move(&alloc->list, &page_table_cache.full); + } + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + *table_page = (MALI_MMU_PAGE_SIZE * page_number) + alloc->pages.phys_base; + *mapping = (mali_io_address)((MALI_MMU_PAGE_SIZE * page_number) + (u32)alloc->pages.mapping); + MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); + MALI_SUCCESS; + } + else + { + mali_mmu_page_table_allocation * alloc; + /* no free pages, allocate a new one */ + + alloc = (mali_mmu_page_table_allocation *)_mali_osk_calloc(1, sizeof(mali_mmu_page_table_allocation)); + if (NULL == alloc) + { + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _MALI_OSK_INIT_LIST_HEAD(&alloc->list); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_page_tables(memory_engine, &alloc->pages, physical_memory_allocators)) + { + MALI_DEBUG_PRINT(1, ("No more memory for page tables\n")); + _mali_osk_free(alloc); + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + *mapping = NULL; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + /* create the usage map */ + alloc->num_pages = alloc->pages.size / MALI_MMU_PAGE_SIZE; + alloc->usage_count = 1; + MALI_DEBUG_PRINT(3, ("New page table cache expansion, %d pages in new cache allocation\n", alloc->num_pages)); + alloc->usage_map = _mali_osk_calloc(1, ((alloc->num_pages + BITS_PER_LONG - 1) & ~(BITS_PER_LONG-1) / BITS_PER_LONG) * sizeof(unsigned long)); + if (NULL == alloc->usage_map) + { + MALI_DEBUG_PRINT(1, ("Failed to allocate memory to describe MMU page table cache usage\n")); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc); + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + *mapping = NULL; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_set_nonatomic_bit(0, alloc->usage_map); + + if (alloc->num_pages > 1) + { + _mali_osk_list_add(&alloc->list, &page_table_cache.partial); + } + else + { + _mali_osk_list_add(&alloc->list, &page_table_cache.full); + } + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = alloc->pages.phys_base; /* return the first page */ + *mapping = alloc->pages.mapping; /* Mapping for first page */ + MALI_DEBUG_PRINT(4, ("Page table allocated: VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); + MALI_SUCCESS; + } +} + +void mali_mmu_release_table_page(u32 pa) +{ + mali_mmu_page_table_allocation * alloc, * temp_alloc; + + MALI_DEBUG_PRINT_IF(1, pa & 4095, ("Bad page address 0x%x given to mali_mmu_release_table_page\n", (void*)pa)); + + MALI_DEBUG_PRINT(4, ("Releasing table page 0x%08X to the cache\n", pa)); + + _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + /* find the entry this address belongs to */ + /* first check the partial list */ + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.partial, mali_mmu_page_table_allocation, list) + { + u32 start = alloc->pages.phys_base; + u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; + if (pa >= start && pa <= last) + { + MALI_DEBUG_ASSERT(0 != _mali_osk_test_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map)); + _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); + alloc->usage_count--; + + _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); + + if (0 == alloc->usage_count) + { + /* empty, release whole page alloc */ + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(4, ("(partial list)Released table page 0x%08X to the cache\n", pa)); + return; + } + } + + /* the check the full list */ + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.full, mali_mmu_page_table_allocation, list) + { + u32 start = alloc->pages.phys_base; + u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; + if (pa >= start && pa <= last) + { + _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); + alloc->usage_count--; + + _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); + + + if (0 == alloc->usage_count) + { + /* empty, release whole page alloc */ + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + else + { + /* transfer to partial list */ + _mali_osk_list_move(&alloc->list, &page_table_cache.partial); + } + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(4, ("(full list)Released table page 0x%08X to the cache\n", pa)); + return; + } + } + + MALI_DEBUG_PRINT(1, ("pa 0x%x not found in the page table cache\n", (void*)pa)); + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); +} + +static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void) +{ + page_table_cache.lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE); + MALI_CHECK_NON_NULL( page_table_cache.lock, _MALI_OSK_ERR_FAULT ); + _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.partial); + _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.full); + MALI_SUCCESS; +} + +static void mali_mmu_page_table_cache_destroy(void) +{ + mali_mmu_page_table_allocation * alloc, *temp; + + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.partial, mali_mmu_page_table_allocation, list) + { + MALI_DEBUG_PRINT_IF(1, 0 != alloc->usage_count, ("Destroying page table cache while pages are tagged as in use. %d allocations still marked as in use.\n", alloc->usage_count)); + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + + MALI_DEBUG_PRINT_IF(1, 0 == _mali_osk_list_empty(&page_table_cache.full), ("Page table cache full list contains one or more elements \n")); + + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.full, mali_mmu_page_table_allocation, list) + { + MALI_DEBUG_PRINT(1, ("Destroy alloc 0x%08X with usage count %d\n", (u32)alloc, alloc->usage_count)); + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + + _mali_osk_lock_term(page_table_cache.lock); +} diff --git a/drivers/media/video/samsung/mali/common/mali_memory.h b/drivers/media/video/samsung/mali/common/mali_memory.h new file mode 100644 index 0000000..53a994c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_memory.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __MALI_MEMORY_H__ +#define __MALI_MEMORY_H__ + +#include "mali_osk.h" +#include "mali_session.h" + +struct mali_cluster; +struct mali_group; + +/** @brief Initialize Mali memory subsystem + * + * Allocate and initialize internal data structures. Must be called before + * allocating Mali memory. + * + * @return On success _MALI_OSK_ERR_OK, othervise some error code describing the error. + */ +_mali_osk_errcode_t mali_memory_initialize(void); + +/** @brief Terminate Mali memory system + * + * Clean up and release internal data structures. + */ +void mali_memory_terminate(void); + +/** @brief Start new Mali memory session + * + * Allocate and prepare session specific memory allocation data data. The + * session page directory, lock, and descriptor map is set up. + * + * @param mali_session_data pointer to the session data structure + */ +_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data *mali_session_data); + +/** @brief Close a Mali memory session + * + * Release session specific memory allocation related data. + * + * @param mali_session_data pointer to the session data structure + */ +void mali_memory_session_end(struct mali_session_data *mali_session_data); + +/** @brief Allocate a page table page + * + * Allocate a page for use as a page directory or page table. The page is + * mapped into kernel space. + * + * @return _MALI_OSK_ERR_OK on success, othervise an error code + * @param table_page GPU pointer to the allocated page + * @param mapping CPU pointer to the mapping of the allocated page + */ +_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping); + +/** @brief Release a page table page + * + * Release a page table page allocated through \a mali_mmu_get_table_page + * + * @param pa the GPU address of the page to release + */ +void mali_mmu_release_table_page(u32 pa); + + +/** @brief Parse resource and prepare the OS memory allocator + */ +_mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource); + +/** @brief Parse resource and prepare the dedicated memory allocator + */ +_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource); + +#endif /* __MALI_MEMORY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mmu.c b/drivers/media/video/samsung/mali/common/mali_mmu.c new file mode 100644 index 0000000..2f2fa4d --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu.c @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2010-2012 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_osk.h" +#include "mali_osk_bitops.h" +#include "mali_osk_list.h" +#include "mali_ukk.h" + +#include "mali_mmu.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_mmu_page_directory.h" + +/** + * Size of the MMU registers in bytes + */ +#define MALI_MMU_REGISTERS_SIZE 0x24 + +/** + * MMU register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_mmu_register { + MALI_MMU_REGISTER_DTE_ADDR = 0x0000, /**< Current Page Directory Pointer */ + MALI_MMU_REGISTER_STATUS = 0x0004, /**< Status of the MMU */ + MALI_MMU_REGISTER_COMMAND = 0x0008, /**< Command register, used to control the MMU */ + MALI_MMU_REGISTER_PAGE_FAULT_ADDR = 0x000C, /**< Logical address of the last page fault */ + MALI_MMU_REGISTER_ZAP_ONE_LINE = 0x010, /**< Used to invalidate the mapping of a single page from the MMU */ + MALI_MMU_REGISTER_INT_RAWSTAT = 0x0014, /**< Raw interrupt status, all interrupts visible */ + MALI_MMU_REGISTER_INT_CLEAR = 0x0018, /**< Indicate to the MMU that the interrupt has been received */ + MALI_MMU_REGISTER_INT_MASK = 0x001C, /**< Enable/disable types of interrupts */ + MALI_MMU_REGISTER_INT_STATUS = 0x0020 /**< Interrupt status based on the mask */ +} mali_mmu_register; + +/** + * MMU interrupt register bits + * Each cause of the interrupt is reported + * through the (raw) interrupt status registers. + * Multiple interrupts can be pending, so multiple bits + * can be set at once. + */ +typedef enum mali_mmu_interrupt +{ + MALI_MMU_INTERRUPT_PAGE_FAULT = 0x01, /**< A page fault occured */ + MALI_MMU_INTERRUPT_READ_BUS_ERROR = 0x02 /**< A bus read error occured */ +} mali_mmu_interrupt; + +/** + * MMU commands + * These are the commands that can be sent + * to the MMU unit. + */ +typedef enum mali_mmu_command +{ + MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */ + MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */ + MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**< Enable stall on page fault */ + MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */ + MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */ + MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */ + MALI_MMU_COMMAND_HARD_RESET = 0x06 /**< Reset the MMU back to power-on settings */ +} mali_mmu_command; + +typedef enum mali_mmu_status_bits +{ + MALI_MMU_STATUS_BIT_PAGING_ENABLED = 1 << 0, + MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE = 1 << 1, + MALI_MMU_STATUS_BIT_STALL_ACTIVE = 1 << 2, + MALI_MMU_STATUS_BIT_IDLE = 1 << 3, + MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY = 1 << 4, + MALI_MMU_STATUS_BIT_PAGE_FAULT_IS_WRITE = 1 << 5, +} mali_mmu_status_bits; + +/** + * Definition of the MMU struct + * Used to track a MMU unit in the system. + * Contains information about the mapping of the registers + */ +struct mali_mmu_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent core group */ + _mali_osk_irq_t *irq; /**< IRQ handler */ +}; + +/** + * The MMU interrupt handler + * Upper half of the MMU interrupt processing. + * Called by the kernel when the MMU has triggered an interrupt. + * The interrupt function supports IRQ sharing. So it'll probe the MMU in question + * @param irq The irq number (not used) + * @param dev_id Points to the MMU object being handled + * @param regs Registers of interrupted process (not used) + * @return Standard Linux interrupt result. + * Subset used by the driver is IRQ_HANDLED processed + * IRQ_NONE Not processed + */ +static _mali_osk_errcode_t mali_mmu_upper_half(void * data); + +/** + * The MMU reset hander + * Bottom half of the MMU interrupt processing for page faults and bus errors + * @param work The item to operate on, NULL in our case + */ +static void mali_mmu_bottom_half(void *data); + +static void mali_mmu_probe_trigger(void *data); +static _mali_osk_errcode_t mali_mmu_probe_ack(void *data); + +MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu); + +/* page fault queue flush helper pages + * note that the mapping pointers are currently unused outside of the initialization functions */ +static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; +static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE; +static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE; + +/* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */ +static u32 mali_empty_page_directory = MALI_INVALID_PAGE; + +_mali_osk_errcode_t mali_mmu_initialize(void) +{ + /* allocate the helper pages */ + mali_empty_page_directory = mali_allocate_empty_page(); + if(0 == mali_empty_page_directory) + { + mali_empty_page_directory = MALI_INVALID_PAGE; + return _MALI_OSK_ERR_NOMEM; + } + + if (_MALI_OSK_ERR_OK != mali_create_fault_flush_pages(&mali_page_fault_flush_page_directory, + &mali_page_fault_flush_page_table, &mali_page_fault_flush_data_page)) + { + mali_free_empty_page(mali_empty_page_directory); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +void mali_mmu_terminate(void) +{ + MALI_DEBUG_PRINT(3, ("Mali MMU: terminating\n")); + + /* Free global helper pages */ + mali_free_empty_page(mali_empty_page_directory); + + /* Free the page fault flush pages */ + mali_destroy_fault_flush_pages(&mali_page_fault_flush_page_directory, + &mali_page_fault_flush_page_table, &mali_page_fault_flush_data_page); +} + +struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource) +{ + struct mali_mmu_core* mmu = NULL; + + MALI_DEBUG_ASSERT_POINTER(resource); + + MALI_DEBUG_PRINT(2, ("Mali MMU: Creating Mali MMU: %s\n", resource->description)); + + mmu = _mali_osk_calloc(1,sizeof(struct mali_mmu_core)); + if (NULL != mmu) + { + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&mmu->hw_core, resource, MALI_MMU_REGISTERS_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_mmu_reset(mmu)) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + mmu->irq = _mali_osk_irq_init(resource->irq, + mali_mmu_upper_half, + mali_mmu_bottom_half, + mali_mmu_probe_trigger, + mali_mmu_probe_ack, + mmu, + "mali_mmu_irq_handlers"); + if (NULL != mmu->irq) + { + return mmu; + } + else + { + MALI_PRINT_ERROR(("Failed to setup interrupt handlers for MMU %s\n", mmu->hw_core.description)); + } + } + mali_hw_core_delete(&mmu->hw_core); + } + + _mali_osk_free(mmu); + } + else + { + MALI_PRINT_ERROR(("Failed to allocate memory for MMU\n")); + } + + return NULL; +} + +void mali_mmu_delete(struct mali_mmu_core *mmu) +{ + _mali_osk_irq_term(mmu->irq); + mali_hw_core_delete(&mmu->hw_core); + _mali_osk_free(mmu); +} + +void mali_mmu_set_group(struct mali_mmu_core *mmu, struct mali_group *group) +{ + mmu->group = group; +} + +static void mali_mmu_enable_paging(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING); + + for (i = 0; i < max_loop_count; ++i) + { + if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Enable paging request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + } +} + +mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 999; + int i; + u32 mmu_status; + + /* There are no group when it is called from mali_mmu_create */ + if ( mmu->group ) MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED) ) + { + MALI_DEBUG_PRINT(4, ("MMU stall is implicit when Paging is not enebled.\n")); + return MALI_TRUE; + } + + if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it is in pagefault state.\n")); + return MALI_FALSE; + } + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL); + + for (i = 0; i < max_loop_count; ++i) + { + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + if ( mmu_status & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) + { + break; + } + if ( 0 == (mmu_status & ( MALI_MMU_STATUS_BIT_PAGING_ENABLED ))) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Enable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + return MALI_FALSE; + } + + if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it has a pagefault.\n")); + return MALI_FALSE; + } + + return MALI_TRUE; +} + +void mali_mmu_disable_stall(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + u32 mmu_status; + /* There are no group when it is called from mali_mmu_create */ + if ( mmu->group ) MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) + { + MALI_DEBUG_PRINT(3, ("MMU disable skipped since it was not enabled.\n")); + return; + } + if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) + { + MALI_DEBUG_PRINT(2, ("Aborting MMU disable stall request since it is in pagefault state.\n")); + return; + } + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL); + + for (i = 0; i < max_loop_count; ++i) + { + u32 status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + if ( 0 == (status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) ) + { + break; + } + if ( status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + break; + } + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) MALI_DEBUG_PRINT(1,("Disable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); +} + +void mali_mmu_page_fault_done(struct mali_mmu_core *mmu) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + MALI_DEBUG_PRINT(4, ("Mali MMU: %s: Leaving page fault mode\n", mmu->hw_core.description)); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE); +} + +MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + /* The _if_ is neccessary when called from mali_mmu_create and NULL==group */ + if (mmu->group)MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_HARD_RESET); + + for (i = 0; i < max_loop_count; ++i) + { + if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR) == 0) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Reset request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + /* The _if_ is neccessary when called from mali_mmu_create and NULL==group */ + if (mmu->group) + { + MALI_ASSERT_GROUP_LOCKED(mmu->group); + } + + stall_success = mali_mmu_enable_stall(mmu); + + /* The stall can not fail in current hw-state */ + MALI_DEBUG_ASSERT(stall_success); + + MALI_DEBUG_PRINT(3, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->hw_core.description)); + + if (_MALI_OSK_ERR_OK == mali_mmu_raw_reset(mmu)) + { + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); + /* no session is active, so just activate the empty page directory */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); + mali_mmu_enable_paging(mmu); + err = _MALI_OSK_ERR_OK; + } + mali_mmu_disable_stall(mmu); + + return err; +} + + +/* ------------- interrupt handling below ------------------ */ + +static _mali_osk_errcode_t mali_mmu_upper_half(void * data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + u32 int_stat; + + MALI_DEBUG_ASSERT_POINTER(mmu); + + /* Check if it was our device which caused the interrupt (we could be sharing the IRQ line) */ + int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); + if (0 != int_stat) + { + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, 0); + mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) + { + _mali_osk_irq_schedulework(mmu->irq); + } + + if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) + { + /* clear interrupt flag */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); + /* reenable it */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, + mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK) | MALI_MMU_INTERRUPT_READ_BUS_ERROR); + MALI_PRINT_ERROR(("Mali MMU: Read bus error\n")); + } + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_mmu_bottom_half(void * data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core*)data; + u32 raw, status, fault_address; + + MALI_DEBUG_ASSERT_POINTER(mmu); + + MALI_DEBUG_PRINT(3, ("Mali MMU: Page fault bottom half: Locking subsystems\n")); + + mali_group_lock(mmu->group); /* Unlocked in mali_group_bottom_half */ + + if ( MALI_FALSE == mali_group_power_is_on(mmu->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.",mmu->hw_core.description)); + mali_group_unlock(mmu->group); + return; + } + + raw = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT); + status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( (0==(raw & MALI_MMU_INTERRUPT_PAGE_FAULT)) && (0==(status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) ) + { + MALI_DEBUG_PRINT(2, ("Mali MMU: Page fault bottom half: No Irq found.\n")); + mali_group_unlock(mmu->group); + /* MALI_DEBUG_ASSERT(0); */ + return; + } + + /* An actual page fault has occurred. */ + + fault_address = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_PAGE_FAULT_ADDR); + + MALI_DEBUG_PRINT(2,("Mali MMU: Page fault detected at 0x%x from bus id %d of type %s on %s\n", + (void*)fault_address, + (status >> 6) & 0x1F, + (status & 32) ? "write" : "read", + mmu->hw_core.description)); + + mali_group_bottom_half(mmu->group, GROUP_EVENT_MMU_PAGE_FAULT); /* Unlocks the group lock */ +} + +mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu) +{ + mali_bool stall_success; + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + stall_success = mali_mmu_enable_stall(mmu); + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); + + if (MALI_FALSE == stall_success) + { + /* False means that it is in Pagefault state. Not possible to disable_stall then */ + return MALI_FALSE; + } + + mali_mmu_disable_stall(mmu); + return MALI_TRUE; +} + +void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); +} + + +void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_ZAP_ONE_LINE, MALI_MMU_PDE_ENTRY(mali_address)); +} + +static void mali_mmu_activate_address_space(struct mali_mmu_core *mmu, u32 page_directory) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + /* The MMU must be in stalled or page fault mode, for this writing to work */ + MALI_DEBUG_ASSERT( 0 != ( mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) + & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) ); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, page_directory); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); + +} + +mali_bool mali_mmu_activate_page_directory(struct mali_mmu_core *mmu, struct mali_page_directory *pagedir) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + MALI_DEBUG_PRINT(5, ("Asked to activate page directory 0x%x on MMU %s\n", pagedir, mmu->hw_core.description)); + stall_success = mali_mmu_enable_stall(mmu); + + if ( MALI_FALSE==stall_success ) return MALI_FALSE; + mali_mmu_activate_address_space(mmu, pagedir->page_directory); + mali_mmu_disable_stall(mmu); + return MALI_TRUE; +} + +void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + MALI_DEBUG_PRINT(3, ("Activating the empty page directory on MMU %s\n", mmu->hw_core.description)); + + stall_success = mali_mmu_enable_stall(mmu); + /* This function can only be called when the core is idle, so it could not fail. */ + MALI_DEBUG_ASSERT( stall_success ); + mali_mmu_activate_address_space(mmu, mali_empty_page_directory); + mali_mmu_disable_stall(mmu); +} + +void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + MALI_DEBUG_PRINT(3, ("Activating the page fault flush page directory on MMU %s\n", mmu->hw_core.description)); + stall_success = mali_mmu_enable_stall(mmu); + /* This function is expect to fail the stalling, since it might be in PageFault mode when it is called */ + mali_mmu_activate_address_space(mmu, mali_page_fault_flush_page_directory); + if ( MALI_TRUE==stall_success ) mali_mmu_disable_stall(mmu); +} + +/* Is called when we want the mmu to give an interrupt */ +static void mali_mmu_probe_trigger(void *data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR); +} + +/* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */ +static _mali_osk_errcode_t mali_mmu_probe_ack(void *data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + u32 int_stat; + + int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); + + MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat)); + if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) + { + MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n")); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); + } + else + { + MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n")); + } + + if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) + { + MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n")); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); + } + else + { + MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n")); + } + + if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) == + (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) + { + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +#if 0 +void mali_mmu_print_state(struct mali_mmu_core *mmu) +{ + MALI_DEBUG_PRINT(2, ("MMU: State of %s is 0x%08x\n", mmu->hw_core.description, mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_mmu.h b/drivers/media/video/samsung/mali/common/mali_mmu.h new file mode 100644 index 0000000..c7274b8 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +#ifndef __MALI_MMU_H__ +#define __MALI_MMU_H__ + +#include "mali_osk.h" +#include "mali_mmu_page_directory.h" + +/* Forward declaration from mali_group.h */ +struct mali_group; + +struct mali_mmu_core; + +_mali_osk_errcode_t mali_mmu_initialize(void); + +void mali_mmu_terminate(void); + +struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource); +void mali_mmu_set_group(struct mali_mmu_core *mmu, struct mali_group *group); +void mali_mmu_delete(struct mali_mmu_core *mmu); + +_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu); +mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu); +void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu); +void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address); + +mali_bool mali_mmu_activate_page_directory(struct mali_mmu_core* mmu, struct mali_page_directory *pagedir); +void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu); +void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu); + +/** + * Issues the enable stall command to the MMU and waits for HW to complete the request + * @param mmu The MMU to enable paging for + * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out) + */ +mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu); + +/** + * Issues the disable stall command to the MMU and waits for HW to complete the request + * @param mmu The MMU to enable paging for + */ +void mali_mmu_disable_stall(struct mali_mmu_core *mmu); + +void mali_mmu_page_fault_done(struct mali_mmu_core *mmu); + + +#endif /* __MALI_MMU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c new file mode 100644 index 0000000..43a4cf4 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2011-2012 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_kernel_core.h" +#include "mali_osk.h" +#include "mali_uk_types.h" +#include "mali_mmu_page_directory.h" +#include "mali_memory.h" + +#include "mali_cluster.h" +#include "mali_group.h" + +static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data); + +u32 mali_allocate_empty_page(void) +{ + _mali_osk_errcode_t err; + mali_io_address mapping; + u32 address; + + if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&address, &mapping)) + { + /* Allocation failed */ + return 0; + } + + MALI_DEBUG_ASSERT_POINTER( mapping ); + + err = fill_page(mapping, 0); + if (_MALI_OSK_ERR_OK != err) + { + mali_mmu_release_table_page(address); + } + return address; +} + +void mali_free_empty_page(u32 address) +{ + if (MALI_INVALID_PAGE != address) + { + mali_mmu_release_table_page(address); + } +} + +_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page) +{ + _mali_osk_errcode_t err; + mali_io_address page_directory_mapping; + mali_io_address page_table_mapping; + mali_io_address data_page_mapping; + + err = mali_mmu_get_table_page(data_page, &data_page_mapping); + if (_MALI_OSK_ERR_OK == err) + { + err = mali_mmu_get_table_page(page_table, &page_table_mapping); + if (_MALI_OSK_ERR_OK == err) + { + err = mali_mmu_get_table_page(page_directory, &page_directory_mapping); + if (_MALI_OSK_ERR_OK == err) + { + fill_page(data_page_mapping, 0); + fill_page(page_table_mapping, *data_page | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); + fill_page(page_directory_mapping, *page_table | MALI_MMU_FLAGS_PRESENT); + MALI_SUCCESS; + } + mali_mmu_release_table_page(*page_table); + *page_table = MALI_INVALID_PAGE; + } + mali_mmu_release_table_page(*data_page); + *data_page = MALI_INVALID_PAGE; + } + return err; +} + +void mali_destroy_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page) +{ + if (MALI_INVALID_PAGE != *page_directory) + { + mali_mmu_release_table_page(*page_directory); + *page_directory = MALI_INVALID_PAGE; + } + + if (MALI_INVALID_PAGE != *page_table) + { + mali_mmu_release_table_page(*page_table); + *page_table = MALI_INVALID_PAGE; + } + + if (MALI_INVALID_PAGE != *data_page) + { + mali_mmu_release_table_page(*data_page); + *data_page = MALI_INVALID_PAGE; + } +} + +static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data) +{ + int i; + MALI_DEBUG_ASSERT_POINTER( mapping ); + + for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) + { + _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data); + } + _mali_osk_mem_barrier(); + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size) +{ + const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); + const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); + _mali_osk_errcode_t err; + mali_io_address pde_mapping; + u32 pde_phys; + int i; + + for(i = first_pde; i <= last_pde; i++) + { + if(0 == (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & MALI_MMU_FLAGS_PRESENT)) + { + /* Page table not present */ + MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); + MALI_DEBUG_ASSERT(NULL == pagedir->page_entries_mapped[i]); + + err = mali_mmu_get_table_page(&pde_phys, &pde_mapping); + if(_MALI_OSK_ERR_OK != err) + { + MALI_PRINT_ERROR(("Failed to allocate page table page.\n")); + return err; + } + pagedir->page_entries_mapped[i] = pde_mapping; + + /* Update PDE, mark as present */ + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), + pde_phys | MALI_MMU_FLAGS_PRESENT); + + MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); + pagedir->page_entries_usage_count[i] = 1; + } + else + { + pagedir->page_entries_usage_count[i]++; + } + } + _mali_osk_write_mem_barrier(); + + MALI_SUCCESS; +} + +MALI_STATIC_INLINE void mali_mmu_zero_pte(mali_io_address page_table, u32 mali_address, u32 size) +{ + int i; + const int first_pte = MALI_MMU_PTE_ENTRY(mali_address); + const int last_pte = MALI_MMU_PTE_ENTRY(mali_address + size - 1); + + for (i = first_pte; i <= last_pte; i++) + { + _mali_osk_mem_iowrite32_relaxed(page_table, i * sizeof(u32), 0); + } +} + +_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size) +{ + const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); + const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); + u32 left = size; + int i; +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + mali_bool pd_changed = MALI_FALSE; + u32 pages_to_invalidate[3]; /* hard-coded to 3: max two pages from the PT level plus max one page from PD level */ + u32 num_pages_inv = 0; +#endif + + /* For all page directory entries in range. */ + for (i = first_pde; i <= last_pde; i++) + { + u32 size_in_pde, offset; + + MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[i]); + MALI_DEBUG_ASSERT(0 != pagedir->page_entries_usage_count[i]); + + /* Offset into page table, 0 if mali_address is 4MiB aligned */ + offset = (mali_address & (MALI_MMU_VIRTUAL_PAGE_SIZE - 1)); + if (left < MALI_MMU_VIRTUAL_PAGE_SIZE - offset) + { + size_in_pde = left; + } + else + { + size_in_pde = MALI_MMU_VIRTUAL_PAGE_SIZE - offset; + } + + pagedir->page_entries_usage_count[i]--; + + /* If entire page table is unused, free it */ + if (0 == pagedir->page_entries_usage_count[i]) + { + u32 page_address; + MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n")); + /* last reference removed, no need to zero out each PTE */ + + page_address = MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32))); + pagedir->page_entries_mapped[i] = NULL; + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), 0); + + mali_mmu_release_table_page(page_address); +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + pd_changed = MALI_TRUE; +#endif + } + else + { +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + pages_to_invalidate[num_pages_inv] = mali_page_directory_get_phys_address(pagedir, i); + num_pages_inv++; + MALI_DEBUG_ASSERT(num_pages_inv<3); +#endif + + /* If part of the page table is still in use, zero the relevant PTEs */ + mali_mmu_zero_pte(pagedir->page_entries_mapped[i], mali_address, size_in_pde); + } + + left -= size_in_pde; + mali_address += size_in_pde; + } + _mali_osk_write_mem_barrier(); + +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + /* L2 pages invalidation */ + if (MALI_TRUE == pd_changed) + { + pages_to_invalidate[num_pages_inv] = pagedir->page_directory; + num_pages_inv++; + MALI_DEBUG_ASSERT(num_pages_inv<3); + } + + if (_MALI_PRODUCT_ID_MALI200 != mali_kernel_core_get_product_id()) + { + mali_cluster_invalidate_pages(pages_to_invalidate, num_pages_inv); + } +#endif + + MALI_SUCCESS; +} + +struct mali_page_directory *mali_mmu_pagedir_alloc(void) +{ + struct mali_page_directory *pagedir; + + pagedir = _mali_osk_calloc(1, sizeof(struct mali_page_directory)); + if(NULL == pagedir) + { + return NULL; + } + + if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&pagedir->page_directory, &pagedir->page_directory_mapped)) + { + _mali_osk_free(pagedir); + return NULL; + } + + /* Zero page directory */ + fill_page(pagedir->page_directory_mapped, 0); + + return pagedir; +} + +void mali_mmu_pagedir_free(struct mali_page_directory *pagedir) +{ + const int num_page_table_entries = sizeof(pagedir->page_entries_mapped) / sizeof(pagedir->page_entries_mapped[0]); + int i; + + /* Free referenced page tables and zero PDEs. */ + for (i = 0; i < num_page_table_entries; i++) + { + if (pagedir->page_directory_mapped && (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT)) + { + mali_mmu_release_table_page( _mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i * sizeof(u32), 0); + } + } + _mali_osk_write_mem_barrier(); + + /* Free the page directory page. */ + mali_mmu_release_table_page(pagedir->page_directory); + + _mali_osk_free(pagedir); +} + + +void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size) +{ + u32 end_address = mali_address + size; + + /* Map physical pages into MMU page tables */ + for ( ; mali_address < end_address; mali_address += MALI_MMU_PAGE_SIZE, phys_address += MALI_MMU_PAGE_SIZE) + { + MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]); + _mali_osk_mem_iowrite32_relaxed(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)], + MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32), + phys_address | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); + } + _mali_osk_write_mem_barrier(); +} + +u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index) +{ + return (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, index*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); +} + +/* For instrumented */ +struct dump_info +{ + u32 buffer_left; + u32 register_writes_size; + u32 page_table_dump_size; + u32 *buffer; +}; + +static _mali_osk_errcode_t writereg(u32 where, u32 what, const char *comment, struct dump_info *info) +{ + if (NULL != info) + { + info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */ + + if (NULL != info->buffer) + { + /* check that we have enough space */ + if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + *info->buffer = where; + info->buffer++; + + *info->buffer = what; + info->buffer++; + + info->buffer_left -= sizeof(u32)*2; + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info) +{ + if (NULL != info) + { + /* 4096 for the page and 4 bytes for the address */ + const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4; + const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE; + const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4; + + info->page_table_dump_size += dump_size_in_bytes; + + if (NULL != info->buffer) + { + if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + *info->buffer = phys_addr; + info->buffer++; + + _mali_osk_memcpy(info->buffer, page, page_size_in_bytes); + info->buffer += page_size_in_elements; + + info->buffer_left -= dump_size_in_bytes; + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_mmu_page_table(struct mali_page_directory *pagedir, struct dump_info * info) +{ + MALI_DEBUG_ASSERT_POINTER(pagedir); + MALI_DEBUG_ASSERT_POINTER(info); + + if (NULL != pagedir->page_directory_mapped) + { + int i; + + MALI_CHECK_NO_ERROR( + dump_page(pagedir->page_directory_mapped, pagedir->page_directory, info) + ); + + for (i = 0; i < 1024; i++) + { + if (NULL != pagedir->page_entries_mapped[i]) + { + MALI_CHECK_NO_ERROR( + dump_page(pagedir->page_entries_mapped[i], + _mali_osk_mem_ioread32(pagedir->page_directory_mapped, + i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info) + ); + } + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_mmu_registers(struct mali_page_directory *pagedir, struct dump_info * info) +{ + MALI_CHECK_NO_ERROR(writereg(0x00000000, pagedir->page_directory, + "set the page directory address", info)); + MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info)); + MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info)); + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) +{ + struct dump_info info = { 0, 0, 0, NULL }; + struct mali_session_data * session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)(args->ctx); + + MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); + MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); + args->size = info.register_writes_size + info.page_table_dump_size; + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) +{ + struct dump_info info = { 0, 0, 0, NULL }; + struct mali_session_data * session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)(args->ctx); + + info.buffer_left = args->size; + info.buffer = args->buffer; + + args->register_writes = info.buffer; + MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); + + args->page_table_dump = info.buffer; + MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); + + args->register_writes_size = info.register_writes_size; + args->page_table_dump_size = info.page_table_dump_size; + + MALI_SUCCESS; +} diff --git a/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h new file mode 100644 index 0000000..8aababe --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_MMU_PAGE_DIRECTORY_H__ +#define __MALI_MMU_PAGE_DIRECTORY_H__ + +#include "mali_osk.h" + +/** + * Size of an MMU page in bytes + */ +#define MALI_MMU_PAGE_SIZE 0x1000 + +/* + * Size of the address space referenced by a page table page + */ +#define MALI_MMU_VIRTUAL_PAGE_SIZE 0x400000 /* 4 MiB */ + +/** + * Page directory index from address + * Calculates the page directory index from the given address + */ +#define MALI_MMU_PDE_ENTRY(address) (((address)>>22) & 0x03FF) + +/** + * Page table index from address + * Calculates the page table index from the given address + */ +#define MALI_MMU_PTE_ENTRY(address) (((address)>>12) & 0x03FF) + +/** + * Extract the memory address from an PDE/PTE entry + */ +#define MALI_MMU_ENTRY_ADDRESS(value) ((value) & 0xFFFFFC00) + +#define MALI_INVALID_PAGE ((u32)(~0)) + +/** + * + */ +typedef enum mali_mmu_entry_flags +{ + MALI_MMU_FLAGS_PRESENT = 0x01, + MALI_MMU_FLAGS_READ_PERMISSION = 0x02, + MALI_MMU_FLAGS_WRITE_PERMISSION = 0x04, + MALI_MMU_FLAGS_MASK = 0x07 +} mali_mmu_entry_flags; + + +struct mali_page_directory +{ + u32 page_directory; /**< Physical address of the memory session's page directory */ + mali_io_address page_directory_mapped; /**< Pointer to the mapped version of the page directory into the kernel's address space */ + + mali_io_address page_entries_mapped[1024]; /**< Pointers to the page tables which exists in the page directory mapped into the kernel's address space */ + u32 page_entries_usage_count[1024]; /**< Tracks usage count of the page table pages, so they can be releases on the last reference */ +}; + +/* Map Mali virtual address space (i.e. ensure page tables exist for the virtual range) */ +_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size); +_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size); + +/* Back virtual address space with actual pages. Assumes input is contiguous and 4k aligned. */ +void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size); + +u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index); + +u32 mali_allocate_empty_page(void); +void mali_free_empty_page(u32 address); +_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page); +void mali_destroy_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page); + +struct mali_page_directory *mali_mmu_pagedir_alloc(void); +void mali_mmu_pagedir_free(struct mali_page_directory *pagedir); + +#endif /* __MALI_MMU_PAGE_DIRECTORY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_osk.h b/drivers/media/video/samsung/mali/common/mali_osk.h index 72d851d..e32d15d 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk.h +++ b/drivers/media/video/samsung/mali/common/mali_osk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -165,9 +165,6 @@ typedef void (*_mali_osk_irq_bhandler_t)( void * arg ); * This is public for allocation on stack. On systems that support it, this is just a single 32-bit value. * On others, it could be encapsulating an object stored elsewhere. * - * Even though the structure has space for a u32, the counters will only - * represent signed 24-bit integers. - * * Regardless of implementation, the \ref _mali_osk_atomic functions \b must be used * for all accesses to the variable's value, even if atomicity is not required. * Do not access u.val or u.obj directly. @@ -186,6 +183,40 @@ typedef struct /** @defgroup _mali_osk_lock OSK Mutual Exclusion Locks * @{ */ + +/** @brief OSK Mutual Exclusion Lock ordered list + * + * This lists the various types of locks in the system and is used to check + * that locks are taken in the correct order. + * + * Holding more than one lock of the same order at the same time is not + * allowed. + * + */ +typedef enum +{ + _MALI_OSK_LOCK_ORDER_LAST = 0, + + _MALI_OSK_LOCK_ORDER_PM_EXECUTE, + _MALI_OSK_LOCK_ORDER_UTILIZATION, + _MALI_OSK_LOCK_ORDER_L2_COUNTER, + _MALI_OSK_LOCK_ORDER_PROFILING, + _MALI_OSK_LOCK_ORDER_L2_COMMAND, + _MALI_OSK_LOCK_ORDER_PM_CORE_STATE, + _MALI_OSK_LOCK_ORDER_GROUP, + _MALI_OSK_LOCK_ORDER_SCHEDULER, + + _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP, + _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE, + _MALI_OSK_LOCK_ORDER_MEM_INFO, + _MALI_OSK_LOCK_ORDER_MEM_SESSION, + + _MALI_OSK_LOCK_ORDER_SESSIONS, + + _MALI_OSK_LOCK_ORDER_FIRST +} _mali_osk_lock_order_t; + + /** @brief OSK Mutual Exclusion Lock flags type * * Flags are supplied at the point where the Lock is initialized. Each flag can @@ -271,6 +302,17 @@ typedef enum /** @brief Private type for Mutual Exclusion lock objects */ typedef struct _mali_osk_lock_t_struct _mali_osk_lock_t; + +#ifdef DEBUG +/** @brief Macro for asserting that the current thread holds a given lock + */ +#define MALI_DEBUG_ASSERT_LOCK_HELD(l) MALI_DEBUG_ASSERT(_mali_osk_lock_get_owner(l) == _mali_osk_get_tid()); + +/** @brief returns a lock's owner (thread id) if debugging is enabled + */ +u32 _mali_osk_lock_get_owner( _mali_osk_lock_t *lock ); +#endif + /** @} */ /* end group _mali_osk_lock */ /** @defgroup _mali_osk_low_level_memory OSK Low-level Memory Operations @@ -368,7 +410,6 @@ typedef struct _mali_osk_notification_queue_t_struct _mali_osk_notification_queu /** @brief Public notification data object type */ typedef struct _mali_osk_notification_t_struct { - u32 magic_code; u32 notification_type; /**< The notification type */ u32 result_buffer_size; /**< Size of the result buffer to copy to user space */ void * result_buffer; /**< Buffer containing any type specific data */ @@ -527,20 +568,35 @@ typedef struct _mali_osk_list_s typedef enum _mali_osk_resource_type { RESOURCE_TYPE_FIRST =0, /**< Duplicate resource marker for the first resource*/ + MEMORY =0, /**< Physically contiguous memory block, not managed by the OS */ OS_MEMORY =1, /**< Memory managed by and shared with the OS */ - MALI200 =3, /**< Mali200 Programmable Fragment Shader */ - MALIGP2 =4, /**< MaliGP2 Programmable Vertex Shader */ - MMU =5, /**< Mali MMU (Memory Management Unit) */ - FPGA_FRAMEWORK =6, /**< Mali registers specific to FPGA implementations */ - MALI400L2 =7, /**< Mali400 L2 Cache */ - MALI300L2 =7, /**< Mali300 L2 Cache */ - MALI400GP =8, /**< Mali400 Programmable Vertex Shader Core */ - MALI300GP =8, /**< Mali300 Programmable Vertex Shader Core */ - MALI400PP =9, /**< Mali400 Programmable Fragment Shader Core */ - MALI300PP =9, /**< Mali300 Programmable Fragment Shader Core */ - MEM_VALIDATION =10, /**< External Memory Validator */ - PMU =11, /**< Power Manangement Unit */ + + MALI_PP =2, /**< Mali Pixel Processor core */ + MALI450PP =2, /**< Compatibility option */ + MALI400PP =2, /**< Compatibility option */ + MALI300PP =2, /**< Compatibility option */ + MALI200 =2, /**< Compatibility option */ + + MALI_GP =3, /**< Mali Geometry Processor core */ + MALI450GP =3, /**< Compatibility option */ + MALI400GP =3, /**< Compatibility option */ + MALI300GP =3, /**< Compatibility option */ + MALIGP2 =3, /**< Compatibility option */ + + MMU =4, /**< Mali MMU (Memory Management Unit) */ + + FPGA_FRAMEWORK =5, /**< Mali registers specific to FPGA implementations */ + + MALI_L2 =6, /**< Mali Level 2 cache core */ + MALI450L2 =6, /**< Compatibility option */ + MALI400L2 =6, /**< Compatibility option */ + MALI300L2 =6, /**< Compatibility option */ + + MEM_VALIDATION =7, /**< External Memory Validator */ + + PMU =8, /**< Power Manangement Unit */ + RESOURCE_TYPE_COUNT /**< The total number of known resources */ } _mali_osk_resource_type_t; @@ -726,11 +782,6 @@ void _mali_osk_atomic_dec( _mali_osk_atomic_t *atom ); /** @brief Decrement an atomic counter, return new value * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * - * @note It is an error to decrement the counter beyond -(1<<23) - * * @param atom pointer to an atomic counter * @return The new value, after decrement */ u32 _mali_osk_atomic_dec_return( _mali_osk_atomic_t *atom ); @@ -744,19 +795,11 @@ void _mali_osk_atomic_inc( _mali_osk_atomic_t *atom ); /** @brief Increment an atomic counter, return new value * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * - * @note It is an error to increment the counter beyond (1<<23)-1 - * * @param atom pointer to an atomic counter */ u32 _mali_osk_atomic_inc_return( _mali_osk_atomic_t *atom ); /** @brief Initialize an atomic counter * - * The counters have storage for signed 24-bit integers. Initializing to signed - * values requiring more than 24-bits storage will fail. - * * @note the parameter required is a u32, and so signed integers should be * cast to u32. * @@ -769,9 +812,6 @@ _mali_osk_errcode_t _mali_osk_atomic_init( _mali_osk_atomic_t *atom, u32 val ); /** @brief Read a value from an atomic counter * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * * This can only be safely used to determine the value of the counter when it * is guaranteed that other threads will not be modifying the counter. This * makes its usefulness limited. @@ -1624,6 +1664,41 @@ u64 _mali_osk_time_get_ns( void ); u32 _mali_osk_clz( u32 val ); /** @} */ /* end group _mali_osk_math */ +/** @defgroup _mali_osk_wait_queue OSK Wait Queue functionality + * @{ */ +/** @brief Private type for wait queue objects */ +typedef struct _mali_osk_wait_queue_t_struct _mali_osk_wait_queue_t; + +/** @brief Initialize an empty Wait Queue */ +_mali_osk_wait_queue_t* _mali_osk_wait_queue_init( void ); + +/** @brief Sleep if condition is false + * + * @param queue the queue to use + * @param condition function pointer to a boolean function + * + * Put thread to sleep if the given \a codition function returns false. When + * being asked to wake up again, the condition will be re-checked and the + * thread only woken up if the condition is now true. + */ +void _mali_osk_wait_queue_wait_event( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void) ); + +/** @brief Wake up all threads in wait queue if their respective conditions are + * true + * + * @param queue the queue whose threads should be woken up + * + * Wake up all threads in wait queue \a queue whose condition is now true. + */ +void _mali_osk_wait_queue_wake_up( _mali_osk_wait_queue_t *queue ); + +/** @brief terminate a wait queue + * + * @param queue the queue to terminate. + */ +void _mali_osk_wait_queue_term( _mali_osk_wait_queue_t *queue ); +/** @} */ /* end group _mali_osk_wait_queue */ + /** @addtogroup _mali_osk_miscellaneous * @{ */ @@ -1647,6 +1722,7 @@ void _mali_osk_dbgmsg( const char *fmt, ... ); * @param size the total number of bytes allowed to write to \a buf * @param fmt a _mali_osu_vsnprintf() style format string * @param ... a variable-number of parameters suitable for \a fmt + * @return The number of bytes written to \a buf */ u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ); @@ -1685,13 +1761,19 @@ u32 _mali_osk_get_pid(void); */ u32 _mali_osk_get_tid(void); -void _mali_osk_profiling_add_event(u32 event_id, u32 data0); -void _mali_osk_profiling_add_counter(u32 event_id, u32 data0); -int _mali_osk_counter_event(u32 counter, u32 event); -extern u32 counter_table[]; +/** @brief Enable OS controlled runtime power management + */ +void _mali_osk_pm_dev_enable(void); -/** @} */ /* end group _mali_osk_miscellaneous */ +/** @brief Tells the OS that device is now idle + */ +_mali_osk_errcode_t _mali_osk_pm_dev_idle(void); +/** @brief Tells the OS that the device is about to become active + */ +_mali_osk_errcode_t _mali_osk_pm_dev_activate(void); + +/** @} */ /* end group _mali_osk_miscellaneous */ /** @} */ /* end group osuapi */ diff --git a/drivers/media/video/samsung/mali/common/mali_osk_list.h b/drivers/media/video/samsung/mali/common/mali_osk_list.h index 3a562bb..a8d15f2 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk_list.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_list.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 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. diff --git a/drivers/media/video/samsung/mali/common/mali_osk_mali.h b/drivers/media/video/samsung/mali/common/mali_osk_mali.h index 0b1d13a..427fcc8 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk_mali.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_mali.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -26,36 +26,6 @@ extern "C" /** @addtogroup _mali_osk_miscellaneous * @{ */ -/** @brief Initialize the OSK layer - * - * This function is used to setup any initialization of OSK functionality, if - * required. - * - * This must be the first function called from the common code, specifically, - * from the common code entry-point, mali_kernel_constructor. - * - * The OS-integration into the OS's kernel must handle calling of - * mali_kernel_constructor when the device driver is loaded. - * - * @return _MALI_OSK_ERR_OK on success, or a suitable _mali_osk_errcode_t on - * failure. - */ -_mali_osk_errcode_t _mali_osk_init( void ); - -/** @brief Terminate the OSK layer - * - * This function is used to terminate any resources initialized by - * _mali_osk_init. - * - * This must be the last function called from the common code, specifically, - * from the common code closedown function, mali_kernel_destructor, and the - * error path in mali_kernel_constructor. - * - * The OS-integration into the OS's kernel must handle calling of - * mali_kernel_destructor when the device driver is terminated. - */ -void _mali_osk_term( void ); - /** @brief Read the Mali Resource configuration * * Populates a _mali_arch_resource_t array from configuration settings, which diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.h b/drivers/media/video/samsung/mali/common/mali_osk_profiling.h index eb1e6c2..fd9a8fb 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_profiling.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -8,31 +8,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_PROFILING_H__ -#define __MALI_KERNEL_PROFILING_H__ +#ifndef __MALI_OSK_PROFILING_H__ +#define __MALI_OSK_PROFILING_H__ #if MALI_TIMELINE_PROFILING_ENABLED -#include "cinstr/mali_cinstr_profiling_events_m200.h" +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +#include "mali_linux_trace.h" +#endif /* CONFIG_TRACEPOINTS && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED */ + +#include "mali_profiling_events.h" #define MALI_PROFILING_MAX_BUFFER_ENTRIES 1048576 +#define MALI_PROFILING_NO_HW_COUNTER = ((u32)-1) + +/** @defgroup _mali_osk_profiling External profiling connectivity + * @{ */ + /** * Initialize the profiling module. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start); +_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start); /* * Terminate the profiling module. */ -void _mali_profiling_term(void); - -/** Add a counter event - * @param event_id - Magic counter id - * @param data0 - Value of counter - */ -void _mali_profiling_add_counter(u32 event_id, u32 data0); +void _mali_osk_profiling_term(void); /** * Start recording profiling data @@ -43,7 +46,7 @@ void _mali_profiling_add_counter(u32 event_id, u32 data0); * @param limit The desired maximum number of events to record on input, the actual maximum on output. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_start(u32 * limit); +_mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit); /** * Add an profiling event @@ -56,7 +59,35 @@ _mali_osk_errcode_t _mali_profiling_start(u32 * limit); * @param data4 Fifth data parameter, depending on event_id specified. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4); +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +/* Call Linux tracepoint directly */ +#define _mali_osk_profiling_add_event(event_id, data0, data1, data2, data3, data4) trace_mali_timeline_event((event_id), (data0), (data1), (data2), (data3), (data4)) +#else +/* Internal profiling is handled like a plain function call */ +void _mali_osk_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4); +#endif + +/** + * Report a hardware counter event. + * + * @param counter_id The ID of the counter. + * @param value The value of the counter. + */ + +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +/* Call Linux tracepoint directly */ +#define _mali_osk_profiling_report_hw_counter(counter_id, value) trace_mali_hw_counter(counter_id, value) +#else +/* Internal profiling is handled like a plain function call */ +void _mali_osk_profiling_report_hw_counter(u32 counter_id, u32 value); +#endif + +/** + * Report SW counters + * + * @param counters array of counter values + */ +void _mali_osk_profiling_report_sw_counters(u32 *counters); /** * Stop recording profiling data @@ -64,14 +95,14 @@ _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1 * @param count Returns the number of recorded events. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_stop(u32 * count); +_mali_osk_errcode_t _mali_osk_profiling_stop(u32 * count); /** * Retrieves the number of events that can be retrieved * * @return The number of recorded events that can be retrieved. */ -u32 _mali_profiling_get_count(void); +u32 _mali_osk_profiling_get_count(void); /** * Retrieve an event @@ -81,7 +112,8 @@ u32 _mali_profiling_get_count(void); * @param event_id The event ID for the retrieved event will be stored here. * @param data The 5 data values for the retrieved event will be stored here. * @return _MALI_OSK_ERR_OK on success, otherwise failure. - */_mali_osk_errcode_t _mali_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); + */ +_mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); /** * Clear the recorded buffer. @@ -90,38 +122,26 @@ u32 _mali_profiling_get_count(void); * * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_clear(void); +_mali_osk_errcode_t _mali_osk_profiling_clear(void); /** * Checks if a recording of profiling data is in progress * * @return MALI_TRUE if recording of profiling data is in progress, MALI_FALSE if not */ -mali_bool _mali_profiling_is_recording(void); +mali_bool _mali_osk_profiling_is_recording(void); /** * Checks if profiling data is available for retrival * * @return MALI_TRUE if profiling data is avaiable, MALI_FALSE if not */ -mali_bool _mali_profiling_have_recording(void); +mali_bool _mali_osk_profiling_have_recording(void); -/** - * Enable or disable profiling events as default for new sessions (applications) - * - * @param enable MALI_TRUE if profiling events should be turned on, otherwise MALI_FALSE - */ -void _mali_profiling_set_default_enable_state(mali_bool enable); - -/** - * Get current default enable state for new sessions (applications) - * - * @return MALI_TRUE if profiling events should be turned on, otherwise MALI_FALSE - */ -mali_bool _mali_profiling_get_default_enable_state(void); +/** @} */ /* end group _mali_osk_profiling */ #endif /* MALI_TIMELINE_PROFILING_ENABLED */ -#endif /* __MALI_KERNEL_PROFILING_H__ */ +#endif /* __MALI_OSK_PROFILING_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pm.c b/drivers/media/video/samsung/mali/common/mali_pm.c new file mode 100644 index 0000000..1ef3807 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pm.c @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2011-2012 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_pm.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_platform.h" +#include "mali_kernel_utilization.h" +#include "mali_kernel_core.h" +#include "mali_group.h" + +#define MALI_PM_LIGHT_SLEEP_TIMEOUT 1000 + +enum mali_pm_scheme +{ + MALI_PM_SCHEME_DYNAMIC, + MALI_PM_SCHEME_OS_SUSPENDED, + MALI_PM_SCHEME_ALWAYS_ON +}; + +enum mali_pm_level +{ + MALI_PM_LEVEL_1_ON, + MALI_PM_LEVEL_2_STANDBY, + MALI_PM_LEVEL_3_LIGHT_SLEEP, + MALI_PM_LEVEL_4_DEEP_SLEEP +}; +static _mali_osk_lock_t *mali_pm_lock_set_next_state; +static _mali_osk_lock_t *mali_pm_lock_set_core_states; +static _mali_osk_lock_t *mali_pm_lock_execute_state_change; +static _mali_osk_irq_t *wq_irq; + +static _mali_osk_timer_t *idle_timer = NULL; +static mali_bool idle_timer_running = MALI_FALSE; +static u32 mali_pm_event_number = 0; + +static u32 num_active_gps = 0; +static u32 num_active_pps = 0; + +static enum mali_pm_scheme current_scheme = MALI_PM_SCHEME_DYNAMIC; +static enum mali_pm_level current_level = MALI_PM_LEVEL_1_ON; +static enum mali_pm_level next_level_dynamic = MALI_PM_LEVEL_2_STANDBY; /* Should be the state we go to when we go out of MALI_PM_SCHEME_ALWAYS_ON during init */ + + + +static _mali_osk_errcode_t mali_pm_upper_half(void *data); +static void mali_pm_bottom_half(void *data); +static void mali_pm_powerup(void); +static void mali_pm_powerdown(mali_power_mode power_mode); + +static void timeout_light_sleep(void* arg); +#if 0 +/* Deep sleep timout not supported */ +static void timeout_deep_sleep(void* arg); +#endif +static u32 mali_pm_event_number_get(void); +static void mali_pm_event(enum mali_pm_event pm_event, mali_bool schedule_work, u32 timer_time ); + +_mali_osk_errcode_t mali_pm_initialize(void) +{ + mali_pm_lock_execute_state_change = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ORDERED |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PM_EXECUTE); + + if (NULL != mali_pm_lock_execute_state_change ) + { + mali_pm_lock_set_next_state = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ONELOCK| _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_LAST); + + if (NULL != mali_pm_lock_set_next_state) + { + mali_pm_lock_set_core_states = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PM_CORE_STATE); + + if (NULL != mali_pm_lock_set_core_states) + { + idle_timer = _mali_osk_timer_init(); + if (NULL != idle_timer) + { + wq_irq = _mali_osk_irq_init(_MALI_OSK_IRQ_NUMBER_PMM, + mali_pm_upper_half, + mali_pm_bottom_half, + NULL, + NULL, + (void *)NULL, + "Mali PM deferred work"); + if (NULL != wq_irq) + { + if (_MALI_OSK_ERR_OK == mali_platform_init()) + { +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + _mali_osk_pm_dev_enable(); + mali_pm_powerup(); +#endif + return _MALI_OSK_ERR_OK; + } + + _mali_osk_irq_term(wq_irq); + } + + _mali_osk_timer_del(idle_timer); + _mali_osk_timer_term(idle_timer); + } + _mali_osk_lock_term(mali_pm_lock_set_core_states); + } + _mali_osk_lock_term(mali_pm_lock_set_next_state); + } + _mali_osk_lock_term(mali_pm_lock_execute_state_change); + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_pm_terminate(void) +{ + mali_platform_deinit(); + _mali_osk_irq_term(wq_irq); + _mali_osk_timer_del(idle_timer); + _mali_osk_timer_term(idle_timer); + _mali_osk_lock_term(mali_pm_lock_execute_state_change); + _mali_osk_lock_term(mali_pm_lock_set_next_state); + _mali_osk_lock_term(mali_pm_lock_set_core_states); +} + + +inline void mali_pm_lock(void) +{ + _mali_osk_lock_wait(mali_pm_lock_set_next_state, _MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_unlock(void) +{ + _mali_osk_lock_signal(mali_pm_lock_set_next_state, _MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_execute_state_change_lock(void) +{ + _mali_osk_lock_wait(mali_pm_lock_execute_state_change,_MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_execute_state_change_unlock(void) +{ + _mali_osk_lock_signal(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); +} + +static void mali_pm_powerup(void) +{ + MALI_DEBUG_PRINT(3, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_ON\n")); + mali_platform_power_mode_change(MALI_POWER_MODE_ON); + +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + + /* Aquire our reference */ + MALI_DEBUG_PRINT(4, ("Mali PM: Getting device PM reference (=> requesting MALI_POWER_MODE_ON)\n")); + _mali_osk_pm_dev_activate(); +#endif + + mali_group_power_on(); +} + +static void mali_pm_powerdown(mali_power_mode power_mode) +{ + if ( (MALI_PM_LEVEL_1_ON == current_level) || (MALI_PM_LEVEL_2_STANDBY == current_level) ) + { + mali_group_power_off(); + } + mali_platform_power_mode_change(power_mode); + +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + _mali_osk_pm_dev_idle(); +#endif +} + +mali_bool mali_pm_is_powered_on(void) +{ + mali_bool is_on = MALI_TRUE; + + if( ! (MALI_PM_SCHEME_ALWAYS_ON == current_scheme || MALI_PM_SCHEME_DYNAMIC == current_scheme) ) + { + is_on = MALI_FALSE; + } + else if ( ! (MALI_PM_LEVEL_1_ON == current_level || MALI_PM_LEVEL_2_STANDBY == current_level)) + { + is_on = MALI_FALSE; + } + else if ( ! (MALI_PM_LEVEL_1_ON == next_level_dynamic || MALI_PM_LEVEL_2_STANDBY == next_level_dynamic)) + { + is_on = MALI_FALSE; + } + + return is_on; +} + +MALI_DEBUG_CODE( +static const char *state_as_string(enum mali_pm_level level) +{ + switch(level) + { + case MALI_PM_LEVEL_1_ON: + return "MALI_PM_LEVEL_1_ON"; + case MALI_PM_LEVEL_2_STANDBY: + return "MALI_PM_LEVEL_2_STANDBY"; + case MALI_PM_LEVEL_3_LIGHT_SLEEP: + return "MALI_PM_LEVEL_3_LIGHT_SLEEP"; + case MALI_PM_LEVEL_4_DEEP_SLEEP: + return "MALI_PM_LEVEL_4_DEEP_SLEEP"; + default: + return "UNKNOWN LEVEL"; + } +}); + +/* This could be used from another thread (work queue), if we need that */ +static void mali_pm_process_next(void) +{ + enum mali_pm_level pm_level_to_set; + + _mali_osk_lock_wait(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); + + pm_level_to_set = current_level; + + if (MALI_PM_SCHEME_DYNAMIC == current_scheme) + { + pm_level_to_set = next_level_dynamic; + + MALI_DEBUG_PRINT(4, ("Mali PM: Dynamic scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(pm_level_to_set))); + + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + /* Start timers according to new state, so we get STANDBY -> LIGHT_SLEEP -> DEEP_SLEEP */ + + if (MALI_TRUE == idle_timer_running) + { + /* There is an existing timeout, so delete it */ + _mali_osk_timer_del(idle_timer); + idle_timer_running = MALI_FALSE; + } + + /* Making sure that we turn on through the platform file + Since it was turned OFF directly through the platform file. + This might lead to double turn-on, but the plaform file supports that.*/ + if ( current_level == MALI_PM_LEVEL_4_DEEP_SLEEP) + { + mali_pm_powerup(); + mali_kernel_core_wakeup(); + + } + if (MALI_PM_LEVEL_1_ON == pm_level_to_set) + { + if (MALI_PM_LEVEL_2_STANDBY != current_level) + { + /* We only need to do anything if we came from one of the sleeping states */ + mali_pm_powerup(); + + /* Wake up Mali cores since we came from a sleep state */ + mali_kernel_core_wakeup(); + } + } + else if (MALI_PM_LEVEL_2_STANDBY == pm_level_to_set) + { + /* This is just an internal state, so we don't bother to report it to the platform file */ + idle_timer_running = MALI_TRUE; + _mali_osk_timer_setcallback(idle_timer, timeout_light_sleep, (void*) mali_pm_event_number_get()); + _mali_osk_timer_add(idle_timer, _mali_osk_time_mstoticks(MALI_PM_LIGHT_SLEEP_TIMEOUT)); + } + else if (MALI_PM_LEVEL_3_LIGHT_SLEEP == pm_level_to_set) + { + mali_pm_powerdown(MALI_POWER_MODE_LIGHT_SLEEP); + } + else if (MALI_PM_LEVEL_4_DEEP_SLEEP == pm_level_to_set) + { + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_DEEP_SLEEP\n")); + mali_pm_powerdown(MALI_POWER_MODE_DEEP_SLEEP); + } + } + else if (MALI_PM_SCHEME_OS_SUSPENDED == current_scheme) + { + MALI_DEBUG_PRINT(4, ("Mali PM: OS scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(MALI_PM_LEVEL_4_DEEP_SLEEP))); + + pm_level_to_set = MALI_PM_LEVEL_4_DEEP_SLEEP; + + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + /* Cancel any timers */ + if (MALI_TRUE == idle_timer_running) + { + /* There is an existing timeout, so delete it */ + _mali_osk_timer_del(idle_timer); + idle_timer_running = MALI_FALSE; + } + + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_DEEP_SLEEP\n")); + mali_pm_powerdown(MALI_POWER_MODE_DEEP_SLEEP); + next_level_dynamic = current_level; + } + else if (MALI_PM_SCHEME_ALWAYS_ON == current_scheme) + { + MALI_DEBUG_PRINT(4, ("Mali PM: Always on scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(MALI_PM_LEVEL_1_ON))); + + pm_level_to_set = MALI_PM_LEVEL_1_ON; + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_ON\n")); + mali_pm_powerup(); + if (MALI_PM_LEVEL_2_STANDBY != current_level) + { + /* Wake up Mali cores since we came from a sleep state */ + mali_kernel_core_wakeup(); + } + } + else + { + MALI_PRINT_ERROR(("MALI PM: Illegal scheme")); + } + + current_level = pm_level_to_set; + +end_function: + _mali_osk_lock_signal(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); + +} + +void mali_pm_always_on(mali_bool enable) +{ + if (MALI_TRUE == enable) + { + /* The event is processed in current thread synchronously */ + mali_pm_event(MALI_PM_EVENT_SCHEME_ALWAYS_ON, MALI_FALSE, 0 ); + } + else + { + /* The event is processed in current thread synchronously */ + mali_pm_event(MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL, MALI_FALSE, 0 ); + } +} + +static _mali_osk_errcode_t mali_pm_upper_half(void *data) +{ + /* not used */ + return _MALI_OSK_ERR_OK; +} + +static void mali_pm_bottom_half(void *data) +{ + mali_pm_process_next(); +} + +static u32 mali_pm_event_number_get(void) +{ + u32 retval; + + mali_pm_lock(); /* spinlock: mali_pm_lock_set_next_state */ + retval = ++mali_pm_event_number; + if (0==retval ) retval = ++mali_pm_event_number; + mali_pm_unlock(); + + return retval; +} + +static void mali_pm_event(enum mali_pm_event pm_event, mali_bool schedule_work, u32 timer_time ) +{ + mali_pm_lock(); /* spinlock: mali_pm_lock_set_next_state */ + /* Only timer events should set this variable, all other events must set it to zero. */ + if ( 0 != timer_time ) + { + MALI_DEBUG_ASSERT( (pm_event==MALI_PM_EVENT_TIMER_LIGHT_SLEEP) || (pm_event==MALI_PM_EVENT_TIMER_DEEP_SLEEP) ); + if ( mali_pm_event_number != timer_time ) + { + /* In this case there have been processed newer events since the timer event was set up. + If so we always ignore the timing event */ + mali_pm_unlock(); + return; + } + } + else + { + /* Delete possible ongoing timers + if ( (MALI_PM_LEVEL_2_STANDBY==current_level) || (MALI_PM_LEVEL_3_LIGHT_SLEEP==current_level) ) + { + _mali_osk_timer_del(idle_timer); + } + */ + } + mali_pm_event_number++; + switch (pm_event) + { + case MALI_PM_EVENT_CORES_WORKING: + next_level_dynamic = MALI_PM_LEVEL_1_ON; + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + break; + case MALI_PM_EVENT_CORES_IDLE: + next_level_dynamic = MALI_PM_LEVEL_2_STANDBY; + /*MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme );*/ + break; + case MALI_PM_EVENT_TIMER_LIGHT_SLEEP: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + next_level_dynamic = MALI_PM_LEVEL_3_LIGHT_SLEEP; + break; + case MALI_PM_EVENT_TIMER_DEEP_SLEEP: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + next_level_dynamic = MALI_PM_LEVEL_4_DEEP_SLEEP; + break; + case MALI_PM_EVENT_OS_SUSPEND: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + current_scheme = MALI_PM_SCHEME_OS_SUSPENDED; + next_level_dynamic = MALI_PM_LEVEL_4_DEEP_SLEEP; /* Dynamic scheme will go into level when we are resumed */ + break; + case MALI_PM_EVENT_OS_RESUME: + MALI_DEBUG_ASSERT(MALI_PM_SCHEME_OS_SUSPENDED == current_scheme ); + current_scheme = MALI_PM_SCHEME_DYNAMIC; + break; + case MALI_PM_EVENT_SCHEME_ALWAYS_ON: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + current_scheme = MALI_PM_SCHEME_ALWAYS_ON; + break; + case MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON == current_scheme || MALI_PM_SCHEME_DYNAMIC == current_scheme ); + current_scheme = MALI_PM_SCHEME_DYNAMIC; + break; + default: + MALI_DEBUG_PRINT_ERROR(("Unknown next state.")); + mali_pm_unlock(); + return; + } + mali_pm_unlock(); + + if (MALI_TRUE == schedule_work) + { + _mali_osk_irq_schedulework(wq_irq); + } + else + { + mali_pm_process_next(); + } +} + +static void timeout_light_sleep(void* arg) +{ + /* State change only if no newer power events have happend from the time in arg. + Actual work will be scheduled on worker thread. */ + mali_pm_event(MALI_PM_EVENT_TIMER_LIGHT_SLEEP, MALI_TRUE, (u32) arg); +} + +void mali_pm_core_event(enum mali_core_event core_event) +{ + mali_bool transition_working = MALI_FALSE; + mali_bool transition_idle = MALI_FALSE; + + _mali_osk_lock_wait(mali_pm_lock_set_core_states, _MALI_OSK_LOCKMODE_RW); + + switch (core_event) + { + case MALI_CORE_EVENT_GP_START: + if (num_active_pps + num_active_gps == 0) + { + transition_working = MALI_TRUE; + } + num_active_gps++; + break; + case MALI_CORE_EVENT_GP_STOP: + if (num_active_pps + num_active_gps == 1) + { + transition_idle = MALI_TRUE; + } + num_active_gps--; + break; + case MALI_CORE_EVENT_PP_START: + if (num_active_pps + num_active_gps == 0) + { + transition_working = MALI_TRUE; + } + num_active_pps++; + break; + case MALI_CORE_EVENT_PP_STOP: + if (num_active_pps + num_active_gps == 1) + { + transition_idle = MALI_TRUE; + } + num_active_pps--; + break; + } + + if (transition_working == MALI_TRUE) + { +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_core_start(_mali_osk_time_get_ns()); +#endif + mali_pm_event(MALI_PM_EVENT_CORES_WORKING, MALI_FALSE, 0); /* process event in same thread */ + } + else if (transition_idle == MALI_TRUE) + { +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_core_end(_mali_osk_time_get_ns()); +#endif + mali_pm_event(MALI_PM_EVENT_CORES_IDLE, MALI_FALSE, 0); /* process event in same thread */ + } + + _mali_osk_lock_signal(mali_pm_lock_set_core_states, _MALI_OSK_LOCKMODE_RW); +} + +void mali_pm_os_suspend(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS suspending...\n")); + + mali_gp_scheduler_suspend(); + mali_pp_scheduler_suspend(); + mali_pm_event(MALI_PM_EVENT_OS_SUSPEND, MALI_FALSE, 0); /* process event in same thread */ + + MALI_DEBUG_PRINT(2, ("Mali PM: OS suspend completed\n")); +} + +void mali_pm_os_resume(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS resuming...\n")); + + mali_pm_event(MALI_PM_EVENT_OS_RESUME, MALI_FALSE, 0); /* process event in same thread */ + mali_gp_scheduler_resume(); + mali_pp_scheduler_resume(); + + MALI_DEBUG_PRINT(2, ("Mali PM: OS resume completed\n")); +} + +void mali_pm_runtime_suspend(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS runtime suspended\n")); +} + +void mali_pm_runtime_resume(void) +{ + MALI_DEBUG_PRINT(3, ("Mali PM: OS runtime resumed\n")); +} diff --git a/drivers/media/video/samsung/mali/common/mali_pm.h b/drivers/media/video/samsung/mali/common/mali_pm.h new file mode 100644 index 0000000..d4ccfde --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pm.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_PM_H__ +#define __MALI_PM_H__ + +#include "mali_osk.h" + +enum mali_core_event +{ + MALI_CORE_EVENT_GP_START, + MALI_CORE_EVENT_GP_STOP, + MALI_CORE_EVENT_PP_START, + MALI_CORE_EVENT_PP_STOP +}; + +enum mali_pm_event +{ + MALI_PM_EVENT_CORES_WORKING, + MALI_PM_EVENT_CORES_IDLE, + MALI_PM_EVENT_TIMER_LIGHT_SLEEP, + MALI_PM_EVENT_TIMER_DEEP_SLEEP, + MALI_PM_EVENT_OS_SUSPEND, + MALI_PM_EVENT_OS_RESUME, + MALI_PM_EVENT_SCHEME_ALWAYS_ON, + MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL, +}; + +_mali_osk_errcode_t mali_pm_initialize(void); +void mali_pm_terminate(void); +void mali_pm_always_on(mali_bool enable); + +void mali_pm_lock(void); +void mali_pm_unlock(void); +void mali_pm_execute_state_change_lock(void); + +void mali_pm_execute_state_change_unlock(void); + +mali_bool mali_pm_is_powered_on(void); + +void mali_pm_core_event(enum mali_core_event core_event); + +void mali_pm_os_suspend(void); +void mali_pm_os_resume(void); +void mali_pm_runtime_suspend(void); +void mali_pm_runtime_resume(void); + + +#endif /* __MALI_PM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pmu.c b/drivers/media/video/samsung/mali/common/mali_pmu.c new file mode 100644 index 0000000..348b5dc --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pmu.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +/** + * @file mali_pmu.c + * Mali driver functions for Mali 400 PMU hardware + */ +#include "mali_hw_core.h" +#include "mali_pmu.h" +#include "mali_pp.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" + +static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches); + +/** @brief MALI inbuilt PMU hardware info and PMU hardware has knowledge of cores power mask + */ +struct mali_pmu_core +{ + struct mali_hw_core hw_core; + u32 mali_registered_cores_power_mask; +}; + +static struct mali_pmu_core *mali_global_pmu_core = NULL; + +/** @brief Register layout for hardware PMU + */ +typedef enum { + PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ + PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ + PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ + PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ + PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x10, /*< Size of register space */ +} pmu_reg_addr_mgmt_addr; + +struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource, u32 number_of_pp_cores, u32 number_of_l2_caches) +{ + struct mali_pmu_core* pmu; + + MALI_DEBUG_ASSERT(NULL == mali_global_pmu_core); + MALI_DEBUG_PRINT(2, ("Mali PMU: Creating Mali PMU core\n")); + + pmu = (struct mali_pmu_core *)_mali_osk_malloc(sizeof(struct mali_pmu_core)); + if (NULL != pmu) + { + pmu->mali_registered_cores_power_mask = mali_pmu_detect_mask(number_of_pp_cores, number_of_l2_caches); + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&pmu->hw_core, resource, PMU_REGISTER_ADDRESS_SPACE_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_pmu_reset(pmu)) + { + mali_global_pmu_core = pmu; + return pmu; + } + mali_hw_core_delete(&pmu->hw_core); + } + _mali_osk_free(pmu); + } + + return NULL; +} + +void mali_pmu_delete(struct mali_pmu_core *pmu) +{ + MALI_DEBUG_ASSERT_POINTER(pmu); + + mali_hw_core_delete(&pmu->hw_core); + _mali_osk_free(pmu); + pmu = NULL; +} + +_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu) +{ + /* Don't use interrupts - just poll status */ + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0); + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pmu_powerdown_all(struct mali_pmu_core *pmu) +{ + u32 stat; + u32 timeout; + + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 ); + MALI_DEBUG_PRINT( 4, ("Mali PMU: power down (0x%08X)\n", pmu->mali_registered_cores_power_mask) ); + + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_DOWN, pmu->mali_registered_cores_power_mask); + + /* Wait for cores to be powered down (100 x 100us = 100ms) */ + timeout = 100; + do + { + /* Get status of sleeping cores */ + stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); + stat &= pmu->mali_registered_cores_power_mask; + if( stat == pmu->mali_registered_cores_power_mask ) break; /* All cores we wanted are now asleep */ + _mali_osk_time_ubusydelay(100); + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) + { + return _MALI_OSK_ERR_TIMEOUT; + } + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pmu_powerup_all(struct mali_pmu_core *pmu) +{ + u32 stat; + u32 timeout; + + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 ); /* Shouldn't be zero */ + MALI_DEBUG_PRINT( 4, ("Mali PMU: power up (0x%08X)\n", pmu->mali_registered_cores_power_mask) ); + + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_UP, pmu->mali_registered_cores_power_mask); + + /* Wait for cores to be powered up (100 x 100us = 100ms) */ + timeout = 100; + do + { + /* Get status of sleeping cores */ + stat = mali_hw_core_register_read(&pmu->hw_core,PMU_REG_ADDR_MGMT_STATUS); + stat &= pmu->mali_registered_cores_power_mask; + if( stat == 0 ) break; /* All cores we wanted are now awake */ + _mali_osk_time_ubusydelay(100); + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) + { + return _MALI_OSK_ERR_TIMEOUT; + } + + return _MALI_OSK_ERR_OK; +} + +struct mali_pmu_core *mali_pmu_get_global_pmu_core(void) +{ + return mali_global_pmu_core; +} + +static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches) +{ + u32 mask = 0; + + if (number_of_l2_caches == 1) + { + /* Mali-300 or Mali-400 */ + u32 i; + + /* GP */ + mask = 0x01; + + /* L2 cache */ + mask |= 0x01<<1; + + /* Set bit for each PP core */ + for (i = 0; i < number_of_pp_cores; i++) + { + mask |= 0x01<<(i+2); + } + } + else if (number_of_l2_caches > 1) + { + /* Mali-450 */ + + /* GP (including its L2 cache) */ + mask = 0x01; + + /* There is always at least one PP (including its L2 cache) */ + mask |= 0x01<<1; + + /* Additional PP cores in same L2 cache */ + if (number_of_pp_cores >= 2) + { + mask |= 0x01<<2; + } + + /* Additional PP cores in a third L2 cache */ + if (number_of_pp_cores >= 5) + { + mask |= 0x01<<3; + } + } + + MALI_DEBUG_PRINT(4, ("Mali PMU: Power mask is 0x%08X (%u + %u)\n", mask, number_of_pp_cores, number_of_l2_caches)); + + return mask; +} diff --git a/drivers/media/video/samsung/mali/common/mali_pmu.h b/drivers/media/video/samsung/mali/common/mali_pmu.h new file mode 100644 index 0000000..fd10c08 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pmu.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010-2012 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. + */ + +/** + * @file mali_platform.h + * Platform specific Mali driver functions + */ + +#include "mali_osk.h" + +struct mali_pmu_core; + +/** @brief Initialisation of MALI PMU + * + * This is called from entry point of the driver in order to create and intialize the PMU resource + * + * @param resource it will be a pointer to a PMU resource + * @param number_of_pp_cores Number of found PP resources in configuration + * @param number_of_l2_caches Number of found L2 cache resources in configuration + * @return The created PMU object, or NULL in case of failure. + */ +struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource, u32 number_of_pp_cores, u32 number_of_l2_caches); + +/** @brief It deallocates the PMU resource + * + * This is called on the exit of the driver to terminate the PMU resource + * + * @param pmu Pointer to PMU core object to delete + */ +void mali_pmu_delete(struct mali_pmu_core *pmu); + +/** @brief Reset PMU core + * + * @param pmu Pointer to PMU core object to reset + * @return _MALI_OSK_ERR_OK on success, otherwise failure. + */ +_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu); + +/** @brief MALI GPU power down using MALI in-built PMU + * + * called to power down all cores + * + * @param pmu Pointer to PMU core object to power down + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_pmu_powerdown_all(struct mali_pmu_core *pmu); + + +/** @brief MALI GPU power up using MALI in-built PMU + * + * called to power up all cores + * + * @param pmu Pointer to PMU core object to power up + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_pmu_powerup_all(struct mali_pmu_core *pmu); + + +/** @brief Retrieves the Mali PMU core object (if any) + * + * @return The Mali PMU object, or NULL if no PMU exists. + */ +struct mali_pmu_core *mali_pmu_get_global_pmu_core(void); diff --git a/drivers/media/video/samsung/mali/common/mali_pp.c b/drivers/media/video/samsung/mali/common/mali_pp.c new file mode 100644 index 0000000..5549f82 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp.c @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2011-2012 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_pp.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "regs/mali_200_regs.h" +#include "mali_kernel_common.h" +#include "mali_kernel_core.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" +#endif + +/* See mali_gp.c file for description on how to handle the interrupt mask. + * This is how to do it on PP: mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + */ + +#define MALI_MAX_NUMBER_OF_PP_CORES 8 + +/** + * Definition of the PP core struct + * Used to track a PP core in the system. + */ +struct mali_pp_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent group for this core */ + _mali_osk_irq_t *irq; /**< IRQ handler */ + u32 core_id; /**< Unique core ID */ + struct mali_pp_job *running_job; /**< Current running (super) job */ + u32 running_sub_job; /**< Current running sub job */ + _mali_osk_timer_t *timeout_timer; /**< timeout timer for this core */ + u32 timeout_job_id; /**< job id for the timed out job - relevant only if pp_core_timed_out == MALI_TRUE */ + mali_bool core_timed_out; /**< if MALI_TRUE, this pp core has timed out; if MALI_FALSE, no timeout on this pp core */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src0_used; /**< The selected performance counter 0 when a job is running */ + u32 counter_src1_used; /**< The selected performance counter 1 when a job is running */ +}; + +static struct mali_pp_core* mali_global_pp_cores[MALI_MAX_NUMBER_OF_PP_CORES]; +static u32 mali_global_num_pp_cores = 0; + +/* Interrupt handlers */ +static _mali_osk_errcode_t mali_pp_upper_half(void *data); +static void mali_pp_bottom_half(void *data); +static void mali_pp_irq_probe_trigger(void *data); +static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data); +static void mali_pp_post_process_job(struct mali_pp_core *core); +static void mali_pp_timeout(void *data); + +struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t *resource, struct mali_group *group) +{ + struct mali_pp_core* core = NULL; + + MALI_DEBUG_PRINT(2, ("Mali PP: Creating Mali PP core: %s\n", resource->description)); + MALI_DEBUG_PRINT(2, ("Mali PP: Base address of PP core: 0x%x\n", resource->base)); + + if (mali_global_num_pp_cores >= MALI_MAX_NUMBER_OF_PP_CORES) + { + MALI_PRINT_ERROR(("Mali PP: Too many PP core objects created\n")); + return NULL; + } + + core = _mali_osk_malloc(sizeof(struct mali_pp_core)); + if (NULL != core) + { + core->group = group; + core->core_id = mali_global_num_pp_cores; + core->running_job = NULL; + core->counter_src0 = MALI_HW_CORE_NO_COUNTER; + core->counter_src1 = MALI_HW_CORE_NO_COUNTER; + core->counter_src0_used = MALI_HW_CORE_NO_COUNTER; + core->counter_src1_used = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI200_REG_SIZEOF_REGISTER_BANK)) + { + _mali_osk_errcode_t ret; + + mali_group_lock(group); + ret = mali_pp_reset(core); + mali_group_unlock(group); + + if (_MALI_OSK_ERR_OK == ret) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + core->irq = _mali_osk_irq_init(resource->irq, + mali_pp_upper_half, + mali_pp_bottom_half, + mali_pp_irq_probe_trigger, + mali_pp_irq_probe_ack, + core, + "mali_pp_irq_handlers"); + if (NULL != core->irq) + { + /* Initialise the timeout timer */ + core->timeout_timer = _mali_osk_timer_init(); + if(NULL != core->timeout_timer) + { + _mali_osk_timer_setcallback(core->timeout_timer, mali_pp_timeout, (void *)core); + + mali_global_pp_cores[mali_global_num_pp_cores] = core; + mali_global_num_pp_cores++; + + return core; + } + else + { + MALI_PRINT_ERROR(("Failed to setup timeout timer for PP core %s\n", core->hw_core.description)); + /* Release IRQ handlers */ + _mali_osk_irq_term(core->irq); + } + } + else + { + MALI_PRINT_ERROR(("Mali PP: Failed to setup interrupt handlers for PP core %s\n", core->hw_core.description)); + } + } + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Mali PP: Failed to allocate memory for PP core\n")); + } + + return NULL; +} + +void mali_pp_delete(struct mali_pp_core *core) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(core); + + _mali_osk_timer_term(core->timeout_timer); + _mali_osk_irq_term(core->irq); + mali_hw_core_delete(&core->hw_core); + + /* Remove core from global list */ + for (i = 0; i < mali_global_num_pp_cores; i++) + { + if (mali_global_pp_cores[i] == core) + { + mali_global_pp_cores[i] = NULL; + mali_global_num_pp_cores--; + break; + } + } + + _mali_osk_free(core); +} + +void mali_pp_stop_bus(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + /* Will only send the stop bus command, and not wait for it to complete */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); +} + +_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + /* Send the stop bus command. */ + mali_pp_stop_bus(core); + + /* Wait for bus to be stopped */ + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) + break; + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali PP: Failed to stop bus on %s. Status: 0x%08x\n", core->hw_core.description, mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core) +{ + /* Bus must be stopped before calling this function */ + const int reset_finished_loop_count = 15; + const u32 reset_invalid_value = 0xC0FFE000; + const u32 reset_check_value = 0xC01A0000; + int i; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(2, ("Mali PP: Hard reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_pp_post_process_job(core); /* @@@@ is there some cases where it is unsafe to post process the job here? */ + + /* Set register to a bogus value. The register will be used to detect when reset is complete */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_invalid_value); + + /* Force core to reset */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET); + + /* Wait for reset to be complete */ + for (i = 0; i < reset_finished_loop_count; i++) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_check_value); + if (reset_check_value == mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW)) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (i == reset_finished_loop_count) + { + MALI_PRINT_ERROR(("Mali PP: The hard reset loop didn't work, unable to recover\n")); + } + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, 0x00000000); /* set it back to the default */ + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali PP: Reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_pp_post_process_job(core); /* @@@@ is there some cases where it is unsafe to post process the job here? */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ + +#if defined(USING_MALI200) + + /* On Mali-200, stop the bus, then do a hard reset of the core */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali PP: Failed to stop bus for core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT ; + } + + /* the bus was stopped OK, do the hard reset */ + mali_pp_hard_reset(core); + +#elif defined(USING_MALI400) + + /* Mali-300 and Mali-400 have a safe reset command which we use */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI400PP_REG_VAL_IRQ_RESET_COMPLETED); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_DEBUG_PRINT(2, ("Mali PP: Failed to reset core %s, Status: 0x%08x\n", core->hw_core.description, mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + return _MALI_OSK_ERR_FAULT; + } +#else +#error "no supported mali core defined" +#endif + + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job) +{ + u32 *frame_registers = mali_pp_job_get_frame_registers(job); + u32 *wb0_registers = mali_pp_job_get_wb0_registers(job); + u32 *wb1_registers = mali_pp_job_get_wb1_registers(job); + u32 *wb2_registers = mali_pp_job_get_wb2_registers(job); + core->counter_src0_used = core->counter_src0; + core->counter_src1_used = core->counter_src1; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_FRAME, frame_registers, MALI200_NUM_REGS_FRAME); + if (0 != sub_job) + { + /* + * There are two frame registers which are different for each sub job. + * For the first sub job, these are correctly represented in the frame register array, + * but we need to patch these for all other sub jobs + */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_FRAME, mali_pp_job_get_addr_frame(job, sub_job)); + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_STACK, mali_pp_job_get_addr_stack(job, sub_job)); + } + + if (wb0_registers[0]) /* M200_WB0_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB0, wb0_registers, MALI200_NUM_REGS_WBx); + } + + if (wb1_registers[0]) /* M200_WB1_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB1, wb1_registers, MALI200_NUM_REGS_WBx); + } + + if (wb2_registers[0]) /* M200_WB2_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB2, wb2_registers, MALI200_NUM_REGS_WBx); + } + + /* This selects which performance counters we are reading */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used || MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + /* global_config has enabled HW counters, this will override anything specified by user space */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + } + else + { + /* Use HW counters from job object, if any */ + u32 perf_counter_flag = mali_pp_job_get_perf_counter_flag(job); + if (0 != perf_counter_flag) + { + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) + { + core->counter_src0_used = mali_pp_job_get_perf_counter_src0(job); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) + { + core->counter_src1_used = mali_pp_job_get_perf_counter_src1(job); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + } + } + + MALI_DEBUG_PRINT(3, ("Mali PP: Starting job 0x%08X part %u/%u on PP core %s\n", job, sub_job + 1, mali_pp_job_get_sub_job_count(job), core->hw_core.description)); + + /* Adding barrier to make sure all rester writes are finished */ + _mali_osk_write_mem_barrier(); + + /* This is the command that starts the core. */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); + + /* Adding barrier to make sure previous rester writes is finished */ + _mali_osk_write_mem_barrier(); + + /* Setup the timeout timer value and save the job id for the job running on the pp core */ + _mali_osk_timer_add(core->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); + core->timeout_job_id = mali_pp_job_get_id(job); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, job->frame_builder_id, job->flush_id, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id), job->pid, job->tid, 0, 0, 0); +#endif + + core->running_job = job; + core->running_sub_job = sub_job; +} + +u32 mali_pp_core_get_version(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION); +} + +u32 mali_pp_core_get_id(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->core_id; +} + +mali_bool mali_pp_core_set_counter_src0(struct mali_pp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src0 = counter; + return MALI_TRUE; +} + +mali_bool mali_pp_core_set_counter_src1(struct mali_pp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src1 = counter; + return MALI_TRUE; +} + +u32 mali_pp_core_get_counter_src0(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src0; +} + +u32 mali_pp_core_get_counter_src1(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src1; +} + +struct mali_pp_core* mali_pp_get_global_pp_core(u32 index) +{ + if (MALI_MAX_NUMBER_OF_PP_CORES > index) + { + return mali_global_pp_cores[index]; + } + + return NULL; +} + +u32 mali_pp_get_glob_num_pp_cores(void) +{ + return mali_global_num_pp_cores; +} + +u32 mali_pp_get_max_num_pp_cores(void) +{ + return MALI_MAX_NUMBER_OF_PP_CORES; +} + +/* ------------- interrupt handling below ------------------ */ +static _mali_osk_errcode_t mali_pp_upper_half(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); + if (MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout) + { + /* Mask out all IRQs from this core until IRQ is handled */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); +#endif + + /* We do need to handle this in a bottom half */ + _mali_osk_irq_schedulework(core->irq); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_pp_bottom_half(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + u32 irq_errors; + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_START| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); +#endif +#endif + + mali_group_lock(core->group); /* Group lock grabbed in core handlers, but released in common group handler */ + + if ( MALI_FALSE == mali_group_power_is_on(core->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", core->hw_core.description)); + mali_group_unlock(core->group); + return; + } + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED; + + MALI_DEBUG_PRINT(4, ("Mali PP: Bottom half IRQ 0x%08X from core %s\n", irq_readout, core->hw_core.description)); + + if (irq_readout & MALI200_REG_VAL_IRQ_END_OF_FRAME) + { + mali_pp_post_process_job(core); + MALI_DEBUG_PRINT(3, ("Mali PP: Job completed, calling group handler\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_COMPLETED); /* Will release group lock */ + return; + } + + /* + * Now lets look at the possible error cases (IRQ indicating error or timeout) + * END_OF_FRAME and HANG interrupts are not considered error. + */ + irq_errors = irq_readout & ~(MALI200_REG_VAL_IRQ_END_OF_FRAME|MALI200_REG_VAL_IRQ_HANG); + if (0 != irq_errors) + { + mali_pp_post_process_job(core); + MALI_PRINT_ERROR(("Mali PP: Unknown interrupt 0x%08X from core %s, aborting job\n", + irq_readout, core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_FAILED); /* Will release group lock */ + return; + } + else if (MALI_TRUE == core->core_timed_out) /* SW timeout */ + { + if (core->timeout_job_id == mali_pp_job_get_id(core->running_job)) + { + mali_pp_post_process_job(core); + MALI_DEBUG_PRINT(2, ("Mali PP: Job %d timed out on core %s\n", + mali_pp_job_get_id(core->running_job), core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_TIMED_OUT); /* Will release group lock */ + } + else + { + mali_group_unlock(core->group); + } + core->core_timed_out = MALI_FALSE; + return; + } + else if (irq_readout & MALI200_REG_VAL_IRQ_HANG) + { + /* Just ignore hang interrupts, the job timer will detect hanging jobs anyways */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_HANG); + } + + /* + * The only way to get here is if we got a HANG interrupt, which we ignore. + * Re-enable interrupts and let core continue to run + */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + mali_group_unlock(core->group); + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_STOP| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); +#endif +#endif +} + +static void mali_pp_irq_probe_trigger(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); /* @@@@ This should not be needed */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); +} + +static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); + if (MALI200_REG_VAL_IRQ_FORCE_HANG & irq_readout) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + + +/* ------ local helper functions below --------- */ +static void mali_pp_post_process_job(struct mali_pp_core *core) +{ + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (NULL != core->running_job) + { + u32 val0 = 0; + u32 val1 = 0; +#if MALI_TIMELINE_PROFILING_ENABLED + int counter_index = COUNTER_FP0_C0 + (2 * core->core_id); +#endif + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + val0 = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE); + if (mali_pp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE && mali_pp_job_get_perf_counter_src0(core->running_job) == core->counter_src0_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_pp_job_set_perf_counter_value0(core->running_job, core->running_sub_job, val0); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_pp_job_set_perf_counter_value0(core->running_job, core->running_sub_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(counter_index, val0); +#endif + } + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + val1 = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE); + if (mali_pp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE && mali_pp_job_get_perf_counter_src1(core->running_job) == core->counter_src1_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_pp_job_set_perf_counter_value1(core->running_job, core->running_sub_job, val1); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_pp_job_set_perf_counter_value1(core->running_job, core->running_sub_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(counter_index + 1, val1); +#endif + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id), + val0, val1, core->counter_src0_used | (core->counter_src1_used << 8), 0, 0); +#endif + + /* We are no longer running a job... */ + core->running_job = NULL; + _mali_osk_timer_del(core->timeout_timer); + } +} + +/* callback function for pp core timeout */ +static void mali_pp_timeout(void *data) +{ + struct mali_pp_core * core = ((struct mali_pp_core *)data); + + MALI_DEBUG_PRINT(3, ("Mali PP: TIMEOUT callback \n")); + core->core_timed_out = MALI_TRUE; + _mali_osk_irq_schedulework(core->irq); +} + +#if 0 +static void mali_pp_print_registers(struct mali_pp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_VERSION = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_RAWSTAT = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_MASK = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE))); +} +#endif + +#if 0 +void mali_pp_print_state(struct mali_pp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali PP: State: 0x%08x\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) )); +} +#endif + +#if MALI_STATE_TRACKING +u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "\tPP #%d: %s\n", core->core_id, core->hw_core.description); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_pp.h b/drivers/media/video/samsung/mali/common/mali_pp.h new file mode 100644 index 0000000..9b425a0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_PP_H__ +#define __MALI_PP_H__ + +#include "mali_osk.h" +#include "mali_pp_job.h" + +struct mali_pp_core; +struct mali_group; + +_mali_osk_errcode_t mali_pp_initialize(void); +void mali_pp_terminate(void); + +struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t * resource, struct mali_group *group); +void mali_pp_delete(struct mali_pp_core *core); + +void mali_pp_stop_bus(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core); + +void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job); + +u32 mali_pp_core_get_version(struct mali_pp_core *core); + +u32 mali_pp_core_get_id(struct mali_pp_core *core); + +mali_bool mali_pp_core_set_counter_src0(struct mali_pp_core *core, u32 counter); +mali_bool mali_pp_core_set_counter_src1(struct mali_pp_core *core, u32 counter); +u32 mali_pp_core_get_counter_src0(struct mali_pp_core *core); +u32 mali_pp_core_get_counter_src1(struct mali_pp_core *core); +struct mali_pp_core* mali_pp_get_global_pp_core(u32 index); +u32 mali_pp_get_glob_num_pp_cores(void); +u32 mali_pp_get_max_num_pp_cores(void); +/* Debug */ +u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size); + +#endif /* __MALI_PP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pp_job.c b/drivers/media/video/samsung/mali/common/mali_pp_job.c new file mode 100644 index 0000000..1efcfda --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_job.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011-2012 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_pp_job.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_kernel_common.h" +#include "mali_uk_types.h" + +struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *args, u32 id) +{ + struct mali_pp_job *job; + + if (args->num_cores > _MALI_PP_MAX_SUB_JOBS) + { + MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n")); + return NULL; + } + + job = _mali_osk_malloc(sizeof(struct mali_pp_job)); + if (NULL != job) + { + u32 i; + _mali_osk_list_init(&job->list); + job->session = session; + job->id = id; + job->user_id = args->user_job_ptr; + _mali_osk_memcpy(job->frame_registers, args->frame_registers, sizeof(job->frame_registers)); + _mali_osk_memcpy(job->frame_registers_addr_frame, args->frame_registers_addr_frame, sizeof(job->frame_registers_addr_frame)); + _mali_osk_memcpy(job->frame_registers_addr_stack, args->frame_registers_addr_stack, sizeof(job->frame_registers_addr_stack)); + + /* Only copy write back registers for the units that are enabled */ + job->wb0_registers[0] = 0; + job->wb1_registers[0] = 0; + job->wb2_registers[0] = 0; + if (args->wb0_registers[0]) /* M200_WB0_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb0_registers, args->wb0_registers, sizeof(job->wb0_registers)); + } + if (args->wb1_registers[0]) /* M200_WB1_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb1_registers, args->wb1_registers, sizeof(job->wb1_registers)); + } + if (args->wb2_registers[0]) /* M200_WB2_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb2_registers, args->wb2_registers, sizeof(job->wb2_registers)); + } + + job->perf_counter_flag = args->perf_counter_flag; + job->perf_counter_src0 = args->perf_counter_src0; + job->perf_counter_src1 = args->perf_counter_src1; + for (i = 0; i < args->num_cores; i++) + { + job->perf_counter_value0[i] = 0; + job->perf_counter_value1[i] = 0; + } + job->sub_job_count = args->num_cores; + job->sub_jobs_started = 0; + job->sub_jobs_completed = 0; + job->sub_job_errors = 0; + + job->pid = _mali_osk_get_pid(); + job->tid = _mali_osk_get_tid(); + job->frame_builder_id = args->frame_builder_id; + job->flush_id = args->flush_id; + + return job; + } + + return NULL; +} + +void mali_pp_job_delete(struct mali_pp_job *job) +{ + _mali_osk_free(job); +} + +_mali_osk_errcode_t mali_pp_job_check(struct mali_pp_job *job) +{ + if ((0 == job->frame_registers[0]) || (0 == job->frame_registers[1])) + { + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} diff --git a/drivers/media/video/samsung/mali/common/mali_pp_job.h b/drivers/media/video/samsung/mali/common/mali_pp_job.h new file mode 100644 index 0000000..7fe87f8 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_job.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2011-2012 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. + */ + +#ifndef __MALI_PP_JOB_H__ +#define __MALI_PP_JOB_H__ + +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" +#include "mali_session.h" +#include "mali_kernel_common.h" +#include "regs/mali_200_regs.h" + +/** + * The structure represends a PP job, including all sub-jobs + * (This struct unfortunatly needs to be public because of how the _mali_osk_list_* + * mechanism works) + */ +struct mali_pp_job +{ + _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ + struct mali_session_data *session; /**< Session which submitted this job */ + u32 id; /**< identifier for this job in kernel space (sequencial numbering) */ + u32 user_id; /**< identifier for the job in user space */ + u32 frame_registers[_MALI_PP_MAX_FRAME_REGISTERS]; /**< core specific registers associated with this job, see ARM DDI0415A */ + u32 frame_registers_addr_frame[_MALI_PP_MAX_SUB_JOBS - 1]; /**< ADDR_FRAME registers for sub job 1-7 */ + u32 frame_registers_addr_stack[_MALI_PP_MAX_SUB_JOBS - 1]; /**< ADDR_STACK registers for sub job 1-7 */ + u32 wb0_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 0 registers */ + u32 wb1_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 1 registers */ + u32 wb2_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 2 registers */ + u32 perf_counter_flag; /**< bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ + u32 perf_counter_src0; /**< Source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_src1; /**< Source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_value0[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 0 (to be returned to user space), one for each sub job */ + u32 perf_counter_value1[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 1 (to be returned to user space), one for each sub job */ + u32 sub_job_count; /**< Total number of sub-jobs in this superjob */ + u32 sub_jobs_started; /**< Total number of sub-jobs started (always started in ascending order) */ + u32 sub_jobs_completed; /**< Number of completed sub-jobs in this superjob */ + u32 sub_job_errors; /**< Bitfield with errors (errors for each single sub-job is or'ed together) */ + u32 pid; /**< Process ID of submitting process */ + u32 tid; /**< Thread ID of submitting thread */ + u32 frame_builder_id; /**< id of the originating frame builder */ + u32 flush_id; /**< flush id within the originating frame builder */ +}; + +struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *args, u32 id); +void mali_pp_job_delete(struct mali_pp_job *job); + +_mali_osk_errcode_t mali_pp_job_check(struct mali_pp_job *job); + +/****************************************************** + * simple utility functions for dealing with pp jobs: + *****************************************************/ + +MALI_STATIC_INLINE u32 mali_pp_job_get_id(struct mali_pp_job *job) +{ + return (NULL == job) ? 0 : job->id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_user_id(struct mali_pp_job *job) +{ + return job->user_id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_frame_builder_id(struct mali_pp_job *job) +{ + return job->frame_builder_id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_flush_id(struct mali_pp_job *job) +{ + return job->flush_id; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_frame_registers(struct mali_pp_job *job) +{ + return job->frame_registers; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_addr_frame(struct mali_pp_job *job, u32 sub_job) +{ + if (sub_job == 0) + { + return job->frame_registers[MALI200_REG_ADDR_FRAME / sizeof(u32)]; + } + else if (sub_job < _MALI_PP_MAX_SUB_JOBS) + { + return job->frame_registers_addr_frame[sub_job - 1]; + } + + return 0; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_addr_stack(struct mali_pp_job *job, u32 sub_job) +{ + if (sub_job == 0) + { + return job->frame_registers[MALI200_REG_ADDR_STACK / sizeof(u32)]; + } + else if (sub_job < _MALI_PP_MAX_SUB_JOBS) + { + return job->frame_registers_addr_stack[sub_job - 1]; + } + + return 0; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb0_registers(struct mali_pp_job *job) +{ + return job->wb0_registers; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb1_registers(struct mali_pp_job *job) +{ + return job->wb1_registers; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb2_registers(struct mali_pp_job *job) +{ + return job->wb2_registers; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb0(struct mali_pp_job *job) +{ + job->wb0_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb1(struct mali_pp_job *job) +{ + job->wb1_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb2(struct mali_pp_job *job) +{ + job->wb2_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE struct mali_session_data *mali_pp_job_get_session(struct mali_pp_job *job) +{ + return job->session; +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_has_unstarted_sub_jobs(struct mali_pp_job *job) +{ + return (job->sub_jobs_started < job->sub_job_count) ? MALI_TRUE : MALI_FALSE; +} + +/* Function used when we are terminating a session with jobs. Return TRUE if it has a rendering job. + Makes sure that no new subjobs is started. */ +MALI_STATIC_INLINE mali_bool mali_pp_job_is_currently_rendering_and_if_so_abort_new_starts(struct mali_pp_job *job) +{ + /* All can not be started, since then it would not be in the job queue */ + MALI_DEBUG_ASSERT( job->sub_jobs_started != job->sub_job_count ); + + /* If at least one job is started */ + if ( (job->sub_jobs_started > 0) ) + { + /* If at least one job is currently being rendered, and thus assigned to a group and core */ + if (job->sub_jobs_started > job->sub_jobs_completed ) + { + u32 jobs_remaining = job->sub_job_count - job->sub_jobs_started; + job->sub_jobs_started += jobs_remaining; + job->sub_jobs_completed += jobs_remaining; + job->sub_job_errors += jobs_remaining; + /* Returning TRUE indicating that we can not delete this job which is being redered */ + return MALI_TRUE; + } + } + /* The job is not being rendered to at the moment and can then safely be deleted */ + return MALI_FALSE; +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_is_complete(struct mali_pp_job *job) +{ + return (job->sub_job_count == job->sub_jobs_completed) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_first_unstarted_sub_job(struct mali_pp_job *job) +{ + return job->sub_jobs_started; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_sub_job_count(struct mali_pp_job *job) +{ + return job->sub_job_count; +} + +MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_started(struct mali_pp_job *job, u32 sub_job) +{ + /* Assert that we are marking the "first unstarted sub job" as started */ + MALI_DEBUG_ASSERT(job->sub_jobs_started == sub_job); + job->sub_jobs_started++; +} + +MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_completed(struct mali_pp_job *job, mali_bool success) +{ + job->sub_jobs_completed++; + if ( MALI_FALSE == success ) + { + job->sub_job_errors++; + } +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_was_success(struct mali_pp_job *job) +{ + if ( 0 == job->sub_job_errors ) + { + return MALI_TRUE; + } + return MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_flag(struct mali_pp_job *job) +{ + return job->perf_counter_flag; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_src0(struct mali_pp_job *job) +{ + return job->perf_counter_src0; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_src1(struct mali_pp_job *job) +{ + return job->perf_counter_src1; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value0(struct mali_pp_job *job, u32 sub_job) +{ + return job->perf_counter_value0[sub_job]; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value1(struct mali_pp_job *job, u32 sub_job) +{ + return job->perf_counter_value1[sub_job]; +} + +MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value0(struct mali_pp_job *job, u32 sub_job, u32 value) +{ + job->perf_counter_value0[sub_job] = value; +} + +MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value1(struct mali_pp_job *job, u32 sub_job, u32 value) +{ + job->perf_counter_value1[sub_job] = value; +} + +#endif /* __MALI_PP_JOB_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c new file mode 100644 index 0000000..ce07a76 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2012 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_pp_scheduler.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_scheduler.h" +#include "mali_pp.h" +#include "mali_pp_job.h" +#include "mali_group.h" +#include "mali_cluster.h" + +/* Maximum of 8 PP cores (a group can only have maximum of 1 PP core) */ +#define MALI_MAX_NUMBER_OF_PP_GROUPS 8 + +static mali_bool mali_pp_scheduler_is_suspended(void); + +enum mali_pp_slot_state +{ + MALI_PP_SLOT_STATE_IDLE, + MALI_PP_SLOT_STATE_WORKING, +}; + +/* A render slot is an entity which jobs can be scheduled onto */ +struct mali_pp_slot +{ + struct mali_group *group; + /* + * We keep track of the state here as well as in the group object + * so we don't need to take the group lock so often (and also avoid clutter with the working lock) + */ + enum mali_pp_slot_state state; +}; + +static u32 pp_version = 0; +static _MALI_OSK_LIST_HEAD(job_queue); /* List of jobs with some unscheduled work */ +static struct mali_pp_slot slots[MALI_MAX_NUMBER_OF_PP_GROUPS]; +static u32 num_slots = 0; +static u32 num_slots_idle = 0; + +/* Variables to allow safe pausing of the scheduler */ +static _mali_osk_wait_queue_t *pp_scheduler_working_wait_queue = NULL; +static u32 pause_count = 0; + +static _mali_osk_lock_t *pp_scheduler_lock = NULL; +/* Contains tid of thread that locked the scheduler or 0, if not locked */ +MALI_DEBUG_CODE(static u32 pp_scheduler_lock_owner = 0); + +_mali_osk_errcode_t mali_pp_scheduler_initialize(void) +{ + u32 i; + + _MALI_OSK_INIT_LIST_HEAD(&job_queue); + + pp_scheduler_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_SCHEDULER); + if (NULL == pp_scheduler_lock) + { + return _MALI_OSK_ERR_NOMEM; + } + + pp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); + if (NULL == pp_scheduler_working_wait_queue) + { + _mali_osk_lock_term(pp_scheduler_lock); + return _MALI_OSK_ERR_NOMEM; + } + + /* Find all the available PP cores */ + for (i = 0; i < mali_cluster_get_glob_num_clusters(); i++) + { + u32 group_id = 0; + struct mali_cluster *curr_cluster = mali_cluster_get_global_cluster(i); + struct mali_group *group = mali_cluster_get_group(curr_cluster, group_id); + while (NULL != group) + { + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + if (NULL != pp_core) + { + if (0 == pp_version) + { + /* Retrieve PP version from first avaiable PP core */ + pp_version = mali_pp_core_get_version(pp_core); + } + slots[num_slots].group = group; + slots[num_slots].state = MALI_PP_SLOT_STATE_IDLE; + num_slots++; + num_slots_idle++; + } + group_id++; + group = mali_cluster_get_group(curr_cluster, group_id); + } + } + + return _MALI_OSK_ERR_OK; +} + +void mali_pp_scheduler_terminate(void) +{ + _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue); + _mali_osk_lock_term(pp_scheduler_lock); +} + +MALI_STATIC_INLINE void mali_pp_scheduler_lock(void) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(pp_scheduler_lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali PP scheduler: PP scheduler lock taken\n")); + MALI_DEBUG_ASSERT(0 == pp_scheduler_lock_owner); + MALI_DEBUG_CODE(pp_scheduler_lock_owner = _mali_osk_get_tid()); +} + +MALI_STATIC_INLINE void mali_pp_scheduler_unlock(void) +{ + MALI_DEBUG_PRINT(5, ("Mali PP scheduler: Releasing PP scheduler lock\n")); + MALI_DEBUG_ASSERT(_mali_osk_get_tid() == pp_scheduler_lock_owner); + MALI_DEBUG_CODE(pp_scheduler_lock_owner = 0); + _mali_osk_lock_signal(pp_scheduler_lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +MALI_STATIC_INLINE void mali_pp_scheduler_assert_locked(void) +{ + MALI_DEBUG_ASSERT(_mali_osk_get_tid() == pp_scheduler_lock_owner); +} +#define MALI_ASSERT_PP_SCHEDULER_LOCKED() mali_pp_scheduler_assert_locked() +#else +#define MALI_ASSERT_PP_SCHEDULER_LOCKED() +#endif + +static void mali_pp_scheduler_schedule(void) +{ + u32 i; + struct mali_pp_job *job; +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + struct mali_session_data * session; +#endif + + MALI_ASSERT_PP_SCHEDULER_LOCKED(); + + if (0 < pause_count || 0 == num_slots_idle || _mali_osk_list_empty(&job_queue)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", + pause_count, num_slots_idle)); + return; /* Nothing to do, so early out */ + } + + +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP + if ( num_slots_idle < num_slots ) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started, since only %d/%d cores are available\n", num_slots_idle,num_slots)); + return; + } +#endif + +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + /* Finding initial session for the PP cores */ + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); + session = job->session; + if ( num_slots != num_slots_idle ) + { + for (i = 0; (i < num_slots) ; i++) + { + if ( slots[i].state == MALI_PP_SLOT_STATE_IDLE ) + { + continue; + } + session = mali_group_get_session(slots[i].group); + break; + } + } +#endif + + for (i = 0; (i < num_slots) && (0 < num_slots_idle); i++) + { + u32 sub_job; + + if (_mali_osk_list_empty(&job_queue)) /* move this check down to where we know we have started all sub jobs for this job??? */ + { + break; /* No more jobs to schedule, so early out */ + } + + if (MALI_PP_SLOT_STATE_IDLE != slots[i].state) + { + continue; + } + + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); + MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); /* All jobs on the job_queue should have unstarted sub jobs */ + + #if MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED + if ( (0==job->sub_jobs_started) && (num_slots_idle < num_slots) && (job->sub_job_count > num_slots_idle)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job with %d subjobs not started, since only %d/%d cores are available\n", job->sub_job_count, num_slots_idle,num_slots)); + return; + } + #endif + + #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + if ( job->session != session ) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started since existing job is from another application\n")); + return; + } + #endif + + sub_job = mali_pp_job_get_first_unstarted_sub_job(job); + + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Starting job %u (0x%08X) part %u/%u\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); + if (_MALI_OSK_ERR_OK == mali_group_start_pp_job(slots[i].group, job, sub_job)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job %u (0x%08X) part %u/%u started\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); + + /* Mark this sub job as started */ + mali_pp_job_mark_sub_job_started(job, sub_job); + + /* Mark slot as busy */ + slots[i].state = MALI_PP_SLOT_STATE_WORKING; + num_slots_idle--; + + if (!mali_pp_job_has_unstarted_sub_jobs(job)) + { + /* + * All sub jobs have now started for this job, remove this job from the job queue. + * The job will now only be referred to by the slots which are running it. + * The last slot to complete will make sure it is returned to user space. + */ + _mali_osk_list_del(&job->list); +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP + MALI_DEBUG_PRINT(6, ("Mali PP scheduler: Skip scheduling more jobs when MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP is set.\n")); + return; +#endif + } + } + else + { + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Failed to start PP job\n")); + return; + } + } +} + +static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job) +{ + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s)); + if (NULL != notobj) + { + u32 i; + u32 sub_jobs = mali_pp_job_get_sub_job_count(job); + mali_bool success = mali_pp_job_was_success(job); + + _mali_uk_pp_job_finished_s *jobres = notobj->result_buffer; + _mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ + jobres->user_job_ptr = mali_pp_job_get_user_id(job); + if (MALI_TRUE == success) + { + jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; + } + else + { + jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; + } + + for (i = 0; i < sub_jobs; i++) + { + jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i); + jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i); + } + + mali_session_send_notification(mali_pp_job_get_session(job), notobj); + } + else + { + MALI_PRINT_ERROR(("Mali PP scheduler: Unable to allocate notification object\n")); + } + + mali_pp_job_delete(job); +} + +void mali_pp_scheduler_do_schedule(void) +{ + mali_pp_scheduler_lock(); + + mali_pp_scheduler_schedule(); + + mali_pp_scheduler_unlock(); +} + +void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success) +{ + u32 i; + mali_bool job_is_done; + + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Job %u (0x%08X) part %u/%u completed (%s)\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job), success ? "success" : "failure")); + + mali_pp_scheduler_lock(); + + /* Find slot which was running this job */ + for (i = 0; i < num_slots; i++) + { + if (slots[i].group == group) + { + MALI_DEBUG_ASSERT(MALI_PP_SLOT_STATE_WORKING == slots[i].state); + slots[i].state = MALI_PP_SLOT_STATE_IDLE; + num_slots_idle++; + mali_pp_job_mark_sub_job_completed(job, success); + } + } + + /* If paused, then this was the last job, so wake up sleeping workers */ + if (pause_count > 0) + { + /* Wake up sleeping workers. Their wake-up condition is that + * num_slots == num_slots_idle, so unless we are done working, no + * threads will actually be woken up. + */ + _mali_osk_wait_queue_wake_up(pp_scheduler_working_wait_queue); + } + else + { + mali_pp_scheduler_schedule(); + } + + job_is_done = mali_pp_job_is_complete(job); + + mali_pp_scheduler_unlock(); + + if (job_is_done) + { + /* Send notification back to user space */ + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: All parts completed for job %u (0x%08X)\n", mali_pp_job_get_id(job), job)); + mali_pp_scheduler_return_job_to_user(job); + } +} + +void mali_pp_scheduler_suspend(void) +{ + mali_pp_scheduler_lock(); + pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ + mali_pp_scheduler_unlock(); + + /*mali_pp_scheduler_working_lock();*/ + /* We have now aquired the working lock, which means that we have successfully paused the scheduler */ + /*mali_pp_scheduler_working_unlock();*/ + + /* go to sleep. When woken up again (in mali_pp_scheduler_job_done), the + * mali_pp_scheduler_suspended() function will be called. This will return true + * iff state is idle and pause_count > 0, so if the core is active this + * will not do anything. + */ + _mali_osk_wait_queue_wait_event(pp_scheduler_working_wait_queue, mali_pp_scheduler_is_suspended); +} + +void mali_pp_scheduler_resume(void) +{ + mali_pp_scheduler_lock(); + pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ + if (0 == pause_count) + { + mali_pp_scheduler_schedule(); + } + mali_pp_scheduler_unlock(); +} + +_mali_osk_errcode_t _mali_ukk_pp_start_job(_mali_uk_pp_start_job_s *args) +{ + struct mali_session_data *session; + struct mali_pp_job *job; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + + session = (struct mali_session_data*)args->ctx; + + job = mali_pp_job_create(session, args, mali_scheduler_get_new_id()); + if (NULL == job) + { + return _MALI_OSK_ERR_NOMEM; + } + + if (_MALI_OSK_ERR_OK != mali_pp_job_check(job)) + { + /* Not a valid job, return to user immediately */ + mali_pp_job_mark_sub_job_completed(job, MALI_FALSE); /* Flagging the job as failed. */ + mali_pp_scheduler_return_job_to_user(job); /* This will also delete the job object */ + return _MALI_OSK_ERR_OK; /* User is notified via a notification, so this call is ok */ + } + + mali_pp_scheduler_lock(); + + _mali_osk_list_addtail(&job->list, &job_queue); + + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Job %u (0x%08X) with %u parts queued\n", mali_pp_job_get_id(job), job, mali_pp_job_get_sub_job_count(job))); + + mali_pp_scheduler_schedule(); + + mali_pp_scheduler_unlock(); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + args->number_of_cores = num_slots; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + args->version = pp_version; + return _MALI_OSK_ERR_OK; +} + +void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args) +{ + struct mali_session_data *session; + struct mali_pp_job *job; + struct mali_pp_job *tmp; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + + session = (struct mali_session_data*)args->ctx; + + mali_pp_scheduler_lock(); + + /* Check queue for jobs that match */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_pp_job, list) + { + if (mali_pp_job_get_session(job) == session && + mali_pp_job_get_frame_builder_id(job) == (u32)args->fb_id && + mali_pp_job_get_flush_id(job) == (u32)args->flush_id) + { + if (args->wbx & _MALI_UK_PP_JOB_WB0) + { + mali_pp_job_disable_wb0(job); + } + if (args->wbx & _MALI_UK_PP_JOB_WB1) + { + mali_pp_job_disable_wb1(job); + } + if (args->wbx & _MALI_UK_PP_JOB_WB2) + { + mali_pp_job_disable_wb2(job); + } + break; + } + } + + mali_pp_scheduler_unlock(); +} + +void mali_pp_scheduler_abort_session(struct mali_session_data *session) +{ + struct mali_pp_job *job, *tmp; + int i; + + mali_pp_scheduler_lock(); + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborting all jobs from session 0x%08x\n", session)); + + /* Check queue for jobs and remove */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_pp_job, list) + { + if (mali_pp_job_get_session(job) == session) + { + _mali_osk_list_del(&(job->list)); + + if ( mali_pp_job_is_currently_rendering_and_if_so_abort_new_starts(job) ) + { + /* The job is in the render pipeline, we can not delete it yet. */ + /* It will be deleted in the mali_group_abort_session() call below */ + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Keeping partially started PP job 0x%08x in queue\n", job)); + continue; + } + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Removing PP job 0x%08x from queue\n", job)); + mali_pp_job_delete(job); + } + } + + mali_pp_scheduler_unlock(); + + /* Abort running jobs from this session */ + for (i = 0; i < num_slots; i++) + { + struct mali_group *group = slots[i].group; + + MALI_DEBUG_PRINT(5, ("PP sched abort: Looking at group 0x%08x\n", group)); + + if (MALI_PP_SLOT_STATE_WORKING == slots[i].state) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Aborting session 0x%08x from group 0x%08x\n", session, group)); + + mali_group_abort_session(group, session); + } + } +} + +static mali_bool mali_pp_scheduler_is_suspended(void) +{ + mali_bool ret; + + mali_pp_scheduler_lock(); + ret = pause_count > 0 && num_slots == num_slots_idle; + mali_pp_scheduler_unlock(); + + return ret; +} + +#if MALI_STATE_TRACKING +u32 mali_pp_scheduler_dump_state(char *buf, u32 size) +{ + int n = 0; + int i; + + n += _mali_osk_snprintf(buf + n, size - n, "PP:\n"); + n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); + n += _mali_osk_snprintf(buf + n, size - n, "\n"); + + for (i = 0; i < num_slots; i++) + { + n += mali_group_dump_state(slots[i].group, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", slots[i].state); + } + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h new file mode 100644 index 0000000..48eb3bd --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef __MALI_PP_SCHEDULER_H__ +#define __MALI_PP_SCHEDULER_H__ + +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_pp_job.h" + +_mali_osk_errcode_t mali_pp_scheduler_initialize(void); +void mali_pp_scheduler_terminate(void); + +void mali_pp_scheduler_do_schedule(void); +void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success); + +void mali_pp_scheduler_suspend(void); +void mali_pp_scheduler_resume(void); + +/** @brief Abort all PP jobs from session running or queued + * + * This functions aborts all PP jobs from the specified session. Queued jobs are removed from the queue and jobs + * currently running on a core will be aborted. + * + * @param session Pointer to session whose jobs should be aborted + */ +void mali_pp_scheduler_abort_session(struct mali_session_data *session); + +u32 mali_pp_scheduler_dump_state(char *buf, u32 size); + +#endif /* __MALI_PP_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_scheduler.c b/drivers/media/video/samsung/mali/common/mali_scheduler.c new file mode 100644 index 0000000..52159a0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_scheduler.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 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_osk.h" + +static _mali_osk_atomic_t mali_job_autonumber; + +_mali_osk_errcode_t mali_scheduler_initialize(void) +{ + if ( _MALI_OSK_ERR_OK != _mali_osk_atomic_init(&mali_job_autonumber, 0)) + { + MALI_DEBUG_PRINT(1, ("Initialization of atomic job id counter failed.\n")); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +void mali_scheduler_terminate(void) +{ + _mali_osk_atomic_term(&mali_job_autonumber); +} + +u32 mali_scheduler_get_new_id(void) +{ + u32 job_id = _mali_osk_atomic_inc_return(&mali_job_autonumber); + return job_id; +} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem.h b/drivers/media/video/samsung/mali/common/mali_scheduler.h index 8caafe3..74f0947 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem.h +++ b/drivers/media/video/samsung/mali/common/mali_scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2012 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. @@ -8,10 +8,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_MEM_H__ -#define __MALI_KERNEL_MEM_H__ +#ifndef __MALI_SCHEDULER_H__ +#define __MALI_SCHEDULER_H__ -#include "mali_kernel_subsystem.h" -extern struct mali_kernel_subsystem mali_subsystem_memory; +#include "mali_osk.h" -#endif /* __MALI_KERNEL_MEM_H__ */ +_mali_osk_errcode_t mali_scheduler_initialize(void); +void mali_scheduler_terminate(void); + +u32 mali_scheduler_get_new_id(void); + +#endif /* __MALI_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_session.c b/drivers/media/video/samsung/mali/common/mali_session.c new file mode 100644 index 0000000..2394bb9 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_session.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 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_osk.h" +#include "mali_osk_list.h" +#include "mali_session.h" + +_MALI_OSK_LIST_HEAD(mali_sessions); + +_mali_osk_lock_t *mali_sessions_lock; + +_mali_osk_errcode_t mali_session_initialize(void) +{ + _MALI_OSK_INIT_LIST_HEAD(&mali_sessions); + + mali_sessions_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_SESSIONS); + + if (NULL == mali_sessions_lock) return _MALI_OSK_ERR_NOMEM; + + return _MALI_OSK_ERR_OK; +} + +void mali_session_terminate(void) +{ + _mali_osk_lock_term(mali_sessions_lock); +} + +void mali_session_add(struct mali_session_data *session) +{ + mali_session_lock(); + _mali_osk_list_add(&session->link, &mali_sessions); + mali_session_unlock(); +} + +void mali_session_remove(struct mali_session_data *session) +{ + mali_session_lock(); + _mali_osk_list_delinit(&session->link); + mali_session_unlock(); +} diff --git a/drivers/media/video/samsung/mali/common/mali_session.h b/drivers/media/video/samsung/mali/common/mali_session.h new file mode 100644 index 0000000..b47c340 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_session.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010, 2012 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. + */ + +#ifndef __MALI_SESSION_H__ +#define __MALI_SESSION_H__ + +#include "mali_mmu_page_directory.h" +#include "mali_kernel_descriptor_mapping.h" +#include "mali_osk.h" +#include "mali_osk_list.h" + +struct mali_session_data +{ + _mali_osk_notification_queue_t * ioctl_queue; + + _mali_osk_lock_t *memory_lock; /**< Lock protecting the vm manipulation */ + mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ + _mali_osk_list_t memory_head; /**< Track all the memory allocated in this session, for freeing on abnormal termination */ + + struct mali_page_directory *page_directory; /**< MMU page directory for this session */ + + _MALI_OSK_LIST_HEAD(link); /**< Link for list of all sessions */ +}; + +_mali_osk_errcode_t mali_session_initialize(void); +void mali_session_terminate(void); + +/* List of all sessions. Actual list head in mali_kernel_core.c */ +extern _mali_osk_list_t mali_sessions; +/* Lock to protect modification and access to the mali_sessions list */ +extern _mali_osk_lock_t *mali_sessions_lock; + +MALI_STATIC_INLINE void mali_session_lock(void) +{ + _mali_osk_lock_wait(mali_sessions_lock, _MALI_OSK_LOCKMODE_RW); +} + +MALI_STATIC_INLINE void mali_session_unlock(void) +{ + _mali_osk_lock_signal(mali_sessions_lock, _MALI_OSK_LOCKMODE_RW); +} + +void mali_session_add(struct mali_session_data *session); +void mali_session_remove(struct mali_session_data *session); +#define MALI_SESSION_FOREACH(session, tmp, link) \ + _MALI_OSK_LIST_FOREACHENTRY(session, tmp, &mali_sessions, struct mali_session_data, link) + +MALI_STATIC_INLINE struct mali_page_directory *mali_session_get_page_directory(struct mali_session_data *session) +{ + return session->page_directory; +} + +MALI_STATIC_INLINE void mali_session_send_notification(struct mali_session_data *session, _mali_osk_notification_t *object) +{ + _mali_osk_notification_queue_send(session->ioctl_queue, object); +} + +#endif /* __MALI_SESSION_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_uk_types.h b/drivers/media/video/samsung/mali/common/mali_uk_types.h deleted file mode 100644 index e114fa8..0000000 --- a/drivers/media/video/samsung/mali/common/mali_uk_types.h +++ /dev/null @@ -1,1176 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_uk_types.h - * Defines the types and constants used in the user-kernel interface - */ - -#ifndef __MALI_UK_TYPES_H__ -#define __MALI_UK_TYPES_H__ - -/* - * NOTE: Because this file can be included from user-side and kernel-side, - * it is up to the includee to ensure certain typedefs (e.g. u32) are already - * defined when #including this. - */ -#include "regs/mali_200_regs.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup uddapi Unified Device Driver (UDD) APIs - * - * @{ - */ - -/** - * @addtogroup u_k_api UDD User/Kernel Interface (U/K) APIs - * - * @{ - */ - -/** @defgroup _mali_uk_core U/K Core - * @{ */ - -/** Definition of subsystem numbers, to assist in creating a unique identifier - * for each U/K call. - * - * @see _mali_uk_functions */ -typedef enum -{ - _MALI_UK_CORE_SUBSYSTEM, /**< Core Group of U/K calls */ - _MALI_UK_MEMORY_SUBSYSTEM, /**< Memory Group of U/K calls */ - _MALI_UK_PP_SUBSYSTEM, /**< Fragment Processor Group of U/K calls */ - _MALI_UK_GP_SUBSYSTEM, /**< Vertex Processor Group of U/K calls */ - _MALI_UK_PROFILING_SUBSYSTEM, /**< Profiling Group of U/K calls */ - _MALI_UK_PMM_SUBSYSTEM, /**< Power Management Module Group of U/K calls */ - _MALI_UK_VSYNC_SUBSYSTEM, /**< VSYNC Group of U/K calls */ -} _mali_uk_subsystem_t; - -/** Within a function group each function has its unique sequence number - * to assist in creating a unique identifier for each U/K call. - * - * An ordered pair of numbers selected from - * ( \ref _mali_uk_subsystem_t,\ref _mali_uk_functions) will uniquely identify the - * U/K call across all groups of functions, and all functions. */ -typedef enum -{ - /** Core functions */ - - _MALI_UK_OPEN = 0, /**< _mali_ukk_open() */ - _MALI_UK_CLOSE, /**< _mali_ukk_close() */ - _MALI_UK_GET_SYSTEM_INFO_SIZE, /**< _mali_ukk_get_system_info_size() */ - _MALI_UK_GET_SYSTEM_INFO, /**< _mali_ukk_get_system_info() */ - _MALI_UK_WAIT_FOR_NOTIFICATION, /**< _mali_ukk_wait_for_notification() */ - _MALI_UK_GET_API_VERSION, /**< _mali_ukk_get_api_version() */ - _MALI_UK_POST_NOTIFICATION, /**< _mali_ukk_post_notification() */ - - /** Memory functions */ - - _MALI_UK_INIT_MEM = 0, /**< _mali_ukk_init_mem() */ - _MALI_UK_TERM_MEM, /**< _mali_ukk_term_mem() */ - _MALI_UK_GET_BIG_BLOCK, /**< _mali_ukk_get_big_block() */ - _MALI_UK_FREE_BIG_BLOCK, /**< _mali_ukk_free_big_block() */ - _MALI_UK_MAP_MEM, /**< _mali_ukk_mem_mmap() */ - _MALI_UK_UNMAP_MEM, /**< _mali_ukk_mem_munmap() */ - _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, /**< _mali_ukk_mem_get_mmu_page_table_dump_size() */ - _MALI_UK_DUMP_MMU_PAGE_TABLE, /**< _mali_ukk_mem_dump_mmu_page_table() */ - _MALI_UK_ATTACH_UMP_MEM, /**< _mali_ukk_attach_ump_mem() */ - _MALI_UK_RELEASE_UMP_MEM, /**< _mali_ukk_release_ump_mem() */ - _MALI_UK_MAP_EXT_MEM, /**< _mali_uku_map_external_mem() */ - _MALI_UK_UNMAP_EXT_MEM, /**< _mali_uku_unmap_external_mem() */ - _MALI_UK_VA_TO_MALI_PA, /**< _mali_uku_va_to_mali_pa() */ - - /** Common functions for each core */ - - _MALI_UK_START_JOB = 0, /**< Start a Fragment/Vertex Processor Job on a core */ - _MALI_UK_ABORT_JOB, /**< Abort a job */ - _MALI_UK_GET_NUMBER_OF_CORES, /**< Get the number of Fragment/Vertex Processor cores */ - _MALI_UK_GET_CORE_VERSION, /**< Get the Fragment/Vertex Processor version compatible with all cores */ - - /** Fragment Processor Functions */ - - _MALI_UK_PP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_pp_start_job() */ - _MALI_UK_PP_ABORT_JOB = _MALI_UK_ABORT_JOB, /**< _mali_ukk_pp_abort_job() */ - _MALI_UK_GET_PP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_pp_number_of_cores() */ - _MALI_UK_GET_PP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_pp_core_version() */ - - /** Vertex Processor Functions */ - - _MALI_UK_GP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_gp_start_job() */ - _MALI_UK_GP_ABORT_JOB = _MALI_UK_ABORT_JOB, /**< _mali_ukk_gp_abort_job() */ - _MALI_UK_GET_GP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_gp_number_of_cores() */ - _MALI_UK_GET_GP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_gp_core_version() */ - _MALI_UK_GP_SUSPEND_RESPONSE, /**< _mali_ukk_gp_suspend_response() */ - - /** Profiling functions */ - - _MALI_UK_PROFILING_START = 0, /**< __mali_uku_profiling_start() */ - _MALI_UK_PROFILING_ADD_EVENT, /**< __mali_uku_profiling_add_event() */ - _MALI_UK_PROFILING_STOP, /**< __mali_uku_profiling_stop() */ - _MALI_UK_PROFILING_GET_EVENT, /**< __mali_uku_profiling_get_event() */ - _MALI_UK_PROFILING_CLEAR, /**< __mali_uku_profiling_clear() */ - _MALI_UK_PROFILING_GET_CONFIG, /**< __mali_uku_profiling_get_config() */ - _MALI_UK_TRANSFER_SW_COUNTERS, - -#if USING_MALI_PMM - /** Power Management Module Functions */ - _MALI_UK_PMM_EVENT_MESSAGE = 0, /**< Raise an event message */ -#endif - - /** VSYNC reporting fuctions */ - _MALI_UK_VSYNC_EVENT_REPORT = 0, /**< _mali_ukk_vsync_event_report() */ - -} _mali_uk_functions; - -/** @brief Get the size necessary for system info - * - * @see _mali_ukk_get_system_info_size() - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 size; /**< [out] size of buffer necessary to hold system information data, in bytes */ -} _mali_uk_get_system_info_size_s; - - -/** @defgroup _mali_uk_getsysteminfo U/K Get System Info - * @{ */ - -/** - * Type definition for the core version number. - * Used when returning the version number read from a core - * - * Its format is that of the 32-bit Version register for a particular core. - * Refer to the "Mali200 and MaliGP2 3D Graphics Processor Technical Reference - * Manual", ARM DDI 0415C, for more information. - */ -typedef u32 _mali_core_version; - -/** - * Enum values for the different modes the driver can be put in. - * Normal is the default mode. The driver then uses a job queue and takes job objects from the clients. - * Job completion is reported using the _mali_ukk_wait_for_notification call. - * The driver blocks this io command until a job has completed or failed or a timeout occurs. - * - * The 'raw' mode is reserved for future expansion. - */ -typedef enum _mali_driver_mode -{ - _MALI_DRIVER_MODE_RAW = 1, /**< Reserved for future expansion */ - _MALI_DRIVER_MODE_NORMAL = 2 /**< Normal mode of operation */ -} _mali_driver_mode; - -/** @brief List of possible cores - * - * add new entries to the end of this enum */ -typedef enum _mali_core_type -{ - _MALI_GP2 = 2, /**< MaliGP2 Programmable Vertex Processor */ - _MALI_200 = 5, /**< Mali200 Programmable Fragment Processor */ - _MALI_400_GP = 6, /**< Mali400 Programmable Vertex Processor */ - _MALI_400_PP = 7, /**< Mali400 Programmable Fragment Processor */ - /* insert new core here, do NOT alter the existing values */ -} _mali_core_type; - -/** @brief Information about each Mali Core - * - * Information is stored in a linked list, which is stored entirely in the - * buffer pointed to by the system_info member of the - * _mali_uk_get_system_info_s arguments provided to _mali_ukk_get_system_info() - * - * Both Fragment Processor (PP) and Vertex Processor (GP) cores are represented - * by this struct. - * - * The type is reported by the type field, _mali_core_info::_mali_core_type. - * - * Each core is given a unique Sequence number identifying it, the core_nr - * member. - * - * Flags are taken directly from the resource's flags, and are currently unused. - * - * Multiple mali_core_info structs are linked in a single linked list using the next field - */ -typedef struct _mali_core_info -{ - _mali_core_type type; /**< Type of core */ - _mali_core_version version; /**< Core Version, as reported by the Core's Version Register */ - u32 reg_address; /**< Address of Registers */ - u32 core_nr; /**< Sequence number */ - u32 flags; /**< Flags. Currently Unused. */ - struct _mali_core_info * next; /**< Next core in Linked List */ -} _mali_core_info; - -/** @brief Capabilities of Memory Banks - * - * These may be used to restrict memory banks for certain uses. They may be - * used when access is not possible (e.g. Bus does not support access to it) - * or when access is possible but not desired (e.g. Access is slow). - * - * In the case of 'possible but not desired', there is no way of specifying - * the flags as an optimization hint, so that the memory could be used as a - * last resort. - * - * @see _mali_mem_info - */ -typedef enum _mali_bus_usage -{ - - _MALI_PP_READABLE = (1<<0), /** Readable by the Fragment Processor */ - _MALI_PP_WRITEABLE = (1<<1), /** Writeable by the Fragment Processor */ - _MALI_GP_READABLE = (1<<2), /** Readable by the Vertex Processor */ - _MALI_GP_WRITEABLE = (1<<3), /** Writeable by the Vertex Processor */ - _MALI_CPU_READABLE = (1<<4), /** Readable by the CPU */ - _MALI_CPU_WRITEABLE = (1<<5), /** Writeable by the CPU */ - _MALI_MMU_READABLE = _MALI_PP_READABLE | _MALI_GP_READABLE, /** Readable by the MMU (including all cores behind it) */ - _MALI_MMU_WRITEABLE = _MALI_PP_WRITEABLE | _MALI_GP_WRITEABLE, /** Writeable by the MMU (including all cores behind it) */ -} _mali_bus_usage; - -/** @brief Information about the Mali Memory system - * - * Information is stored in a linked list, which is stored entirely in the - * buffer pointed to by the system_info member of the - * _mali_uk_get_system_info_s arguments provided to _mali_ukk_get_system_info() - * - * Each element of the linked list describes a single Mali Memory bank. - * Each allocation can only come from one bank, and will not cross multiple - * banks. - * - * Each bank is uniquely identified by its identifier member. On Mali-nonMMU - * systems, to allocate from this bank, the value of identifier must be passed - * as the type_id member of the _mali_uk_get_big_block_s arguments to - * _mali_ukk_get_big_block. - * - * On Mali-MMU systems, there is only one bank, which describes the maximum - * possible address range that could be allocated (which may be much less than - * the available physical memory) - * - * The flags member describes the capabilities of the memory. It is an error - * to attempt to build a job for a particular core (PP or GP) when the memory - * regions used do not have the capabilities for supporting that core. This - * would result in a job abort from the Device Driver. - * - * For example, it is correct to build a PP job where read-only data structures - * are taken from a memory with _MALI_PP_READABLE set and - * _MALI_PP_WRITEABLE clear, and a framebuffer with _MALI_PP_WRITEABLE set and - * _MALI_PP_READABLE clear. However, it would be incorrect to use a framebuffer - * where _MALI_PP_WRITEABLE is clear. - */ -typedef struct _mali_mem_info -{ - u32 size; /**< Size of the memory bank in bytes */ - _mali_bus_usage flags; /**< Capabilitiy flags of the memory */ - u32 maximum_order_supported; /**< log2 supported size */ - u32 identifier; /**< Unique identifier, to be used in allocate calls */ - struct _mali_mem_info * next; /**< Next List Link */ -} _mali_mem_info; - -/** @brief Info about the whole Mali system. - * - * This Contains a linked list of the cores and memory banks available. Each - * list pointer will remain inside the system_info buffer supplied in the - * _mali_uk_get_system_info_s arguments to a _mali_ukk_get_system_info call. - * - * The has_mmu member must be inspected to ensure the correct group of - * Memory function calls is obtained - that is, those for either Mali-MMU - * or Mali-nonMMU. @see _mali_uk_memory - */ -typedef struct _mali_system_info -{ - _mali_core_info * core_info; /**< List of _mali_core_info structures */ - _mali_mem_info * mem_info; /**< List of _mali_mem_info structures */ - u32 has_mmu; /**< Non-zero if Mali-MMU present. Zero otherwise. */ - _mali_driver_mode drivermode; /**< Reserved. Must always be _MALI_DRIVER_MODE_NORMAL */ -} _mali_system_info; - -/** @brief Arguments to _mali_ukk_get_system_info() - * - * A buffer of the size returned by _mali_ukk_get_system_info_size() must be - * allocated, and the pointer to this buffer must be written into the - * system_info member. The buffer must be suitably aligned for storage of - * the _mali_system_info structure - for example, one returned by - * _mali_osk_malloc(), which will be suitably aligned for any structure. - * - * The ukk_private member must be set to zero by the user-side. Under an OS - * implementation, the U/K interface must write in the user-side base address - * into the ukk_private member, so that the common code in - * _mali_ukk_get_system_info() can determine how to adjust the pointers such - * that they are sensible from user space. Leaving ukk_private as NULL implies - * that no pointer adjustment is necessary - which will be the case on a - * bare-metal/RTOS system. - * - * @see _mali_system_info - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 size; /**< [in] size of buffer provided to store system information data */ - _mali_system_info * system_info; /**< [in,out] pointer to buffer to store system information data. No initialisation of buffer required on input. */ - u32 ukk_private; /**< [in] Kernel-side private word inserted by certain U/K interface implementations. Caller must set to Zero. */ -} _mali_uk_get_system_info_s; -/** @} */ /* end group _mali_uk_getsysteminfo */ - -/** @} */ /* end group _mali_uk_core */ - - -/** @defgroup _mali_uk_gp U/K Vertex Processor - * @{ */ - -/** @defgroup _mali_uk_gp_suspend_response_s Vertex Processor Suspend Response - * @{ */ - -/** @brief Arguments for _mali_ukk_gp_suspend_response() - * - * When _mali_wait_for_notification() receives notification that a - * Vertex Processor job was suspended, you need to send a response to indicate - * what needs to happen with this job. You can either abort or resume the job. - * - * - set @c code to indicate response code. This is either @c _MALIGP_JOB_ABORT or - * @c _MALIGP_JOB_RESUME_WITH_NEW_HEAP to indicate you will provide a new heap - * for the job that will resolve the out of memory condition for the job. - * - copy the @c cookie value from the @c _mali_uk_gp_job_suspended_s notification; - * this is an identifier for the suspended job - * - set @c arguments[0] and @c arguments[1] to zero if you abort the job. If - * you resume it, @c argument[0] should specify the Mali start address for the new - * heap and @c argument[1] the Mali end address of the heap. - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - */ -typedef enum _maligp_job_suspended_response_code -{ - _MALIGP_JOB_ABORT, /**< Abort the Vertex Processor job */ - _MALIGP_JOB_RESUME_WITH_NEW_HEAP /**< Resume the Vertex Processor job with a new heap */ -} _maligp_job_suspended_response_code; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 cookie; /**< [in] cookie from the _mali_uk_gp_job_suspended_s notification */ - _maligp_job_suspended_response_code code; /**< [in] abort or resume response code, see \ref _maligp_job_suspended_response_code */ - u32 arguments[2]; /**< [in] 0 when aborting a job. When resuming a job, the Mali start and end address for a new heap to resume the job with */ -} _mali_uk_gp_suspend_response_s; - -/** @} */ /* end group _mali_uk_gp_suspend_response_s */ - -/** @defgroup _mali_uk_gpstartjob_s Vertex Processor Start Job - * @{ */ - -/** @brief Status indicating the result of starting a Vertex or Fragment processor job */ -typedef enum -{ - _MALI_UK_START_JOB_STARTED, /**< Job started */ - _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED, /**< Job started and bumped a lower priority job that was pending execution */ - _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE /**< Job could not be started at this time. Try starting the job again */ -} _mali_uk_start_job_status; - -/** @brief Status indicating the result of starting a Vertex or Fragment processor job */ -typedef enum -{ - MALI_UK_START_JOB_FLAG_DEFAULT = 0, /**< Default behaviour; Flush L2 caches before start, no following jobs */ - MALI_UK_START_JOB_FLAG_NO_FLUSH = 1, /**< No need to flush L2 caches before start */ - MALI_UK_START_JOB_FLAG_MORE_JOBS_FOLLOW = 2, /**< More related jobs follows, try to schedule them as soon as possible after this job */ -} _mali_uk_start_job_flags; - -/** @brief Status indicating the result of the execution of a Vertex or Fragment processor job */ - -typedef enum -{ - _MALI_UK_JOB_STATUS_END_SUCCESS = 1<<(16+0), - _MALI_UK_JOB_STATUS_END_OOM = 1<<(16+1), - _MALI_UK_JOB_STATUS_END_ABORT = 1<<(16+2), - _MALI_UK_JOB_STATUS_END_TIMEOUT_SW = 1<<(16+3), - _MALI_UK_JOB_STATUS_END_HANG = 1<<(16+4), - _MALI_UK_JOB_STATUS_END_SEG_FAULT = 1<<(16+5), - _MALI_UK_JOB_STATUS_END_ILLEGAL_JOB = 1<<(16+6), - _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR = 1<<(16+7), - _MALI_UK_JOB_STATUS_END_SHUTDOWN = 1<<(16+8), - _MALI_UK_JOB_STATUS_END_SYSTEM_UNUSABLE = 1<<(16+9) -} _mali_uk_job_status; - -#define MALIGP2_NUM_REGS_FRAME (6) - -/** @brief Arguments for _mali_ukk_gp_start_job() - * - * To start a Vertex Processor job - * - associate the request with a reference to a @c mali_gp_job_info by setting - * user_job_ptr to the address of the @c mali_gp_job_info of the job. - * - set @c priority to the priority of the @c mali_gp_job_info - * - specify a timeout for the job by setting @c watchdog_msecs to the number of - * milliseconds the job is allowed to run. Specifying a value of 0 selects the - * default timeout in use by the device driver. - * - copy the frame registers from the @c mali_gp_job_info into @c frame_registers. - * - set the @c perf_counter_flag, @c perf_counter_src0 and @c perf_counter_src1 to zero - * for a non-instrumented build. For an instrumented build you can use up - * to two performance counters. Set the corresponding bit in @c perf_counter_flag - * to enable them. @c perf_counter_src0 and @c perf_counter_src1 specify - * the source of what needs to get counted (e.g. number of vertex loader - * cache hits). For source id values, see ARM DDI0415A, Table 3-60. - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - * When @c _mali_ukk_gp_start_job() returns @c _MALI_OSK_ERR_OK, status contains the - * result of the request (see \ref _mali_uk_start_job_status). If the job could - * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be - * tried again. If the job had a higher priority than the one currently pending - * execution (@c _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED), it will bump - * the lower priority job and returns the address of the @c mali_gp_job_info - * for that job in @c returned_user_job_ptr. That job should get requeued. - * - * After the job has started, @c _mali_wait_for_notification() will be notified - * that the job finished or got suspended. It may get suspended due to - * resource shortage. If it finished (see _mali_ukk_wait_for_notification()) - * the notification will contain a @c _mali_uk_gp_job_finished_s result. If - * it got suspended the notification will contain a @c _mali_uk_gp_job_suspended_s - * result. - * - * The @c _mali_uk_gp_job_finished_s contains the job status (see \ref _mali_uk_job_status), - * the number of milliseconds the job took to render, and values of core registers - * when the job finished (irq status, performance counters, renderer list - * address). A job has finished succesfully when its status is - * @c _MALI_UK_JOB_STATUS_FINISHED. If the hardware detected a timeout while rendering - * the job, or software detected the job is taking more than watchdog_msecs to - * complete, the status will indicate @c _MALI_UK_JOB_STATUS_HANG. - * If the hardware detected a bus error while accessing memory associated with the - * job, status will indicate @c _MALI_UK_JOB_STATUS_SEG_FAULT. - * status will indicate @c _MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to - * stop the job but the job didn't start on the hardware yet, e.g. when the - * driver shutdown. - * - * In case the job got suspended, @c _mali_uk_gp_job_suspended_s contains - * the @c user_job_ptr identifier used to start the job with, the @c reason - * why the job stalled (see \ref _maligp_job_suspended_reason) and a @c cookie - * to identify the core on which the job stalled. This @c cookie will be needed - * when responding to this nofication by means of _mali_ukk_gp_suspend_response(). - * (see _mali_ukk_gp_suspend_response()). The response is either to abort or - * resume the job. If the job got suspended due to an out of memory condition - * you may be able to resolve this by providing more memory and resuming the job. - * - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 user_job_ptr; /**< [in] identifier for the job in user space, a @c mali_gp_job_info* */ - u32 priority; /**< [in] job priority. A lower number means higher priority */ - u32 watchdog_msecs; /**< [in] maximum allowed runtime in milliseconds. The job gets killed if it runs longer than this. A value of 0 selects the default used by the device driver. */ - u32 frame_registers[MALIGP2_NUM_REGS_FRAME]; /**< [in] core specific registers associated with this job */ - u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ - u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 returned_user_job_ptr; /**< [out] identifier for the returned job in user space, a @c mali_gp_job_info* */ - _mali_uk_start_job_status status; /**< [out] indicates job start status (success, previous job returned, requeue) */ - u32 abort_id; /**< [in] abort id of this job, used to identify this job for later abort requests */ - u32 perf_counter_l2_src0; /**< [in] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [in] source id for Mali-400 MP L2 cache performance counter 1 */ - u32 frame_builder_id; /**< [in] id of the originating frame builder */ - u32 flush_id; /**< [in] flush id within the originating frame builder */ -} _mali_uk_gp_start_job_s; - -#define _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE (1<<0) /**< Enable performance counter SRC0 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE (1<<1) /**< Enable performance counter SRC1 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE (1<<2) /**< Enable performance counter L2_SRC0 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE (1<<3) /**< Enable performance counter L2_SRC1 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET (1<<4) /**< Enable performance counter L2_RESET for a job */ - -/** @} */ /* end group _mali_uk_gpstartjob_s */ - -typedef struct -{ - u32 user_job_ptr; /**< [out] identifier for the job in user space */ - _mali_uk_job_status status; /**< [out] status of finished job */ - u32 irq_status; /**< [out] value of the GP interrupt rawstat register (see ARM DDI0415A) */ - u32 status_reg_on_stop; /**< [out] value of the GP control register */ - u32 vscl_stop_addr; /**< [out] value of the GP VLSCL start register */ - u32 plbcl_stop_addr; /**< [out] value of the GP PLBCL start register */ - u32 heap_current_addr; /**< [out] value of the GP PLB PL heap start address register */ - u32 perf_counter_src0; /**< [out] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [out] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter0; /**< [out] value of perfomance counter 0 (see ARM DDI0415A) */ - u32 perf_counter1; /**< [out] value of perfomance counter 1 (see ARM DDI0415A) */ - u32 render_time; /**< [out] number of microseconds it took for the job to render */ - u32 perf_counter_l2_src0; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0; /**< [out] Value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1; /**< [out] Value of the Mali-400 MP L2 cache performance counter 1 */ -} _mali_uk_gp_job_finished_s; - -typedef enum _maligp_job_suspended_reason -{ - _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY /**< Polygon list builder unit (PLBU) has run out of memory */ -} _maligp_job_suspended_reason; - -typedef struct -{ - u32 user_job_ptr; /**< [out] identifier for the job in user space */ - _maligp_job_suspended_reason reason; /**< [out] reason why the job stalled */ - u32 cookie; /**< [out] identifier for the core in kernel space on which the job stalled */ -} _mali_uk_gp_job_suspended_s; - -/** @} */ /* end group _mali_uk_gp */ - - -/** @defgroup _mali_uk_pp U/K Fragment Processor - * @{ */ - -/** @defgroup _mali_uk_ppstartjob_s Fragment Processor Start Job - * @{ */ - -/** @brief Arguments for _mali_ukk_pp_start_job() - * - * To start a Fragment Processor job - * - associate the request with a reference to a mali_pp_job by setting - * @c user_job_ptr to the address of the @c mali_pp_job of the job. - * - set @c priority to the priority of the mali_pp_job - * - specify a timeout for the job by setting @c watchdog_msecs to the number of - * milliseconds the job is allowed to run. Specifying a value of 0 selects the - * default timeout in use by the device driver. - * - copy the frame registers from the @c mali_pp_job into @c frame_registers. - * For MALI200 you also need to copy the write back 0,1 and 2 registers. - * - set the @c perf_counter_flag, @c perf_counter_src0 and @c perf_counter_src1 to zero - * for a non-instrumented build. For an instrumented build you can use up - * to two performance counters. Set the corresponding bit in @c perf_counter_flag - * to enable them. @c perf_counter_src0 and @c perf_counter_src1 specify - * the source of what needs to get counted (e.g. number of vertex loader - * cache hits). For source id values, see ARM DDI0415A, Table 3-60. - * - pass in the user-kernel context in @c ctx that was returned from _mali_ukk_open() - * - * When _mali_ukk_pp_start_job() returns @c _MALI_OSK_ERR_OK, @c status contains the - * result of the request (see \ref _mali_uk_start_job_status). If the job could - * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be - * tried again. If the job had a higher priority than the one currently pending - * execution (@c _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED), it will bump - * the lower priority job and returns the address of the @c mali_pp_job - * for that job in @c returned_user_job_ptr. That job should get requeued. - * - * After the job has started, _mali_wait_for_notification() will be notified - * when the job finished. The notification will contain a - * @c _mali_uk_pp_job_finished_s result. It contains the @c user_job_ptr - * identifier used to start the job with, the job @c status (see \ref _mali_uk_job_status), - * the number of milliseconds the job took to render, and values of core registers - * when the job finished (irq status, performance counters, renderer list - * address). A job has finished succesfully when its status is - * @c _MALI_UK_JOB_STATUS_FINISHED. If the hardware detected a timeout while rendering - * the job, or software detected the job is taking more than @c watchdog_msecs to - * complete, the status will indicate @c _MALI_UK_JOB_STATUS_HANG. - * If the hardware detected a bus error while accessing memory associated with the - * job, status will indicate @c _MALI_UK_JOB_STATUS_SEG_FAULT. - * status will indicate @c _MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to - * stop the job but the job didn't start on the hardware yet, e.g. when the - * driver shutdown. - * - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 user_job_ptr; /**< [in] identifier for the job in user space */ - u32 priority; /**< [in] job priority. A lower number means higher priority */ - u32 watchdog_msecs; /**< [in] maximum allowed runtime in milliseconds. The job gets killed if it runs longer than this. A value of 0 selects the default used by the device driver. */ - u32 frame_registers[MALI200_NUM_REGS_FRAME]; /**< [in] core specific registers associated with this job, see ARM DDI0415A */ - u32 wb0_registers[MALI200_NUM_REGS_WBx]; - u32 wb1_registers[MALI200_NUM_REGS_WBx]; - u32 wb2_registers[MALI200_NUM_REGS_WBx]; - u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ - u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 returned_user_job_ptr; /**< [out] identifier for the returned job in user space */ - _mali_uk_start_job_status status; /**< [out] indicates job start status (success, previous job returned, requeue) */ - u32 abort_id; /**< [in] abort id of this job, used to identify this job for later abort requests */ - u32 perf_counter_l2_src0; /**< [in] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [in] source id for Mali-400 MP L2 cache performance counter 1 */ - u32 frame_builder_id; /**< [in] id of the originating frame builder */ - u32 flush_id; /**< [in] flush id within the originating frame builder */ - _mali_uk_start_job_flags flags; /**< [in] Flags for job, see _mali_uk_start_job_flags for more information */ -} _mali_uk_pp_start_job_s; -/** @} */ /* end group _mali_uk_ppstartjob_s */ - -typedef struct -{ - u32 user_job_ptr; /**< [out] identifier for the job in user space */ - _mali_uk_job_status status; /**< [out] status of finished job */ - u32 irq_status; /**< [out] value of interrupt rawstat register (see ARM DDI0415A) */ - u32 last_tile_list_addr; /**< [out] value of renderer list register (see ARM DDI0415A); necessary to restart a stopped job */ - u32 perf_counter_src0; /**< [out] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [out] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter0; /**< [out] value of perfomance counter 0 (see ARM DDI0415A) */ - u32 perf_counter1; /**< [out] value of perfomance counter 1 (see ARM DDI0415A) */ - u32 render_time; /**< [out] number of microseconds it took for the job to render */ - u32 perf_counter_l2_src0; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0; /**< [out] Value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1; /**< [out] Value of the Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0_raw; /**< [out] Raw value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1_raw; /**< [out] Raw value of the Mali-400 MP L2 cache performance counter 1 */ -} _mali_uk_pp_job_finished_s; -/** @} */ /* end group _mali_uk_pp */ - - -/** @addtogroup _mali_uk_core U/K Core - * @{ */ - -/** @defgroup _mali_uk_waitfornotification_s Wait For Notification - * @{ */ - -/** @brief Notification type encodings - * - * Each Notification type is an ordered pair of (subsystem,id), and is unique. - * - * The encoding of subsystem,id into a 32-bit word is: - * encoding = (( subsystem << _MALI_NOTIFICATION_SUBSYSTEM_SHIFT ) & _MALI_NOTIFICATION_SUBSYSTEM_MASK) - * | (( id << _MALI_NOTIFICATION_ID_SHIFT ) & _MALI_NOTIFICATION_ID_MASK) - * - * @see _mali_uk_wait_for_notification_s - */ -typedef enum -{ - /** core notifications */ - - _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x20, - _MALI_NOTIFICATION_APPLICATION_QUIT = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x40, - - /** Fragment Processor notifications */ - - _MALI_NOTIFICATION_PP_FINISHED = (_MALI_UK_PP_SUBSYSTEM << 16) | 0x10, - - /** Vertex Processor notifications */ - - _MALI_NOTIFICATION_GP_FINISHED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x10, - _MALI_NOTIFICATION_GP_STALLED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x20, -} _mali_uk_notification_type; - -/** to assist in splitting up 32-bit notification value in subsystem and id value */ -#define _MALI_NOTIFICATION_SUBSYSTEM_MASK 0xFFFF0000 -#define _MALI_NOTIFICATION_SUBSYSTEM_SHIFT 16 -#define _MALI_NOTIFICATION_ID_MASK 0x0000FFFF -#define _MALI_NOTIFICATION_ID_SHIFT 0 - - -/** @brief Arguments for _mali_ukk_wait_for_notification() - * - * On successful return from _mali_ukk_wait_for_notification(), the members of - * this structure will indicate the reason for notification. - * - * Specifically, the source of the notification can be identified by the - * subsystem and id fields of the mali_uk_notification_type in the code.type - * member. The type member is encoded in a way to divide up the types into a - * subsystem field, and a per-subsystem ID field. See - * _mali_uk_notification_type for more information. - * - * Interpreting the data union member depends on the notification type: - * - * - type == _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS - * - The kernel side is shutting down. No further - * _mali_uk_wait_for_notification() calls should be made. - * - In this case, the value of the data union member is undefined. - * - This is used to indicate to the user space client that it should close - * the connection to the Mali Device Driver. - * - type == _MALI_NOTIFICATION_PP_FINISHED - * - The notification data is of type _mali_uk_pp_job_finished_s. It contains the user_job_ptr - * identifier used to start the job with, the job status, the number of milliseconds the job took to render, - * and values of core registers when the job finished (irq status, performance counters, renderer list - * address). - * - A job has finished succesfully when its status member is _MALI_UK_JOB_STATUS_FINISHED. - * - If the hardware detected a timeout while rendering the job, or software detected the job is - * taking more than watchdog_msecs (see _mali_ukk_pp_start_job()) to complete, the status member will - * indicate _MALI_UK_JOB_STATUS_HANG. - * - If the hardware detected a bus error while accessing memory associated with the job, status will - * indicate _MALI_UK_JOB_STATUS_SEG_FAULT. - * - Status will indicate MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to stop the job but the job - * didn't start the hardware yet, e.g. when the driver closes. - * - type == _MALI_NOTIFICATION_GP_FINISHED - * - The notification data is of type _mali_uk_gp_job_finished_s. The notification is similar to that of - * type == _MALI_NOTIFICATION_PP_FINISHED, except that several other GP core register values are returned. - * The status values have the same meaning for type == _MALI_NOTIFICATION_PP_FINISHED. - * - type == _MALI_NOTIFICATION_GP_STALLED - * - The nofication data is of type _mali_uk_gp_job_suspended_s. It contains the user_job_ptr - * identifier used to start the job with, the reason why the job stalled and a cookie to identify the core on - * which the job stalled. - * - The reason member of gp_job_suspended is set to _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY - * when the polygon list builder unit has run out of memory. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_uk_notification_type type; /**< [out] Type of notification available */ - union - { - _mali_uk_gp_job_suspended_s gp_job_suspended;/**< [out] Notification data for _MALI_NOTIFICATION_GP_STALLED notification type */ - _mali_uk_gp_job_finished_s gp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_GP_FINISHED notification type */ - _mali_uk_pp_job_finished_s pp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_PP_FINISHED notification type */ - } data; -} _mali_uk_wait_for_notification_s; - -/** @brief Arguments for _mali_ukk_post_notification() - * - * Posts the specified notification to the notification queue for this application. - * This is used to send a quit message to the callback thread. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_uk_notification_type type; /**< [in] Type of notification to post */ -} _mali_uk_post_notification_s; -/** @} */ /* end group _mali_uk_waitfornotification_s */ - -/** @defgroup _mali_uk_getapiversion_s Get API Version - * @{ */ - -/** helpers for Device Driver API version handling */ - -/** @brief Encode a version ID from a 16-bit input - * - * @note the input is assumed to be 16 bits. It must not exceed 16 bits. */ -#define _MAKE_VERSION_ID(x) (((x) << 16UL) | (x)) - -/** @brief Check whether a 32-bit value is likely to be Device Driver API - * version ID. */ -#define _IS_VERSION_ID(x) (((x) & 0xFFFF) == (((x) >> 16UL) & 0xFFFF)) - -/** @brief Decode a 16-bit version number from a 32-bit Device Driver API version - * ID */ -#define _GET_VERSION(x) (((x) >> 16UL) & 0xFFFF) - -/** @brief Determine whether two 32-bit encoded version IDs match */ -#define _IS_API_MATCH(x, y) (IS_VERSION_ID((x)) && IS_VERSION_ID((y)) && (GET_VERSION((x)) == GET_VERSION((y)))) - -/** - * API version define. - * Indicates the version of the kernel API - * The version is a 16bit integer incremented on each API change. - * The 16bit integer is stored twice in a 32bit integer - * For example, for version 1 the value would be 0x00010001 - */ -#define _MALI_API_VERSION 10 -#define _MALI_UK_API_VERSION _MAKE_VERSION_ID(_MALI_API_VERSION) - -/** - * The API version is a 16-bit integer stored in both the lower and upper 16-bits - * of a 32-bit value. The 16-bit API version value is incremented on each API - * change. Version 1 would be 0x00010001. Used in _mali_uk_get_api_version_s. - */ -typedef u32 _mali_uk_api_version; - -/** @brief Arguments for _mali_uk_get_api_version() - * - * The user-side interface version must be written into the version member, - * encoded using _MAKE_VERSION_ID(). It will be compared to the API version of - * the kernel-side interface. - * - * On successful return, the version member will be the API version of the - * kernel-side interface. _MALI_UK_API_VERSION macro defines the current version - * of the API. - * - * The compatible member must be checked to see if the version of the user-side - * interface is compatible with the kernel-side interface, since future versions - * of the interface may be backwards compatible. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_uk_api_version version; /**< [in,out] API version of user-side interface. */ - int compatible; /**< [out] @c 1 when @version is compatible, @c 0 otherwise */ -} _mali_uk_get_api_version_s; -/** @} */ /* end group _mali_uk_getapiversion_s */ - -/** @} */ /* end group _mali_uk_core */ - - -/** @defgroup _mali_uk_memory U/K Memory - * @{ */ - -/** @brief Arguments for _mali_ukk_init_mem(). */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 mali_address_base; /**< [out] start of MALI address space */ - u32 memory_size; /**< [out] total MALI address space available */ -} _mali_uk_init_mem_s; - -/** @brief Arguments for _mali_ukk_term_mem(). */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ -} _mali_uk_term_mem_s; - -/** @brief Arguments for _mali_ukk_get_big_block() - * - * - type_id should be set to the value of the identifier member of one of the - * _mali_mem_info structures returned through _mali_ukk_get_system_info() - * - ukk_private must be zero when calling from user-side. On Kernel-side, the - * OS implementation of the U/K interface can use it to communicate data to the - * OS implementation of the OSK layer. Specifically, ukk_private will be placed - * into the ukk_private member of the _mali_uk_mem_mmap_s structure. See - * _mali_ukk_mem_mmap() for more details. - * - minimum_size_requested will be updated if it is too small - * - block_size will always be >= minimum_size_requested, because the underlying - * allocation mechanism may only be able to divide up memory regions in certain - * ways. To avoid wasting memory, block_size should always be taken into account - * rather than assuming minimum_size_requested was really allocated. - * - to free the memory, the returned cookie member must be stored, and used to - * refer to it. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 type_id; /**< [in] the type id of the memory bank to allocate memory from */ - u32 minimum_size_requested; /**< [in,out] minimum size of the allocation */ - u32 ukk_private; /**< [in] Kernel-side private word inserted by certain U/K interface implementations. Caller must set to Zero. */ - u32 mali_address; /**< [out] address of the allocation in mali address space */ - void *cpuptr; /**< [out] address of the allocation in the current process address space */ - u32 block_size; /**< [out] size of the block that got allocated */ - u32 flags; /**< [out] flags associated with the allocated block, of type _mali_bus_usage */ - u32 cookie; /**< [out] identifier for the allocated block in kernel space */ -} _mali_uk_get_big_block_s; - -/** @brief Arguments for _mali_ukk_free_big_block() - * - * All that is required is that the cookie member must be set to the value of - * the cookie member returned through _mali_ukk_get_big_block() - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 cookie; /**< [in] identifier for mapped memory object in kernel space */ -} _mali_uk_free_big_block_s; - -/** @note Mali-MMU only */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 phys_addr; /**< [in] physical address */ - u32 size; /**< [in] size */ - u32 mali_address; /**< [in] mali address to map the physical memory to */ - u32 rights; /**< [in] rights necessary for accessing memory */ - u32 flags; /**< [in] flags, see \ref _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE */ - u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ -} _mali_uk_map_external_mem_s; - -/** Flag for _mali_uk_map_external_mem_s and _mali_uk_attach_ump_mem_s */ -#define _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE (1<<0) - -/** @note Mali-MMU only */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ -} _mali_uk_unmap_external_mem_s; - -/** @note This is identical to _mali_uk_map_external_mem_s above, however phys_addr is replaced by secure_id */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 secure_id; /**< [in] secure id */ - u32 size; /**< [in] size */ - u32 mali_address; /**< [in] mali address to map the physical memory to */ - u32 rights; /**< [in] rights necessary for accessing memory */ - u32 flags; /**< [in] flags, see \ref _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE */ - u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ -} _mali_uk_attach_ump_mem_s; - -/** @note Mali-MMU only; will be supported in future version */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 cookie; /**< [in] identifier for mapped memory object in kernel space */ -} _mali_uk_release_ump_mem_s; - -/** @brief Arguments for _mali_ukk_va_to_mali_pa() - * - * if size is zero or not a multiple of the system's page size, it will be - * rounded up to the next multiple of the page size. This will occur before - * any other use of the size parameter. - * - * if va is not PAGE_SIZE aligned, it will be rounded down to the next page - * boundary. - * - * The range (va) to ((u32)va)+(size-1) inclusive will be checked for physical - * contiguity. - * - * The implementor will check that the entire physical range is allowed to be mapped - * into user-space. - * - * Failure will occur if either of the above are not satisfied. - * - * Otherwise, the physical base address of the range is returned through pa, - * va is updated to be page aligned, and size is updated to be a non-zero - * multiple of the system's pagesize. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - void *va; /**< [in,out] Virtual address of the start of the range */ - u32 pa; /**< [out] Physical base address of the range */ - u32 size; /**< [in,out] Size of the range, in bytes. */ -} _mali_uk_va_to_mali_pa_s; - - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 size; /**< [out] size of MMU page table information (registers + page tables) */ -} _mali_uk_query_mmu_page_table_dump_size_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 size; /**< [in] size of buffer to receive mmu page table information */ - void *buffer; /**< [in,out] buffer to receive mmu page table information */ - u32 register_writes_size; /**< [out] size of MMU register dump */ - u32 *register_writes; /**< [out] pointer within buffer where MMU register dump is stored */ - u32 page_table_dump_size; /**< [out] size of MMU page table dump */ - u32 *page_table_dump; /**< [out] pointer within buffer where MMU page table dump is stored */ -} _mali_uk_dump_mmu_page_table_s; - -/** @} */ /* end group _mali_uk_memory */ - - -/** @addtogroup _mali_uk_pp U/K Fragment Processor - * @{ */ - -/** @brief Arguments for _mali_ukk_get_pp_number_of_cores() - * - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - Upon successful return from _mali_ukk_get_pp_number_of_cores(), @c number_of_cores - * will contain the number of Fragment Processor cores in the system. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 number_of_cores; /**< [out] number of Fragment Processor cores in the system */ -} _mali_uk_get_pp_number_of_cores_s; - -/** @brief Arguments for _mali_ukk_get_pp_core_version() - * - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - Upon successful return from _mali_ukk_get_pp_core_version(), @c version contains - * the version that all Fragment Processor cores are compatible with. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_core_version version; /**< [out] version returned from core, see \ref _mali_core_version */ -} _mali_uk_get_pp_core_version_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 abort_id; /**< [in] ID of job(s) to abort */ -} _mali_uk_pp_abort_job_s; - -/** @} */ /* end group _mali_uk_pp */ - - -/** @addtogroup _mali_uk_gp U/K Vertex Processor - * @{ */ - -/** @brief Arguments for _mali_ukk_get_gp_number_of_cores() - * - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - Upon successful return from _mali_ukk_get_gp_number_of_cores(), @c number_of_cores - * will contain the number of Vertex Processor cores in the system. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 number_of_cores; /**< [out] number of Vertex Processor cores in the system */ -} _mali_uk_get_gp_number_of_cores_s; - -/** @brief Arguments for _mali_ukk_get_gp_core_version() - * - * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() - * - Upon successful return from _mali_ukk_get_gp_core_version(), @c version contains - * the version that all Vertex Processor cores are compatible with. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_core_version version; /**< [out] version returned from core, see \ref _mali_core_version */ -} _mali_uk_get_gp_core_version_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 abort_id; /**< [in] ID of job(s) to abort */ -} _mali_uk_gp_abort_job_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 limit; /**< [in,out] The desired limit for number of events to record on input, actual limit on output */ -} _mali_uk_profiling_start_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 event_id; /**< [in] event id to register (see enum mali_profiling_events for values) */ - u32 data[5]; /**< [in] event specific data */ -} _mali_uk_profiling_add_event_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 count; /**< [out] The number of events sampled */ -} _mali_uk_profiling_stop_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 index; /**< [in] which index to get (starting at zero) */ - u64 timestamp; /**< [out] timestamp of event */ - u32 event_id; /**< [out] event id of event (see enum mali_profiling_events for values) */ - u32 data[5]; /**< [out] event specific data */ -} _mali_uk_profiling_get_event_s; - -typedef struct -{ - void *ctx; - - u32 id; - s64 value; -} _mali_uk_sw_counters_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ -} _mali_uk_profiling_clear_s; - -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 enable_events; /**< [out] 1 if user space process should generate events, 0 if not */ -} _mali_uk_profiling_get_config_s; - - -/** @} */ /* end group _mali_uk_gp */ - - -/** @addtogroup _mali_uk_memory U/K Memory - * @{ */ - -/** @brief Arguments to _mali_ukk_mem_mmap() - * - * Use of the phys_addr member depends on whether the driver is compiled for - * Mali-MMU or nonMMU: - * - in the nonMMU case, this is the physical address of the memory as seen by - * the CPU (which may be a constant offset from that used by Mali) - * - in the MMU case, this is the Mali Virtual base address of the memory to - * allocate, and the particular physical pages used to back the memory are - * entirely determined by _mali_ukk_mem_mmap(). The details of the physical pages - * are not reported to user-space for security reasons. - * - * The cookie member must be stored for use later when freeing the memory by - * calling _mali_ukk_mem_munmap(). In the Mali-MMU case, the cookie is secure. - * - * The ukk_private word must be set to zero when calling from user-space. On - * Kernel-side, the OS implementation of the U/K interface can use it to - * communicate data to the OS implementation of the OSK layer. In particular, - * _mali_ukk_get_big_block() directly calls _mali_ukk_mem_mmap directly, and - * will communicate its own ukk_private word through the ukk_private member - * here. The common code itself will not inspect or modify the ukk_private - * word, and so it may be safely used for whatever purposes necessary to - * integrate Mali Memory handling into the OS. - * - * The uku_private member is currently reserved for use by the user-side - * implementation of the U/K interface. Its value must be zero. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - void *mapping; /**< [out] Returns user-space virtual address for the mapping */ - u32 size; /**< [in] Size of the requested mapping */ - u32 phys_addr; /**< [in] Physical address - could be offset, depending on caller+callee convention */ - u32 cookie; /**< [out] Returns a cookie for use in munmap calls */ - void *uku_private; /**< [in] User-side Private word used by U/K interface */ - void *ukk_private; /**< [in] Kernel-side Private word used by U/K interface */ -} _mali_uk_mem_mmap_s; - -/** @brief Arguments to _mali_ukk_mem_munmap() - * - * The cookie and mapping members must be that returned from the same previous - * call to _mali_ukk_mem_mmap(). The size member must correspond to cookie - * and mapping - that is, it must be the value originally supplied to a call to - * _mali_ukk_mem_mmap that returned the values of mapping and cookie. - * - * An error will be returned if an attempt is made to unmap only part of the - * originally obtained range, or to unmap more than was originally obtained. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - void *mapping; /**< [in] The mapping returned from mmap call */ - u32 size; /**< [in] The size passed to mmap call */ - u32 cookie; /**< [in] Cookie from mmap call */ -} _mali_uk_mem_munmap_s; -/** @} */ /* end group _mali_uk_memory */ - -#if USING_MALI_PMM - -/** @defgroup _mali_uk_pmm U/K Power Management Module - * @{ */ - -/** @brief Power management event message identifiers. - * - * U/K events start after id 200, and can range up to 999 - * Adding new events will require updates to the PMM mali_pmm_event_id type - */ -#define _MALI_PMM_EVENT_UK_EXAMPLE 201 - -/** @brief Generic PMM message data type, that will be dependent on the event msg - */ -typedef u32 mali_pmm_message_data; - - -/** @brief Arguments to _mali_ukk_pmm_event_message() - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 id; /**< [in] event id */ - mali_pmm_message_data data; /**< [in] specific data associated with the event */ -} _mali_uk_pmm_message_s; - -/** @} */ /* end group _mali_uk_pmm */ -#endif /* USING_MALI_PMM */ - -/** @defgroup _mali_uk_vsync U/K VSYNC Wait Reporting Module - * @{ */ - -/** @brief VSYNC events - * - * These events are reported when DDK starts to wait for vsync and when the - * vsync has occured and the DDK can continue on the next frame. - */ -typedef enum _mali_uk_vsync_event -{ - _MALI_UK_VSYNC_EVENT_BEGIN_WAIT = 0, - _MALI_UK_VSYNC_EVENT_END_WAIT -} _mali_uk_vsync_event; - -/** @brief Arguments to _mali_ukk_vsync_event() - * - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - _mali_uk_vsync_event event; /**< [in] VSYNCH event type */ -} _mali_uk_vsync_event_report_s; - -/** @} */ /* end group _mali_uk_vsync */ - -/** @} */ /* end group u_k_api */ - -/** @} */ /* end group uddapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_UK_TYPES_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_ukk.h b/drivers/media/video/samsung/mali/common/mali_ukk.h index 94efdf5..8ff2002 100644 --- a/drivers/media/video/samsung/mali/common/mali_ukk.h +++ b/drivers/media/video/samsung/mali/common/mali_ukk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 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. @@ -17,7 +17,7 @@ #define __MALI_UKK_H__ #include "mali_osk.h" -#include "mali_uk_types.h" +#include "../linux/mali_uk_types.h" #ifdef __cplusplus extern "C" @@ -139,14 +139,6 @@ extern "C" * (_mali_osk_mem_mapregion_init()) functions will collaborate on the * meaning of ukk_private member. On other OSs, it may be unused by both * U/K and OSK layers - * - On OS systems (not including direct function call U/K interface - * implementations), _mali_ukk_get_big_block() may succeed, but the subsequent - * copying to user space may fail. - * - A problem scenario exists: some memory has been reserved by - * _mali_ukk_get_big_block(), but the user-mode will be unaware of it (it will - * never receive any information about this memory). In this case, the U/K - * implementation must do everything necessary to 'rollback' the \em atomic - * _mali_ukk_get_big_block() transaction. * - Therefore, on error inside the U/K interface implementation itself, * it will be as though the _mali_ukk function itself had failed, and cleaned * up after itself. @@ -233,7 +225,7 @@ _mali_osk_errcode_t _mali_ukk_close( void **context ); * allocated, and a pointer to this memory written into the system_info member * of _mali_uk_get_system_info_s. * - * @param args see _mali_uk_get_system_info_size_s in "mali_uk_types.h" + * @param args see _mali_uk_get_system_info_size_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_system_info_size( _mali_uk_get_system_info_size_s *args ); @@ -270,7 +262,7 @@ _mali_osk_errcode_t _mali_ukk_get_system_info_size( _mali_uk_get_system_info_siz * destination address for pointer-patching to occur. When NULL, it is unused, an no pointer-patching occurs in the * common code. * - * @param args see _mali_uk_get_system_info_s in "mali_uk_types.h" + * @param args see _mali_uk_get_system_info_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args ); @@ -279,24 +271,37 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args * * Sleeps until notified or a timeout occurs. Returns information about the notification. * - * @param args see _mali_uk_wait_for_notification_s in "mali_uk_types.h" + * @param args see _mali_uk_wait_for_notification_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args ); /** @brief Post a notification to the notification queue of this application. * - * @param args see _mali_uk_post_notification_s in "mali_uk_types.h" + * @param args see _mali_uk_post_notification_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args ); /** @brief Verifies if the user and kernel side of this API are compatible. * - * @param args see _mali_uk_get_api_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_api_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ); + +/** @brief Get the user space settings applicable for calling process. + * + * @param args see _mali_uk_get_user_settings_s in "mali_utgard_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args); + +/** @brief Get a user space setting applicable for calling process. + * + * @param args see _mali_uk_get_user_setting_s in "mali_utgard_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args); + /** @} */ /* end group _mali_uk_core */ @@ -324,7 +329,7 @@ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args * @note This function is for Mali-MMU builds \b only. It should not be called * when the drivers are built without Mali-MMU support. * - * @param args see \ref _mali_uk_init_mem_s in mali_uk_types.h + * @param args see \ref _mali_uk_init_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable * _mali_osk_errcode_t on failure. */ @@ -340,43 +345,18 @@ _mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ); * @note This function is for Mali-MMU builds \b only. It should not be called * when the drivers are built without Mali-MMU support. * - * @param args see \ref _mali_uk_term_mem_s in mali_uk_types.h + * @param args see \ref _mali_uk_term_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable * _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ); -/** @brief Map a block of memory into the current user process - * - * Allocates a minimum of minimum_size_requested bytes of MALI memory and maps it into the current - * process space. The number of bytes allocated is returned in args->block_size. - * - * This is only used for Mali-nonMMU mode. - * - * @param args see _mali_uk_get_big_block_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ); - -/** @brief Unmap a block of memory from the current user process - * - * Frees allocated MALI memory and unmaps it from the current process space. The previously allocated memory - * is indicated by the cookie as returned by _mali_ukk_get_big_block(). - * - * This is only used for Mali-nonMMU mode. - * - * @param args see _mali_uk_free_big_block_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); - /** @brief Map Mali Memory into the current user process * * Maps Mali memory into the current user process in a generic way. * * This function is to be used for Mali-MMU mode. The function is available in both Mali-MMU and Mali-nonMMU modes, - * but should not be called by a user process in Mali-nonMMU mode. In Mali-nonMMU mode, the function is callable - * from the kernel side, and is used to implement _mali_ukk_get_big_block() in this case. + * but should not be called by a user process in Mali-nonMMU mode. * * The implementation and operation of _mali_ukk_mem_mmap() is dependant on whether the driver is built for Mali-MMU * or Mali-nonMMU: @@ -392,9 +372,6 @@ _mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); * they are unnecsessary; the \em Mali-virtual address range must be used for * programming Mali structures. * - * This means that in the first (nonMMU) case, the caller must manage the physical address allocations. The caller - * in this case is _mali_ukk_get_big_block(), which does indeed manage the Mali physical address ranges. - * * In the second (MMU) case, _mali_ukk_mem_mmap() handles management of * CPU-virtual and CPU-physical ranges, but the \em caller must manage the * \em Mali-virtual address range from the user-side. @@ -403,7 +380,7 @@ _mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); * It is not possible for a process to accidentally corrupt another process' * \em Mali-virtual address space. * - * @param args see _mali_uk_mem_mmap_s in "mali_uk_types.h" + * @param args see _mali_uk_mem_mmap_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ); @@ -413,42 +390,42 @@ _mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ); * Unmaps Mali memory from the current user process in a generic way. This only operates on Mali memory supplied * from _mali_ukk_mem_mmap(). * - * @param args see _mali_uk_mem_munmap_s in "mali_uk_types.h" + * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ); /** @brief Determine the buffer size necessary for an MMU page table dump. - * @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_uk_types.h + * @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ); /** @brief Dump MMU Page tables. - * @param args see _mali_uk_dump_mmu_page_table_s in mali_uk_types.h + * @param args see _mali_uk_dump_mmu_page_table_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ); /** @brief Map a physically contiguous range of memory into Mali - * @param args see _mali_uk_map_external_mem_s in mali_uk_types.h + * @param args see _mali_uk_map_external_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ); /** @brief Unmap a physically contiguous range of memory from Mali - * @param args see _mali_uk_unmap_external_mem_s in mali_uk_types.h + * @param args see _mali_uk_unmap_external_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ); #if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 /** @brief Map UMP memory into Mali - * @param args see _mali_uk_attach_ump_mem_s in mali_uk_types.h + * @param args see _mali_uk_attach_ump_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ); /** @brief Unmap UMP memory from Mali - * @param args see _mali_uk_release_ump_mem_s in mali_uk_types.h + * @param args see _mali_uk_release_ump_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ); @@ -492,7 +469,7 @@ _mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args * @note if implemented, this function is entirely platform-dependant, and does * not exist in common code. * - * @param args see _mali_uk_va_to_mali_pa_s in "mali_uk_types.h" + * @param args see _mali_uk_va_to_mali_pa_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args ); @@ -519,20 +496,16 @@ _mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args ); * existing one returned, otherwise the new job is started and the status field args->status is set to * _MALI_UK_START_JOB_STARTED. * - * If an existing lower priority job is returned, args->returned_user_job_ptr contains a - * pointer to the returned job and the status field args->status is set to - * _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED. - * * Job completion can be awaited with _mali_ukk_wait_for_notification(). * - * @param args see _mali_uk_pp_start_job_s in "mali_uk_types.h" + * @param args see _mali_uk_pp_start_job_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_pp_start_job( _mali_uk_pp_start_job_s *args ); /** @brief Returns the number of Fragment Processors in the system * - * @param args see _mali_uk_get_pp_number_of_cores_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_number_of_cores_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args ); @@ -542,22 +515,18 @@ _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_ * This function may only be called when _mali_ukk_get_pp_number_of_cores() indicated at least one Fragment * Processor core is available. * - * @param args see _mali_uk_get_pp_core_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args ); -/** @brief Abort any PP jobs with the given ID. +/** @brief Disable Write-back unit(s) on specified job * - * Jobs internally queued or currently running on the hardware is to be stopped/aborted. - * Jobs aborted are reported via the normal job completion system. - * Any jobs, running or internally queued should be aborted imediately. - * Normal notifiction procedures to report on the status of these jobs. - * - * - * @param args see _malu_uk_pp_abort_job_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" */ -void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s *args ); +void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args); + + /** @} */ /* end group _mali_uk_pp */ @@ -580,20 +549,16 @@ void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s *args ); * existing one returned, otherwise the new job is started and the status field args->status is set to * _MALI_UK_START_JOB_STARTED. * - * If an existing lower priority job is returned, args->returned_user_job_ptr contains a pointer to - * the returned job and the status field args->status is set to - * _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED. - * * Job completion can be awaited with _mali_ukk_wait_for_notification(). * - * @param args see _mali_uk_gp_start_job_s in "mali_uk_types.h" + * @param args see _mali_uk_gp_start_job_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_gp_start_job( _mali_uk_gp_start_job_s *args ); /** @brief Returns the number of Vertex Processors in the system. * - * @param args see _mali_uk_get_gp_number_of_cores_s in "mali_uk_types.h" + * @param args see _mali_uk_get_gp_number_of_cores_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args ); @@ -603,7 +568,7 @@ _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_ * This function may only be called when _mali_uk_get_gp_number_of_cores() indicated at least one Vertex * Processor core is available. * - * @param args see _mali_uk_get_gp_core_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_gp_core_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args ); @@ -613,85 +578,47 @@ _mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_ * After receiving notification that a Vertex Processor job was suspended from * _mali_ukk_wait_for_notification() you can use this function to resume or abort the job. * - * @param args see _mali_uk_gp_suspend_response_s in "mali_uk_types.h" + * @param args see _mali_uk_gp_suspend_response_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args ); -/** @brief Abort any GP jobs with the given ID. - * - * Jobs internally queued or currently running on the hardware is to be stopped/aborted. - * Jobs aborted are reported via the normal job completion system. - * - * Any jobs, running or internally queued should be aborted imediately. - * Normal notifiction procedures to report on the status of these jobs. - * - * @param args see _mali_uk_gp_abort_job_s in "mali_uk_types.h" - */ -void _mali_ukk_gp_abort_job( _mali_uk_gp_abort_job_s *args ); /** @} */ /* end group _mali_uk_gp */ -#if USING_MALI_PMM -/** @addtogroup _mali_uk_pmm U/K Power Management Module - * @{ */ - -/* @brief Power Management Module event message - * - * @note The event message can fail to be sent due to OOM but this is - * stored in the PMM state machine to be handled later - * - * @param args see _mali_uk_pmm_event_message_s in "mali_uk_types.h" - */ -void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args ); -/** @} */ /* end group _mali_uk_pmm */ -#endif /* USING_MALI_PMM */ - #if MALI_TIMELINE_PROFILING_ENABLED /** @addtogroup _mali_uk_profiling U/K Timeline profiling module * @{ */ /** @brief Start recording profiling events. * - * @param args see _mali_uk_profiling_start_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_start_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args); /** @brief Add event to profiling buffer. * - * @param args see _mali_uk_profiling_add_event_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_add_event_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args); /** @brief Stop recording profiling events. * - * @param args see _mali_uk_profiling_stop_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_stop_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args); /** @brief Retrieve a recorded profiling event. * - * @param args see _mali_uk_profiling_get_event_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_get_event_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args); /** @brief Clear recorded profiling events. * - * @param args see _mali_uk_profiling_clear_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_clear_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args); -/** @brief Get the profiling config applicable for calling process. - * - * @param args see _mali_uk_profiling_get_config_s in "mali_uk_types.h" - */ -_mali_osk_errcode_t _mali_ukk_profiling_get_config(_mali_uk_profiling_get_config_s *args); - -/** @brief Transfer software counters from user to kernel space - * - * @param args see _mali_uk_transfer_sw_counters_s in "mali_uk_types.h" - */ -_mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args); - /** @} */ /* end group _mali_uk_profiling */ #endif @@ -704,12 +631,23 @@ _mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args) * waiting is finished. This information can then be used in kernel space to * complement the GPU utilization metric. * - * @param args see _mali_uk_vsync_event_report_s in "mali_uk_types.h" + * @param args see _mali_uk_vsync_event_report_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args); /** @} */ /* end group _mali_uk_vsync */ +/** @addtogroup _mali_sw_counters_report U/K Software counter reporting + * @{ */ + +/** @brief Report software counters. + * + * @param args see _mali_uk_sw_counters_report_s in "mali_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args); + +/** @} */ /* end group _mali_sw_counters_report */ + /** @} */ /* end group u_k_api */ /** @} */ /* end group uddapi */ diff --git a/drivers/media/video/samsung/mali/common/mali_user_settings_db.c b/drivers/media/video/samsung/mali/common/mali_user_settings_db.c new file mode 100644 index 0000000..681c2b0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_user_settings_db.c @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2012 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_osk.h" +#include "mali_kernel_common.h" +#include "mali_uk_types.h" +#include "mali_user_settings_db.h" +#include "mali_session.h" + +static u32 mali_user_settings[_MALI_UK_USER_SETTING_MAX]; +const char *_mali_uk_user_setting_descriptions[] = _MALI_UK_USER_SETTING_DESCRIPTIONS; + +static void mali_user_settings_notify(_mali_uk_user_setting_t setting, u32 value) +{ + struct mali_session_data *session, *tmp; + + mali_session_lock(); + MALI_SESSION_FOREACH(session, tmp, link) + { + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_SETTINGS_CHANGED, sizeof(_mali_uk_settings_changed_s)); + _mali_uk_settings_changed_s *data = notobj->result_buffer; + data->setting = setting; + data->value = value; + + mali_session_send_notification(session, notobj); + } + mali_session_unlock(); +} + +void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value) +{ + mali_bool notify = MALI_FALSE; + + MALI_DEBUG_ASSERT(setting < _MALI_UK_USER_SETTING_MAX && setting >= 0); + + if (mali_user_settings[setting] != value) + { + notify = MALI_TRUE; + } + + mali_user_settings[setting] = value; + + if (notify) + { + mali_user_settings_notify(setting, value); + } +} + +u32 mali_get_user_setting(_mali_uk_user_setting_t setting) +{ + MALI_DEBUG_ASSERT(setting < _MALI_UK_USER_SETTING_MAX && setting >= 0); + + return mali_user_settings[setting]; +} + +_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args) +{ + _mali_uk_user_setting_t setting; + MALI_DEBUG_ASSERT_POINTER(args); + + setting = args->setting; + + if (0 <= setting && _MALI_UK_USER_SETTING_MAX > setting) + { + args->value = mali_user_settings[setting]; + return _MALI_OSK_ERR_OK; + } + else + { + return _MALI_OSK_ERR_INVALID_ARGS; + } +} + +_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + + _mali_osk_memcpy(args->settings, mali_user_settings, (sizeof(u32) * _MALI_UK_USER_SETTING_MAX)); + + return _MALI_OSK_ERR_OK; +} diff --git a/drivers/media/video/samsung/mali/common/mali_user_settings_db.h b/drivers/media/video/samsung/mali/common/mali_user_settings_db.h new file mode 100644 index 0000000..fbb9415 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_user_settings_db.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2012 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. + */ + +#ifndef __MALI_USER_SETTINGS_DB_H__ +#define __MALI_USER_SETTINGS_DB_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "mali_uk_types.h" + +/** @brief Set Mali user setting in DB + * + * Update the DB with a new value for \a setting. If the value is different from theprevious set value running sessions will be notified of the change. + * + * @param setting the setting to be changed + * @param value the new value to set + */ +void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value); + +/** @brief Get current Mali user setting value from DB + * + * @param setting the setting to extract + * @return the value of the selected setting + */ +u32 mali_get_user_setting(_mali_uk_user_setting_t setting); + +#ifdef __cplusplus +} +#endif +#endif /* __MALI_KERNEL_USER_SETTING__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c deleted file mode 100644 index 7041391..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm.c - * Implementation of the power management module for the kernel device driver - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" -#include "mali_pmm_pmu.h" -#include "mali_platform.h" -#include "mali_kernel_pm.h" - -/* Internal PMM subsystem state */ -static _mali_pmm_internal_state_t *pmm_state = NULL; -/* Mali kernel subsystem id */ -static mali_kernel_subsystem_identifier mali_subsystem_pmm_id = -1; - -#define GET_PMM_STATE_PTR (pmm_state) - -/* Internal functions */ -static _mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource); -static void pmm_event_process( void ); -_mali_osk_errcode_t malipmm_irq_uhandler(void *data); -void malipmm_irq_bhandler(void *data); - -/** @brief Start the PMM subsystem - * - * @param id Subsystem id to uniquely identify this subsystem - * @return _MALI_OSK_ERR_OK if the system started successfully, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id ); - -/** @brief Perform post start up of the PMM subsystem - * - * Post start up includes initializing the current policy, now that the system is - * completely started - to stop policies turning off hardware during the start up - * - * @param id the unique subsystem id - * @return _MALI_OSK_ERR_OK if the post startup was successful, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id ); - -/** @brief Terminate the PMM subsystem - * - * @param id the unique subsystem id - */ -void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id ); - -#if MALI_STATE_TRACKING -u32 malipmm_subsystem_dump_state( char *buf, u32 size ); -#endif - - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ -struct mali_kernel_subsystem mali_subsystem_pmm= -{ - malipmm_kernel_subsystem_start, /* startup */ - NULL, /*malipmm_kernel_subsystem_terminate,*/ /* shutdown */ - malipmm_kernel_load_complete, /* loaded all subsystems */ - NULL, - NULL, - NULL, - NULL, -#if MALI_STATE_TRACKING - malipmm_subsystem_dump_state, /* dump_state */ -#endif -}; - -#if PMM_OS_TEST - -u32 power_test_event = 0; -mali_bool power_test_flag = MALI_FALSE; -_mali_osk_timer_t *power_test_timer = NULL; - -void _mali_osk_pmm_power_up_done(mali_pmm_message_data data) -{ - MALI_PRINT(("POWER TEST OS UP DONE\n")); -} - -void _mali_osk_pmm_power_down_done(mali_pmm_message_data data) -{ - MALI_PRINT(("POWER TEST OS DOWN DONE\n")); -} - -/** - * Symbian OS Power Up call to the driver - */ -void power_test_callback( void *arg ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - power_test_flag = MALI_TRUE; - _mali_osk_irq_schedulework( pmm->irq ); -} - -void power_test_start() -{ - power_test_timer = _mali_osk_timer_init(); - _mali_osk_timer_setcallback( power_test_timer, power_test_callback, NULL ); - - /* First event is power down */ - power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN; - _mali_osk_timer_add( power_test_timer, 10000 ); -} - -mali_bool power_test_check() -{ - if( power_test_flag ) - { - _mali_uk_pmm_message_s event = { - NULL, - 0, - 1 }; - event.id = power_test_event; - - power_test_flag = MALI_FALSE; - - /* Send event */ - _mali_ukk_pmm_event_message( &event ); - - /* Switch to next event to test */ - if( power_test_event == MALI_PMM_EVENT_OS_POWER_DOWN ) - { - power_test_event = MALI_PMM_EVENT_OS_POWER_UP; - } - else - { - power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN; - } - _mali_osk_timer_add( power_test_timer, 5000 ); - - return MALI_TRUE; - } - - return MALI_FALSE; -} - -void power_test_end() -{ - _mali_osk_timer_del( power_test_timer ); - _mali_osk_timer_term( power_test_timer ); - power_test_timer = NULL; -} - -#endif - -void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - _mali_osk_notification_t *msg; - mali_pmm_message_t *event; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(args); - - MALIPMM_DEBUG_PRINT( ("PMM: sending message\n") ); - -#if MALI_PMM_TRACE && MALI_PMM_TRACE_SENT_EVENTS - _mali_pmm_trace_event_message( args, MALI_FALSE ); -#endif - - msg = _mali_osk_notification_create( MALI_PMM_NOTIFICATION_TYPE, sizeof( mali_pmm_message_t ) ); - - if( msg ) - { - event = (mali_pmm_message_t *)msg->result_buffer; - event->id = args->id; - event->ts = _mali_osk_time_tickcount(); - event->data = args->data; - - _mali_osk_atomic_inc( &(pmm->messages_queued) ); - - if( args->id > MALI_PMM_EVENT_INTERNALS ) - { - /* Internal PMM message */ - _mali_osk_notification_queue_send( pmm->iqueue, msg ); - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->imessages_sent++; - #endif - } - else - { - /* Real event */ - _mali_osk_notification_queue_send( pmm->queue, msg ); - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->messages_sent++; - #endif - } - } - else - { - MALI_PRINT_ERROR( ("PMM: Could not send message %d", args->id) ); - /* Make note of this OOM - which has caused a missed event */ - pmm->missed++; - } - - /* Schedule time to look at the event or the fact we couldn't create an event */ - _mali_osk_irq_schedulework( pmm->irq ); -} - -mali_pmm_state _mali_pmm_state( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm && (mali_subsystem_pmm_id != -1) ) - { - return pmm->state; - } - - /* No working subsystem yet */ - return MALI_PMM_STATE_UNAVAILABLE; -} - - -mali_pmm_core_mask _mali_pmm_cores_list( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - return pmm->cores_registered; -} - -mali_pmm_core_mask _mali_pmm_cores_powered( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - return pmm->cores_powered; -} - - -_mali_osk_errcode_t _mali_pmm_list_policies( - u32 policy_list_size, - mali_pmm_policy *policy_list, - u32 *policies_available ) -{ - /* TBD - This is currently a stub function for basic power management */ - - MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED ); -} - -_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy ) -{ - /* TBD - This is currently a stub function for basic power management */ - -/* TBD - When this is not a stub... include tracing... -#if MALI_PMM_TRACE - _mali_pmm_trace_policy_change( old, newpolicy ); -#endif -*/ - MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED ); -} - -_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy ) -{ - if( policy ) - { - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm ) - { - *policy = pmm->policy; - MALI_SUCCESS; - } - else - { - *policy = MALI_PMM_POLICY_NONE; - MALI_ERROR( _MALI_OSK_ERR_FAULT ); - } - } - - /* No return argument */ - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); -} - -#if ( MALI_PMM_TRACE || MALI_STATE_TRACKING ) - -/* Event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events[] = { - "OS_POWER_UP", - "OS_POWER_DOWN", - "JOB_SCHEDULED", - "JOB_QUEUED", - "JOB_FINISHED", - "TIMEOUT", -}; - -/* State names - order must match mali_pmm_state enum */ -static char *pmm_trace_state[] = { - "UNAVAILABLE", - "SYSTEM ON", - "SYSTEM OFF", - "SYSTEM TRANSITION", -}; - -/* Policy names - order must match mali_pmm_policy enum */ -static char *pmm_trace_policy[] = { - "NONE", - "ALWAYS ON", - "JOB CONTROL", -}; - -/* Status names - order must match mali_pmm_status enum */ -static char *pmm_trace_status[] = { - "MALI_PMM_STATUS_IDLE", /**< PMM is waiting next event */ - "MALI_PMM_STATUS_POLICY_POWER_DOWN", /**< Policy initiated power down */ - "MALI_PMM_STATUS_POLICY_POWER_UP", /**< Policy initiated power down */ - "MALI_PMM_STATUS_OS_WAITING", /**< PMM is waiting for OS power up */ - "MALI_PMM_STATUS_OS_POWER_DOWN", /**< OS initiated power down */ - "MALI_PMM_STATUS_RUNTIME_IDLE_IN_PROGRESS", - "MALI_PMM_STATUS_DVFS_PAUSE", /**< PMM DVFS Status Pause */ - "MALI_PMM_STATUS_OS_POWER_UP", /**< OS initiated power up */ - "MALI_PMM_STATUS_OFF", /**< PMM is not active */ -}; - -#endif /* MALI_PMM_TRACE || MALI_STATE_TRACKING */ -#if MALI_PMM_TRACE - -/* UK event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events_uk[] = { - "UKS", - "UK_EXAMPLE", -}; - -/* Internal event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events_internal[] = { - "INTERNALS", - "INTERNAL_POWER_UP_ACK", - "INTERNAL_POWER_DOWN_ACK", -}; - -void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate ) -{ - const char *dname; - const char *cname; - const char *ename; - - if( old != newstate ) - { - if( newstate == 0 ) - { - dname = "NO cores"; - } - else - { - dname = pmm_trace_get_core_name( newstate ); - } - - /* These state checks only work if the assumption that only cores can be - * turned on or turned off in seperate actions is true. If core power states can - * be toggled (some one, some off) at the same time, this check does not work - */ - if( old > newstate ) - { - /* Cores have turned off */ - cname = pmm_trace_get_core_name( old - newstate ); - ename = "OFF"; - } - else - { - /* Cores have turned on */ - cname = pmm_trace_get_core_name( newstate - old ); - ename = "ON"; - } - MALI_PRINT( ("PMM Trace: Hardware %s ON, %s just turned %s. { 0x%08x -> 0x%08x }", dname, cname, ename, old, newstate) ); - } -} - -void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate ) -{ - if( old != newstate ) - { - MALI_PRINT( ("PMM Trace: State changed from %s to %s", pmm_trace_state[old], pmm_trace_state[newstate]) ); - } -} - -void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy ) -{ - if( old != newpolicy ) - { - MALI_PRINT( ("PMM Trace: Policy changed from %s to %s", pmm_trace_policy[old], pmm_trace_policy[newpolicy]) ); - } -} - -void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received ) -{ - const char *ename; - const char *dname; - const char *tname; - const char *format = "PMM Trace: Event %s { (%d) %s, %d ticks, (0x%x) %s }"; - - MALI_DEBUG_ASSERT_POINTER(event); - - tname = (received) ? "received" : "sent"; - - if( event->id >= MALI_PMM_EVENT_INTERNALS ) - { - ename = pmm_trace_events_internal[((int)event->id) - MALI_PMM_EVENT_INTERNALS]; - } - else if( event->id >= MALI_PMM_EVENT_UKS ) - { - ename = pmm_trace_events_uk[((int)event->id) - MALI_PMM_EVENT_UKS]; - } - else - { - ename = pmm_trace_events[event->id]; - } - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - case MALI_PMM_EVENT_OS_POWER_DOWN: - dname = "os event"; - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - dname = pmm_trace_get_core_name( (mali_pmm_core_mask)event->data ); - break; - - case MALI_PMM_EVENT_TIMEOUT: - dname = "timeout start"; - /* Print data with a different format */ - format = "PMM Trace: Event %s { (%d) %s, %d ticks, %d ticks %s }"; - break; - default: - dname = "unknown data"; - } - - MALI_PRINT( (format, tname, (u32)event->id, ename, event->ts, (u32)event->data, dname) ); -} - -#endif /* MALI_PMM_TRACE */ - - -/****************** Mali Kernel API *****************/ - -_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id ) -{ - mali_subsystem_pmm_id = id; - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(PMU, malipmm_create)); - MALI_SUCCESS; -} - -_mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource) -{ - /* Create PMM state memory */ - MALI_DEBUG_ASSERT( pmm_state == NULL ); - pmm_state = (_mali_pmm_internal_state_t *) _mali_osk_malloc(sizeof(*pmm_state)); - MALI_CHECK_NON_NULL( pmm_state, _MALI_OSK_ERR_NOMEM ); - - /* All values get 0 as default */ - _mali_osk_memset(pmm_state, 0, sizeof(*pmm_state)); - - /* Set up the initial PMM state */ - pmm_state->waiting = 0; - pmm_state->status = MALI_PMM_STATUS_IDLE; - pmm_state->state = MALI_PMM_STATE_UNAVAILABLE; /* Until a core registers */ - - /* Set up policy via compile time option for the moment */ -#if MALI_PMM_ALWAYS_ON - pmm_state->policy = MALI_PMM_POLICY_ALWAYS_ON; -#else - pmm_state->policy = MALI_PMM_POLICY_JOB_CONTROL; -#endif - -#if MALI_PMM_TRACE - _mali_pmm_trace_policy_change( MALI_PMM_POLICY_NONE, pmm_state->policy ); -#endif - - /* Set up assumes all values are initialized to NULL or MALI_FALSE, so - * we can exit halfway through set up and perform clean up - */ - -#if USING_MALI_PMU - if( mali_pmm_pmu_init(resource) != _MALI_OSK_ERR_OK ) goto pmm_fail_cleanup; - pmm_state->pmu_initialized = MALI_TRUE; -#endif - pmm_state->queue = _mali_osk_notification_queue_init(); - if( !pmm_state->queue ) goto pmm_fail_cleanup; - - pmm_state->iqueue = _mali_osk_notification_queue_init(); - if( !pmm_state->iqueue ) goto pmm_fail_cleanup; - - /* We are creating an IRQ handler just for the worker thread it gives us */ - pmm_state->irq = _mali_osk_irq_init( _MALI_OSK_IRQ_NUMBER_PMM, - malipmm_irq_uhandler, - malipmm_irq_bhandler, - NULL, - NULL, - (void *)pmm_state, /* PMM state is passed to IRQ */ - "PMM handler" ); - - if( !pmm_state->irq ) goto pmm_fail_cleanup; - - pmm_state->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 75); - if( !pmm_state->lock ) goto pmm_fail_cleanup; - - if( _mali_osk_atomic_init( &(pmm_state->messages_queued), 0 ) != _MALI_OSK_ERR_OK ) - { - goto pmm_fail_cleanup; - } - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem created, policy=%d\n", pmm_state->policy) ); - - MALI_SUCCESS; - -pmm_fail_cleanup: - MALI_PRINT_ERROR( ("PMM: subsystem failed to be created\n") ); - if( pmm_state ) - { - if( pmm_state->lock ) _mali_osk_lock_term( pmm_state->lock ); - if( pmm_state->irq ) _mali_osk_irq_term( pmm_state->irq ); - if( pmm_state->queue ) _mali_osk_notification_queue_term( pmm_state->queue ); - if( pmm_state->iqueue ) _mali_osk_notification_queue_term( pmm_state->iqueue ); -#if USING_MALI_PMU - if( pmm_state->pmu_initialized ) - { - _mali_osk_resource_type_t t = PMU; - mali_pmm_pmu_deinit(&t); - } -#endif /* USING_MALI_PMU */ - - _mali_osk_free(pmm_state); - pmm_state = NULL; - } - MALI_ERROR( _MALI_OSK_ERR_FAULT ); -} - -_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem loaded, policy initializing\n") ); - -#if PMM_OS_TEST - power_test_start(); -#endif - - /* Initialize the profile now the system has loaded - so that cores are - * not turned off during start up - */ - return pmm_policy_init( pmm ); -} - -void malipmm_force_powerup( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_LOCK(pmm); - pmm->status = MALI_PMM_STATUS_OFF; - MALI_PMM_UNLOCK(pmm); - - /* flush PMM workqueue */ - _mali_osk_flush_workqueue( pmm->irq ); - - if (pmm->cores_powered == 0) - { - malipmm_powerup(pmm->cores_registered); - } -} - -void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id ) -{ - /* Check this is the right system */ - MALI_DEBUG_ASSERT( id == mali_subsystem_pmm_id ); - MALI_DEBUG_ASSERT_POINTER(pmm_state); - - if( pmm_state ) - { -#if PMM_OS_TEST - power_test_end(); -#endif - /* Get the lock so we can shutdown */ - MALI_PMM_LOCK(pmm_state); -#if MALI_STATE_TRACKING - pmm_state->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - pmm_state->status = MALI_PMM_STATUS_OFF; -#if MALI_STATE_TRACKING - pmm_state->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - MALI_PMM_UNLOCK(pmm_state); - _mali_osk_pmm_ospmm_cleanup(); - pmm_policy_term(pmm_state); - _mali_osk_irq_term( pmm_state->irq ); - _mali_osk_notification_queue_term( pmm_state->queue ); - _mali_osk_notification_queue_term( pmm_state->iqueue ); - if (pmm_state->cores_registered) malipmm_powerdown(pmm_state->cores_registered,MALI_POWER_MODE_LIGHT_SLEEP); -#if USING_MALI_PMU - if( pmm_state->pmu_initialized ) - { - _mali_osk_resource_type_t t = PMU; - mali_pmm_pmu_deinit(&t); - } -#endif /* USING_MALI_PMU */ - - _mali_osk_atomic_term( &(pmm_state->messages_queued) ); - MALI_PMM_LOCK_TERM(pmm_state); - _mali_osk_free(pmm_state); - pmm_state = NULL; - } - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem terminated\n") ); -} - -_mali_osk_errcode_t malipmm_powerup( u32 cores ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - /* If all the cores are powered down, power up the MALI */ - if (pmm->cores_powered == 0) { - mali_platform_power_mode_change(MALI_POWER_MODE_ON); -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - /* Initiate the power up */ - if (_mali_osk_pmm_dev_activate() < 0) { - MALI_PRINT(("PMM: Try again PD_G3D enable\n")); - if (mali_pd_enable() < 0) { - MALI_PRINT(("PMM: Mali PMM device activate failed\n")); - err = _MALI_OSK_ERR_FAULT; - return err; - } - } -#endif - } - -#if USING_MALI_PMU - err = mali_pmm_pmu_powerup( cores ); -#endif - -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - mali_platform_powerup(cores); -#endif - - return err; -} - -_mali_osk_errcode_t malipmm_powerdown( u32 cores, mali_power_mode power_mode ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - mali_platform_powerdown(cores); -#endif - -#if USING_MALI_PMU - err = mali_pmm_pmu_powerdown( cores ); -#endif - - /* If all cores are powered down, power off the MALI */ - if (pmm->cores_powered == 0) - { -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - /* Initiate the power down */ - _mali_osk_pmm_dev_idle(); -#endif - mali_platform_power_mode_change(power_mode); - } - return err; -} - -_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core ) -{ - _mali_osk_errcode_t err; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - if( pmm == NULL ) - { - /* PMM state has not been created, this is because the PMU resource has not been - * created yet. - * This probably means that the PMU resource has not been specfied as the first - * resource in the config file - */ - MALI_PRINT_ERROR( ("PMM: Cannot register core %s because the PMU resource has not been\n initialized. Please make sure the PMU resource is the first resource in the\n resource configuration.\n", - pmm_trace_get_core_name(core)) ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Check if the core is registered more than once in PMM */ - MALI_DEBUG_ASSERT( (pmm->cores_registered & core) == 0 ); - - MALIPMM_DEBUG_PRINT( ("PMM: core registered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) ); - -#if !MALI_PMM_NO_PMU - /* Make sure the core is powered up */ - err = malipmm_powerup( core ); -#else - err = _MALI_OSK_ERR_OK; -#endif - if( _MALI_OSK_ERR_OK == err ) - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Assume a registered core is now powered up and idle */ - pmm->cores_registered |= core; - pmm->cores_idle |= core; - pmm->cores_powered |= core; - pmm_update_system_state( pmm ); - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - else - { - MALI_PRINT_ERROR( ("PMM: Error(%d) powering up registered core: (0x%x) %s\n", - err, core, pmm_trace_get_core_name(core)) ); - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - - return err; -} - -void malipmm_core_unregister( mali_pmm_core_id core ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Check if the core is registered in PMM */ - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, core ); - - MALIPMM_DEBUG_PRINT( ("PMM: core unregistered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) ); - - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - - /* Remove the core from the system */ - pmm->cores_idle &= (~core); - pmm->cores_powered &= (~core); - pmm->cores_pend_down &= (~core); - pmm->cores_pend_up &= (~core); - pmm->cores_ack_down &= (~core); - pmm->cores_ack_up &= (~core); - - pmm_update_system_state( pmm ); - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); -} -void malipmm_core_power_down_okay( mali_pmm_core_id core ) -{ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK, - 0 }; - - event.data = core; - - _mali_ukk_pmm_event_message( &event ); -} - -void malipmm_set_policy_check() -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - pmm->check_policy = MALI_TRUE; - - /* To check the policy we need to schedule some work */ - _mali_osk_irq_schedulework( pmm->irq ); -} - -_mali_osk_errcode_t malipmm_irq_uhandler(void *data) -{ - MALIPMM_DEBUG_PRINT( ("PMM: uhandler - not expected to be used\n") ); - - MALI_SUCCESS; -} - -void malipmm_irq_bhandler(void *data) -{ - _mali_pmm_internal_state_t *pmm; - pmm = (_mali_pmm_internal_state_t *)data; - MALI_DEBUG_ASSERT_POINTER(pmm); - -#if PMM_OS_TEST - if( power_test_check() ) return; -#endif - - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* Quick out when we are shutting down */ - if( pmm->status == MALI_PMM_STATUS_OFF ) - { - - #if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; - #endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - return; - } - - MALIPMM_DEBUG_PRINT( ("PMM: bhandler - Processing event\n") ); - - if( pmm->missed > 0 ) - { - MALI_PRINT_ERROR( ("PMM: Failed to send %d events", pmm->missed) ); - pmm_fatal_reset( pmm ); - } - - if( pmm->check_policy ) - { - pmm->check_policy = MALI_FALSE; - pmm_policy_check_policy(pmm); - } - else - { - /* Perform event processing */ - pmm_event_process(); - if( pmm->fatal_power_err ) - { - /* Try a reset */ - pmm_fatal_reset( pmm ); - } - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); -} - -static void pmm_event_process( void ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_osk_notification_t *msg = NULL; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - mali_pmm_message_t *event; - u32 process_messages; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - - /* Max number of messages to process before exiting - as we shouldn't stay - * processing the messages for a long time - */ - process_messages = _mali_osk_atomic_read( &(pmm->messages_queued) ); - - while( process_messages > 0 ) - { - /* Check internal message queue first */ - err = _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ); - - if( err != _MALI_OSK_ERR_OK ) - { - if( pmm->status == MALI_PMM_STATUS_IDLE || pmm->status == MALI_PMM_STATUS_OS_WAITING || pmm->status == MALI_PMM_STATUS_DVFS_PAUSE) - { - if( pmm->waiting > 0 ) pmm->waiting--; - - /* We aren't busy changing state, so look at real events */ - err = _mali_osk_notification_queue_dequeue( pmm->queue, &msg ); - - if( err != _MALI_OSK_ERR_OK ) - { - pmm->no_events++; - MALIPMM_DEBUG_PRINT( ("PMM: event_process - No message to process\n") ); - /* Nothing to do - so return */ - return; - } - else - { - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->messages_received++; - #endif - } - } - else - { - /* Waiting for an internal message */ - pmm->waiting++; - MALIPMM_DEBUG_PRINT( ("PMM: event_process - Waiting for internal message, messages queued=%d\n", pmm->waiting) ); - return; - } - } - else - { - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->imessages_received++; - #endif - } - - MALI_DEBUG_ASSERT_POINTER( msg ); - /* Check the message type matches */ - MALI_DEBUG_ASSERT( msg->notification_type == MALI_PMM_NOTIFICATION_TYPE ); - - event = msg->result_buffer; - - _mali_osk_atomic_dec( &(pmm->messages_queued) ); - process_messages--; - - #if MALI_PMM_TRACE - /* Trace before we process the event in case we have an error */ - _mali_pmm_trace_event_message( event, MALI_TRUE ); - #endif - err = pmm_policy_process( pmm, event ); - - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_PRINT_ERROR( ("PMM: Error(%d) in policy %d when processing event message with id: %d", - err, pmm->policy, event->id) ); - } - - /* Delete notification */ - _mali_osk_notification_delete ( msg ); - - if( pmm->fatal_power_err ) - { - /* Nothing good has happened - exit */ - return; - } - - - #if MALI_PMM_TRACE - MALI_PRINT( ("PMM Trace: Event processed, msgs (sent/read) = %d/%d, int msgs (sent/read) = %d/%d, no events = %d, waiting = %d\n", - pmm->messages_sent, pmm->messages_received, pmm->imessages_sent, pmm->imessages_received, pmm->no_events, pmm->waiting) ); - #endif - } - - if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->waiting > 0 ) - { - /* For events we ignored whilst we were busy, add a new - * scheduled time to look at them */ - _mali_osk_irq_schedulework( pmm->irq ); - } -} - -#if MALI_STATE_TRACKING -u32 malipmm_subsystem_dump_state(char *buf, u32 size) -{ - int len = 0; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - if( !pmm ) - { - len += _mali_osk_snprintf(buf + len, size + len, "PMM: Null state\n"); - } - else - { - len += _mali_osk_snprintf(buf+len, size+len, "Locks:\n PMM lock acquired: %s\n", - pmm->mali_pmm_lock_acquired ? "true" : "false"); - len += _mali_osk_snprintf(buf+len, size+len, - "PMM state:\n Previous status: %s\n Status: %s\n Current event: %s\n Policy: %s\n Check policy: %s\n State: %s\n", - pmm_trace_status[pmm->mali_last_pmm_status], pmm_trace_status[pmm->status], - pmm_trace_events[pmm->mali_new_event_status], pmm_trace_policy[pmm->policy], - pmm->check_policy ? "true" : "false", pmm_trace_state[pmm->state]); - len += _mali_osk_snprintf(buf+len, size+len, - "PMM cores:\n Cores registered: %d\n Cores powered: %d\n Cores idle: %d\n" - " Cores pending down: %d\n Cores pending up: %d\n Cores ack down: %d\n Cores ack up: %d\n", - pmm->cores_registered, pmm->cores_powered, pmm->cores_idle, pmm->cores_pend_down, - pmm->cores_pend_up, pmm->cores_ack_down, pmm->cores_ack_up); - len += _mali_osk_snprintf(buf+len, size+len, "PMM misc:\n PMU init: %s\n Messages queued: %d\n" - " Waiting: %d\n No events: %d\n Missed events: %d\n Fatal power error: %s\n", - pmm->pmu_initialized ? "true" : "false", _mali_osk_atomic_read(&(pmm->messages_queued)), - pmm->waiting, pmm->no_events, pmm->missed, pmm->fatal_power_err ? "true" : "false"); - } - return len; -} -#endif /* MALI_STATE_TRACKING */ - -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h deleted file mode 100644 index 5170650..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm.h - * Defines the power management module for the kernel device driver - */ - -#ifndef __MALI_PMM_H__ -#define __MALI_PMM_H__ - -/* For mali_pmm_message_data and MALI_PMM_EVENT_UK_* defines */ -#include "mali_uk_types.h" -#include "mali_platform.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @defgroup pmmapi Power Management Module APIs - * - * @{ - */ - -/** OS event tester */ -#define PMM_OS_TEST 0 - -/** @brief Compile option to turn on/off tracing */ -#define MALI_PMM_TRACE 0 -#define MALI_PMM_TRACE_SENT_EVENTS 0 - -/** @brief Compile option to switch between always on or job control PMM policy */ -#define MALI_PMM_ALWAYS_ON 0 - -/** @brief Overrides hardware PMU and uses software simulation instead - * @note This even stops intialization of PMU and cores being powered on at start up - */ -#define MALI_PMM_NO_PMU 0 - -/** @brief PMM debug print to control debug message level */ -#define MALIPMM_DEBUG_PRINT(args) \ - MALI_DEBUG_PRINT(3, args) - - -/** @brief power management event message identifiers. - */ -/* These must match up with the pmm_trace_events & pmm_trace_events_internal - * arrays - */ -typedef enum mali_pmm_event_id -{ - MALI_PMM_EVENT_OS_POWER_UP = 0, /**< OS power up event */ - MALI_PMM_EVENT_OS_POWER_DOWN = 1, /**< OS power down event */ - MALI_PMM_EVENT_JOB_SCHEDULED = 2, /**< Job scheduled to run event */ - MALI_PMM_EVENT_JOB_QUEUED = 3, /**< Job queued (but not run) event */ - MALI_PMM_EVENT_JOB_FINISHED = 4, /**< Job finished event */ - MALI_PMM_EVENT_TIMEOUT = 5, /**< Time out timer has expired */ - MALI_PMM_EVENT_DVFS_PAUSE = 6, /**< Mali device pause event */ - MALI_PMM_EVENT_DVFS_RESUME = 7, /**< Mali device resume event */ - - MALI_PMM_EVENT_UKS = 200, /**< Events from the user-side start here */ - MALI_PMM_EVENT_UK_EXAMPLE = _MALI_PMM_EVENT_UK_EXAMPLE, - - MALI_PMM_EVENT_INTERNALS = 1000, - MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK = 1001, /**< Internal power up acknowledgement */ - MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK = 1002, /**< Internal power down acknowledgment */ -} mali_pmm_event_id; - - -/** @brief Use this when the power up/down callbacks do not need any OS data. */ -#define MALI_PMM_NO_OS_DATA 1 - - -/* @brief Geometry and pixel processor identifiers for the PMM - * - * @note these match the ARM Mali 400 PMU hardware definitions, apart from the "SYSTEM" - */ -typedef enum mali_pmm_core_id_tag -{ - MALI_PMM_CORE_SYSTEM = 0x00000000, /**< All of the Mali hardware */ - MALI_PMM_CORE_GP = 0x00000001, /**< Mali GP2 */ - MALI_PMM_CORE_L2 = 0x00000002, /**< Level 2 cache */ - MALI_PMM_CORE_PP0 = 0x00000004, /**< Mali 200 pixel processor 0 */ - MALI_PMM_CORE_PP1 = 0x00000008, /**< Mali 200 pixel processor 1 */ - MALI_PMM_CORE_PP2 = 0x00000010, /**< Mali 200 pixel processor 2 */ - MALI_PMM_CORE_PP3 = 0x00000020, /**< Mali 200 pixel processor 3 */ - MALI_PMM_CORE_PP_ALL = 0x0000003C /**< Mali 200 pixel processors 0-3 */ -} mali_pmm_core_id; - - -/* @brief PMM bitmask of mali_pmm_core_ids - */ -typedef u32 mali_pmm_core_mask; - -/* @brief PMM event timestamp type - */ -typedef u32 mali_pmm_timestamp; - -/** @brief power management event message struct - */ -typedef struct _mali_pmm_message -{ - mali_pmm_event_id id; /**< event id */ - mali_pmm_message_data data; /**< specific data associated with the event */ - mali_pmm_timestamp ts; /**< timestamp the event was placed in the event queue */ -} mali_pmm_message_t; - - - -/** @brief the state of the power management module. - */ -/* These must match up with the pmm_trace_state array */ -typedef enum mali_pmm_state_tag -{ - MALI_PMM_STATE_UNAVAILABLE = 0, /**< PMM is not available */ - MALI_PMM_STATE_SYSTEM_ON = 1, /**< All of the Mali hardware is on */ - MALI_PMM_STATE_SYSTEM_OFF = 2, /**< All of the Mali hardware is off */ - MALI_PMM_STATE_SYSTEM_TRANSITION = 3 /**< System is changing state */ -} mali_pmm_state; - - -/** @brief a power management policy. - */ -/* These must match up with the pmm_trace_policy array */ -typedef enum mali_pmm_policy_tag -{ - MALI_PMM_POLICY_NONE = 0, /**< No policy */ - MALI_PMM_POLICY_ALWAYS_ON = 1, /**< Always on policy */ - MALI_PMM_POLICY_JOB_CONTROL = 2, /**< Job control policy */ - MALI_PMM_POLICY_RUNTIME_JOB_CONTROL = 3 /**< Run time power management control policy */ -} mali_pmm_policy; - -/** @brief Function to power up MALI - * - * @param cores core mask to power up the cores - * - * @return error code if MALI fails to power up - */ -_mali_osk_errcode_t malipmm_powerup( u32 cores ); - -/** @brief Function to power down MALI - * - * @param cores core mask to power down the cores - * @param The power mode to which MALI transitions - * - * @return error code if MALI fails to power down - */ -_mali_osk_errcode_t malipmm_powerdown( u32 cores, mali_power_mode power_mode ); - -/** @brief Function to report to the OS when the power down has finished - * - * @param data The event message data that initiated the power down - */ -void _mali_osk_pmm_power_down_done(mali_pmm_message_data data); - -/** @brief Function to report to the OS when the power up has finished - * - * @param data The event message data that initiated the power up - */ -void _mali_osk_pmm_power_up_done(mali_pmm_message_data data); - -/** @brief Function to report that DVFS operation done - * - * @param data The event message data - */ -void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data); - -#if MALI_POWER_MGMT_TEST_SUITE -/** @brief Function to notify power management events - * - * @param data The event message data - */ -void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id event_id); - -#endif - -/** @brief Function to power up MALI - * - * @note powers up the MALI during MALI device driver is unloaded - */ -void malipmm_force_powerup( void ); - -/** @brief Function to report the OS that device is idle - * - * @note inform the OS that device is idle - */ -_mali_osk_errcode_t _mali_osk_pmm_dev_idle( void ); - -/** @brief Function to report the OS to activate device - * - * @note inform the os that device needs to be activated - */ -int _mali_osk_pmm_dev_activate( void ); - -/** @brief Function to report OS PMM for cleanup - * - * @note Function to report OS PMM for cleanup - */ -void _mali_osk_pmm_ospmm_cleanup( void ); - -/** @brief Queries the current state of the PMM software - * - * @note the state of the PMM can change after this call has returned - * - * @return the current PMM state value - */ -mali_pmm_state _mali_pmm_state( void ); - -/** @brief List of cores that are registered with the PMM - * - * This will return the cores that have been currently registered with the PMM, - * which is a bitwise OR of the mali_pmm_core_id_tags. A value of 0x0 means that - * there are no cores registered. - * - * @note the list of cores can change after this call has returned - * - * @return a bit mask representing all the cores that have been registered with the PMM - */ -mali_pmm_core_mask _mali_pmm_cores_list( void ); - -/** @brief List of cores that are powered up in the PMM - * - * This will return the subset of the cores that can be listed using mali_pmm_cores_ - * list, that have power. It is a bitwise OR of the mali_pmm_core_id_tags. A value of - * 0x0 means that none of the cores registered are powered. - * - * @note the list of cores can change after this call has returned - * - * @return a bit mask representing all the cores that are powered up - */ -mali_pmm_core_mask _mali_pmm_cores_powered( void ); - - -/** @brief List of power management policies that are supported by the PMM - * - * Given an empty array of policies - policy_list - which contains the number - * of entries as specified by - policy_list_size, this function will populate - * the list with the available policies. If the policy_list is too small for - * all the policies then only policy_list_size entries will be returned. If the - * policy_list is bigger than the number of available policies then, the extra - * entries will be set to MALI_PMM_POLICY_NONE. - * The function will also update available_policies with the number of policies - * that are available, even if it exceeds the policy_list_size. - * The function will succeed if all policies could be returned, else it will - * fail if none or only a subset of policies could be returned. - * The function will also fail if no policy_list is supplied, though - * available_policies is optional. - * - * @note this is a STUB function and is not yet implemented - * - * @param policy_list_size is the number of policies that can be returned in - * the policy_list argument - * @param policy_list is an array of policies that should be populated with - * the list of policies that are supported by the PMM - * @param policies_available optional argument, if non-NULL will be set to the - * number of policies available - * @return _MALI_OSK_ERR_OK if the policies could be listed, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_list_policies( - u32 policy_list_size, - mali_pmm_policy *policy_list, - u32 *policies_available ); - -/** @brief Set the power management policy in the PMM - * - * Given a valid supported policy, this function will change the PMM to use - * this new policy - * The function will fail if the policy given is invalid or unsupported. - * - * @note this is a STUB function and is not yet implemented - * - * @param policy the new policy to be set - * @return _MALI_OSK_ERR_OK if the policy could be set, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy ); - -/** @brief Get the current power management policy in the PMM - * - * Given a pointer to a policy data type, this function will return the current - * policy that is in effect for the PMM. This maybe out of date if there is a - * pending set policy call that has not been serviced. - * The function will fail if the policy given is NULL. - * - * @note the policy of the PMM can change after this call has returned - * - * @param policy a pointer to a policy that can be updated to the current - * policy - * @return _MALI_OSK_ERR_OK if the policy could be returned, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy ); - -#if MALI_PMM_TRACE - -/** @brief Indicates when a hardware state change occurs in the PMM - * - * @param old a mask of the cores indicating the previous state of the cores - * @param newstate a mask of the cores indicating the new current state of the cores - */ -void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate ); - -/** @brief Indicates when a state change occurs in the PMM - * - * @param old the previous state for the PMM - * @param newstate the new current state of the PMM - */ -void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate ); - -/** @brief Indicates when a policy change occurs in the PMM - * - * @param old the previous policy for the PMM - * @param newpolicy the new current policy of the PMM - */ -void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy ); - -/** @brief Records when an event message is read by the event system - * - * @param event the message details - * @param received MALI_TRUE when the message is received by the PMM, else it is being sent - */ -void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received ); - -#endif /* MALI_PMM_TRACE */ - -/** @brief Dumps the current state of OS PMM thread - */ -#if MALI_STATE_TRACKING -u32 mali_pmm_dump_os_thread_state( char *buf, u32 size ); -#endif /* MALI_STATE_TRACKING */ - -/** @} */ /* end group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c deleted file mode 100644 index a8160ac..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_pmu.c - * Mali driver functions for Mali 400 PMU hardware - */ -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_platform.h" - -#if USING_MALI_PMU -#if USING_MALI_PMM - -#include "mali_pmm.h" - -/* Internal test on/off */ -#define PMU_TEST 0 - -#if MALI_POWER_MGMT_TEST_SUITE -#include "mali_platform_pmu_internal_testing.h" -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - -/** @brief PMU hardware info - */ -typedef struct platform_pmu -{ - u32 reg_base_addr; /**< PMU registers base address */ - u32 reg_size; /**< PMU registers size */ - const char *name; /**< PMU name */ - u32 irq_num; /**< PMU irq number */ - - mali_io_address reg_mapped; /**< IO-mapped pointer to registers */ -} platform_pmu_t; - -static platform_pmu_t *pmu_info = NULL; - -/** @brief Register layout for hardware PMU - */ -typedef enum { - PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ - PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ - PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ - PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ - PMU_REG_ADDR_MGMT_INT_RAWSTAT = 0x10, /*< Interrupt raw status register */ - PMU_REG_ADDR_MGMT_INT_STAT = 0x14, /*< Interrupt status register */ - PMU_REG_ADDR_MGMT_INT_CLEAR = 0x18, /*< Interrupt clear register */ - PMU_REG_ADDR_MGMT_SW_DELAY = 0x1C, /*< Software delay register */ - PMU_REG_ADDR_MGMT_MASTER_PWR_UP = 0x24, /*< Master power up register */ - PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x28, /*< Size of register space */ -} pmu_reg_addr_mgmt_addr; - -/* Internal functions */ -static u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address); -static void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val); -static mali_pmm_core_mask pmu_translate_cores_to_pmu(mali_pmm_core_mask cores); -#if PMU_TEST -static void pmm_pmu_dump_regs( platform_pmu_t *pmu ); -static pmm_pmu_test( platform_pmu_t *pmu, u32 cores ); -#endif - -_mali_osk_errcode_t mali_pmm_pmu_init(_mali_osk_resource_t *resource) -{ - - if( resource->type == PMU ) - { - if( (resource->base == 0) || - (resource->description == NULL) ) - { - /* NOTE: We currently don't care about any other resource settings */ - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Missing PMU set up information\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - pmu_info = (platform_pmu_t *)_mali_osk_malloc(sizeof(*pmu_info)); - MALI_CHECK_NON_NULL( pmu_info, _MALI_OSK_ERR_NOMEM ); - - /* All values get 0 as default */ - _mali_osk_memset(pmu_info, 0, sizeof(*pmu_info)); - - pmu_info->reg_base_addr = resource->base; - pmu_info->reg_size = (u32)PMU_REGISTER_ADDRESS_SPACE_SIZE; - pmu_info->name = resource->description; - pmu_info->irq_num = resource->irq; - - if( _MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name) ) - { - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not request register region (0x%08X - 0x%08X) for %s\n", - pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); - goto cleanup; - } - else - { - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: request_mem_region: (0x%08X - 0x%08X) for %s\n", - pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); - } - - pmu_info->reg_mapped = _mali_osk_mem_mapioregion( pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name ); - - if( 0 == pmu_info->reg_mapped ) - { - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not ioremap registers for %s .\n", pmu_info->name)); - _mali_osk_mem_unreqregion( pmu_info->reg_base_addr, pmu_info->reg_size ); - goto cleanup; - } - else - { - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) for %s\n", - (u32) pmu_info->reg_mapped, - ((u32)pmu_info->reg_mapped)+ pmu_info->reg_size - 1, - pmu_info->name)); - } - - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: Mapping registers to %s\n", pmu_info->name)); - -#if PMU_TEST - pmu_test(pmu_info, (MALI_PMM_CORE_GP)); - pmu_test(pmu_info, (MALI_PMM_CORE_GP|MALI_PMM_CORE_L2|MALI_PMM_CORE_PP0)); -#endif - - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Initialized - %s\n", pmu_info->name) ); - } - else - { - /* Didn't expect a different resource */ - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_SUCCESS; - -cleanup: - _mali_osk_free(pmu_info); - pmu_info = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); -} - -_mali_osk_errcode_t mali_pmm_pmu_deinit(_mali_osk_resource_type_t *type) -{ - if (*type == PMU) - { - if( pmu_info ) - { - _mali_osk_mem_unmapioregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->reg_mapped); - _mali_osk_mem_unreqregion(pmu_info->reg_base_addr, pmu_info->reg_size); - _mali_osk_free(pmu_info); - pmu_info = NULL; - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Terminated PMU\n") ); - } - } - else - { - /* Didn't expect a different resource */ - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_SUCCESS; - -} - -_mali_osk_errcode_t mali_pmm_pmu_powerdown(u32 cores) -{ - u32 stat; - u32 timeout; - u32 cores_pmu; - - MALI_DEBUG_ASSERT_POINTER(pmu_info); - MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power down (0x%x)\n", cores) ); - - cores_pmu = pmu_translate_cores_to_pmu(cores); - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_DOWN, cores_pmu ); - - /* Wait for cores to be powered down */ - timeout = 10; /* 10ms */ - do - { - /* Get status of sleeping cores */ - stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); - stat &= cores_pmu; - if( stat == cores_pmu ) break; /* All cores we wanted are now asleep */ - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } while( timeout > 0 ); - - if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_pmm_pmu_powerup(u32 cores) -{ - u32 cores_pmu; - u32 stat; - u32 timeout; - - MALI_DEBUG_ASSERT_POINTER(pmu_info); - MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power up (0x%x)\n", cores) ); - - /* Don't use interrupts - just poll status */ - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_INT_MASK, 0 ); - cores_pmu = pmu_translate_cores_to_pmu(cores); - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_UP, cores_pmu ); - - timeout = 10; /* 10ms */ - do - { - /* Get status of sleeping cores */ - stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); - stat &= cores_pmu; - if( stat == 0 ) break; /* All cores we wanted are now awake */ - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } while( timeout > 0 ); - - if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); - - MALI_SUCCESS; -} - - -/***** INTERNAL *****/ - -/** @brief Internal PMU function to translate the cores bit mask - * into something the hardware PMU understands - * - * @param cores PMM cores bitmask - * @return PMU hardware cores bitmask - */ -static u32 pmu_translate_cores_to_pmu(mali_pmm_core_mask cores) -{ - /* For Mali 400 PMU the cores mask is already the same as what - * the hardware PMU expects. - * For other hardware, some translation can be done here, by - * translating the MALI_PMM_CORE_* bits into specific hardware - * bits - */ - return cores; -} - -/** @brief Internal PMU function to read a PMU register - * - * @param pmu handle that identifies the PMU hardware - * @param relative_address relative PMU hardware address to read from - * @return 32-bit value that was read from the address - */ -static u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address) -{ - u32 read_val; - - MALI_DEBUG_ASSERT_POINTER(pmu); - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); - - read_val = _mali_osk_mem_ioread32(pmu->reg_mapped, relative_address); - - MALI_DEBUG_PRINT( 5, ("PMU: reg_read: %s Addr:0x%04X Val:0x%08x\n", - pmu->name, relative_address, read_val)); - - return read_val; -} - -/** @brief Internal PMU function to write to a PMU register - * - * @param pmu handle that identifies the PMU hardware - * @param relative_address relative PMU hardware address to write to - * @param new_val new 32-bit value to write into the address - */ -static void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val) -{ - MALI_DEBUG_ASSERT_POINTER(pmu); - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); - - MALI_DEBUG_PRINT( 5, ("PMU: reg_write: %s Addr:0x%04X Val:0x%08x\n", - pmu->name, relative_address, new_val)); - - _mali_osk_mem_iowrite32(pmu->reg_mapped, relative_address, new_val); -} - -#if PMU_TEST - -/***** TEST *****/ - -static void pmu_dump_regs( platform_pmu_t *pmu ) -{ - u32 addr; - for( addr = 0x0; addr < PMU_REGISTER_ADDRESS_SPACE_SIZE; addr += 0x4 ) - { - MALI_PRINT( ("PMU_REG: 0x%08x: 0x%04x\n", (addr + pmu->reg_base_addr), pmu_reg_read( pmu, addr ) ) ); - } -} - -/* This function is an internal test for the PMU without any Mali h/w interaction */ -static void pmu_test( platform_pmu_t *pmu, u32 cores ) -{ - u32 stat; - u32 timeout; - - MALI_PRINT( ("PMU_TEST: Start\n") ); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Power down cores: 0x%x\n", cores) ); - _mali_pmm_pmu_power_down( pmu, cores, MALI_TRUE ); - - stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); - MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == cores ? "SUCCESS" : "FAIL" ) ); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Power up cores: 0x%x\n", cores) ); - _mali_pmm_pmu_power_up( pmu, cores, MALI_FALSE ); - - MALI_PRINT( ("PMU_TEST: Waiting for power up...\n") ); - timeout = 1000; /* 1 sec */ - while( !_mali_pmm_pmu_irq_power_up(pmu) && timeout > 0 ) - { - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } - - MALI_PRINT( ("PMU_TEST: Waited %dms for interrupt\n", (1000-timeout)) ); - stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); - MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == 0 ? "SUCCESS" : "FAIL" ) ); - - _mali_pmm_pmu_irq_power_up_clear(pmu); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Finish\n") ); -} -#endif /* PMU_TEST */ - -#if MALI_POWER_MGMT_TEST_SUITE - -u32 pmu_get_power_up_down_info(void) -{ - return pmu_reg_read(pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS); -} - -#endif /* MALI_POWER_MGMT_TEST_SUITE */ -#endif /* USING_MALI_PMM */ -#endif /* USING_MALI_PMU */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h deleted file mode 100644 index 7525cac..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ -/** - * @file mali_platform.h - * Platform specific Mali driver functions - */ - -#include "mali_osk.h" - -#if !USING_MALI_PMM -/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */ -#define MALI_PLATFORM_SYSTEM 0 -#endif - -#if USING_MALI_PMM -#if USING_MALI_PMU -#include "mali_pmm.h" - -/** @brief Platform specific setup and initialisation of MALI - * - * This is called from the entrypoint of the driver to initialize the platform - * When using PMM, it is also called from the PMM start up to initialise the - * system PMU - * - * @param resource This is NULL when called on first driver start up, else it will - * be a pointer to a PMU resource - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_init(_mali_osk_resource_t *resource); - -/** @brief Platform specific deinitialisation of MALI - * - * This is called on the exit of the driver to terminate the platform - * When using PMM, it is also called from the PMM termination code to clean up the - * system PMU - * - * @param type This is NULL when called on driver exit, else it will - * be a pointer to a PMU resource type (not the full resource) - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_deinit(_mali_osk_resource_type_t *type); - -/** @brief Platform specific powerdown sequence of MALI - * - * Called as part of platform init if there is no PMM support, else the - * PMM will call it. - * - * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will - * be a mask of cores to power down based on the mali_pmm_core_id enum - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_powerdown(u32 cores); - -/** @brief Platform specific powerup sequence of MALI - * - * Called as part of platform deinit if there is no PMM support, else the - * PMM will call it. - * - * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will - * be a mask of cores to power down based on the mali_pmm_core_id enum - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_powerup(u32 cores); - -#if MALI_POWER_MGMT_TEST_SUITE -#if USING_MALI_PMM -#if USING_MALI_PMU -/** @brief function to get status of individual cores - * - * This function is used by power management test suite to get the status of powered up/down the number - * of cores - * @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization. - */ -u32 pmu_get_power_up_down_info(void); -#endif -#endif -#endif -#endif -#endif diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c deleted file mode 100644 index 87b6ec2..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy.c - * Implementation of the common routines for power management module - * policies - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" - -#include "mali_pmm_policy_alwayson.h" -#include "mali_pmm_policy_jobcontrol.h" - -/* Call back function for timer expiration */ -static void pmm_policy_timer_callback( void *arg ); - -_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* All values get 0 as default */ - _mali_osk_memset(pptimer, 0, sizeof(*pptimer)); - - pptimer->timer = _mali_osk_timer_init(); - if( pptimer->timer ) - { - _mali_osk_timer_setcallback( pptimer->timer, pmm_policy_timer_callback, (void *)pptimer ); - pptimer->timeout = timeout; - pptimer->event_id = id; - MALI_SUCCESS; - } - - return _MALI_OSK_ERR_FAULT; -} - -static void pmm_policy_timer_callback( void *arg ) -{ - _pmm_policy_timer_t *pptimer = (_pmm_policy_timer_t *)arg; - - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT( pptimer->set ); - - /* Set timer expired and flag there is a policy to check */ - pptimer->expired = MALI_TRUE; - malipmm_set_policy_check(); -} - - -void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - _mali_osk_timer_del( pptimer->timer ); - _mali_osk_timer_term( pptimer->timer ); - pptimer->timer = NULL; -} - -mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT_POINTER(pptimer->timer); - - if( !(pptimer->set) ) - { - pptimer->set = MALI_TRUE; - pptimer->expired = MALI_FALSE; - pptimer->start = _mali_osk_time_tickcount(); - _mali_osk_timer_add( pptimer->timer, pptimer->timeout ); - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT_POINTER(pptimer->timer); - - if( pptimer->set ) - { - _mali_osk_timer_del( pptimer->timer ); - pptimer->set = MALI_FALSE; - pptimer->expired = MALI_FALSE; - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - if( pptimer->expired ) - { - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_TIMEOUT, /* Assume timeout id, but set it below */ - 0 }; - - event.id = pptimer->event_id; - event.data = (mali_pmm_message_data)pptimer->start; - - /* Don't need to do any other notification with this timer */ - pptimer->expired = MALI_FALSE; - /* Unset timer so it is free to be set again */ - pptimer->set = MALI_FALSE; - - _mali_ukk_pmm_event_message( &event ); - - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start ) -{ - return (_mali_osk_time_after( other_start, timer_start ) == 0); -} - - -_mali_osk_errcode_t pmm_policy_init(_mali_pmm_internal_state_t *pmm) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - err = pmm_policy_init_always_on(); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - err = pmm_policy_init_job_control(pmm); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - err = _MALI_OSK_ERR_FAULT; - } - - return err; -} - -void pmm_policy_term(_mali_pmm_internal_state_t *pmm) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - pmm_policy_term_always_on(); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - pmm_policy_term_job_control(); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - MALI_PRINT_ERROR( ("PMM: Invalid policy terminated %d\n", pmm->policy) ); - } -} - - -_mali_osk_errcode_t pmm_policy_process(_mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - err = pmm_policy_process_always_on( pmm, event ); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - err = pmm_policy_process_job_control( pmm, event ); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - err = _MALI_OSK_ERR_FAULT; - } - - return err; -} - - -void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_JOB_CONTROL: - { - pmm_policy_check_job_control(); - } - break; - - default: - /* Nothing needs to be done */ - break; - } -} - - -#endif /* USING_MALI_PMM */ - diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h deleted file mode 100644 index 75ac8c8..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy.h - * Defines the power management module policies - */ - -#ifndef __MALI_PMM_POLICY_H__ -#define __MALI_PMM_POLICY_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief Generic timer for use with policies - */ -typedef struct _pmm_policy_timer -{ - u32 timeout; /**< Timeout for this timer in ticks */ - mali_pmm_event_id event_id; /**< Event id that will be raised when timer expires */ - _mali_osk_timer_t *timer; /**< Timer */ - mali_bool set; /**< Timer set */ - mali_bool expired; /**< Timer expired - event needs to be raised */ - u32 start; /**< Timer start ticks */ -} _pmm_policy_timer_t; - -/** @brief Policy timer initialization - * - * This will create a timer for use in policies, but won't start it - * - * @param pptimer An empty timer structure to be initialized - * @param timeout Timeout in ticks for the timer - * @param id Event id that will be raised on timeout - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id ); - -/** @brief Policy timer termination - * - * This will clean up a timer that was previously used in policies, it - * will also stop it if started - * - * @param pptimer An initialized timer structure to be terminated - */ -void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer start - * - * This will start a previously created timer for use in policies - * When the timer expires after the initialized timeout it will raise - * a PMM event of the event id given on initialization - * As data for the event it will pass the start time of the timer - * - * @param pptimer A previously initialized policy timer - * @return MALI_TRUE if the timer was started, MALI_FALSE if it is already started - */ -mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer stop - * - * This will stop a previously created timer for use in policies - * - * @param pptimer A previously started policy timer - * @return MALI_TRUE if the timer was stopped, MALI_FALSE if it is already stopped - */ -mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer stop - * - * This raise an event for an expired timer - * - * @param pptimer An expired policy timer - * @return MALI_TRUE if an event was raised, else MALI_FALSE - */ -mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer valid checker - * - * This will check that a timer was started after a given time - * - * @param timer_start Time the timer was started - * @param other_start Time when another event or action occurred - * @return MALI_TRUE if the timer was started after the other time, else MALI_FALSE - */ -mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start ); - - -/** @brief Common policy initialization - * - * This will initialize the current policy - * - * @note Any previously initialized policy should be terminated first - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init( _mali_pmm_internal_state_t *pmm ); - -/** @brief Common policy termination - * - * This will terminate the current policy. - * @note This can be called when a policy has not been initialized - */ -void pmm_policy_term( _mali_pmm_internal_state_t *pmm ); - -/** @brief Common policy state changer - * - * Given the next available event message, this routine passes it to - * the current policy for processing - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - - -/** @brief Common policy checker - * - * If a policy timer fires then this function will be called to - * allow the policy to take the correct action - * - * @param pmm internal PMM state - */ -void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm ); - -/** @} */ /* End group pmmapi_policy */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c deleted file mode 100644 index 0a6b471..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy_alwayson.c - * Implementation of the power management module policy - always on - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy_alwayson.h" - -_mali_osk_errcode_t pmm_policy_init_always_on(void) -{ - /* Nothing to set up */ - MALI_SUCCESS; -} - -void pmm_policy_term_always_on(void) -{ - /* Nothing to tear down */ -} - -_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* We aren't going to do anything, but signal so we don't block the OS - * NOTE: This may adversely affect any jobs Mali is currently running - */ - _mali_osk_pmm_power_down_done( event->data ); - break; - - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - /* Not expected in this policy */ - MALI_DEBUG_ASSERT( MALI_FALSE ); - break; - - case MALI_PMM_EVENT_OS_POWER_UP: - /* Nothing to do */ - _mali_osk_pmm_power_up_done( event->data ); - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - /* Nothing to do - we are always on */ - break; - - case MALI_PMM_EVENT_TIMEOUT: - /* Not expected in this policy */ - MALI_DEBUG_ASSERT( MALI_FALSE ); - break; - - default: - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - - MALI_SUCCESS; -} - -#endif diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h deleted file mode 100644 index da13224..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy_alwayson.h - * Defines the power management module policy for always on - */ - -#ifndef __MALI_PMM_POLICY_ALWAYSON_H__ -#define __MALI_PMM_POLICY_ALWAYSON_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief Always on policy initialization - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init_always_on(void); - -/** @brief Always on policy termination - */ -void pmm_policy_term_always_on(void); - -/** @brief Always on policy state changer - * - * Given the next available event message, this routine processes it - * for the policy and changes state as needed. - * - * Always on policy will ignore all events and keep the Mali cores on - * all the time - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @} */ /* End group pmmapi_policies */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_ALWAYSON_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c deleted file mode 100644 index 237d702..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy_jobcontrol.c - * Implementation of the power management module policy - job control - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_platform.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" -#include "mali_pmm_policy_jobcontrol.h" - -typedef struct _pmm_policy_data_job_control -{ - _pmm_policy_timer_t latency; /**< Latency timeout timer for all cores */ - u32 core_active_start; /**< Last time a core was set to active */ - u32 timeout; /**< Timeout in ticks for latency timer */ -} _pmm_policy_data_job_control_t; - - -/* @ brief Local data for this policy - */ -static _pmm_policy_data_job_control_t *data_job_control = NULL; - -/* @brief Set up the timeout if it hasn't already been set and if there are active cores */ -static void job_control_timeout_setup( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* Do we have an inactivity time out and some powered cores? */ - if( pptimer->timeout > 0 && pmm->cores_powered != 0 ) - { - /* Is the system idle and all the powered cores are idle? */ - if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->cores_idle == pmm->cores_powered ) - { - if( pmm_policy_timer_start(pptimer) ) - { - MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Setting in-activity latency timer\n") ); - } - } - else - { - /* We are not idle so there is no need for an inactivity timer - */ - if( pmm_policy_timer_stop(pptimer) ) - { - MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Removing in-activity latency timer\n") ); - } - } - } -} - -/* @brief Check the validity of the timeout - and if there is one set */ -static mali_bool job_control_timeout_valid( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer, u32 timer_start ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* Not a valid timer! */ - if( pptimer->timeout == 0 ) return MALI_FALSE; - - /* Are some cores powered and are they all idle? */ - if( (pmm->cores_powered != 0) && (pmm->cores_idle == pmm->cores_powered) ) - { - /* Has latency timeout started after the last core was active? */ - if( pmm_policy_timer_valid( timer_start, data_job_control->core_active_start ) ) - { - return MALI_TRUE; - } - else - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - out of date\n") ); - } - } - else - { - if( pmm->cores_powered == 0 ) - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores already off\n") ); - } - else - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores active\n") ); - } - } - - return MALI_FALSE; -} - -_mali_osk_errcode_t pmm_policy_init_job_control( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER( pmm ); - MALI_DEBUG_ASSERT( data_job_control == NULL ); - - data_job_control = (_pmm_policy_data_job_control_t *) _mali_osk_malloc(sizeof(*data_job_control)); - MALI_CHECK_NON_NULL( data_job_control, _MALI_OSK_ERR_NOMEM ); - - data_job_control->core_active_start = _mali_osk_time_tickcount(); - data_job_control->timeout = MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT; - - err = pmm_policy_timer_init( &data_job_control->latency, data_job_control->timeout, MALI_PMM_EVENT_TIMEOUT ); - if( err != _MALI_OSK_ERR_OK ) - { - _mali_osk_free( data_job_control ); - data_job_control = NULL; - return err; - } - - /* Start the latency timeout */ - job_control_timeout_setup( pmm, &data_job_control->latency ); - - MALI_SUCCESS; -} - -void pmm_policy_term_job_control(void) -{ - if( data_job_control != NULL ) - { - pmm_policy_timer_term( &data_job_control->latency ); - _mali_osk_free( data_job_control ); - data_job_control = NULL; - } -} - -static void pmm_policy_job_control_job_queued( _mali_pmm_internal_state_t *pmm ) -{ - mali_pmm_core_mask cores; - mali_pmm_core_mask cores_subset; - - /* Make sure that all cores are powered in this - * simple policy - */ - cores = pmm->cores_registered; - cores_subset = pmm_cores_to_power_up( pmm, cores ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - if( !pmm_invoke_power_up( pmm ) ) - { - /* Need to wait until finished */ - pmm->status = MALI_PMM_STATUS_POLICY_POWER_UP; - } - } -} - -_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - mali_pmm_core_mask cores; - mali_pmm_core_mask cores_subset; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - MALI_DEBUG_ASSERT_POINTER(data_job_control); - - MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process start - status=%d\n", pmm->status) ); - - /* Mainly the data is the cores */ - cores = pmm_cores_from_event_data( pmm, event ); - -#if MALI_STATE_TRACKING - pmm->mali_last_pmm_status = pmm->status; -#endif /* MALI_STATE_TRACKING */ - - switch( pmm->status ) - { - /**************** IDLE ****************/ - case MALI_PMM_STATUS_IDLE: - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - /* Not expected in this state */ - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - - /* Update idle cores to indicate active - remove these! */ - pmm_cores_set_active( pmm, cores ); - /* Remember when this happened */ - data_job_control->core_active_start = event->ts; -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_SCHEDULED); -#endif - - /*** FALL THROUGH to QUEUED to check POWER UP ***/ - - case MALI_PMM_EVENT_JOB_QUEUED: - - pmm_policy_job_control_job_queued( pmm ); -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_QUEUED); -#endif - break; - - case MALI_PMM_EVENT_DVFS_PAUSE: - - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE ); - if ( cores_subset != 0 ) - { - if ( !pmm_power_down_okay( pmm ) ) - { - pmm->is_dvfs_active = 1; - pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN; - pmm_save_os_event_data( pmm, event->data ); - break; - } - } - pmm->status = MALI_PMM_STATUS_DVFS_PAUSE; - _mali_osk_pmm_dvfs_operation_done(0); - break; - - case MALI_PMM_EVENT_OS_POWER_DOWN: - - /* Need to power down all cores even if we need to wait for them */ - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering down */ - if( !pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - /* We need to wait until they are idle */ - - pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN; - /* Save the OS data to respond later */ - pmm_save_os_event_data( pmm, event->data ); - /* Exit this case - as we have to wait */ - break; - } - } - else - { - mali_platform_power_mode_change(MALI_POWER_MODE_DEEP_SLEEP); - - } - /* Set waiting status */ - pmm->status = MALI_PMM_STATUS_OS_WAITING; - /* All cores now down - respond to OS power event */ - _mali_osk_pmm_power_down_done( event->data ); - break; - - case MALI_PMM_EVENT_JOB_FINISHED: - - /* Update idle cores - add these! */ - pmm_cores_set_idle( pmm, cores ); -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_FINISHED); -#endif - if( data_job_control->timeout > 0 ) - { - /* Wait for time out to fire */ - break; - } - /* For job control policy - turn off all cores */ - cores = pmm->cores_powered; - - /*** FALL THROUGH to TIMEOUT TEST as NO TIMEOUT ***/ - - case MALI_PMM_EVENT_TIMEOUT: - - /* Main job control policy - turn off cores after inactivity */ - if( job_control_timeout_valid( pmm, &data_job_control->latency, (u32)event->data ) ) - { - /* Valid timeout of inactivity - so find out if we can power down - * immedately - if we can't then this means the cores are still in fact - * active - */ - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_TRUE ); - if( cores_subset != 0 ) - { - /* Check if we can really power down, if not then we are not - * really in-active - */ - if( !pmm_invoke_power_down( pmm, MALI_POWER_MODE_LIGHT_SLEEP ) ) - { - pmm_power_down_cancel( pmm ); - } - } - /* else there are no cores powered up! */ - } -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_TIMEOUT); -#endif - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - /******************DVFS PAUSE**************/ - case MALI_PMM_STATUS_DVFS_PAUSE: - switch ( event->id ) - { - case MALI_PMM_EVENT_DVFS_RESUME: - - if ( pmm->cores_powered != 0 ) - { - pmm->cores_ack_down =0; - pmm_power_down_cancel( pmm ); - pmm->status = MALI_PMM_STATUS_IDLE; - } - else - { - pmm_policy_job_control_job_queued( pmm ); - } - _mali_osk_pmm_dvfs_operation_done( 0 ); - break; - - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* Set waiting status */ - pmm->status = MALI_PMM_STATUS_OS_WAITING; - if ( pmm->cores_powered != 0 ) - { - if ( pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - _mali_osk_pmm_power_down_done( 0 ); - break; - } - } - else - { - mali_platform_power_mode_change(MALI_POWER_MODE_DEEP_SLEEP); - } - _mali_osk_pmm_power_down_done( 0 ); - break; - default: - break; - } - break; - - /**************** POWER UP ****************/ - case MALI_PMM_STATUS_OS_POWER_UP: - case MALI_PMM_STATUS_POLICY_POWER_UP: - switch( event->id ) - { - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - /* Make sure cores powered off equal what we expect */ - MALI_DEBUG_ASSERT( cores == pmm->cores_pend_up ); - pmm_cores_set_up_ack( pmm, cores ); - - if( pmm_invoke_power_up( pmm ) ) - { - if( pmm->status == MALI_PMM_STATUS_OS_POWER_UP ) - { - /* Get the OS data and respond to the power up */ - _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) ); - } - pmm->status = MALI_PMM_STATUS_IDLE; - } - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - /**************** POWER DOWN ****************/ - case MALI_PMM_STATUS_OS_POWER_DOWN: - case MALI_PMM_STATUS_POLICY_POWER_DOWN: - switch( event->id ) - { - - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - - pmm_cores_set_down_ack( pmm, cores ); - - if ( pmm->is_dvfs_active == 1 ) - { - if( pmm_power_down_okay( pmm ) ) - { - pmm->is_dvfs_active = 0; - pmm->status = MALI_PMM_STATUS_DVFS_PAUSE; - _mali_osk_pmm_dvfs_operation_done( pmm_retrieve_os_event_data( pmm ) ); - } - break; - } - - /* Now check if we can power down */ - if( pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - if( pmm->status == MALI_PMM_STATUS_OS_POWER_DOWN ) - { - /* Get the OS data and respond to the power down */ - _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) ); - } - pmm->status = MALI_PMM_STATUS_OS_WAITING; - } - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - case MALI_PMM_STATUS_OS_WAITING: - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - cores_subset = pmm_cores_to_power_up( pmm, cores ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - if( !pmm_invoke_power_up( pmm ) ) - { - /* Need to wait until power up complete */ - pmm->status = MALI_PMM_STATUS_OS_POWER_UP; - /* Save the OS data to respond later */ - pmm_save_os_event_data( pmm, event->data ); - /* Exit this case - as we have to wait */ - break; - } - } - pmm->status = MALI_PMM_STATUS_IDLE; - /* All cores now up - respond to OS power up event */ - _mali_osk_pmm_power_up_done( event->data ); - break; - - default: - /* All other messages are ignored in this state */ - break; - } - break; - - default: - /* Unexpected state */ - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Set in-activity latency timer - if required */ - job_control_timeout_setup( pmm, &data_job_control->latency ); - - /* Update the PMM state */ - pmm_update_system_state( pmm ); -#if MALI_STATE_TRACKING - pmm->mali_new_event_status = event->id; -#endif /* MALI_STATE_TRACKING */ - - MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process end - status=%d and event=%d\n", pmm->status,event->id) ); - - MALI_SUCCESS; -} - -void pmm_policy_check_job_control() -{ - MALI_DEBUG_ASSERT_POINTER(data_job_control); - - /* Latency timer must have expired raise the event */ - pmm_policy_timer_raise_event(&data_job_control->latency); -} - - -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h deleted file mode 100644 index dcfa438..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/** - * @file mali_pmm_policy.h - * Defines the power management module policies - */ - -#ifndef __MALI_PMM_POLICY_JOBCONTROL_H__ -#define __MALI_PMM_POLICY_JOBCONTROL_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief The jobcontrol policy inactivity latency timeout (in ticks) - * before the hardware is switched off - * - * @note Setting this low whilst tracing or producing debug output can - * cause alot of timeouts to fire which can affect the PMM behaviour - */ -#define MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT 50 - -/** @brief Job control policy initialization - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init_job_control(_mali_pmm_internal_state_t *pmm); - -/** @brief Job control policy termination - */ -void pmm_policy_term_job_control(void); - -/** @brief Job control policy state changer - * - * Given the next available event message, this routine processes it - * for the policy and changes state as needed. - * - * Job control policy depends on events from the Mali cores, and will - * power down all cores after an inactivity latency timeout. It will - * power the cores back on again when a job is scheduled to run. - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @brief Job control policy checker - * - * The latency timer has fired and we need to raise the correct event to - * handle it - * - * @param pmm internal PMM state - */ -void pmm_policy_check_job_control(void); - -/** @} */ /* End group pmmapi_policy */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_JOBCONTROL_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c deleted file mode 100644 index d529b9a..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#include "mali_pmm.h" -#include "mali_pmm_state.h" -#include "mali_pmm_system.h" - -#include "mali_kernel_core.h" -#include "mali_platform.h" - -#define SIZEOF_CORES_LIST 6 - -/* NOTE: L2 *MUST* be first on the list so that it - * is correctly powered on first and powered off last - */ -static mali_pmm_core_id cores_list[] = { MALI_PMM_CORE_L2, - MALI_PMM_CORE_GP, - MALI_PMM_CORE_PP0, - MALI_PMM_CORE_PP1, - MALI_PMM_CORE_PP2, - MALI_PMM_CORE_PP3 }; - - - -void pmm_update_system_state( _mali_pmm_internal_state_t *pmm ) -{ - mali_pmm_state state; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm->cores_registered == 0 ) - { - state = MALI_PMM_STATE_UNAVAILABLE; - } - else if( pmm->cores_powered == 0 ) - { - state = MALI_PMM_STATE_SYSTEM_OFF; - } - else if( pmm->cores_powered == pmm->cores_registered ) - { - state = MALI_PMM_STATE_SYSTEM_ON; - } - else - { - /* Some other state where not everything is on or off */ - state = MALI_PMM_STATE_SYSTEM_TRANSITION; - } - -#if MALI_PMM_TRACE - _mali_pmm_trace_state_change( pmm->state, state ); -#endif - pmm->state = state; -} - -mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - mali_pmm_core_mask cores; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* All cores - the system */ - cores = pmm->cores_registered; - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - /* Currently the main event data is only the cores - * for these messages - */ - cores = (mali_pmm_core_mask)event->data; - if( cores == MALI_PMM_CORE_SYSTEM ) - { - cores = pmm->cores_registered; - } - else if( cores == MALI_PMM_CORE_PP_ALL ) - { - /* Get the subset of registered PP cores */ - cores = (pmm->cores_registered & MALI_PMM_CORE_PP_ALL); - } - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - break; - - default: - /* Assume timeout messages - report cores still powered */ - cores = pmm->cores_powered; - break; - } - - return cores; -} - -mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - mali_pmm_core_mask cores_subset; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check that cores aren't pending power down when asked for power up */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 ); - - cores_subset = (~(pmm->cores_powered) & cores); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - pmm->cores_pend_up = cores_subset; - } - - return cores_subset; -} - -mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only ) -{ - mali_pmm_core_mask cores_subset; - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check that cores aren't pending power up when asked for power down */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 ); - - cores_subset = (pmm->cores_powered & cores); - if( cores_subset != 0 ) - { - int n; - volatile mali_pmm_core_mask *ppowered = &(pmm->cores_powered); - - /* There are some cores that need powering up, but we may - * need to wait until they are idle - */ - for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- ) - { - if( (cores_list[n] & cores_subset) != 0 ) - { - /* Core is to be powered down */ - pmm->cores_pend_down |= cores_list[n]; - - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following function could fail - * as the core is unregistered before we tell it to power - * down, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* Signal the core to power down - * If it is busy (not idle) it will set a pending power down flag - * (as long as we don't want to only immediately power down). - * If it isn't busy it will move out of the idle queue right - * away - */ - err = mali_core_signal_power_down( cores_list[n], immediate_only ); - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Re-read cores_subset in case it has changed */ - cores_subset = (*ppowered & cores); - - if( err == _MALI_OSK_ERR_OK ) - { - /* We moved an idle core to the power down queue - * which means it is now acknowledged (if it is still - * registered) - */ - pmm->cores_ack_down |= (cores_list[n] & cores_subset); - } - else - { - MALI_DEBUG_PRINT(1,("PMM: In pmm_cores_to_power_down, the error and cores powered are..%x....%x",err,*ppowered)); - MALI_DEBUG_ASSERT( err == _MALI_OSK_ERR_BUSY || - (err == _MALI_OSK_ERR_FAULT && - (*ppowered & cores_list[n]) == 0) ); - /* If we didn't move a core - it must be active, so - * leave it pending, so we get an acknowledgement (when - * not in immediate only mode) - * Alternatively we are shutting down and the core has - * been unregistered - */ - } - } - } - } - - return cores_subset; -} - -void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm ) -{ - int n; - mali_pmm_core_mask pd, ad; - _mali_osk_errcode_t err; - volatile mali_pmm_core_mask *pregistered; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALIPMM_DEBUG_PRINT( ("PMM: Cancelling power down\n") ); - - pd = pmm->cores_pend_down; - ad = pmm->cores_ack_down; - /* Clear the pending cores so that they don't move to the off - * queue if they haven't already - */ - pmm->cores_pend_down = 0; - pmm->cores_ack_down = 0; - pregistered = &(pmm->cores_registered); - - /* Power up all the pending power down cores - just so - * we make sure the system is in a known state, as a - * pending core might have sent an acknowledged message - * which hasn't been read yet. - */ - for( n = 0; n < SIZEOF_CORES_LIST; n++ ) - { - if( (cores_list[n] & pd) != 0 ) - { - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following power up function could fail - * as the core is unregistered before we tell it to power - * up, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* As we are cancelling - only move the cores back to the queue - - * no reset needed - */ - err = mali_core_signal_power_up( cores_list[n], MALI_TRUE ); - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* Update pending list with the current registered cores */ - pd &= (*pregistered); - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_BUSY && - ((cores_list[n] & ad) == 0)) || - (err == _MALI_OSK_ERR_FAULT && - (*pregistered & cores_list[n]) == 0) ); - /* If we didn't power up a core - it must be active and - * hasn't actually tried to power down - this is expected - * for cores that haven't acknowledged - * Alternatively we are shutting down and the core has - * been unregistered - */ - } - } - } - /* Only used in debug builds */ - MALI_IGNORE(ad); -} - - -mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - return ( pmm->cores_pend_down == pmm->cores_ack_down ? MALI_TRUE : MALI_FALSE ); -} - -mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm, mali_power_mode power_mode ) -{ - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER(pmm); - - /* Check that cores are pending power down during power down invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down != 0 ); - /* Check that cores are not pending power up during power down invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 ); - - if( !pmm_power_down_okay( pmm ) ) - { - MALIPMM_DEBUG_PRINT( ("PMM: Waiting for cores to go idle for power off - 0x%08x / 0x%08x\n", - pmm->cores_pend_down, pmm->cores_ack_down) ); - return MALI_FALSE; - } - else - { - pmm->cores_powered &= ~(pmm->cores_pend_down); -#if !MALI_PMM_NO_PMU - err = malipmm_powerdown( pmm->cores_pend_down, power_mode); -#else - err = _MALI_OSK_ERR_OK; -#endif - - if( err == _MALI_OSK_ERR_OK ) - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Remove powered down cores from idle and powered list */ - pmm->cores_idle &= ~(pmm->cores_pend_down); - /* Reset pending/acknowledged status */ - pmm->cores_pend_down = 0; - pmm->cores_ack_down = 0; -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - else - { - pmm->cores_powered |= pmm->cores_pend_down; - MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power down cores - (0x%x) %s", - pmm->cores_pend_down, pmm_trace_get_core_name(pmm->cores_pend_down)) ); - pmm->fatal_power_err = MALI_TRUE; - } - } - - return MALI_TRUE; -} - - -mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - return ( pmm->cores_pend_up == pmm->cores_ack_up ? MALI_TRUE : MALI_FALSE ); -} - - -mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - /* Check that cores are pending power up during power up invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up != 0 ); - /* Check that cores are not pending power down during power up invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 ); - - if( pmm_power_up_okay( pmm ) ) - { - /* Power up has completed - sort out subsystem core status */ - - int n; - /* Use volatile to access, so that it is updated if any cores are unregistered */ - volatile mali_pmm_core_mask *ppendup = &(pmm->cores_pend_up); -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Move cores into idle queues */ - for( n = 0; n < SIZEOF_CORES_LIST; n++ ) - { - if( (cores_list[n] & (*ppendup)) != 0 ) - { - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following function could fail - * as the core is unregistered before we tell it to power - * up, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - err = mali_core_signal_power_up( cores_list[n], MALI_FALSE ); - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_DEBUG_PRINT(1,("In pmm_invoke_power_up:: The error and pending cores to be powered up are...%x...%x",err,*ppendup)); - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_FAULT && - (*ppendup & cores_list[n]) == 0) ); - /* We only expect this to fail when we are shutting down - * and the core has been unregistered - */ - } - } - } - /* Finished power up - add cores to idle and powered list */ - pmm->cores_powered |= (*ppendup); - pmm->cores_idle |= (*ppendup); - /* Reset pending/acknowledge status */ - pmm->cores_pend_up = 0; - pmm->cores_ack_up = 0; - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - return MALI_TRUE; - } - else - { -#if !MALI_PMM_NO_PMU - /* Power up must now be done */ - err = malipmm_powerup( pmm->cores_pend_up ); -#else - err = _MALI_OSK_ERR_OK; -#endif - if( err != _MALI_OSK_ERR_OK ) - { - MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power up cores - (0x%x) %s", - pmm->cores_pend_up, pmm_trace_get_core_name(pmm->cores_pend_up)) ); - pmm->fatal_power_err = MALI_TRUE; - } - else - { - /* TBD - Update core status immediately rather than use event message */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK, - 0 }; - /* All the cores that were pending power up, have now completed power up */ - event.data = pmm->cores_pend_up; - _mali_ukk_pmm_event_message( &event ); - MALIPMM_DEBUG_PRINT( ("PMM: Sending ACK to power up") ); - } - } - - /* Always return false, as we need an interrupt to acknowledge - * when power up is complete - */ - return MALI_FALSE; -} - -mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - pmm->cores_idle &= (~cores); - return pmm->cores_idle; -} - -mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - pmm->cores_idle |= (cores); - return pmm->cores_idle; -} - -mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check core is not pending a power down */ - MALI_DEBUG_ASSERT( (pmm->cores_pend_down & cores) != 0 ); - /* Check core has not acknowledged power down more than once */ - MALI_DEBUG_ASSERT( (pmm->cores_ack_down & cores) == 0 ); - - pmm->cores_ack_down |= (cores); - - return pmm->cores_ack_down; -} - -void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_osk_notification_t *msg = NULL; - mali_pmm_status status; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALIPMM_DEBUG_PRINT( ("PMM: Fatal Reset called") ); - - MALI_DEBUG_ASSERT( pmm->status != MALI_PMM_STATUS_OFF ); - - /* Reset the common status */ - pmm->waiting = 0; - pmm->missed = 0; - pmm->fatal_power_err = MALI_FALSE; - pmm->no_events = 0; - pmm->check_policy = MALI_FALSE; - pmm->cores_pend_down = 0; - pmm->cores_pend_up = 0; - pmm->cores_ack_down = 0; - pmm->cores_ack_up = 0; - pmm->is_dvfs_active = 0; -#if MALI_PMM_TRACE - pmm->messages_sent = 0; - pmm->messages_received = 0; - pmm->imessages_sent = 0; - pmm->imessages_received = 0; - MALI_PRINT( ("PMM Trace: *** Fatal reset occurred ***") ); -#endif - - /* Set that we are unavailable whilst resetting */ - pmm->state = MALI_PMM_STATE_UNAVAILABLE; - status = pmm->status; - pmm->status = MALI_PMM_STATUS_OFF; - - /* We want all cores powered */ - pmm->cores_powered = pmm->cores_registered; - /* The cores may not be idle, but this state will be rectified later */ - pmm->cores_idle = pmm->cores_registered; - - /* So power on any cores that are registered */ - if( pmm->cores_registered != 0 ) - { - int n; - volatile mali_pmm_core_mask *pregistered = &(pmm->cores_registered); -#if !MALI_PMM_NO_PMU - err = malipmm_powerup( pmm->cores_registered ); -#endif - if( err != _MALI_OSK_ERR_OK ) - { - /* This is very bad as we can't even be certain the cores are now - * powered up - */ - MALI_PRINT_ERROR( ("PMM: Failed to perform PMM reset!\n") ); - /* TBD driver exit? */ - } - - for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- ) - { - if( (cores_list[n] & (*pregistered)) != 0 ) - { -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* Core is now active - so try putting it in the idle queue */ - err = mali_core_signal_power_up( cores_list[n], MALI_FALSE ); - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* We either succeeded, or we were not off anyway, or we have - * just be deregistered - */ - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_OK) || - (err == _MALI_OSK_ERR_BUSY) || - (err == _MALI_OSK_ERR_FAULT && - (*pregistered & cores_list[n]) == 0) ); - } - } - } - - /* Unblock any pending OS event */ - if( status == MALI_PMM_STATUS_OS_POWER_UP ) - { - /* Get the OS data and respond to the power up */ - _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) ); - } - if( status == MALI_PMM_STATUS_OS_POWER_DOWN ) - { - /* Get the OS data and respond to the power down - * NOTE: We are not powered down at this point due to power problems, - * so we are lying to the system, but something bad has already - * happened and we are trying unstick things - * TBD - Add busy loop to power down cores? - */ - _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) ); - } - - /* Purge the event queues */ - do - { - if( _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ) == _MALI_OSK_ERR_OK ) - { - _mali_osk_notification_delete ( msg ); - break; - } - } while (MALI_TRUE); - - do - { - if( _mali_osk_notification_queue_dequeue( pmm->queue, &msg ) == _MALI_OSK_ERR_OK ) - { - _mali_osk_notification_delete ( msg ); - break; - } - } while (MALI_TRUE); - - /* Return status/state to normal */ - pmm->status = MALI_PMM_STATUS_IDLE; - pmm_update_system_state(pmm); -} - -mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check core is not pending a power up */ - MALI_DEBUG_ASSERT( (pmm->cores_pend_up & cores) != 0 ); - /* Check core has not acknowledged power up more than once */ - MALI_DEBUG_ASSERT( (pmm->cores_ack_up & cores) == 0 ); - - pmm->cores_ack_up |= (cores); - - return pmm->cores_ack_up; -} - -void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - /* Check that there is no saved data */ - MALI_DEBUG_ASSERT( pmm->os_data == 0 ); - /* Can't store zero data - as retrieve check will fail */ - MALI_DEBUG_ASSERT( data != 0 ); - - pmm->os_data = data; -} - -mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm) -{ - mali_pmm_message_data data; - - MALI_DEBUG_ASSERT_POINTER(pmm); - /* Check that there is saved data */ - MALI_DEBUG_ASSERT( pmm->os_data != 0 ); - - /* Get data, and clear the saved version */ - data = pmm->os_data; - pmm->os_data = 0; - - return data; -} - -/* Create list of core names to look up - * We are doing it this way to overcome the need for - * either string allocation, or stack space, so we - * use constant strings instead - */ -typedef struct pmm_trace_corelist -{ - mali_pmm_core_mask id; - const char *name; -} pmm_trace_corelist_t; - -static pmm_trace_corelist_t pmm_trace_cores[] = { - { MALI_PMM_CORE_SYSTEM, "SYSTEM" }, - { MALI_PMM_CORE_GP, "GP" }, - { MALI_PMM_CORE_L2, "L2" }, - { MALI_PMM_CORE_PP0, "PP0" }, - { MALI_PMM_CORE_PP1, "PP1" }, - { MALI_PMM_CORE_PP2, "PP2" }, - { MALI_PMM_CORE_PP3, "PP3" }, - { MALI_PMM_CORE_PP_ALL, "PP (all)" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0), - "GP+L2+PP0" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0), - "GP+PP0" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1), - "GP+L2+PP0+PP1" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1), - "GP+PP0+PP1" }, - { 0, NULL } /* Terminator of list */ -}; - -const char *pmm_trace_get_core_name( mali_pmm_core_mask cores ) -{ - const char *dname = NULL; - int cl; - - /* Look up name in corelist */ - cl = 0; - while( pmm_trace_cores[cl].name != NULL ) - { - if( pmm_trace_cores[cl].id == cores ) - { - dname = pmm_trace_cores[cl].name; - break; - } - cl++; - } - - if( dname == NULL ) - { - /* We don't know a good short-hand for the configuration */ - dname = "[multi-core]"; - } - - return dname; -} - -#endif /* USING_MALI_PMM */ - diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h deleted file mode 100644 index 4768344..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_PMM_STATE_H__ -#define __MALI_PMM_STATE_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_state Power Management Module State - * - * @{ - */ - -/* Check that the subset is really a subset of cores */ -#define MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( cores, subset ) \ - MALI_DEBUG_ASSERT( ((~(cores)) & (subset)) == 0 ) - - -/* Locking macros */ -#define MALI_PMM_LOCK(pmm) \ - _mali_osk_lock_wait( pmm->lock, _MALI_OSK_LOCKMODE_RW ) -#define MALI_PMM_UNLOCK(pmm) \ - _mali_osk_lock_signal( pmm->lock, _MALI_OSK_LOCKMODE_RW ) -#define MALI_PMM_LOCK_TERM(pmm) \ - _mali_osk_lock_term( pmm->lock ) - -/* Notification type for messages */ -#define MALI_PMM_NOTIFICATION_TYPE 0 - -/** @brief Status of the PMM state machine - */ -typedef enum mali_pmm_status_tag -{ - MALI_PMM_STATUS_IDLE, /**< PMM is waiting next event */ - MALI_PMM_STATUS_POLICY_POWER_DOWN, /**< Policy initiated power down */ - MALI_PMM_STATUS_POLICY_POWER_UP, /**< Policy initiated power down */ - MALI_PMM_STATUS_OS_WAITING, /**< PMM is waiting for OS power up */ - MALI_PMM_STATUS_OS_POWER_DOWN, /**< OS initiated power down */ - MALI_PMM_STATUS_DVFS_PAUSE, /**< PMM DVFS Status Pause */ - MALI_PMM_STATUS_OS_POWER_UP, /**< OS initiated power up */ - MALI_PMM_STATUS_OFF, /**< PMM is not active */ -} mali_pmm_status; - - -/** @brief Internal state of the PMM - */ -typedef struct _mali_pmm_internal_state -{ - mali_pmm_status status; /**< PMM state machine */ - mali_pmm_policy policy; /**< PMM policy */ - mali_bool check_policy; /**< PMM policy needs checking */ - mali_pmm_state state; /**< PMM state */ - mali_pmm_core_mask cores_registered; /**< Bitmask of cores registered */ - mali_pmm_core_mask cores_powered; /**< Bitmask of cores powered up */ - mali_pmm_core_mask cores_idle; /**< Bitmask of cores idle */ - mali_pmm_core_mask cores_pend_down; /**< Bitmask of cores pending power down */ - mali_pmm_core_mask cores_pend_up; /**< Bitmask of cores pending power up */ - mali_pmm_core_mask cores_ack_down; /**< Bitmask of cores acknowledged power down */ - mali_pmm_core_mask cores_ack_up; /**< Bitmask of cores acknowledged power up */ - - _mali_osk_notification_queue_t *queue; /**< PMM event queue */ - _mali_osk_notification_queue_t *iqueue; /**< PMM internal event queue */ - _mali_osk_irq_t *irq; /**< PMM irq handler */ - _mali_osk_lock_t *lock; /**< PMM lock */ - - mali_pmm_message_data os_data; /**< OS data sent via the OS events */ - - mali_bool pmu_initialized; /**< PMU initialized */ - - _mali_osk_atomic_t messages_queued; /**< PMM event messages queued */ - u32 waiting; /**< PMM waiting events - due to busy */ - u32 no_events; /**< PMM called to process when no events */ - - u32 missed; /**< PMM missed events due to OOM */ - mali_bool fatal_power_err; /**< PMM has had a fatal power error? */ - u32 is_dvfs_active; /**< PMM DVFS activity */ - -#if MALI_STATE_TRACKING - mali_pmm_status mali_last_pmm_status; /**< The previous PMM status */ - mali_pmm_event_id mali_new_event_status;/**< The type of the last PMM event */ - mali_bool mali_pmm_lock_acquired; /**< Is the PMM lock held somewhere or not */ -#endif - -#if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - u32 messages_sent; /**< Total event messages sent */ - u32 messages_received; /**< Total event messages received */ - u32 imessages_sent; /**< Total event internal messages sent */ - u32 imessages_received; /**< Total event internal messages received */ -#endif -} _mali_pmm_internal_state_t; - -/** @brief Sets that a policy needs a check before processing events - * - * A timer or something has expired that needs dealing with - */ -void malipmm_set_policy_check(void); - -/** @brief Update the PMM externally viewable state depending on the current PMM internal state - * - * @param pmm internal PMM state - * @return MALI_TRUE if the timeout is valid, else MALI_FALSE - */ -void pmm_update_system_state( _mali_pmm_internal_state_t *pmm ); - -/** @brief Returns the core mask from the event data - if applicable - * - * @param pmm internal PMM state - * @param event event message to get the core mask from - * @return mask of cores that is relevant to this event message - */ -mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @brief Sort out which cores need to be powered up from the given core mask - * - * All cores that can be powered up will be put into a pending state - * - * @param pmm internal PMM state - * @param cores mask of cores to check if they need to be powered up - * @return mask of cores that need to be powered up, this can be 0 if all cores - * are powered up already - */ -mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Sort out which cores need to be powered down from the given core mask - * - * All cores that can be powered down will be put into a pending state. If they - * can be powered down immediately they will also be acknowledged that they can be - * powered down. If the immediate_only flag is set, then only those cores that - * can be acknowledged for power down will be put into a pending state. - * - * @param pmm internal PMM state - * @param cores mask of cores to check if they need to be powered down - * @param immediate_only MALI_TRUE means that only cores that can power down now will - * be put into a pending state - * @return mask of cores that need to be powered down, this can be 0 if all cores - * are powered down already - */ -mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only ); - -/** @brief Cancel an invokation to power down (pmm_invoke_power_down) - * - * @param pmm internal PMM state - */ -void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm ); - -/** @brief Check if a call to invoke power down should succeed, or fail - * - * This will report MALI_FALSE if some of the cores are still active and need - * to acknowledge that they are ready to power down - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores to power down have acknowledged they - * can power down, else MALI_FALSE - */ -mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm ); - -/** @brief Try to make all the pending cores power down - * - * If all the pending cores have acknowledged they can power down, this will call the - * PMU power down function to turn them off - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores have been powered down, else MALI_FALSE - */ -mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm, mali_power_mode power_mode ); - -/** @brief Check if all the pending cores to power up have done so - * - * This will report MALI_FALSE if some of the cores are still powered off - * and have not acknowledged that they have powered up - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores to power up have acknowledged they - * are now powered up, else MALI_FALSE - */ -mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm ); - -/** @brief Try to make all the pending cores power up - * - * If all the pending cores have acknowledged they have powered up, this will - * make the cores start processing jobs again, else this will call the PMU - * power up function to turn them on, and the PMM is then expected to wait for an - * interrupt to acknowledge the power up - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores have been powered up, else MALI_FALSE - */ -mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm ); - -/** @brief Set the cores that are now active in the system - * - * Updates which cores are active and returns which cores are still idle - * - * @param pmm internal PMM state - * @param cores mask of cores to set to active - * @return mask of all the cores that are idle - */ -mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that are now idle in the system - * - * Updates which cores are idle and returns which cores are still idle - * - * @param pmm internal PMM state - * @param cores mask of cores to set to idle - * @return mask of all the cores that are idle - */ -mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that have acknowledged a pending power down - * - * Updates which cores have acknowledged the pending power down and are now ready - * to be turned off - * - * @param pmm internal PMM state - * @param cores mask of cores that have acknowledged the pending power down - * @return mask of all the cores that have acknowledged the power down - */ -mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that have acknowledged a pending power up - * - * Updates which cores have acknowledged the pending power up and are now - * fully powered and ready to run jobs - * - * @param pmm internal PMM state - * @param cores mask of cores that have acknowledged the pending power up - * @return mask of all the cores that have acknowledged the power up - */ -mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - - -/** @brief Tries to reset the PMM and PMU hardware to a known state after any fatal issues - * - * This will try and make all the cores powered up and reset the PMM state - * to its initial state after core registration - all cores powered but not - * pending or active. - * All events in the event queues will be thrown away. - * - * @note: Any pending power down will be cancelled including the OS calling for power down - */ -void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm ); - -/** @brief Save the OS specific data for an OS power up/down event - * - * @param pmm internal PMM state - * @param data OS specific event data - */ -void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data); - -/** @brief Retrieve the OS specific data for an OS power up/down event - * - * This will clear the stored OS data, as well as return it. - * - * @param pmm internal PMM state - * @return OS specific event data that was saved previously - */ -mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm); - - -/** @brief Get a human readable name for the cores in a core mask - * - * @param core the core mask - * @return string containing a name relating to the given core mask - */ -const char *pmm_trace_get_core_name( mali_pmm_core_mask core ); - -/** @} */ /* End group pmmapi_state */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_STATE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h deleted file mode 100644 index eccd35b..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef __MALI_PMM_SYSTEM_H__ -#define __MALI_PMM_SYSTEM_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_system Power Management Module System Functions - * - * @{ - */ - -extern struct mali_kernel_subsystem mali_subsystem_pmm; - -/** @brief Register a core with the PMM, which will power up - * the core - * - * @param core the core to register with the PMM - * @return error if the core cannot be powered up - */ -_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core ); - -/** @brief Unregister a core with the PMM - * - * @param core the core to unregister with the PMM - */ -void malipmm_core_unregister( mali_pmm_core_id core ); - -/** @brief Acknowledge that a power down is okay to happen - * - * A core should not be running a job, or be in the idle queue when this - * is called. - * - * @param core the core that can now be powered down - */ -void malipmm_core_power_down_okay( mali_pmm_core_id core ); - -/** @} */ /* End group pmmapi_system */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_H__ */ |