mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
![Andy Shevchenko](/assets/img/avatar_default.png)
kernel.h is being used as a dump for all kinds of stuff for a long time. Here is the attempt to start cleaning it up by splitting out mathematical helpers. At the same time convert users in header and lib folder to use new header. Though for time being include new header back to kernel.h to avoid twisted indirected includes for existing users. [sfr@canb.auug.org.au: fix powerpc build] Link: https://lkml.kernel.org/r/20201029150809.13059608@canb.auug.org.au Link: https://lkml.kernel.org/r/20201028173212.41768-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: "Paul E. McKenney" <paulmck@kernel.org> Cc: Trond Myklebust <trond.myklebust@hammerspace.com> Cc: Jeff Layton <jlayton@kernel.org> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
73 lines
1.5 KiB
C
73 lines
1.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/bitops.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/export.h>
|
|
#include <linux/limits.h>
|
|
#include <linux/math.h>
|
|
#include <linux/minmax.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/reciprocal_div.h>
|
|
|
|
/*
|
|
* For a description of the algorithm please have a look at
|
|
* include/linux/reciprocal_div.h
|
|
*/
|
|
|
|
struct reciprocal_value reciprocal_value(u32 d)
|
|
{
|
|
struct reciprocal_value R;
|
|
u64 m;
|
|
int l;
|
|
|
|
l = fls(d - 1);
|
|
m = ((1ULL << 32) * ((1ULL << l) - d));
|
|
do_div(m, d);
|
|
++m;
|
|
R.m = (u32)m;
|
|
R.sh1 = min(l, 1);
|
|
R.sh2 = max(l - 1, 0);
|
|
|
|
return R;
|
|
}
|
|
EXPORT_SYMBOL(reciprocal_value);
|
|
|
|
struct reciprocal_value_adv reciprocal_value_adv(u32 d, u8 prec)
|
|
{
|
|
struct reciprocal_value_adv R;
|
|
u32 l, post_shift;
|
|
u64 mhigh, mlow;
|
|
|
|
/* ceil(log2(d)) */
|
|
l = fls(d - 1);
|
|
/* NOTE: mlow/mhigh could overflow u64 when l == 32. This case needs to
|
|
* be handled before calling "reciprocal_value_adv", please see the
|
|
* comment at include/linux/reciprocal_div.h.
|
|
*/
|
|
WARN(l == 32,
|
|
"ceil(log2(0x%08x)) == 32, %s doesn't support such divisor",
|
|
d, __func__);
|
|
post_shift = l;
|
|
mlow = 1ULL << (32 + l);
|
|
do_div(mlow, d);
|
|
mhigh = (1ULL << (32 + l)) + (1ULL << (32 + l - prec));
|
|
do_div(mhigh, d);
|
|
|
|
for (; post_shift > 0; post_shift--) {
|
|
u64 lo = mlow >> 1, hi = mhigh >> 1;
|
|
|
|
if (lo >= hi)
|
|
break;
|
|
|
|
mlow = lo;
|
|
mhigh = hi;
|
|
}
|
|
|
|
R.m = (u32)mhigh;
|
|
R.sh = post_shift;
|
|
R.exp = l;
|
|
R.is_wide_m = mhigh > U32_MAX;
|
|
|
|
return R;
|
|
}
|
|
EXPORT_SYMBOL(reciprocal_value_adv);
|