* [PATCH v3 1/2] rust: math: add div64_u64() and div64_u64_round_up()
2026-10-30 2:02 [PATCH v3 0/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST FUJITA Tomonori
@ 2026-10-30 2:02 ` FUJITA Tomonori
2026-10-30 2:02 ` [PATCH v3 2/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST FUJITA Tomonori
2026-10-31 10:37 ` [PATCH v3 0/2] " chenhan
2 siblings, 0 replies; 4+ messages in thread
From: FUJITA Tomonori @ 2026-10-30 2:02 UTC (permalink / raw)
To: fustini, guoren, ojeda, ukleinek, wefu
Cc: a.hindborg, acourbot, aliceryhl, bjorn3_gh, boqun,
chenhan0017.work, dakr, daniel.almeida, gary, linux-riscv, lossin,
m.wilczynski, tamird, tmgross, work, linux-pwm, rust-for-linux,
FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
On 32-bit architectures, dividing a u64 by a u64 with the `/` operator
makes the compiler emit a call to a compiler runtime function, such as
__aeabi_uldivmod() on arm. The kernel does not provide these functions,
so the build fails when Rust code that is also built for 32-bit
architectures uses `/` on u64.
C code uses the helpers in include/linux/math64.h instead. Add a math
module with Rust versions of two of them:
- div64_u64(), the same as div64_u64() in C.
- div64_u64_round_up(), the same as DIV64_U64_ROUND_UP() in C.
On 64-bit architectures, both use `/`. On 32-bit architectures,
div64_u64() calls the C function. Both panic if the divisor is zero,
as `/` does.
Assisted-by: LLM
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/kernel/lib.rs | 1 +
rust/kernel/math.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 rust/kernel/math.rs
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 1ab41129d557..482fef8be2e8 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -100,6 +100,7 @@
pub mod kunit;
pub mod list;
pub mod maple_tree;
+pub mod math;
pub mod mem;
pub mod miscdevice;
pub mod mm;
diff --git a/rust/kernel/math.rs b/rust/kernel/math.rs
new file mode 100644
index 000000000000..395816639af8
--- /dev/null
+++ b/rust/kernel/math.rs
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Integer arithmetic helpers.
+//!
+//! C header: [`include/linux/math64.h`](srctree/include/linux/math64.h).
+
+/// Divides a [`u64`] dividend by a [`u64`] divisor, rounding down.
+///
+/// On 32-bit architectures, `/` on [`u64`] needs a function that the kernel does
+/// not provide. Use this function in code that is also built for 32-bit
+/// architectures.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::math::div64_u64;
+///
+/// assert_eq!(div64_u64(7, 2), 3);
+/// assert_eq!(div64_u64(u64::MAX, 1 << 32), u64::from(u32::MAX));
+/// ```
+#[inline]
+pub fn div64_u64(dividend: u64, divisor: u64) -> u64 {
+ if divisor == 0 {
+ panic!("attempt to divide by zero");
+ }
+
+ #[cfg(CONFIG_64BIT)]
+ {
+ dividend / divisor
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ {
+ // SAFETY: `div64_u64()` requires a non-zero `divisor`, which is
+ // checked above.
+ unsafe { bindings::div64_u64(dividend, divisor) }
+ }
+}
+
+/// Divides a [`u64`] dividend by a [`u64`] divisor, rounding up.
+///
+/// # Panics
+///
+/// Panics if `divisor` is zero.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::math::div64_u64_round_up;
+///
+/// assert_eq!(div64_u64_round_up(7, 2), 4);
+/// assert_eq!(div64_u64_round_up(6, 2), 3);
+/// assert_eq!(div64_u64_round_up(u64::MAX, 2), 1 << 63);
+/// ```
+#[inline]
+pub fn div64_u64_round_up(dividend: u64, divisor: u64) -> u64 {
+ let quotient = div64_u64(dividend, divisor);
+
+ // `quotient * divisor` is not greater than `dividend`, so this does not
+ // overflow.
+ if dividend - quotient * divisor == 0 {
+ quotient
+ } else {
+ // A non-zero remainder means `divisor >= 2`, so this does not overflow.
+ quotient + 1
+ }
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v3 2/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST
2026-10-30 2:02 [PATCH v3 0/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST FUJITA Tomonori
2026-10-30 2:02 ` [PATCH v3 1/2] rust: math: add div64_u64() and div64_u64_round_up() FUJITA Tomonori
@ 2026-10-30 2:02 ` FUJITA Tomonori
2026-10-31 10:37 ` [PATCH v3 0/2] " chenhan
2 siblings, 0 replies; 4+ messages in thread
From: FUJITA Tomonori @ 2026-10-30 2:02 UTC (permalink / raw)
To: fustini, guoren, ojeda, ukleinek, wefu
Cc: a.hindborg, acourbot, aliceryhl, bjorn3_gh, boqun,
chenhan0017.work, dakr, daniel.almeida, gary, linux-riscv, lossin,
m.wilczynski, tamird, tmgross, work, linux-pwm, rust-for-linux,
FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
Fix the following build error on 32-bit ARM with COMPILE_TEST:
ERROR: modpost: drivers/pwm/pwm_th1520.ko: symbol '__aeabi_uldivmod' undefined!
The driver divides u64 values when it converts between nanoseconds and
clock cycles. On 32-bit ARM, these divisions are compiled to calls to
__aeabi_uldivmod, which the kernel does not provide.
Use div64_u64() and div64_u64_round_up() for these divisions, in the
same way as C drivers use div64_u64() and DIV64_U64_ROUND_UP(). The
results do not change.
Fixes: 3c180003dffb ("pwm: th1520: Fix missing Kconfig dependencies")
Reported-by: Andreas Hindborg <a.hindborg@kernel.org>
Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/291565-Help/topic/64bit.20division.20in.20.60pwm_th1520.2Ers.60/near/626825599
Suggested-by: Uwe Kleine-König <ukleinek@kernel.org>
Assisted-by: LLM
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
drivers/pwm/pwm_th1520.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index 728993998446..bd05fe49650e 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -31,6 +31,10 @@
mem::DevresIoMem,
Io, //
},
+ math::{
+ div64_u64,
+ div64_u64_round_up, //
+ },
of,
platform,
prelude::*,
@@ -68,13 +72,13 @@ const fn th1520_pwm_fp(n: u32) -> usize {
fn ns_to_cycles(ns: u64, rate_hz: u64) -> u64 {
const NSEC_PER_SEC_U64: u64 = time::NSEC_PER_SEC as u64;
- ns.saturating_mul(rate_hz) / NSEC_PER_SEC_U64
+ div64_u64(ns.saturating_mul(rate_hz), NSEC_PER_SEC_U64)
}
fn cycles_to_ns(cycles: u32, rate_hz: u64) -> u64 {
const NSEC_PER_SEC_U64: u64 = time::NSEC_PER_SEC as u64;
- (u64::from(cycles) * NSEC_PER_SEC_U64).div_ceil(rate_hz)
+ div64_u64_round_up(u64::from(cycles) * NSEC_PER_SEC_U64, rate_hz)
}
/// Hardware-specific waveform representation for TH1520.
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v3 0/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST
2026-10-30 2:02 [PATCH v3 0/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST FUJITA Tomonori
2026-10-30 2:02 ` [PATCH v3 1/2] rust: math: add div64_u64() and div64_u64_round_up() FUJITA Tomonori
2026-10-30 2:02 ` [PATCH v3 2/2] pwm: th1520: Fix 32-bit build with COMPILE_TEST FUJITA Tomonori
@ 2026-10-31 10:37 ` chenhan
2 siblings, 0 replies; 4+ messages in thread
From: chenhan @ 2026-10-31 10:37 UTC (permalink / raw)
To: FUJITA Tomonori
Cc: fustini, guoren, ojeda, ukleinek, wefu, a.hindborg, acourbot,
aliceryhl, bjorn3_gh, boqun, dakr, daniel.almeida, gary,
linux-riscv, lossin, m.wilczynski, tamird, tmgross, work,
linux-pwm, rust-for-linux, FUJITA Tomonori
Hi Tomonori,
Thanks for CC'ing me.
> Both series use the same module header, so whichever
> is applied later needs only a small rebase.
Agreed. My div64_s64() and div_s64_rem() can share math.rs with your
div64_u64() and div64_u64_round_up(). If your series lands first, I will
rebase patch 3 onto that module, preserving your unsigned helpers and
the common module header.
I have now posted v5 [1], which only changes the SAFETY comments relative
to v4. The first two patches still fix Delta independently of the math
module, so the behavior fix can be taken separately from the extraction.
[1] https://lore.kernel.org/rust-for-linux/20261031103206.24051-1-chenhan0017.work@gmail.com/
Best regards,
chenhan
^ permalink raw reply [flat|nested] 4+ messages in thread