forked from thesofproject/sof
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer_domain.c
More file actions
168 lines (129 loc) · 4.86 KB
/
timer_domain.c
File metadata and controls
168 lines (129 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
#include <rtos/timer.h>
#include <rtos/alloc.h>
#include <sof/lib/cpu.h>
#include <sof/lib/memory.h>
#include <sof/math/numbers.h>
#include <sof/platform.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/schedule/ll_schedule_domain.h>
#include <sof/schedule/schedule.h>
#include <rtos/task.h>
#include <ipc/topology.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define LL_TIMER_SET_OVERHEAD_TICKS 1000 /* overhead/delay to set the tick, in ticks */
struct timer_domain {
struct timer *timer;
void *arg[CONFIG_CORE_COUNT];
};
static void timer_report_delay(int id, uint64_t delay)
{
uint32_t ll_delay_us = (delay * 1000) /
clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1);
if (delay <= UINT_MAX)
tr_err(&ll_tr, "timer_report_delay(): timer %d delayed by %d uS %d ticks",
id, ll_delay_us, (unsigned int)delay);
else
tr_err(&ll_tr, "timer_report_delay(): timer %d delayed by %d uS, ticks > %u",
id, ll_delay_us, UINT_MAX);
/* Fix compile error when traces are disabled */
(void)ll_delay_us;
}
static int timer_domain_register(struct ll_schedule_domain *domain,
struct task *task,
void (*handler)(void *arg), void *arg)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
int core = cpu_get_id();
tr_dbg(&ll_tr, "timer_domain_register()");
/* tasks already registered on this core */
if (timer_domain->arg[core])
return 0;
timer_domain->arg[core] = arg;
tr_info(&ll_tr, "timer_domain_register domain->type %d domain->clk %d domain->ticks_per_ms %d",
domain->type, domain->clk, domain->ticks_per_ms);
return timer_register(timer_domain->timer, handler, arg);
}
static int timer_domain_unregister(struct ll_schedule_domain *domain,
struct task *task, uint32_t num_tasks)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
int core = cpu_get_id();
if (task)
return 0;
tr_dbg(&ll_tr, "timer_domain_unregister()");
/* tasks still registered on this core */
if (!timer_domain->arg[core] || num_tasks)
return 0;
tr_info(&ll_tr, "timer_domain_unregister domain->type %d domain->clk %d",
domain->type, domain->clk);
timer_unregister(timer_domain->timer, timer_domain->arg[core]);
timer_domain->arg[core] = NULL;
return 0;
}
static void timer_domain_enable(struct ll_schedule_domain *domain, int core)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
timer_enable(timer_domain->timer, timer_domain->arg[core], core);
}
static void timer_domain_disable(struct ll_schedule_domain *domain, int core)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
timer_disable(timer_domain->timer, timer_domain->arg[core], core);
}
static void timer_domain_set(struct ll_schedule_domain *domain, uint64_t start)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
uint64_t ticks_set;
/* make sure to require for ticks later than tout from now */
const uint64_t time = platform_timer_get_atomic(timer_domain->timer);
const uint64_t ticks_req = MAX(start, time + LL_TIMER_SET_OVERHEAD_TICKS);
ticks_set = platform_timer_set(timer_domain->timer, ticks_req);
tr_dbg(&ll_tr, "timer_domain_set(): ticks_set %u ticks_req %u current %u",
(unsigned int)ticks_set, (unsigned int)ticks_req,
(unsigned int)platform_timer_get_atomic(timer_get()));
/* Was timer set to the value we requested? If no it means some
* delay occurred and we should report that in error log.
*/
if (ticks_req < ticks_set)
timer_report_delay(timer_domain->timer->id,
ticks_set - ticks_req);
domain->next_tick = ticks_set;
}
static void timer_domain_clear(struct ll_schedule_domain *domain)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
platform_timer_clear(timer_domain->timer);
}
static bool timer_domain_is_pending(struct ll_schedule_domain *domain,
struct task *task, struct comp_dev **comp)
{
return task->start <= platform_timer_get_atomic(timer_get());
}
static const struct ll_schedule_domain_ops timer_domain_ops = {
.domain_register = timer_domain_register,
.domain_unregister = timer_domain_unregister,
.domain_enable = timer_domain_enable,
.domain_disable = timer_domain_disable,
.domain_set = timer_domain_set,
.domain_clear = timer_domain_clear,
.domain_is_pending = timer_domain_is_pending
};
struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk)
{
struct ll_schedule_domain *domain;
struct timer_domain *timer_domain;
domain = domain_init(SOF_SCHEDULE_LL_TIMER, clk, false,
&timer_domain_ops);
timer_domain = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*timer_domain));
timer_domain->timer = timer;
ll_sch_domain_set_pdata(domain, timer_domain);
return domain;
}