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