Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ config RISCV
select CLINT_TIMER if RISCV_M_MODE
select CLONE_BACKWARDS
select COMMON_CLK
select CPU_NO_EFFICIENT_FFS if !RISCV_ISA_ZBB
select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND
select EDAC_SUPPORT
select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE)
Expand Down
6 changes: 6 additions & 0 deletions arch/riscv/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/efi.h>
#include <linux/crash_dump.h>
#include <linux/panic_notifier.h>
#include <linux/jump_label.h>

#include <asm/acpi.h>
#include <asm/alternative.h>
Expand Down Expand Up @@ -51,6 +52,8 @@ atomic_t hart_lottery __section(".sdata")
;
unsigned long boot_cpu_hartid;

DECLARE_STATIC_KEY_TRUE(efficient_ffs_key);

/*
* Place kernel memory regions on the resource tree so that
* kexec-tools can retrieve them from /proc/iomem. While there
Expand Down Expand Up @@ -361,6 +364,9 @@ void __init setup_arch(char **cmdline_p)

riscv_user_isa_enable();
riscv_spinlock_init();

if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))
static_branch_disable(&efficient_ffs_key);
}

bool arch_cpu_is_hotpluggable(int cpu)
Expand Down
25 changes: 16 additions & 9 deletions lib/math/gcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <linux/kernel.h>
#include <linux/gcd.h>
#include <linux/export.h>
#include <linux/jump_label.h>

/*
* This implements the binary GCD algorithm. (Often attributed to Stein,
Expand All @@ -11,16 +12,13 @@
* has decent hardware division.
*/

DEFINE_STATIC_KEY_TRUE(efficient_ffs_key);

#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)

/* If __ffs is available, the even/odd algorithm benchmarks slower. */

/**
* gcd - calculate and return the greatest common divisor of 2 unsigned longs
* @a: first value
* @b: second value
*/
unsigned long gcd(unsigned long a, unsigned long b)
static unsigned long binary_gcd(unsigned long a, unsigned long b)
{
unsigned long r = a | b;

Expand All @@ -44,16 +42,27 @@ unsigned long gcd(unsigned long a, unsigned long b)
}
}

#else
#endif

/* If normalization is done by loops, the even/odd algorithm is a win. */

/**
* gcd - calculate and return the greatest common divisor of 2 unsigned longs
* @a: first value
* @b: second value
*/
unsigned long gcd(unsigned long a, unsigned long b)
{
unsigned long r = a | b;

if (!a || !b)
return r;

#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
if (static_branch_likely(&efficient_ffs_key))
return binary_gcd(a, b);
#endif

/* Isolate lsbit of r */
r &= -r;

Expand All @@ -80,6 +89,4 @@ unsigned long gcd(unsigned long a, unsigned long b)
}
}

#endif

EXPORT_SYMBOL_GPL(gcd);