| /* |
| * Copyright (C) 2010-2014 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_scheduler.h" |
| #include "mali_pm_domain.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_SIZE = 0x0004, |
| 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; |
| |
| #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] = { NULL, }; |
| 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); |
| |
| |
| static void mali_l2_cache_counter_lock(struct mali_l2_cache_core *cache) |
| { |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_lock(cache->counter_lock); |
| #else |
| _mali_osk_spinlock_lock(cache->counter_lock); |
| #endif |
| } |
| |
| static void mali_l2_cache_counter_unlock(struct mali_l2_cache_core *cache) |
| { |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_unlock(cache->counter_lock); |
| #else |
| _mali_osk_spinlock_unlock(cache->counter_lock); |
| #endif |
| } |
| |
| static void mali_l2_cache_command_lock(struct mali_l2_cache_core *cache) |
| { |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_lock(cache->command_lock); |
| #else |
| _mali_osk_spinlock_lock(cache->command_lock); |
| #endif |
| } |
| |
| static void mali_l2_cache_command_unlock(struct mali_l2_cache_core *cache) |
| { |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_unlock(cache->command_lock); |
| #else |
| _mali_osk_spinlock_unlock(cache->command_lock); |
| #endif |
| } |
| |
| struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t *resource) |
| { |
| struct mali_l2_cache_core *cache = NULL; |
| |
| MALI_DEBUG_PRINT(4, ("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; |
| cache->pm_domain = NULL; |
| cache->mali_l2_status = MALI_L2_NORMAL; |
| if (_MALI_OSK_ERR_OK == mali_hw_core_create(&cache->hw_core, resource, MALI400_L2_CACHE_REGISTERS_SIZE)) { |
| MALI_DEBUG_CODE(u32 cache_size = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_SIZE)); |
| MALI_DEBUG_PRINT(2, ("Mali L2 cache: Created %s: % 3uK, %u-way, % 2ubyte cache line, % 3ubit external bus\n", |
| resource->description, |
| 1 << (((cache_size >> 16) & 0xff) - 10), |
| 1 << ((cache_size >> 8) & 0xff), |
| 1 << (cache_size & 0xff), |
| 1 << ((cache_size >> 24) & 0xff))); |
| |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| cache->command_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); |
| #else |
| cache->command_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); |
| #endif |
| if (NULL != cache->command_lock) { |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| cache->counter_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); |
| #else |
| cache->counter_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); |
| #endif |
| if (NULL != cache->counter_lock) { |
| mali_l2_cache_reset(cache); |
| |
| cache->last_invalidated_id = 0; |
| |
| 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 create counter lock for L2 cache core %s\n", cache->hw_core.description)); |
| } |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_term(cache->command_lock); |
| #else |
| _mali_osk_spinlock_term(cache->command_lock); |
| #endif |
| } 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); |
| |
| #ifdef MALI_UPPER_HALF_SCHEDULING |
| _mali_osk_spinlock_irq_term(cache->counter_lock); |
| _mali_osk_spinlock_irq_term(cache->command_lock); |
| #else |
| _mali_osk_spinlock_term(cache->command_lock); |
| _mali_osk_spinlock_term(cache->counter_lock); |
| #endif |
| |
| 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--; |
| |
| if (i != mali_global_num_l2_cache_cores) { |
| /* We removed a l2 cache from the middle of the array -- move the last |
| * l2 cache to the current position to close the gap */ |
| mali_global_l2_cache_cores[i] = mali_global_l2_cache_cores[mali_global_num_l2_cache_cores]; |
| mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = NULL; |
| } |
| |
| break; |
| } |
| } |
| |
| _mali_osk_free(cache); |
| } |
| |
| u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache) |
| { |
| return cache->core_id; |
| } |
| |
| static void mali_l2_cache_core_set_counter_internal(struct mali_l2_cache_core *cache, u32 source_id, u32 counter) |
| { |
| u32 value = 0; /* disabled src */ |
| u32 reg_offset = 0; |
| mali_bool core_is_on; |
| |
| MALI_DEBUG_ASSERT_POINTER(cache); |
| |
| core_is_on = mali_l2_cache_lock_power_state(cache); |
| |
| mali_l2_cache_counter_lock(cache); |
| |
| switch (source_id) { |
| case 0: |
| cache->counter_src0 = counter; |
| reg_offset = MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0; |
| break; |
| |
| case 1: |
| cache->counter_src1 = counter; |
| reg_offset = MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1; |
| break; |
| |
| default: |
| MALI_DEBUG_ASSERT(0); |
| break; |
| } |
| |
| if (MALI_L2_PAUSE == cache->mali_l2_status) { |
| mali_l2_cache_counter_unlock(cache); |
| mali_l2_cache_unlock_power_state(cache); |
| return; |
| } |
| |
| if (MALI_HW_CORE_NO_COUNTER != counter) { |
| value = counter; |
| } |
| |
| if (MALI_TRUE == core_is_on) { |
| mali_hw_core_register_write(&cache->hw_core, reg_offset, value); |
| } |
| |
| mali_l2_cache_counter_unlock(cache); |
| mali_l2_cache_unlock_power_state(cache); |
| } |
| |
| void mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter) |
| { |
| mali_l2_cache_core_set_counter_internal(cache, 0, counter); |
| } |
| |
| void mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter) |
| { |
| mali_l2_cache_core_set_counter_internal(cache, 1, counter); |
| } |
| |
| 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_l2_cache_counter_lock(cache); |
| |
| if (MALI_L2_PAUSE == cache->mali_l2_status) { |
| mali_l2_cache_counter_unlock(cache); |
| |
| return; |
| } |
| |
| *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_src1 != MALI_HW_CORE_NO_COUNTER) { |
| *value1 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); |
| } |
| |
| mali_l2_cache_counter_unlock(cache); |
| } |
| |
| static void mali_l2_cache_reset_counters_all(void) |
| { |
| int i; |
| u32 value; |
| struct mali_l2_cache_core *cache; |
| u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); |
| |
| for (i = 0; i < num_cores; i++) { |
| cache = mali_l2_cache_core_get_glob_l2_core(i); |
| if (!cache) |
| continue; |
| |
| if (mali_l2_cache_lock_power_state(cache)) { |
| mali_l2_cache_counter_lock(cache); |
| |
| if (MALI_L2_PAUSE == cache->mali_l2_status) { |
| mali_l2_cache_counter_unlock(cache); |
| mali_l2_cache_unlock_power_state(cache); |
| return; |
| } |
| |
| /* Reset performance counters */ |
| if (MALI_HW_CORE_NO_COUNTER == cache->counter_src0) { |
| value = 0; |
| } else { |
| value = cache->counter_src0; |
| } |
| mali_hw_core_register_write(&cache->hw_core, |
| MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, value); |
| |
| if (MALI_HW_CORE_NO_COUNTER == cache->counter_src1) { |
| value = 0; |
| } else { |
| value = cache->counter_src1; |
| } |
| mali_hw_core_register_write(&cache->hw_core, |
| MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, value); |
| |
| mali_l2_cache_counter_unlock(cache); |
| } |
| |
| mali_l2_cache_unlock_power_state(cache); |
| } |
| } |
| |
| |
| struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index) |
| { |
| if (mali_global_num_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; |
| } |
| |
| void 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_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); |
| |
| mali_l2_cache_counter_lock(cache); |
| |
| if (MALI_L2_PAUSE == cache->mali_l2_status) { |
| mali_l2_cache_counter_unlock(cache); |
| |
| return; |
| } |
| |
| /* 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) */ |
| 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_l2_cache_counter_unlock(cache); |
| } |
| |
| void mali_l2_cache_reset_all(void) |
| { |
| int i; |
| u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); |
| |
| for (i = 0; i < num_cores; i++) { |
| mali_l2_cache_reset(mali_l2_cache_core_get_glob_l2_core(i)); |
| } |
| } |
| |
| void mali_l2_cache_invalidate(struct mali_l2_cache_core *cache) |
| { |
| MALI_DEBUG_ASSERT_POINTER(cache); |
| |
| if (NULL != cache) { |
| cache->last_invalidated_id = mali_scheduler_get_new_cache_order(); |
| mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); |
| } |
| } |
| |
| mali_bool mali_l2_cache_invalidate_conditional(struct mali_l2_cache_core *cache, u32 id) |
| { |
| MALI_DEBUG_ASSERT_POINTER(cache); |
| |
| if (NULL != cache) { |
| /* 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)cache->last_invalidated_id)) { |
| return MALI_FALSE; |
| } else { |
| cache->last_invalidated_id = mali_scheduler_get_new_cache_order(); |
| } |
| |
| mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); |
| } |
| return MALI_TRUE; |
| } |
| |
| void mali_l2_cache_invalidate_all(void) |
| { |
| u32 i; |
| for (i = 0; i < mali_global_num_l2_cache_cores; i++) { |
| /*additional check*/ |
| if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_l2_cache_cores[i])) { |
| _mali_osk_errcode_t ret; |
| mali_global_l2_cache_cores[i]->last_invalidated_id = mali_scheduler_get_new_cache_order(); |
| ret = mali_l2_cache_send_command(mali_global_l2_cache_cores[i], MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); |
| if (_MALI_OSK_ERR_OK != ret) { |
| MALI_PRINT_ERROR(("Failed to invalidate cache\n")); |
| } |
| } |
| mali_l2_cache_unlock_power_state(mali_global_l2_cache_cores[i]); |
| } |
| } |
| |
| void mali_l2_cache_invalidate_all_pages(u32 *pages, u32 num_pages) |
| { |
| u32 i; |
| for (i = 0; i < mali_global_num_l2_cache_cores; i++) { |
| /*additional check*/ |
| if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_l2_cache_cores[i])) { |
| u32 j; |
| for (j = 0; j < num_pages; j++) { |
| _mali_osk_errcode_t ret; |
| ret = mali_l2_cache_send_command(mali_global_l2_cache_cores[i], MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, pages[j]); |
| if (_MALI_OSK_ERR_OK != ret) { |
| MALI_PRINT_ERROR(("Failed to invalidate page cache\n")); |
| } |
| } |
| } |
| mali_l2_cache_unlock_power_state(mali_global_l2_cache_cores[i]); |
| } |
| } |
| |
| mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache) |
| { |
| return mali_pm_domain_lock_state(cache->pm_domain); |
| } |
| |
| void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache) |
| { |
| return mali_pm_domain_unlock_state(cache->pm_domain); |
| } |
| |
| /* -------- 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_l2_cache_command_lock(cache); |
| |
| if (MALI_L2_PAUSE == cache->mali_l2_status) { |
| mali_l2_cache_command_unlock(cache); |
| MALI_DEBUG_PRINT(1, ("Mali L2 cache: aborting wait for L2 come back\n")); |
| |
| MALI_ERROR(_MALI_OSK_ERR_BUSY); |
| } |
| |
| /* 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_l2_cache_command_unlock(cache); |
| 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_l2_cache_command_unlock(cache); |
| |
| MALI_SUCCESS; |
| } |
| |
| void mali_l2_cache_pause_all(mali_bool pause) |
| { |
| int i; |
| struct mali_l2_cache_core *cache; |
| u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); |
| mali_l2_power_status status = MALI_L2_NORMAL; |
| |
| if (pause) { |
| status = MALI_L2_PAUSE; |
| } |
| |
| for (i = 0; i < num_cores; i++) { |
| cache = mali_l2_cache_core_get_glob_l2_core(i); |
| if (NULL != cache) { |
| cache->mali_l2_status = status; |
| |
| /* Take and release the counter and command locks to |
| * ensure there are no active threads that didn't get |
| * the status flag update. |
| * |
| * The locks will also ensure the necessary memory |
| * barriers are done on SMP systems. |
| */ |
| mali_l2_cache_counter_lock(cache); |
| mali_l2_cache_counter_unlock(cache); |
| |
| mali_l2_cache_command_lock(cache); |
| mali_l2_cache_command_unlock(cache); |
| } |
| } |
| |
| /* Resume from pause: do the cache invalidation here to prevent any |
| * loss of cache operation during the pause period to make sure the SW |
| * status is consistent with L2 cache status. |
| */ |
| if (!pause) { |
| mali_l2_cache_invalidate_all(); |
| mali_l2_cache_reset_counters_all(); |
| } |
| } |