XenevaOS
Loading...
Searching...
No Matches
math64.h
Go to the documentation of this file.
1#ifndef __LINUX_MATH64_H__
2#define __LINUX_MATH64_H__
3
4/*
5 * DCL <linux/math64.h> -- 64-bit division and 32x32->64 multiplication.
6 *
7 * Every body below is the generic C answer (`/`, `%`, `(u64)a * b`) rather
8 * than an arch-specific routine, and that is the correct answer here rather
9 * than a simplification: this target is aarch64, which has a hardware 64-bit
10 * divider and a 32x32->64 multiplier (umulh), so each of these compiles to
11 * one instruction pair with no libgcc call -- the exact problem upstream's
12 * per-arch split (lib/div64.c and the per-arch lib directories) exists to
13 * avoid on 32-bit CPUs that trap or soft-divide. Matching mainline's
14 * *answers* is all that is owed, and for truncating integer division the
15 * hardware and the reference agree bit for bit, including the signed
16 * forms' round-toward-zero.
17 *
18 * include <linux/types.h> supplies u64/s64/u32/s32 (kernel.h's typedefs) so
19 * the prototypes read like mainline's. The include is safe in either
20 * direction: types.h's own kernel.h include is behind kernel.h's include
21 * guard, which any caller of this header has already set, and asm/div64.h
22 * has pulled types.h in before its bottom include of this file.
23 *
24 * Not every consumer names this header. drm_mm.c, drm_file.c, drm_rect.c,
25 * drm_format_helper.c and drm_fourcc.c reach it only through
26 * <asm/div64.h>, which includes it at the bottom -- see the bridge note
27 * there. That is why the helpers must be inline here and not in a DCL shim:
28 * a definition the caller cannot see is not a definition.
29 *
30 * upstream include/linux/math64.h (mainline v7.2)
31 */
32
33#include <linux/types.h>
34
35/*
36 * div64_u64 / DIV64_U64_ROUND_UP -- the one pair this header carried for the
37 * tty/serial stage, kept because serial_core.c:451 still uses it:
38 *
39 * temp *= NSEC_PER_SEC;
40 * port->frame_time = (unsigned int)DIV64_U64_ROUND_UP(temp, baud);
41 *
42 * which turns a bit time into the nanoseconds a whole frame takes, rounded
43 * *up* because a frame time that rounds down would make uart_poll_timeout()
44 * wake before the last stop bit had left the wire -- the caller then polls
45 * once more and, on a slow line, can poll forever. Rounding up is the safe
46 * direction and it is what upstream's div64_u64() does behind this macro.
47 * Written as a macro rather than an inline for the same reachability reason
48 * as the rest, just at an earlier stage: serial_core.c happened to include
49 * the header, and a plain expression cannot disagree with itself.
50 */
51#define div64_u64(a, b) ((u64)(a) / (u64)(b))
52#define DIV64_U64_ROUND_UP(n, d) (div64_u64((u64)(n) + (u64)(d) - 1, (d)))
53
54/*
55 * div64_u64_rem -- 64/64 divide, remainder through the out parameter.
56 *
57 * The two callers, drm_mm.c:575 and :792, use only the remainder: each
58 * adjusts an alignment up to the next multiple of `alignment` when
59 * `alignment` is not a power of two (a power of two goes through the
60 * remainder_mask fast path beside the call). Getting this wrong does not
61 * fault -- it places a node at a misaligned start, and only the
62 * alignment-aware users of drm_mm (address-space VA allocation with a
63 * non-power-of-two guard) would ever see it.
64 */
65static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
66{
67 *remainder = dividend % divisor;
68 return dividend / divisor;
69}
70
71/*
72 * div64_s64 -- signed 64/64 divide.
73 *
74 * Reached from <drm/drm_fixed.h>, whose fixed-point arithmetic is compiled
75 * into vkms_composer.o and vkms_formats.o. drm_fixed.h:166 divides one
76 * fixed-point value by another and :215-227 computes a per-step tolerance
77 * for the blend matrices; both compare the result against zero or against a
78 * tolerance, so a divide that did not follow the operands' sign would flip a
79 * blend decision rather than merely lose a fraction.
80 */
81static inline s64 div64_s64(s64 dividend, s64 divisor)
82{
83 return dividend / divisor;
84}
85
86/*
87 * div_u64 -- unsigned 64/32 divide.
88 *
89 * drm_file.c:857 steps a byte count down by SZ_1K for fdinfo units
90 * (`sz = div_u64(sz, SZ_1K)`) and drm_vblank.c:659-660 turns
91 * pixels * 1000000 into a line/frame duration in nanoseconds
92 * (`div_u64((u64) mode->crtc_htotal * 1000000, dotclock)`). The 64-bit
93 * dividend is the reason the name exists: a plain division by a 32-bit
94 * value would still be a 64-bit operation, but the explicit u32 parameter
95 * is what tells a 32-bit compiler it may use the cheap path.
96 */
97static inline u64 div_u64(u64 dividend, u32 divisor)
98{
99 return dividend / divisor;
100}
101
102/*
103 * div_s64 -- signed 64/32 divide.
104 *
105 * One caller, drm_vblank.c:807: the elapsed-time delta between the queried
106 * scanout position and the start of the display scanline is computed as
107 * `1000000LL * (vpos * mode->crtc_htotal + hpos)`, which is negative when
108 * the query lands before the first line has been scanned. That negative has
109 * to stay negative -- it is added to a raw timestamp -- so the unsigned form
110 * would be a silent timestamp jump of almost 2^64 nanoseconds.
111 */
112static inline s64 div_s64(s64 dividend, s32 divisor)
113{
114 return dividend / divisor;
115}
116
117/*
118 * mul_u32_u32 -- unsigned 32x32 -> 64 multiply.
119 *
120 * Both callers multiply quantities that legitimately exceed 32 bits:
121 * drm_rect.c:65 scales a clipped source rectangle by the destination
122 * extent, and drm_modes.c:1307 computes a fixed-point refresh rate
123 * (`mul_u32_u32(num, 1000)` where num already sits in the fixed-point
124 * domain). Without the widening cast the product would wrap at 2^32 and the
125 * scaled rectangle/rate would be wrong by a multiple of 2^32 -- the
126 * truncation would be invisible until a large mode was used.
127 */
128static inline u64 mul_u32_u32(u32 a, u32 b)
129{
130 return (u64)a * b;
131}
132
133/*
134 * KHZ2PICOS -- a frequency in kHz as picoseconds, `(1000000000UL/(a))`.
135 *
136 * Upstream's home is <uapi/linux/fb.h>:241; DCL's <linux/fb.h> is a stub
137 * kept only so the include resolves -- drm_modes.c:35 includes it with the
138 * comment "for KHZ2PICOS()" and gets nothing from it. The macro is placed
139 * here instead because this header (through the asm/div64.h bridge) is
140 * reached by both comparers: drm_edid.c:4409-4410 and :4511-4512 match an
141 * EDID mode against CEA mode clocks, drm_modes.c:1495 compares two
142 * drm_display_modes. All of them compare `mode->clock` (kHz, an int) after
143 * scaling to picoseconds, which is how KHz becomes comparable with EDID's
144 * kHz-with-decimals without floating point. 1000000000UL fits unsigned long
145 * on this LLP64 target (32 bits) with room to spare, and `a` is a mode clock
146 * in kHz, so the only input that would fault is zero -- which no parsed
147 * display mode carries.
148 */
149#ifndef KHZ2PICOS
150#define KHZ2PICOS(a) (1000000000UL / (a))
151#endif
152
153#endif /* __LINUX_MATH64_H__ */
size_t a
Definition main.cpp:156
size_t b
Definition main.cpp:156
int64_t s64
Definition kernel.h:21
uint64_t u64
Definition kernel.h:17
int32_t s32
Definition kernel.h:20
uint32_t u32
Definition kernel.h:16