Tegra: lib: library for profiling the cold boot path

The non secure world would like to profile the boot path for
the EL3 and S-EL1 firmwares. To allow it to do that, a non-secure
DRAM region (4K) is allocated and the base address is passed to
the EL3 firmware.

This patch adds a library to allow the platform code to store the
tag:timestamp pair to the shared memory. The tegra platform code
then uses the `record` method to add timestamps.

Original change by Akshay Sharan <asharan@nvidia.com>

Change-Id: Idbbef9c83ed84a508b04d85a6637775960dc94ba
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
Varun Wadekar 2017-07-21 13:34:16 -07:00
parent 6460ed7aaa
commit 087cf68a7f
6 changed files with 230 additions and 0 deletions

View File

@ -82,6 +82,8 @@ uint64\_t tzdram\_base;
int uart\_id;
/* L2 ECC parity protection disable flag \*/
int l2\_ecc\_parity\_prot\_dis;
/* SHMEM base address for storing the boot logs \*/
uint64\_t boot\_profiler\_shmem\_base;
} plat\_params\_from\_bl2\_t;
Power Management

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* The profiler stores the timestamps captured during cold boot to the shared
* memory for the non-secure world. The non-secure world driver parses the
* shared memory block and writes the contents to a file on the device, which
* can be later extracted for analysis.
*
* Profiler memory map
*
* TOP --------------------------- ---
* Trusted OS timestamps 3KB
* --------------------------- ---
* Trusted Firmware timestamps 1KB
* BASE --------------------------- ---
*
******************************************************************************/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <mmio.h>
#include <profiler.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <utils_def.h>
#include <xlat_tables_v2.h>
static uint64_t shmem_base_addr;
#define MAX_PROFILER_RECORDS U(16)
#define TAG_LEN_BYTES U(56)
/*******************************************************************************
* Profiler entry format
******************************************************************************/
typedef struct {
/* text explaining the timestamp location in code */
uint8_t tag[TAG_LEN_BYTES];
/* timestamp value */
uint64_t timestamp;
} profiler_rec_t;
static profiler_rec_t *head, *cur, *tail;
static uint32_t tmr;
static bool is_shmem_buf_mapped;
/*******************************************************************************
* Initialise the profiling library
******************************************************************************/
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
{
uint64_t shmem_end_base;
assert(shmem_base != ULL(0));
assert(tmr_base != U(0));
/* store the buffer address */
shmem_base_addr = shmem_base;
/* calculate the base address of the last record */
shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
(MAX_PROFILER_RECORDS - U(1)));
/* calculate the head, tail and cur values */
head = (profiler_rec_t *)shmem_base;
tail = (profiler_rec_t *)shmem_end_base;
cur = head;
/* timer used to get the current timestamp */
tmr = tmr_base;
}
/*******************************************************************************
* Add tag and timestamp to profiler
******************************************************************************/
void boot_profiler_add_record(const char *str)
{
unsigned int len;
/* calculate the length of the tag */
if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
len = TAG_LEN_BYTES;
} else {
len = (unsigned int)strlen(str) + U(1);
}
if (head != NULL) {
/*
* The profiler runs with/without MMU enabled. Check
* if MMU is enabled and memmap the shmem buffer, in
* case it is.
*/
if ((!is_shmem_buf_mapped) &&
((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
(void)mmap_add_dynamic_region(shmem_base_addr,
shmem_base_addr,
PROFILER_SIZE_BYTES,
(MT_NS | MT_RW | MT_EXECUTE_NEVER));
is_shmem_buf_mapped = true;
}
/* write the tag and timestamp to buffer */
(void)snprintf((char *)cur->tag, len, "%s", str);
cur->timestamp = mmio_read_32(tmr);
/* start from head if we reached the end */
if (cur == tail) {
cur = head;
} else {
cur++;
}
}
}
/*******************************************************************************
* Deinint the profiler
******************************************************************************/
void boot_profiler_deinit(void)
{
if (shmem_base_addr != ULL(0)) {
/* clean up resources */
cur = NULL;
head = NULL;
tail = NULL;
/* flush the shmem for it to be visible to the NS world */
flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
/* unmap the shmem buffer */
if (is_shmem_buf_mapped) {
(void)mmap_remove_dynamic_region(shmem_base_addr,
PROFILER_SIZE_BYTES);
}
}
}

View File

@ -26,6 +26,7 @@
#include <plat/common/platform.h>
#include <memctrl.h>
#include <profiler.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
@ -125,6 +126,7 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
image_info_t bl32_img_info = { {0} };
uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
uint32_t console_clock;
int32_t ret;
/*
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
@ -194,6 +196,32 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
TEGRA_CONSOLE_BAUDRATE);
}
/*
* The previous bootloader passes the base address of the shared memory
* location to store the boot profiler logs. Sanity check the
* address and initilise the profiler library, if it looks ok.
*/
if (plat_params->boot_profiler_shmem_base != 0ULL) {
ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base,
PROFILER_SIZE_BYTES);
if (ret == (int32_t)0) {
/* store the membase for the profiler lib */
plat_bl31_params_from_bl2.boot_profiler_shmem_base =
plat_params->boot_profiler_shmem_base;
/* initialise the profiler library */
boot_profiler_init(plat_params->boot_profiler_shmem_base,
TEGRA_TMRUS_BASE);
}
}
/*
* Add timestamp for platform early setup entry.
*/
boot_profiler_add_record("[TF] early setup entry");
/*
* Initialize delay timer
*/
@ -244,6 +272,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* Early platform setup for Tegra SoCs */
plat_early_platform_setup();
/*
* Add timestamp for platform early setup exit.
*/
boot_profiler_add_record("[TF] early setup exit");
INFO("BL3-1: Boot CPU: %s Processor [%lx]\n",
(((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK)
== DENVER_IMPL) ? "Denver" : "ARM", read_mpidr());
@ -268,6 +301,11 @@ void plat_trusty_set_boot_args(aapcs64_params_t *args)
******************************************************************************/
void bl31_platform_setup(void)
{
/*
* Add timestamp for platform setup entry.
*/
boot_profiler_add_record("[TF] plat setup entry");
/* Initialize the gic cpu and distributor interfaces */
plat_gic_setup();
@ -287,6 +325,11 @@ void bl31_platform_setup(void)
*/
tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
/*
* Add timestamp for platform setup exit.
*/
boot_profiler_add_record("[TF] plat setup exit");
INFO("BL3-1: Tegra platform setup complete\n");
}
@ -305,6 +348,12 @@ void bl31_plat_runtime_setup(void)
* disabled before we jump to the non-secure world.
*/
tegra_memctrl_disable_ahb_redirection();
/*
* Add final timestamp before exiting BL31.
*/
boot_profiler_add_record("[TF] bl31 exit");
boot_profiler_deinit();
}
/*******************************************************************************
@ -325,6 +374,11 @@ void bl31_plat_arch_setup(void)
#endif
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
/*
* Add timestamp for arch setup entry.
*/
boot_profiler_add_record("[TF] arch setup entry");
/* add memory regions */
mmap_add_region(rw_start, rw_start,
rw_size,
@ -373,6 +427,11 @@ void bl31_plat_arch_setup(void)
/* enable the MMU */
enable_mmu_el3(0);
/*
* Add timestamp for arch setup exit.
*/
boot_profiler_add_record("[TF] arch setup exit");
INFO("BL3-1: Tegra: MMU enabled\n");
}

View File

@ -5,6 +5,7 @@
#
PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \
-Iplat/nvidia/tegra/include/lib \
-Iplat/nvidia/tegra/include \
-Iplat/nvidia/tegra/include/${TARGET_SOC}
@ -25,6 +26,7 @@ BL31_SOURCES += drivers/console/aarch64/console.S \
${TEGRA_GICv2_SOURCES} \
${COMMON_DIR}/aarch64/tegra_helpers.S \
${COMMON_DIR}/drivers/pmc/pmc.c \
${COMMON_DIR}/lib/debug/profiler.c \
${COMMON_DIR}/tegra_bl31_setup.c \
${COMMON_DIR}/tegra_delay_timer.c \
${COMMON_DIR}/tegra_fiq_glue.c \

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __PROFILER_H__
#define __PROFILER_H__
/*******************************************************************************
* Number of bytes of memory used by the profiler on Tegra
******************************************************************************/
#define PROFILER_SIZE_BYTES U(0x1000)
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base);
void boot_profiler_add_record(const char *str);
void boot_profiler_deinit(void);
#endif /* __PROFILER_H__ */

View File

@ -44,6 +44,8 @@ typedef struct plat_params_from_bl2 {
int32_t uart_id;
/* L2 ECC parity protection disable flag */
int32_t l2_ecc_parity_prot_dis;
/* SHMEM base address for storing the boot logs */
uint64_t boot_profiler_shmem_base;
} plat_params_from_bl2_t;
/*******************************************************************************