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
|
||||||
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)
|
ifneq (${FIP_ALIGN},0)
|
||||||
FIP_ARGS += --align ${FIP_ALIGN}
|
FIP_ARGS += --align ${FIP_ALIGN}
|
||||||
endif
|
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)
|
convert the power-state parameter (possibly encoding a composite power state)
|
||||||
passed in a PSCI `CPU_SUSPEND` call to this representation.
|
passed in a PSCI `CPU_SUSPEND` call to this representation.
|
||||||
|
|
||||||
The following functions must be implemented to initialize PSCI functionality in
|
The following functions form part of platform port of PSCI functionality.
|
||||||
the ARM Trusted Firmware.
|
|
||||||
|
|
||||||
|
|
||||||
|
### 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]
|
### Function : plat_get_target_pwr_state() [optional]
|
||||||
|
|
||||||
Argument : unsigned int, const plat_local_state_t *, unsigned int
|
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
|
* `ENABLE_PSCI_STAT`: Boolean option to enable support for optional PSCI
|
||||||
functions `PSCI_STAT_RESIDENCY` and `PSCI_STAT_COUNT`. Default is 0.
|
functions `PSCI_STAT_RESIDENCY` and `PSCI_STAT_COUNT`. Default is 0.
|
||||||
Enabling this option enables the `ENABLE_PMF` build option as well.
|
In the absence of an alternate stat collection backend, `ENABLE_PMF` must
|
||||||
The PMF is used for collecting the statistics.
|
be enabled. If `ENABLE_PMF` is set, the residency statistics are tracked in
|
||||||
|
software.
|
||||||
|
|
||||||
* `ENABLE_RUNTIME_INSTRUMENTATION`: Boolean option to enable runtime
|
* `ENABLE_RUNTIME_INSTRUMENTATION`: Boolean option to enable runtime
|
||||||
instrumentation which injects timestamp collection points into
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* 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).
|
* 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,
|
plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
|
||||||
const plat_local_state_t *states,
|
const plat_local_state_t *states,
|
||||||
unsigned int ncpu);
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -760,13 +760,7 @@ void psci_warmboot_entrypoint(void)
|
||||||
cpu_idx);
|
cpu_idx);
|
||||||
|
|
||||||
#if ENABLE_PSCI_STAT
|
#if ENABLE_PSCI_STAT
|
||||||
/*
|
plat_psci_stat_accounting_stop(&state_info);
|
||||||
* 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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
|
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
|
* Since caches are now enabled, it's necessary to do cache
|
||||||
* maintenance before reading that same data.
|
* 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
|
#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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* 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);
|
psci_set_cpu_local_state(cpu_pd_state);
|
||||||
|
|
||||||
#if ENABLE_PSCI_STAT
|
#if ENABLE_PSCI_STAT
|
||||||
/*
|
plat_psci_stat_accounting_start(&state_info);
|
||||||
* 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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_RUNTIME_INSTRUMENTATION
|
#if ENABLE_RUNTIME_INSTRUMENTATION
|
||||||
|
@ -144,13 +138,10 @@ int psci_cpu_suspend(unsigned int power_state,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_PSCI_STAT
|
#if ENABLE_PSCI_STAT
|
||||||
/* Capture time-stamp after CPU standby */
|
plat_psci_stat_accounting_stop(&state_info);
|
||||||
PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
|
|
||||||
PMF_NO_CACHE_MAINT);
|
|
||||||
|
|
||||||
/* Update PSCI stats */
|
/* Update PSCI stats */
|
||||||
psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info,
|
psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
|
||||||
PMF_NO_CACHE_MAINT);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return PSCI_E_SUCCESS;
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* 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);
|
psci_plat_pm_ops->pwr_domain_off(&state_info);
|
||||||
|
|
||||||
#if ENABLE_PSCI_STAT
|
#if ENABLE_PSCI_STAT
|
||||||
/*
|
plat_psci_stat_accounting_start(&state_info);
|
||||||
* 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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
exit:
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
#include <bakery_lock.h>
|
#include <bakery_lock.h>
|
||||||
#include <bl_common.h>
|
#include <bl_common.h>
|
||||||
#include <cpu_data.h>
|
#include <cpu_data.h>
|
||||||
#include <pmf.h>
|
|
||||||
#include <psci.h>
|
#include <psci.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
@ -106,15 +105,6 @@
|
||||||
#define is_cpu_standby_req(is_power_down_state, retn_lvl) \
|
#define is_cpu_standby_req(is_power_down_state, retn_lvl) \
|
||||||
(((!(is_power_down_state)) && ((retn_lvl) == 0)) ? 1 : 0)
|
(((!(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
|
* 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
|
* 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,
|
void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
|
||||||
const psci_power_state_t *state_info);
|
const psci_power_state_t *state_info);
|
||||||
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
||||||
const psci_power_state_t *state_info,
|
const psci_power_state_t *state_info);
|
||||||
unsigned int flags);
|
|
||||||
u_register_t psci_stat_residency(u_register_t target_cpu,
|
u_register_t psci_stat_residency(u_register_t target_cpu,
|
||||||
unsigned int power_state);
|
unsigned int power_state);
|
||||||
u_register_t psci_stat_count(u_register_t target_cpu,
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -38,9 +38,6 @@
|
||||||
#define PLAT_MAX_PWR_LVL_STATES 2
|
#define PLAT_MAX_PWR_LVL_STATES 2
|
||||||
#endif
|
#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 */
|
/* Following structure is used for PSCI STAT */
|
||||||
typedef struct psci_stat {
|
typedef struct psci_stat {
|
||||||
u_register_t residency;
|
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]
|
static psci_stat_t psci_non_cpu_stat[PSCI_NUM_NON_CPU_PWR_DOMAINS]
|
||||||
[PLAT_MAX_PWR_LVL_STATES];
|
[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
|
* 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
|
* 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)
|
* It is called with caches enabled and locks acquired(for NON-CPU domain)
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
|
||||||
const psci_power_state_t *state_info,
|
const psci_power_state_t *state_info)
|
||||||
unsigned int flags)
|
|
||||||
{
|
{
|
||||||
int parent_idx, cpu_idx = plat_my_core_pos();
|
int parent_idx, cpu_idx = plat_my_core_pos();
|
||||||
int lvl, stat_idx;
|
int lvl, stat_idx;
|
||||||
plat_local_state_t local_state;
|
plat_local_state_t local_state;
|
||||||
unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
|
|
||||||
u_register_t residency;
|
u_register_t residency;
|
||||||
|
|
||||||
assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
|
assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
|
||||||
assert(state_info);
|
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 */
|
/* Get the index into the stats array */
|
||||||
local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
|
local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
|
||||||
stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL);
|
stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL);
|
||||||
|
|
||||||
/* Calculate stats residency */
|
/* Call into platform interface to calculate residency. */
|
||||||
calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
|
residency = plat_psci_stat_get_residency(PSCI_CPU_PWR_LVL,
|
||||||
|
state_info, cpu_idx);
|
||||||
|
|
||||||
/* Update CPU stats. */
|
/* Update CPU stats. */
|
||||||
psci_cpu_stat[cpu_idx][stat_idx].residency += residency;
|
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);
|
assert(last_cpu_in_non_cpu_pd[parent_idx] != -1);
|
||||||
|
|
||||||
/* Get power down time-stamp for last CPU */
|
/* Call into platform interface to calculate residency. */
|
||||||
PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
|
residency = plat_psci_stat_get_residency(lvl, state_info,
|
||||||
last_cpu_in_non_cpu_pd[parent_idx],
|
last_cpu_in_non_cpu_pd[parent_idx]);
|
||||||
flags, pwrdn_ts);
|
|
||||||
|
|
||||||
/* Initialize back to reset value */
|
/* Initialize back to reset value */
|
||||||
last_cpu_in_non_cpu_pd[parent_idx] = -1;
|
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 */
|
/* Get the index into the stats array */
|
||||||
stat_idx = get_stat_idx(local_state, lvl);
|
stat_idx = get_stat_idx(local_state, lvl);
|
||||||
|
|
||||||
/* Calculate stats residency */
|
|
||||||
calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
|
|
||||||
|
|
||||||
/* Update non cpu stats */
|
/* Update non cpu stats */
|
||||||
psci_non_cpu_stat[parent_idx][stat_idx].residency += residency;
|
psci_non_cpu_stat[parent_idx][stat_idx].residency += residency;
|
||||||
psci_non_cpu_stat[parent_idx][stat_idx].count++;
|
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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* 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);
|
psci_plat_pm_ops->pwr_domain_suspend(state_info);
|
||||||
|
|
||||||
#if ENABLE_PSCI_STAT
|
#if ENABLE_PSCI_STAT
|
||||||
/*
|
plat_psci_stat_accounting_start(state_info);
|
||||||
* 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);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -257,6 +251,10 @@ exit:
|
||||||
PMF_NO_CACHE_MAINT);
|
PMF_NO_CACHE_MAINT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_PSCI_STAT
|
||||||
|
plat_psci_stat_accounting_start(state_info);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We will reach here if only retention/standby states have been
|
* We will reach here if only retention/standby states have been
|
||||||
* requested at multiple power levels. This means that the cpu
|
* requested at multiple power levels. This means that the cpu
|
||||||
|
@ -264,6 +262,11 @@ exit:
|
||||||
*/
|
*/
|
||||||
wfi();
|
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
|
#if ENABLE_RUNTIME_INSTRUMENTATION
|
||||||
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
|
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
|
||||||
RT_INSTR_EXIT_HW_LOW_PWR,
|
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
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions are met:
|
# 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_COUNT/RESIDENCY APIs on ARM platforms
|
||||||
ENABLE_PSCI_STAT := 1
|
ENABLE_PSCI_STAT := 1
|
||||||
|
ENABLE_PMF := 1
|
||||||
|
|
||||||
# On ARM platforms, separate the code and read-only data sections to allow
|
# On ARM platforms, separate the code and read-only data sections to allow
|
||||||
# mapping the former as executable and the latter as execute-never.
|
# 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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -31,8 +31,125 @@
|
||||||
#include <arch.h>
|
#include <arch.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
#include <pmf.h>
|
||||||
#include <psci.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
|
* The PSCI generic code uses this API to let the platform participate in state
|
||||||
* coordination during a power management operation. It compares the platform
|
* coordination during a power management operation. It compares the platform
|
||||||
|
|
Loading…
Reference in New Issue