XenevaOS
Loading...
Searching...
No Matches
hrtimer.h
Go to the documentation of this file.
1#ifndef __LINUX_HRTIMER_H__
2#define __LINUX_HRTIMER_H__
3
4/*
5 * DCL <linux/hrtimer.h> -- the two RS485 turnaround timers 8250_port.c owns.
6 *
7 * This header exists because struct serial8250_em485 embeds two struct
8 * hrtimer BY VALUE (serial_8250.h:126-127), so the type has to be complete at
9 * the point of declaration -- and mainline reaches it there by accident, not
10 * by listing it: upstream's serial_8250.h includes errno/serial_core/
11 * serial_reg/platform_device and nothing that names hrtimer, so struct
12 * hrtimer is complete only because serial_core.h -> sched.h happens to drag it
13 * in. DCL's serial_core.h is assembled from mainline but its include list is
14 * the subset BaseHdr actually has, so the dependency is written down in
15 * serial_8250.h instead of arriving by side effect.
16 *
17 * WHAT THESE DO, AND WHAT THEY DO NOT
18 * -----------------------------------
19 * hrtimer_start() records the target time and sets a pending flag. It does
20 * NOT queue anything, and no callback ever fires from it.
21 *
22 * That is not a placeholder chosen because it was quick: Xeneva runs no timer
23 * interrupt at all, which is already documented at the top of
24 * <linux/timer.h> -- there is no tick to count jiffies, so `extern jiffies`
25 * would link to a word that never moves, and DCL reads the same counter
26 * udelay() burns against instead. With no tick there is no place to run a
27 * timer queue from, and <linux/timer.h>'s add_timer()/mod_timer() have the
28 * same contract today: set pending, do not schedule, with the queue left as a
29 * TODO for whoever brings up real deferred work. These functions are the same
30 * contract, written in ktime rather than jiffies, so the two halves of DCL's
31 * timer story do not disagree.
32 *
33 * The consequence, stated plainly because it is a real limitation and not a
34 * formality: serial8250_em485_handle_stop_tx()/..._handle_start_tx() never
35 * run, so the delay between "shift from TX to RX" and "shift back" is never
36 * applied. That delay exists to let the last stop bit leave the wire before
37 * the driver flips an RS485 transceiver's direction pin.
38 *
39 * Why that costs nothing today: these two timers are armed only by
40 * serial8250_em485_init(), which is called only from
41 * serial8250_em485_config() -- the generic ->rs485_config() callback, i.e.
42 * the handler for TIOCSRS485. No port DCL opens is put into RS485 mode, so
43 * p->em485 is NULL, the em485 code paths are not entered, and nothing is
44 * waiting for a callback that will not come. If a stage ahead does bring up
45 * RS485 (an iMX8MP or RPi transceiver is exactly the hardware this is for),
46 * this header is the thing to replace -- not the drivers, which are already
47 * calling the right functions with the right arguments.
48 *
49 * Struct layout is DCL's own: 8250_port.c never touches a field of struct
50 * hrtimer, it only calls hrtimer_setup/start/cancel/try_to_cancel and returns
51 * HRTIMER_NORESTART from the callbacks, so nothing here needs to agree with
52 * mainline's node/expires layout. See <linux/serial_core.h> for why the same
53 * freedom is NOT taken with struct uart_port -- that one is laid out by
54 * designated initialisers in the driver, field by field.
55 */
56
57#include <linux/ktime.h>
58#include <linux/time.h>
59#include <linux/timerqueue.h> /* struct timerqueue_node -- hrtimer.node below */
60
61/* mainline: uapi/asm-generic/posix_types.h gives clockid_t as an int. DCL has
62 * no posix_types.h, so the typedef lands here, next to the clock IDs it
63 * indexes. */
64typedef int clockid_t;
65
66/*
67 * Callback result. HRTIMER_NORESTART is 0 so a callback that simply returns
68 * does the safe thing; 8250_port.c's two handlers choose between them on
69 * whether more turnaround work is pending.
70 */
75
76/*
77 * ABS/REL is what 8250_port.c passes (REL throughout: "wait n nanoseconds
78 * from now"). PINNED and the _SOFT variants are mainline's set, kept because
79 * they are part of the same value space -- an arm of hrtimer_mode is read
80 * back by nothing today, but a half-populated enum invites the next port to
81 * pass a number that means nothing.
82 */
91
92#define HRTIMER_STATE_INACTIVE 0
93#define HRTIMER_STATE_ENQUEUED 1
94
95struct hrtimer {
96 /*
97 * The expiry node, first because that is where mainline puts it.
98 *
99 * It was not in this struct until drm_vblank.c:2311 needed it: that
100 * line reads `vtimer->timer.node.expires` to re-read an expiry until
101 * two reads agree, which is a member access and cannot be answered by
102 * a stub -- the value is the point of the loop. `expires` is at the
103 * position and of the type mainline uses, so a real queue could be
104 * dropped in underneath without that read site changing.
105 */
107 /* HRTIMER_MODE_* the arm used; recorded so the (future) queue can
108 * decide absolute vs relative without the caller repeating it. */
110 /* Absolute target time for ABS, delta for REL -- as mainline stores
111 * it, so a real queue could be dropped in without touching callers. */
113 enum hrtimer_restart (*function)(struct hrtimer* timer);
114 int state;
116};
117
118/*
119 * All four are static inline rather than defined in a shim .c: there is no
120 * shared state to put in a shim (no queue, no lock, no clock base), and
121 * inlining keeps a driver TU from gaining an unresolved symbol it did not
122 * need. If a queue ever appears, they move to a .c and these disappear.
123 */
124static inline void hrtimer_setup(
125 struct hrtimer* timer,
126 enum hrtimer_restart (*function)(struct hrtimer* timer),
127 clockid_t clock_id, enum hrtimer_mode mode)
128{
129 (void)clock_id; /* CLOCK_MONOTONIC only; see header comment */
130 timer->mode = mode;
131 timer->function = function;
132 timer->_softexpires = 0;
134 timer->pending = 0;
135}
136
137static inline void hrtimer_start(struct hrtimer* timer, ktime_t tim,
138 enum hrtimer_mode mode)
139{
140 timer->mode = mode;
141 timer->_softexpires = tim;
142 /*
143 * node.expires is the absolute expiry, as mainline stores it: for REL
144 * that is now + tim. drm_crtc_vblank_get_vblank_timeout()
145 * (drm_vblank.c:2296) reads this member back as the next vblank
146 * timestamp, so leaving it at zero would hand the timestamping path
147 * a 1970 timestamp and a nonsense subtraction; ktime_get() is the
148 * same generic-timer clock that stamps the vblank counts, which is
149 * what makes that subtraction meaningful.
150 */
151 timer->node.expires = (mode & HRTIMER_MODE_REL)
152 ? ktime_add(ktime_get(), tim) : tim;
154 timer->pending = 1;
155}
156
157/*
158 * -1 means "running, do not delete" on mainline and is what hrtimer_cancel()
159 * retries on. DCL never runs a callback, so nothing can be running and 0/1
160 * (was it armed) is always the whole answer -- the return shape is kept
161 * because hrtimer_cancel()'s callers test it.
162 */
163static inline int hrtimer_try_to_cancel(struct hrtimer* timer)
164{
165 int was_pending = timer->pending;
166 timer->pending = 0;
168 return was_pending;
169}
170
171static inline int hrtimer_cancel(struct hrtimer* timer)
172{
173 return hrtimer_try_to_cancel(timer);
174}
175
176/*
177 * hrtimer_active() -- mainline (kernel/time/hrtimer.c) runs a seqcount-
178 * protected read of "state != INACTIVE || the callback is running". No
179 * callback can be running here, so the state is the whole answer, and
180 * hrtimer_try_to_cancel() above clears it -- the loop at drm_vblank.c:2238
181 * (`while (hrtimer_active()) hrtimer_try_to_cancel();`) therefore exits
182 * after one pass, which is the outcome its comment asks for ("wait for the
183 * previous cancel operation to finish" -- the cancel has taken effect).
184 */
185static inline bool hrtimer_active(const struct hrtimer* timer)
186{
187 return timer->state != HRTIMER_STATE_INACTIVE;
188}
189
190/*
191 * hrtimer_forward_now() -- "expire interval from now", mainline's wrapper
192 * around hrtimer_forward() with the clock base's current time. DCL has no
193 * base and never invokes a callback (the only caller is
194 * drm_vblank_timer_function(), the vblank timer's own callback), so this
195 * re-arms the stored expiry the way the REL arm of hrtimer_start() above
196 * does and returns 1. The return is mainline's overrun count, and 1 is the
197 * normal-path answer its caller expects -- it logs only when the value is
198 * something else.
199 */
200static inline u64 hrtimer_forward_now(struct hrtimer* timer, ktime_t interval)
201{
202 timer->node.expires = ktime_add(ktime_get(), interval);
203 return 1;
204}
205
206#endif /* __LINUX_HRTIMER_H__ */
hrtimer_mode
Definition hrtimer.h:83
@ HRTIMER_MODE_SOFT
Definition hrtimer.h:87
@ HRTIMER_MODE_ABS
Definition hrtimer.h:84
@ HRTIMER_MODE_PINNED
Definition hrtimer.h:86
@ HRTIMER_MODE_ABS_SOFT
Definition hrtimer.h:88
@ HRTIMER_MODE_REL_SOFT
Definition hrtimer.h:89
@ HRTIMER_MODE_REL
Definition hrtimer.h:85
hrtimer_restart
Definition hrtimer.h:71
@ HRTIMER_RESTART
Definition hrtimer.h:73
@ HRTIMER_NORESTART
Definition hrtimer.h:72
#define HRTIMER_STATE_ENQUEUED
Definition hrtimer.h:93
int clockid_t
Definition hrtimer.h:64
#define HRTIMER_STATE_INACTIVE
Definition hrtimer.h:92
uint64_t u64
Definition kernel.h:17
int64_t ktime_t
Definition kernel.h:404
Definition hrtimer.h:95
enum hrtimer_restart(* function)(struct hrtimer *timer)
Definition hrtimer.h:113
enum hrtimer_mode mode
Definition hrtimer.h:109
int state
Definition hrtimer.h:114
int pending
Definition hrtimer.h:115
ktime_t _softexpires
Definition hrtimer.h:112
struct timerqueue_node node
Definition hrtimer.h:106
Definition timerqueue.h:29
ktime_t expires
Definition timerqueue.h:31
#define mode(x)