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); pmm_state->status = MALI_PMM_STATUS_OFF; MALI_PMM_UNLOCK(pmm_state); pmm_policy_term(pmm_state); _mali_osk_irq_term( pmm_state->irq ); #ifdef CONFIG_SMP _mali_osk_lock_term(mali_pmm_lock); #endif /* CONFIG_SMP */ _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") ); }
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); }
_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); /* 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)) ); } MALI_PMM_UNLOCK(pmm); return err; }
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 #ifdef CONFIG_SMP _mali_osk_lock_wait( mali_pmm_lock, _MALI_OSK_LOCKMODE_RW ); #endif /* CONFIG_SMP */ MALI_PMM_LOCK(pmm); /* Quick out when we are shutting down */ if( pmm->status == MALI_PMM_STATUS_OFF ) { MALI_PMM_UNLOCK(pmm); #ifdef CONFIG_SMP _mali_osk_lock_signal( mali_pmm_lock, _MALI_OSK_LOCKMODE_RW ); #endif /* CONFIG_SMP */ 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 ); } } MALI_PMM_UNLOCK(pmm); #ifdef CONFIG_SMP _mali_osk_lock_signal(mali_pmm_lock, _MALI_OSK_LOCKMODE_RW ); #endif /* CONFIG_SMP */ }
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_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); /* 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 } MALI_PMM_UNLOCK(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 ) { #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") ); }
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 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 = mali_platform_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 ) { 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); /* 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_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 */ MALI_PMM_UNLOCK(pmm); err = mali_core_signal_power_up( cores_list[n], MALI_FALSE ); MALI_PMM_LOCK(pmm); if( err != _MALI_OSK_ERR_OK ) { 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 = mali_platform_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; }
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 */ 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); /* 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_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 */ 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); /* 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_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; }