1 /* 2 * This file is part of the coreboot project. 3 * 4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <asm/arch/timestamp.h> 11 #include <asm/arch/sysinfo.h> 12 #include <linux/compiler.h> 13 14 struct timestamp_entry { 15 uint32_t entry_id; 16 uint64_t entry_stamp; 17 } __packed; 18 19 struct timestamp_table { 20 uint64_t base_time; 21 uint32_t max_entries; 22 uint32_t num_entries; 23 struct timestamp_entry entries[0]; /* Variable number of entries */ 24 } __packed; 25 26 static struct timestamp_table *ts_table __attribute__((section(".data"))); 27 28 void timestamp_init(void) 29 { 30 #ifdef CONFIG_SYS_X86_TSC_TIMER 31 uint64_t base_time; 32 #endif 33 34 ts_table = lib_sysinfo.tstamp_table; 35 #ifdef CONFIG_SYS_X86_TSC_TIMER 36 /* 37 * If coreboot is built with CONFIG_COLLECT_TIMESTAMPS, use the value 38 * of base_time in coreboot's timestamp table as our timer base, 39 * otherwise TSC counter value will be used. 40 * 41 * Sometimes even coreboot is built with CONFIG_COLLECT_TIMESTAMPS, 42 * the value of base_time in the timestamp table is still zero, so 43 * we must exclude this case too (this is currently seen on booting 44 * coreboot in qemu) 45 */ 46 if (ts_table && ts_table->base_time) 47 base_time = ts_table->base_time; 48 else 49 base_time = rdtsc(); 50 timer_set_base(base_time); 51 #endif 52 timestamp_add_now(TS_U_BOOT_INITTED); 53 } 54 55 void timestamp_add(enum timestamp_id id, uint64_t ts_time) 56 { 57 struct timestamp_entry *tse; 58 59 if (!ts_table || (ts_table->num_entries == ts_table->max_entries)) 60 return; 61 62 tse = &ts_table->entries[ts_table->num_entries++]; 63 tse->entry_id = id; 64 tse->entry_stamp = ts_time - ts_table->base_time; 65 } 66 67 void timestamp_add_now(enum timestamp_id id) 68 { 69 timestamp_add(id, rdtsc()); 70 } 71 72 int timestamp_add_to_bootstage(void) 73 { 74 uint i; 75 76 if (!ts_table) 77 return -1; 78 79 for (i = 0; i < ts_table->num_entries; i++) { 80 struct timestamp_entry *tse = &ts_table->entries[i]; 81 const char *name = NULL; 82 83 switch (tse->entry_id) { 84 case TS_START_ROMSTAGE: 85 name = "start-romstage"; 86 break; 87 case TS_BEFORE_INITRAM: 88 name = "before-initram"; 89 break; 90 case TS_DEVICE_INITIALIZE: 91 name = "device-initialize"; 92 break; 93 case TS_DEVICE_DONE: 94 name = "device-done"; 95 break; 96 case TS_SELFBOOT_JUMP: 97 name = "selfboot-jump"; 98 break; 99 } 100 if (name) { 101 bootstage_add_record(0, name, BOOTSTAGEF_ALLOC, 102 tse->entry_stamp / 103 get_tbclk_mhz()); 104 } 105 } 106 107 return 0; 108 } 109