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
149 lines (115 loc) · 4.11 KB
/
timer_domain.c
File metadata and controls
149 lines (115 loc) · 4.11 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
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
#include <sof/drivers/timer.h>
#include <sof/lib/alloc.h>
#include <sof/lib/cpu.h>
#include <sof/platform.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/schedule/ll_schedule_domain.h>
#include <sof/schedule/schedule.h>
#include <sof/schedule/task.h>
#include <ipc/topology.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct timer_domain {
struct timer *timer;
uint64_t timeout;
void *arg[PLATFORM_CORE_COUNT];
};
struct ll_schedule_domain_ops timer_domain_ops;
static inline void timer_report_delay(int id, uint64_t delay)
{
uint32_t ll_delay_us = (delay * 1000) /
clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1);
trace_ll_error("timer_report_delay(): timer %d delayed by %d uS %d "
"ticks", id, ll_delay_us, delay);
/* Fix compile error when traces are disabled */
(void)ll_delay_us;
}
static int timer_domain_register(struct ll_schedule_domain *domain,
uint64_t period, 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();
trace_ll("timer_domain_register()");
/* tasks already registered on this core */
if (timer_domain->arg[core])
return 0;
timer_domain->arg[core] = arg;
return timer_register(timer_domain->timer, handler, arg);
}
static void timer_domain_unregister(struct ll_schedule_domain *domain,
uint32_t num_tasks)
{
struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain);
int core = cpu_get_id();
trace_ll("timer_domain_unregister()");
/* tasks still registered on this core */
if (!timer_domain->arg[core] || num_tasks)
return;
timer_unregister(timer_domain->timer, timer_domain->arg[core]);
timer_domain->arg[core] = NULL;
}
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_req = domain->ticks_per_ms * timer_domain->timeout /
1000 + start;
uint64_t ticks_set;
ticks_set = platform_timer_set(timer_domain->timer, ticks_req);
/* 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->last_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)
{
return task->start <= platform_timer_get(platform_timer);
}
struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk,
uint64_t timeout)
{
struct ll_schedule_domain *domain;
struct timer_domain *timer_domain;
trace_ll("timer_domain_init(): clk %d, timeout %u", clk, timeout);
domain = domain_init(SOF_SCHEDULE_LL_TIMER, clk, &timer_domain_ops);
timer_domain = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED,
SOF_MEM_CAPS_RAM, sizeof(*timer_domain));
timer_domain->timer = timer;
timer_domain->timeout = timeout;
ll_sch_domain_set_pdata(domain, timer_domain);
return domain;
}
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
};