1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <fwk_attributes.h>
9 #include <fwk_log.h>
10 #include <fwk_mm.h>
11 #include <fwk_string.h>
12 #include <fwk_trace.h>
13
14 #include <string.h>
15
16 static struct {
17 struct fwk_trace_driver driver; /* Trace driver */
18 fwk_trace_count_t *start_timestamp;
19 bool *entry_pending;
20 } fwk_trace_ctx;
21
fwk_trace_init(void)22 FWK_CONSTRUCTOR void fwk_trace_init(void)
23 {
24 struct fwk_trace_driver driver = fmw_trace_driver();
25 (void)fwk_str_memcpy(&fwk_trace_ctx.driver, &driver, sizeof(driver));
26 if (fwk_trace_ctx.driver.trace_entry_count != 0) {
27 fwk_trace_ctx.start_timestamp = fwk_mm_calloc(
28 fwk_trace_ctx.driver.trace_entry_count + 1,
29 sizeof(fwk_trace_count_t));
30 fwk_trace_ctx.entry_pending = fwk_mm_calloc(
31 fwk_trace_ctx.driver.trace_entry_count + 1,
32 sizeof(fwk_trace_count_t));
33 }
34 }
35
calc_delta(fwk_trace_count_t start,fwk_trace_count_t end)36 static inline fwk_trace_count_t calc_delta(
37 fwk_trace_count_t start,
38 fwk_trace_count_t end)
39 {
40 return (end >= start) ? (end - start) :
41 ((fwk_trace_count_t)(-1) - start + end);
42 }
43
fwk_trace_calc_overhead(void)44 fwk_trace_count_t fwk_trace_calc_overhead(void)
45 {
46 fwk_trace_count_t start = fwk_trace_ctx.driver.get_trace_count();
47 (void)FWK_TRACE_START(fwk_trace_ctx.driver.trace_entry_count);
48 (void)FWK_TRACE_FINISH(fwk_trace_ctx.driver.trace_entry_count, "");
49 return calc_delta(start, fwk_trace_ctx.driver.get_trace_count());
50 }
51
fwk_trace_start(fwk_trace_id_t id)52 int fwk_trace_start(fwk_trace_id_t id)
53 {
54 if (id >= fwk_trace_ctx.driver.trace_entry_count) {
55 FWK_LOG_ERR("id is not valid");
56 return FWK_E_PARAM;
57 }
58 if (fwk_trace_ctx.entry_pending[id] == true) {
59 FWK_LOG_ERR("tracing id 0x%" PRItraceid " has already started", id);
60 return FWK_E_STATE;
61 }
62 if (fwk_trace_ctx.driver.get_trace_count == NULL) {
63 FWK_LOG_ERR("start trace driver is not set!");
64 return FWK_E_DEVICE;
65 }
66 fwk_trace_ctx.entry_pending[id] = true;
67 fwk_trace_ctx.start_timestamp[id] = fwk_trace_ctx.driver.get_trace_count();
68
69 return FWK_SUCCESS;
70 }
71
fwk_trace_finish(const char * filename,const char * func,const unsigned int line,fwk_trace_id_t id,const char * msg)72 int fwk_trace_finish(
73 const char *filename,
74 const char *func,
75 const unsigned int line,
76 fwk_trace_id_t id,
77 const char *msg)
78 {
79 if (id >= fwk_trace_ctx.driver.trace_entry_count) {
80 FWK_LOG_ERR("id is not valid");
81 return FWK_E_PARAM;
82 }
83 if (fwk_trace_ctx.entry_pending[id] == false) {
84 FWK_LOG_ERR(
85 "%s:%u: tracing id 0x%" PRItraceid " has not been started",
86 func,
87 line,
88 id);
89 return FWK_E_STATE;
90 }
91 fwk_trace_ctx.entry_pending[id] = false;
92 if (fwk_trace_ctx.driver.get_trace_count == NULL ||
93 fwk_trace_ctx.driver.report_trace_entry == NULL) {
94 FWK_LOG_ERR("finish trace driver is not set!");
95 return FWK_E_DEVICE;
96 }
97 fwk_trace_count_t trace_count = calc_delta(
98 fwk_trace_ctx.start_timestamp[id],
99 fwk_trace_ctx.driver.get_trace_count());
100 fwk_trace_ctx.start_timestamp[id] = 0;
101 fwk_trace_ctx.driver.report_trace_entry(
102 filename, func, line, id, trace_count, msg);
103
104 return FWK_SUCCESS;
105 }
106
fmw_trace_driver(void)107 FWK_WEAK struct fwk_trace_driver fmw_trace_driver(void)
108 {
109 return (struct fwk_trace_driver){
110 .trace_entry_count = 0,
111 .get_trace_count = NULL,
112 .report_trace_entry = NULL,
113 };
114 }
115