Merge pull request #826 from dp-arm/dp/psci-stat-abstraction
Decouple PSCI stat residency calculation from PMF
This commit is contained in:
commit
fd6d90d8a6
5
Makefile
5
Makefile
|
@ -346,11 +346,6 @@ ifneq (${GENERATE_COT},0)
|
|||
endif
|
||||
endif
|
||||
|
||||
# Make sure PMF is enabled if PSCI STAT is enabled.
|
||||
ifeq (${ENABLE_PSCI_STAT},1)
|
||||
ENABLE_PMF := 1
|
||||
endif
|
||||
|
||||
ifneq (${FIP_ALIGN},0)
|
||||
FIP_ARGS += --align ${FIP_ALIGN}
|
||||
endif
|
||||
|
|
|
@ -1707,10 +1707,56 @@ level could enter. It depends on the `validate_power_state()` handler to
|
|||
convert the power-state parameter (possibly encoding a composite power state)
|
||||
passed in a PSCI `CPU_SUSPEND` call to this representation.
|
||||
|
||||
The following functions must be implemented to initialize PSCI functionality in
|
||||
the ARM Trusted Firmware.
|
||||
The following functions form part of platform port of PSCI functionality.
|
||||
|
||||
|
||||
### Function : plat_psci_stat_accounting_start() [optional]
|
||||
|
||||
Argument : const psci_power_state_t *
|
||||
Return : void
|
||||
|
||||
This is an optional hook that platforms can implement for residency statistics
|
||||
accounting before entering a low power state. The `pwr_domain_state` field of
|
||||
`state_info` (first argument) can be inspected if stat accounting is done
|
||||
differently at CPU level versus higher levels. As an example, if the element at
|
||||
index 0 (CPU power level) in the `pwr_domain_state` array indicates a power down
|
||||
state, special hardware logic may be programmed in order to keep track of the
|
||||
residency statistics. For higher levels (array indices > 0), the residency
|
||||
statistics could be tracked in software using PMF. If `ENABLE_PMF` is set, the
|
||||
default implementation will use PMF to capture timestamps.
|
||||
|
||||
### Function : plat_psci_stat_accounting_stop() [optional]
|
||||
|
||||
Argument : const psci_power_state_t *
|
||||
Return : void
|
||||
|
||||
This is an optional hook that platforms can implement for residency statistics
|
||||
accounting after exiting from a low power state. The `pwr_domain_state` field
|
||||
of `state_info` (first argument) can be inspected if stat accounting is done
|
||||
differently at CPU level versus higher levels. As an example, if the element at
|
||||
index 0 (CPU power level) in the `pwr_domain_state` array indicates a power down
|
||||
state, special hardware logic may be programmed in order to keep track of the
|
||||
residency statistics. For higher levels (array indices > 0), the residency
|
||||
statistics could be tracked in software using PMF. If `ENABLE_PMF` is set, the
|
||||
default implementation will use PMF to capture timestamps.
|
||||
|
||||
### Function : plat_psci_stat_get_residency() [optional]
|
||||
|
||||
Argument : unsigned int, const psci_power_state_t *, int
|
||||
Return : u_register_t
|
||||
|
||||
This is an optional interface that is is invoked after resuming from a low power
|
||||
state and provides the time spent resident in that low power state by the power
|
||||
domain at a particular power domain level. When a CPU wakes up from suspend,
|
||||
all its parent power domain levels are also woken up. The generic PSCI code
|
||||
invokes this function for each parent power domain that is resumed and it
|
||||
identified by the `lvl` (first argument) parameter. The `state_info` (second
|
||||
argument) describes the low power state that the power domain has resumed from.
|
||||
The current CPU is the first CPU in the power domain to resume from the low
|
||||
power state and the `last_cpu_idx` (third parameter) is the index of the last
|
||||
CPU in the power domain to suspend and may be needed to calculate the residency
|
||||
for that power domain.
|
||||
|
||||
### Function : plat_get_target_pwr_state() [optional]
|
||||
|
||||
Argument : unsigned int, const plat_local_state_t *, unsigned int
|
||||
|
|
|
@ -274,8 +274,9 @@ performed.
|
|||
|
||||
* `ENABLE_PSCI_STAT`: Boolean option to enable support for optional PSCI
|
||||
functions `PSCI_STAT_RESIDENCY` and `PSCI_STAT_COUNT`. Default is 0.
|
||||
Enabling this option enables the `ENABLE_PMF` build option as well.
|
||||
The PMF is used for collecting the statistics.
|
||||
In the absence of an alternate stat collection backend, `ENABLE_PMF` must
|
||||
be enabled. If `ENABLE_PMF` is set, the residency statistics are tracked in
|
||||
software.
|
||||
|
||||
* `ENABLE_RUNTIME_INSTRUMENTATION`: Boolean option to enable runtime
|
||||
instrumentation which injects timestamp collection points into
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -254,6 +254,11 @@ const unsigned char *plat_get_power_domain_tree_desc(void);
|
|||
/*******************************************************************************
|
||||
* Optional PSCI functions (BL31).
|
||||
******************************************************************************/
|
||||
void plat_psci_stat_accounting_start(const psci_power_state_t *state_info);
|
||||
void plat_psci_stat_accounting_stop(const psci_power_state_t *state_info);
|
||||
u_register_t plat_psci_stat_get_residency(unsigned int lvl,
|
||||
const psci_power_state_t *state_info,
|
||||
int last_cpu_index);
|
||||
plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
|
||||
const plat_local_state_t *states,
|
||||
unsigned int ncpu);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -760,13 +760,7 @@ void psci_warmboot_entrypoint(void)
|
|||
cpu_idx);
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
/*
|
||||
* Capture power up time-stamp.
|
||||
* No cache maintenance is required as caches are off
|
||||
* and writes are direct to the main memory.
|
||||
*/
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
plat_psci_stat_accounting_stop(&state_info);
|
||||
#endif
|
||||
|
||||
psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
|
||||
|
@ -801,7 +795,7 @@ void psci_warmboot_entrypoint(void)
|
|||
* Since caches are now enabled, it's necessary to do cache
|
||||
* maintenance before reading that same data.
|
||||
*/
|
||||
psci_stats_update_pwr_up(end_pwrlvl, &state_info, PMF_CACHE_MAINT);
|
||||
psci_stats_update_pwr_up(end_pwrlvl, &state_info);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -117,13 +117,7 @@ int psci_cpu_suspend(unsigned int power_state,
|
|||
psci_set_cpu_local_state(cpu_pd_state);
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
/*
|
||||
* Capture time-stamp before CPU standby
|
||||
* No cache maintenance is needed as caches
|
||||
* are ON through out the CPU standby operation.
|
||||
*/
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
plat_psci_stat_accounting_start(&state_info);
|
||||
#endif
|
||||
|
||||
#if ENABLE_RUNTIME_INSTRUMENTATION
|
||||
|
@ -144,13 +138,10 @@ int psci_cpu_suspend(unsigned int power_state,
|
|||
#endif
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
/* Capture time-stamp after CPU standby */
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
plat_psci_stat_accounting_stop(&state_info);
|
||||
|
||||
/* Update PSCI stats */
|
||||
psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
|
||||
#endif
|
||||
|
||||
return PSCI_E_SUCCESS;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -137,13 +137,7 @@ int psci_do_cpu_off(unsigned int end_pwrlvl)
|
|||
psci_plat_pm_ops->pwr_domain_off(&state_info);
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
/*
|
||||
* Capture time-stamp while entering low power state.
|
||||
* No cache maintenance needed because caches are off
|
||||
* and writes are direct to main memory.
|
||||
*/
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
plat_psci_stat_accounting_start(&state_info);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -35,7 +35,6 @@
|
|||
#include <bakery_lock.h>
|
||||
#include <bl_common.h>
|
||||
#include <cpu_data.h>
|
||||
#include <pmf.h>
|
||||
#include <psci.h>
|
||||
#include <spinlock.h>
|
||||
|
||||
|
@ -106,15 +105,6 @@
|
|||
#define is_cpu_standby_req(is_power_down_state, retn_lvl) \
|
||||
(((!(is_power_down_state)) && ((retn_lvl) == 0)) ? 1 : 0)
|
||||
|
||||
/* Following are used as ID's to capture time-stamp */
|
||||
#define PSCI_STAT_ID_ENTER_LOW_PWR 0
|
||||
#define PSCI_STAT_ID_EXIT_LOW_PWR 1
|
||||
#define PSCI_STAT_TOTAL_IDS 2
|
||||
|
||||
/* Declare PMF service functions for PSCI */
|
||||
PMF_DECLARE_CAPTURE_TIMESTAMP(psci_svc)
|
||||
PMF_DECLARE_GET_TIMESTAMP(psci_svc)
|
||||
|
||||
/*******************************************************************************
|
||||
* The following two data structures implement the power domain tree. The tree
|
||||
* is used to track the state of all the nodes i.e. power domain instances
|
||||
|
@ -246,8 +236,7 @@ void __dead2 psci_system_reset(void);
|
|||
void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
|
||||
const psci_power_state_t *state_info);
|
||||
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
||||
const psci_power_state_t *state_info,
|
||||
unsigned int flags);
|
||||
const psci_power_state_t *state_info);
|
||||
u_register_t psci_stat_residency(u_register_t target_cpu,
|
||||
unsigned int power_state);
|
||||
u_register_t psci_stat_count(u_register_t target_cpu,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -38,9 +38,6 @@
|
|||
#define PLAT_MAX_PWR_LVL_STATES 2
|
||||
#endif
|
||||
|
||||
/* Ticks elapsed in one second by a signal of 1 MHz */
|
||||
#define MHZ_TICKS_PER_SEC 1000000
|
||||
|
||||
/* Following structure is used for PSCI STAT */
|
||||
typedef struct psci_stat {
|
||||
u_register_t residency;
|
||||
|
@ -62,27 +59,6 @@ static psci_stat_t psci_cpu_stat[PLATFORM_CORE_COUNT]
|
|||
static psci_stat_t psci_non_cpu_stat[PSCI_NUM_NON_CPU_PWR_DOMAINS]
|
||||
[PLAT_MAX_PWR_LVL_STATES];
|
||||
|
||||
/* Register PMF PSCI service */
|
||||
PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID,
|
||||
PSCI_STAT_TOTAL_IDS, PMF_STORE_ENABLE)
|
||||
|
||||
/* The divisor to use to convert raw timestamp into microseconds */
|
||||
u_register_t residency_div;
|
||||
|
||||
/*
|
||||
* This macro calculates the stats residency in microseconds,
|
||||
* taking in account the wrap around condition.
|
||||
*/
|
||||
#define calc_stat_residency(_pwrupts, _pwrdnts, _res) \
|
||||
do { \
|
||||
if (_pwrupts < _pwrdnts) \
|
||||
_res = UINT64_MAX - _pwrdnts + _pwrupts;\
|
||||
else \
|
||||
_res = _pwrupts - _pwrdnts; \
|
||||
/* Convert timestamp into microseconds */ \
|
||||
_res = _res/residency_div; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* This functions returns the index into the `psci_stat_t` array given the
|
||||
* local power state and power domain level. If the platform implements the
|
||||
|
@ -150,44 +126,23 @@ void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
|
|||
* It is called with caches enabled and locks acquired(for NON-CPU domain)
|
||||
******************************************************************************/
|
||||
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
||||
const psci_power_state_t *state_info,
|
||||
unsigned int flags)
|
||||
const psci_power_state_t *state_info)
|
||||
{
|
||||
int parent_idx, cpu_idx = plat_my_core_pos();
|
||||
int lvl, stat_idx;
|
||||
plat_local_state_t local_state;
|
||||
unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
|
||||
u_register_t residency;
|
||||
|
||||
assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
|
||||
assert(state_info);
|
||||
|
||||
/* Initialize the residency divisor if not already initialized */
|
||||
if (!residency_div) {
|
||||
/* Pre-calculate divisor so that it can be directly used to
|
||||
convert time-stamp into microseconds */
|
||||
residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
|
||||
assert(residency_div);
|
||||
}
|
||||
|
||||
/* Get power down time-stamp for current CPU */
|
||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
cpu_idx, flags, pwrdn_ts);
|
||||
|
||||
/* In the case of 1st power on just return */
|
||||
if (!pwrdn_ts)
|
||||
return;
|
||||
|
||||
/* Get power up time-stamp for current CPU */
|
||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
|
||||
cpu_idx, flags, pwrup_ts);
|
||||
|
||||
/* Get the index into the stats array */
|
||||
local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
|
||||
stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL);
|
||||
|
||||
/* Calculate stats residency */
|
||||
calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
|
||||
/* Call into platform interface to calculate residency. */
|
||||
residency = plat_psci_stat_get_residency(PSCI_CPU_PWR_LVL,
|
||||
state_info, cpu_idx);
|
||||
|
||||
/* Update CPU stats. */
|
||||
psci_cpu_stat[cpu_idx][stat_idx].residency += residency;
|
||||
|
@ -207,10 +162,9 @@ void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
|||
|
||||
assert(last_cpu_in_non_cpu_pd[parent_idx] != -1);
|
||||
|
||||
/* Get power down time-stamp for last CPU */
|
||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
last_cpu_in_non_cpu_pd[parent_idx],
|
||||
flags, pwrdn_ts);
|
||||
/* Call into platform interface to calculate residency. */
|
||||
residency = plat_psci_stat_get_residency(lvl, state_info,
|
||||
last_cpu_in_non_cpu_pd[parent_idx]);
|
||||
|
||||
/* Initialize back to reset value */
|
||||
last_cpu_in_non_cpu_pd[parent_idx] = -1;
|
||||
|
@ -218,9 +172,6 @@ void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
|||
/* Get the index into the stats array */
|
||||
stat_idx = get_stat_idx(local_state, lvl);
|
||||
|
||||
/* Calculate stats residency */
|
||||
calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
|
||||
|
||||
/* Update non cpu stats */
|
||||
psci_non_cpu_stat[parent_idx][stat_idx].residency += residency;
|
||||
psci_non_cpu_stat[parent_idx][stat_idx].count++;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -211,13 +211,7 @@ void psci_cpu_suspend_start(entry_point_info_t *ep,
|
|||
psci_plat_pm_ops->pwr_domain_suspend(state_info);
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
/*
|
||||
* Capture time-stamp while entering low power state.
|
||||
* No cache maintenance needed because caches are off
|
||||
* and writes are direct to main memory.
|
||||
*/
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
plat_psci_stat_accounting_start(state_info);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
|
@ -257,6 +251,10 @@ exit:
|
|||
PMF_NO_CACHE_MAINT);
|
||||
#endif
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
plat_psci_stat_accounting_start(state_info);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We will reach here if only retention/standby states have been
|
||||
* requested at multiple power levels. This means that the cpu
|
||||
|
@ -264,6 +262,11 @@ exit:
|
|||
*/
|
||||
wfi();
|
||||
|
||||
#if ENABLE_PSCI_STAT
|
||||
plat_psci_stat_accounting_stop(state_info);
|
||||
psci_stats_update_pwr_up(end_pwrlvl, state_info);
|
||||
#endif
|
||||
|
||||
#if ENABLE_RUNTIME_INSTRUMENTATION
|
||||
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
|
||||
RT_INSTR_EXIT_HW_LOW_PWR,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
|
||||
# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
|
@ -92,6 +92,7 @@ $(eval $(call add_define,ARM_BL31_IN_DRAM))
|
|||
|
||||
# Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms
|
||||
ENABLE_PSCI_STAT := 1
|
||||
ENABLE_PMF := 1
|
||||
|
||||
# On ARM platforms, separate the code and read-only data sections to allow
|
||||
# mapping the former as executable and the latter as execute-never.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -31,8 +31,125 @@
|
|||
#include <arch.h>
|
||||
#include <assert.h>
|
||||
#include <platform.h>
|
||||
#include <pmf.h>
|
||||
#include <psci.h>
|
||||
|
||||
#if ENABLE_PSCI_STAT && ENABLE_PMF
|
||||
#pragma weak plat_psci_stat_accounting_start
|
||||
#pragma weak plat_psci_stat_accounting_stop
|
||||
#pragma weak plat_psci_stat_get_residency
|
||||
|
||||
/* Ticks elapsed in one second by a signal of 1 MHz */
|
||||
#define MHZ_TICKS_PER_SEC 1000000
|
||||
|
||||
/* Following are used as ID's to capture time-stamp */
|
||||
#define PSCI_STAT_ID_ENTER_LOW_PWR 0
|
||||
#define PSCI_STAT_ID_EXIT_LOW_PWR 1
|
||||
#define PSCI_STAT_TOTAL_IDS 2
|
||||
|
||||
PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS,
|
||||
PMF_STORE_ENABLE)
|
||||
|
||||
/*
|
||||
* This function calculates the stats residency in microseconds,
|
||||
* taking in account the wrap around condition.
|
||||
*/
|
||||
static u_register_t calc_stat_residency(unsigned long long pwrupts,
|
||||
unsigned long long pwrdnts)
|
||||
{
|
||||
/* The divisor to use to convert raw timestamp into microseconds. */
|
||||
u_register_t residency_div;
|
||||
u_register_t res;
|
||||
|
||||
/*
|
||||
* Calculate divisor so that it can be directly used to
|
||||
* convert time-stamp into microseconds.
|
||||
*/
|
||||
residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
|
||||
assert(residency_div);
|
||||
|
||||
if (pwrupts < pwrdnts)
|
||||
res = UINT64_MAX - pwrdnts + pwrupts;
|
||||
else
|
||||
res = pwrupts - pwrdnts;
|
||||
|
||||
return res / residency_div;
|
||||
}
|
||||
|
||||
/*
|
||||
* Capture timestamp before entering a low power state.
|
||||
* No cache maintenance is required when capturing the timestamp.
|
||||
* Cache maintenance may be needed when reading these timestamps.
|
||||
*/
|
||||
void plat_psci_stat_accounting_start(
|
||||
__unused const psci_power_state_t *state_info)
|
||||
{
|
||||
assert(state_info);
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Capture timestamp after exiting a low power state.
|
||||
* No cache maintenance is required when capturing the timestamp.
|
||||
* Cache maintenance may be needed when reading these timestamps.
|
||||
*/
|
||||
void plat_psci_stat_accounting_stop(
|
||||
__unused const psci_power_state_t *state_info)
|
||||
{
|
||||
assert(state_info);
|
||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
|
||||
PMF_NO_CACHE_MAINT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the residency for the given level and power state
|
||||
* information.
|
||||
*/
|
||||
u_register_t plat_psci_stat_get_residency(unsigned int lvl,
|
||||
const psci_power_state_t *state_info,
|
||||
int last_cpu_idx)
|
||||
{
|
||||
plat_local_state_t state;
|
||||
unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
|
||||
unsigned int pmf_flags;
|
||||
|
||||
assert(lvl >= PSCI_CPU_PWR_LVL && lvl <= PLAT_MAX_PWR_LVL);
|
||||
assert(state_info);
|
||||
assert(last_cpu_idx >= 0 && last_cpu_idx <= PLATFORM_CORE_COUNT);
|
||||
|
||||
if (lvl == PSCI_CPU_PWR_LVL)
|
||||
assert(last_cpu_idx == plat_my_core_pos());
|
||||
|
||||
/*
|
||||
* If power down is requested, then timestamp capture will
|
||||
* be with caches OFF. Hence we have to do cache maintenance
|
||||
* when reading the timestamp.
|
||||
*/
|
||||
state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
|
||||
if (is_local_state_off(state)) {
|
||||
pmf_flags = PMF_CACHE_MAINT;
|
||||
} else {
|
||||
assert(is_local_state_retn(state));
|
||||
pmf_flags = PMF_NO_CACHE_MAINT;
|
||||
}
|
||||
|
||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
|
||||
PSCI_STAT_ID_ENTER_LOW_PWR,
|
||||
last_cpu_idx,
|
||||
pmf_flags,
|
||||
pwrdn_ts);
|
||||
|
||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
|
||||
PSCI_STAT_ID_EXIT_LOW_PWR,
|
||||
plat_my_core_pos(),
|
||||
pmf_flags,
|
||||
pwrup_ts);
|
||||
|
||||
return calc_stat_residency(pwrup_ts, pwrdn_ts);
|
||||
}
|
||||
#endif /* ENABLE_PSCI_STAT && ENABLE_PMF */
|
||||
|
||||
/*
|
||||
* The PSCI generic code uses this API to let the platform participate in state
|
||||
* coordination during a power management operation. It compares the platform
|
||||
|
|
Loading…
Reference in New Issue