hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/*
 * Copyright (C) 2006,2007 Philippe Gerum <rpm@xenomai.org>.
 *
 * Xenomai is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * Xenomai is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Xenomai; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */
#ifndef _COBALT_KERNEL_CLOCK_H
#define _COBALT_KERNEL_CLOCK_H
 
#include <pipeline/pipeline.h>
#include <pipeline/clock.h>
#include <cobalt/kernel/list.h>
#include <cobalt/kernel/vfile.h>
#include <cobalt/uapi/kernel/types.h>
#include <asm/xenomai/wrappers.h>
 
/**
 * @addtogroup cobalt_core_clock
 * @{
 */
 
struct xnsched;
struct xntimerdata;
struct __kernel_timex;
 
struct xnclock_gravity {
   unsigned long irq;
   unsigned long kernel;
   unsigned long user;
};
 
struct xnclock {
   /** (ns) */
   xnsticks_t wallclock_offset;
   /** (ns) */
   xnticks_t resolution;
   /** (raw clock ticks). */
   struct xnclock_gravity gravity;
   /** Clock name. */
   const char *name;
   struct {
#ifdef CONFIG_XENO_OPT_EXTCLOCK
       xnticks_t (*read_raw)(struct xnclock *clock);
       xnticks_t (*read_monotonic)(struct xnclock *clock);
       int (*set_time)(struct xnclock *clock,
               const struct timespec64 *ts);
       xnsticks_t (*ns_to_ticks)(struct xnclock *clock,
                     xnsticks_t ns);
       xnsticks_t (*ticks_to_ns)(struct xnclock *clock,
                     xnsticks_t ticks);
       xnsticks_t (*ticks_to_ns_rounded)(struct xnclock *clock,
                         xnsticks_t ticks);
       void (*program_local_shot)(struct xnclock *clock,
                      struct xnsched *sched);
       void (*program_remote_shot)(struct xnclock *clock,
                       struct xnsched *sched);
#endif
       int (*adjust_time)(struct xnclock *clock,
                  struct __kernel_timex *tx);
       int (*set_gravity)(struct xnclock *clock,
                  const struct xnclock_gravity *p);
       void (*reset_gravity)(struct xnclock *clock);
#ifdef CONFIG_XENO_OPT_VFILE
       void (*print_status)(struct xnclock *clock,
                    struct xnvfile_regular_iterator *it);
#endif
   } ops;
   /* Private section. */
   struct xntimerdata *timerdata;
   int id;
#ifdef CONFIG_SMP
   /** Possible CPU affinity of clock beat. */
   cpumask_t affinity;
#endif
#ifdef CONFIG_XENO_OPT_STATS
   struct xnvfile_snapshot timer_vfile;
   struct xnvfile_rev_tag timer_revtag;
   struct list_head timerq;
   int nrtimers;
#endif /* CONFIG_XENO_OPT_STATS */
#ifdef CONFIG_XENO_OPT_VFILE
   struct xnvfile_regular vfile;
#endif
};
 
struct xnclock_ratelimit_state {
   xnticks_t interval;
   xnticks_t begin;
   int burst;
   int printed;
   int missed;
};
 
extern struct xnclock nkclock;
 
int xnclock_register(struct xnclock *clock,
            const cpumask_t *affinity);
 
void xnclock_deregister(struct xnclock *clock);
 
void xnclock_tick(struct xnclock *clock);
 
void xnclock_core_local_shot(struct xnsched *sched);
 
void xnclock_core_remote_shot(struct xnsched *sched);
 
xnsticks_t xnclock_core_ns_to_ticks(xnsticks_t ns);
 
xnsticks_t xnclock_core_ticks_to_ns(xnsticks_t ticks);
 
xnsticks_t xnclock_core_ticks_to_ns_rounded(xnsticks_t ticks);
 
xnticks_t xnclock_core_read_monotonic(void);
 
static inline xnticks_t xnclock_core_read_raw(void)
{
   return pipeline_read_cycle_counter();
}
 
/* We use the Linux defaults */
#define XN_RATELIMIT_INTERVAL    5000000000LL
#define XN_RATELIMIT_BURST    10
 
int __xnclock_ratelimit(struct xnclock_ratelimit_state *rs, const char *func);
 
#define xnclock_ratelimit()    ({                    \
   static struct xnclock_ratelimit_state __state = {        \
       .interval    = XN_RATELIMIT_INTERVAL,        \
       .burst        = XN_RATELIMIT_BURST,            \
   };                                \
   __xnclock_ratelimit(&__state, __func__);            \
})
 
#ifdef CONFIG_XENO_OPT_EXTCLOCK
 
static inline void xnclock_program_shot(struct xnclock *clock,
                   struct xnsched *sched)
{
   if (likely(clock == &nkclock))
       xnclock_core_local_shot(sched);
   else if (clock->ops.program_local_shot)
       clock->ops.program_local_shot(clock, sched);
}
 
static inline void xnclock_remote_shot(struct xnclock *clock,
                      struct xnsched *sched)
{
#ifdef CONFIG_SMP
   if (likely(clock == &nkclock))
       xnclock_core_remote_shot(sched);
   else if (clock->ops.program_remote_shot)
       clock->ops.program_remote_shot(clock, sched);
#endif
}
 
static inline xnticks_t xnclock_read_raw(struct xnclock *clock)
{
   if (likely(clock == &nkclock))
       return xnclock_core_read_raw();
 
   return clock->ops.read_raw(clock);
}
 
static inline xnsticks_t xnclock_ns_to_ticks(struct xnclock *clock,
                        xnsticks_t ns)
{
   if (likely(clock == &nkclock))
       return xnclock_core_ns_to_ticks(ns);
 
   return clock->ops.ns_to_ticks(clock, ns);
}
 
static inline xnsticks_t xnclock_ticks_to_ns(struct xnclock *clock,
                        xnsticks_t ticks)
{
   if (likely(clock == &nkclock))
       return xnclock_core_ticks_to_ns(ticks);
 
   return clock->ops.ticks_to_ns(clock, ticks);
}
 
static inline xnsticks_t xnclock_ticks_to_ns_rounded(struct xnclock *clock,
                            xnsticks_t ticks)
{
   if (likely(clock == &nkclock))
       return xnclock_core_ticks_to_ns_rounded(ticks);
 
   return clock->ops.ticks_to_ns_rounded(clock, ticks);
}
 
static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock)
{
   if (likely(clock == &nkclock))
       return xnclock_core_read_monotonic();
 
   return clock->ops.read_monotonic(clock);
}
 
static inline int xnclock_set_time(struct xnclock *clock,
                  const struct timespec64 *ts)
{
   if (likely(clock == &nkclock))
       return -EINVAL;
 
   return clock->ops.set_time(clock, ts);
}
 
#else /* !CONFIG_XENO_OPT_EXTCLOCK */
 
static inline void xnclock_program_shot(struct xnclock *clock,
                   struct xnsched *sched)
{
   xnclock_core_local_shot(sched);
}
 
static inline void xnclock_remote_shot(struct xnclock *clock,
                      struct xnsched *sched)
{
#ifdef CONFIG_SMP
   xnclock_core_remote_shot(sched);
#endif
}
 
static inline xnticks_t xnclock_read_raw(struct xnclock *clock)
{
   return xnclock_core_read_raw();
}
 
static inline xnsticks_t xnclock_ns_to_ticks(struct xnclock *clock,
                        xnsticks_t ns)
{
   return xnclock_core_ns_to_ticks(ns);
}
 
static inline xnsticks_t xnclock_ticks_to_ns(struct xnclock *clock,
                        xnsticks_t ticks)
{
   return xnclock_core_ticks_to_ns(ticks);
}
 
static inline xnsticks_t xnclock_ticks_to_ns_rounded(struct xnclock *clock,
                            xnsticks_t ticks)
{
   return xnclock_core_ticks_to_ns_rounded(ticks);
}
 
static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock)
{
   return xnclock_core_read_monotonic();
}
 
static inline int xnclock_set_time(struct xnclock *clock,
                  const struct timespec64 *ts)
{
   /*
    * There is no way to change the core clock's idea of time.
    */
   return -EINVAL;
}
 
#endif /* !CONFIG_XENO_OPT_EXTCLOCK */
 
static inline int xnclock_adjust_time(struct xnclock *clock,
                     struct __kernel_timex *tx)
{
   if (clock->ops.adjust_time == NULL)
       return -EOPNOTSUPP;
 
   return clock->ops.adjust_time(clock, tx);
}
 
static inline xnticks_t xnclock_get_offset(struct xnclock *clock)
{
   return clock->wallclock_offset;
}
 
static inline xnticks_t xnclock_get_resolution(struct xnclock *clock)
{
   return clock->resolution; /* ns */
}
 
static inline void xnclock_set_resolution(struct xnclock *clock,
                     xnticks_t resolution)
{
   clock->resolution = resolution; /* ns */
}
 
static inline int xnclock_set_gravity(struct xnclock *clock,
                     const struct xnclock_gravity *gravity)
{
   if (clock->ops.set_gravity)
       return clock->ops.set_gravity(clock, gravity);
 
   return -EINVAL;
}
 
static inline void xnclock_reset_gravity(struct xnclock *clock)
{
   if (clock->ops.reset_gravity)
       clock->ops.reset_gravity(clock);
}
 
#define xnclock_get_gravity(__clock, __type)  ((__clock)->gravity.__type)
 
static inline xnticks_t xnclock_read_realtime(struct xnclock *clock)
{
   if (likely(clock == &nkclock))
       return pipeline_read_wallclock();
   /*
    * Return an adjusted value of the monotonic time with the
    * translated system wallclock offset.
    */
   return xnclock_read_monotonic(clock) + xnclock_get_offset(clock);
}
 
void xnclock_apply_offset(struct xnclock *clock,
             xnsticks_t delta_ns);
 
void xnclock_set_wallclock(xnticks_t epoch_ns);
 
unsigned long long xnclock_divrem_billion(unsigned long long value,
                     unsigned long *rem);
 
#ifdef CONFIG_XENO_OPT_VFILE
 
void xnclock_init_proc(void);
 
void xnclock_cleanup_proc(void);
 
static inline void xnclock_print_status(struct xnclock *clock,
                   struct xnvfile_regular_iterator *it)
{
   if (clock->ops.print_status)
       clock->ops.print_status(clock, it);
}
 
#else
static inline void xnclock_init_proc(void) { }
static inline void xnclock_cleanup_proc(void) { }
#endif
 
int xnclock_init(void);
 
void xnclock_cleanup(void);
 
/** @} */
 
#endif /* !_COBALT_KERNEL_CLOCK_H */