[PATCH 20/74] backports: add mul_u64_u64_div_u64()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johannes Berg <johannes.berg@xxxxxxxxx>

Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
---
 backport/backport-include/linux/math64.h | 11 ++++++
 backport/compat/Makefile                 |  1 +
 backport/compat/backport-5.9.c           | 45 ++++++++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 backport/backport-include/linux/math64.h
 create mode 100644 backport/compat/backport-5.9.c

diff --git a/backport/backport-include/linux/math64.h b/backport/backport-include/linux/math64.h
new file mode 100644
index 000000000000..6aea9c9eec77
--- /dev/null
+++ b/backport/backport-include/linux/math64.h
@@ -0,0 +1,11 @@
+#ifndef __BACKPORT_LINUX_MATH64_H
+#define __BACKPORT_LINUX_MATH64_H
+#include_next <linux/math64.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_IS_LESS(5,9,0)
+#define mul_u64_u64_div_u64 LINUX_BACKPORT(mul_u64_u64_div_u64)
+extern u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c);
+#endif /* < 5.9 */
+
+#endif /* __BACKPORT_LINUX_MATH64_H */
diff --git a/backport/compat/Makefile b/backport/compat/Makefile
index 1d47bd59fe90..3c8430bc4958 100644
--- a/backport/compat/Makefile
+++ b/backport/compat/Makefile
@@ -11,6 +11,7 @@ compat-$(CPTCFG_KERNEL_4_18) += backport-4.18.o
 compat-$(CPTCFG_KERNEL_5_2) += backport-5.2.o backport-genetlink.o
 compat-$(CPTCFG_KERNEL_5_3) += backport-5.3.o
 compat-$(CPTCFG_KERNEL_5_5) += backport-5.5.o
+compat-$(CPTCFG_KERNEL_5_9) += backport-5.9.o
 compat-$(CPTCFG_KERNEL_5_10) += backport-5.10.o
 compat-$(CPTCFG_KERNEL_5_11) += backport-5.11.o
 compat-$(CPTCFG_KERNEL_5_13) += backport-5.13.o
diff --git a/backport/compat/backport-5.9.c b/backport/compat/backport-5.9.c
new file mode 100644
index 000000000000..54d1802efd31
--- /dev/null
+++ b/backport/compat/backport-5.9.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+
+u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
+{
+	u64 res = 0, div, rem;
+	int shift;
+
+	/* can a * b overflow ? */
+	if (ilog2(a) + ilog2(b) > 62) {
+		/*
+		 * (b * a) / c is equal to
+		 *
+		 *      (b / c) * a +
+		 *      (b % c) * a / c
+		 *
+		 * if nothing overflows. Can the 1st multiplication
+		 * overflow? Yes, but we do not care: this can only
+		 * happen if the end result can't fit in u64 anyway.
+		 *
+		 * So the code below does
+		 *
+		 *      res = (b / c) * a;
+		 *      b = b % c;
+		 */
+		div = div64_u64_rem(b, c, &rem);
+		res = div * a;
+		b = rem;
+
+		shift = ilog2(a) + ilog2(b) - 62;
+		if (shift > 0) {
+			/* drop precision */
+			b >>= shift;
+			c >>= shift;
+			if (!c)
+				return res;
+		}
+	}
+
+	return res + div64_u64(a * b, c);
+}
+EXPORT_SYMBOL_GPL(mul_u64_u64_div_u64);
-- 
2.45.1





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux