mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
LinuxKPI: implement mul_u64_u64_div_u64()
Implement mul_u64_u64_div_u64() for an updated iwlwifi driver (though we do not yet use it there; it is used for in-kernel ptp on wifi). Sponsored by: The FreeBSD Foundation Submitted by: cperciva MFC after: 10 days Reviewed by: cperciva, dwmalone Differential Revision: https://reviews.freebsd.org/D40120
This commit is contained in:
parent
98fd1add67
commit
b80ea45237
|
@ -106,6 +106,54 @@ mul_u64_u32_div(uint64_t x, uint32_t y, uint32_t div)
|
||||||
return ((x / div) * y + (rem * y) / div);
|
return ((x / div) * y + (rem * y) / div);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
mul_u64_u64_div_u64(uint64_t x, uint64_t y, uint64_t z)
|
||||||
|
{
|
||||||
|
uint64_t res, rem;
|
||||||
|
uint64_t x1, y1, y1z;
|
||||||
|
|
||||||
|
res = rem = 0;
|
||||||
|
x1 = x;
|
||||||
|
y1z = y / z;
|
||||||
|
y1 = y - y1z * z;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INVARIANT: x * y = res * z + rem + (y1 + y1z * z) * x1
|
||||||
|
* INVARIANT: y1 < z
|
||||||
|
* INVARIANT: rem < z
|
||||||
|
*/
|
||||||
|
while (x1 > 0) {
|
||||||
|
/* Handle low bit. */
|
||||||
|
if (x1 & 1) {
|
||||||
|
x1 &= ~1;
|
||||||
|
res += y1z;
|
||||||
|
rem += y1;
|
||||||
|
if ((rem < y1) || (rem >= z)) {
|
||||||
|
res += 1;
|
||||||
|
rem -= z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shift x1 right and (y1 + y1z * z) left */
|
||||||
|
x1 >>= 1;
|
||||||
|
if ((y1 * 2 < y1) || (y1 * 2 >= z)) {
|
||||||
|
y1z = y1z * 2 + 1;
|
||||||
|
y1 = y1 * 2 - z;
|
||||||
|
} else {
|
||||||
|
y1z *= 2;
|
||||||
|
y1 *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(res * z + rem == x * y, ("%s: res %ju * z %ju + rem %ju != "
|
||||||
|
"x %ju * y %ju", __func__, (uintmax_t)res, (uintmax_t)z,
|
||||||
|
(uintmax_t)rem, (uintmax_t)x, (uintmax_t)y));
|
||||||
|
KASSERT(rem < z, ("%s: rem %ju >= z %ju\n", __func__,
|
||||||
|
(uintmax_t)rem, (uintmax_t)z);
|
||||||
|
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
mul_u64_u32_shr(uint64_t x, uint32_t y, unsigned int shift)
|
mul_u64_u32_shr(uint64_t x, uint32_t y, unsigned int shift)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue