/* * 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. * * 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_platform.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 void malipmm_subsystem_dump_state( void ); #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 */ 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 /* 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", }; /* 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", }; /* 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", }; 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 !MALI_PMM_NO_PMU if( mali_platform_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 ) { _mali_osk_resource_type_t t = PMU; 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( pmm_state->pmu_initialized ) ( mali_platform_deinit(&t) ); _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_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 ) { _mali_osk_resource_type_t t = PMU; #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); 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->pmu_initialized ) mali_platform_deinit(&t); _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_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 = mali_platform_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 #if !MALI_PMM_NO_PMU /* Turn off the core */ if( mali_platform_powerdown( core ) != _MALI_OSK_ERR_OK ) { MALI_PRINT_ERROR( ("PMM: Error powering down unregistered core: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) ); } #endif /* Remove the core from the system */ pmm->cores_registered &= (~core); 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); #ifdef 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 void malipmm_subsystem_dump_state(void) { malipmm_state_dump(); } #endif #if (defined(DEBUG) || MALI_STATE_TRACKING) void malipmm_state_dump() { _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; if( !pmm ) { MALI_PRINT(("PMM: Null state\n")); } else { MALI_PRINT(("Locks::\nPMM_LOCK_STATUS=%ld",pmm->mali_pmm_lock_acquired)); MALI_PRINT(("PMM state:\nPrevious_status=%d\nstatus=%d\nCurrent_event=%d\npolicy=%d\ncheck_policy=%d\nstate=%d\n", pmm->mali_last_pmm_status,pmm->status, pmm->mali_new_event_status, pmm->policy, pmm->check_policy, pmm->state)); MALI_PRINT(("PMM cores:\ncores_registered=%d\ncores_powered=%d\ncores_idle=%d\ncores_pend_down=%d\ncores_pend_up=%d\ncores_ack_down=%d\ncores_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)); MALI_PRINT(("PMM misc:\npmu_init=%d\nmessages_queued=%d\nwaiting=%d\nno_events=%d\nmissed=%d\nfatal_power_err=%d\n", pmm->pmu_initialized, _mali_osk_atomic_read( &(pmm->messages_queued) ), pmm->waiting, pmm->no_events, pmm->missed, pmm->fatal_power_err)); } } #endif #endif /* USING_MALI_PMM */