summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-01-19 05:41:44 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2021-01-19 05:41:44 +0100
commit5fb76871a15151cb725b2d11814f4236429a8634 (patch)
tree8fca8f8151cb1b60bc2b6f9d134e8c76c16ef09a
parent83ec121f239b6af42a408ea75930e3733c27c79a (diff)
parentff8b098a4ad26688a8f2a853a864903b47f240d6 (diff)
downloadbarebox-5fb76871a15151cb725b2d11814f4236429a8634.tar.gz
barebox-5fb76871a15151cb725b2d11814f4236429a8634.tar.xz
Merge branch 'for-next/misc'
-rw-r--r--Documentation/devicetree/bindings/firmware/altr,passive-serial.rst (renamed from Documentation/devicetree/bindings/firmware/altr,passive-serial.txt)16
-rw-r--r--Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.rst (renamed from Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt)8
-rw-r--r--Documentation/devicetree/bindings/mtd/partition.rst42
-rw-r--r--Documentation/devicetree/bindings/mtd/partition.txt39
-rw-r--r--arch/arm/boards/qemu-virt/.gitignore1
-rw-r--r--arch/arm/boards/qemu-virt/Makefile1
-rw-r--r--arch/arm/boards/qemu-virt/board.c34
-rw-r--r--arch/arm/boards/qemu-virt/overlay-of-flash.dts97
-rw-r--r--arch/arm/configs/vexpress_defconfig1
-rw-r--r--arch/arm/mach-vexpress/Kconfig1
-rw-r--r--arch/mips/dts/ar9331-dptechnics-dpt-module.dts2
-rw-r--r--arch/mips/dts/ar9331-okud-max9331.dts2
-rw-r--r--arch/mips/dts/ar9331-openembed-som9331-board.dts2
-rw-r--r--drivers/base/driver.c12
-rw-r--r--drivers/eeprom/at24.c1
-rw-r--r--drivers/net/phy/mdio-gpio.c4
-rw-r--r--drivers/of/overlay.c3
-rw-r--r--include/driver.h5
-rw-r--r--include/linux/math64.h211
-rw-r--r--lib/Makefile1
-rw-r--r--lib/math/Makefile1
-rw-r--r--lib/math/div64.c235
22 files changed, 661 insertions, 58 deletions
diff --git a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt b/Documentation/devicetree/bindings/firmware/altr,passive-serial.rst
index eec12fbace..1012137bc9 100644
--- a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
+++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.rst
@@ -1,20 +1,22 @@
Altera FPGAs in passive serial mode
------------------------------------
+===================================
This binding defines the control interface to Altera FPGAs in
passive serial mode. This is used to upload the firmware and
to start the FPGA.
Required properties:
-- compatible: shall be "altr,fpga-passive-serial" or
- "altr,fpga-arria10-passive-serial" for Arria 10
-- reg: SPI chip select
-- nstat-gpios: Specify GPIO for controlling the nstat pin
-- confd-gpios: Specify GPIO for controlling the confd pin
-- nconfig-gpios: Specify GPIO for controlling the nconfig pin
+- ``compatible``: shall be ``"altr,fpga-passive-serial"`` or
+ ``"altr,fpga-arria10-passive-serial"`` for Arria 10
+- ``reg``: SPI chip select
+- ``nstat-gpios``: Specify GPIO for controlling the nstat pin
+- ``confd-gpios``: Specify GPIO for controlling the confd pin
+- ``nconfig-gpios``: Specify GPIO for controlling the nconfig pin
Example:
+.. code-block:: none
+
fpga@0 {
compatible = "altr,fpga-passive-serial";
nstat-gpios = <&gpio4 18 0>;
diff --git a/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt b/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.rst
index 70ec4abf25..9f7de6b985 100644
--- a/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt
+++ b/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.rst
@@ -1,17 +1,19 @@
Altera SOCFPGA FPGA Manager
----------------------------
+===========================
This binding defines the FPGA Manager on Altera SOCFPGAs. This is used to upload
the firmware to the FPGA part of the SoC.
Required properties:
-- compatible: shall be "altr,socfpga-fpga-mgr"
-- reg: Must contain 2 register ranges:
+- ``compatible``: shall be ``"altr,socfpga-fpga-mgr"``
+- ``reg``: Must contain 2 register ranges:
1. The control address space of the FPGA manager.
2. The configuration data address space where the firmware data is written to.
Example:
+.. code-block:: none
+
fpgamgr@ff706000 {
compatible = "altr,socfpga-fpga-mgr";
reg = <0xff706000 0x1000>,
diff --git a/Documentation/devicetree/bindings/mtd/partition.rst b/Documentation/devicetree/bindings/mtd/partition.rst
new file mode 100644
index 0000000000..6db54070a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partition.rst
@@ -0,0 +1,42 @@
+Representing flash partitions in devicetree
+===========================================
+
+In addition to the upstream binding, another property is added:
+
+Optional properties:
+- ``partuuid`` : The partition UUID for this partition.
+
+Additionally, barebox also supports partitioning the eMMC boot partitions if
+the partition table node is named appropriately:
+- ``partitions`` : user partition
+- ``boot0-partitions`` : boot0 partition
+- ``boot1-partitions`` : boot1 partition
+
+Examples:
+
+.. code-block:: none
+
+ flash@0 {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ state_part: state {
+ partuuid = "16367da7-c518-499f-9aad-e1f366692365";
+ };
+ };
+ };
+
+ emmc@1 {
+ boot0-partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ barebox@0 {
+ label = "barebox";
+ reg = <0x0 0x300000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
deleted file mode 100644
index 4288a82437..0000000000
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-Representing flash partitions in devicetree
-
-In addition to the upstream binding, another property is added:
-
-Optional properties:
-- partuuid : The partition UUID for this partition.
-
-Additionally, barebox also supports partitioning the eMMC boot partitions if
-the partition table node is named appropriately:
-- partitions : user partition
-- boot0-partitions : boot0 partition
-- boot1-partitions : boot1 partition
-
-Examples:
-
-flash@0 {
- partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- state_part: state {
- partuuid = "16367da7-c518-499f-9aad-e1f366692365";
- };
- };
-};
-
-emmc@1 {
- boot0-partitions {
- compatible = "fixed-partitions";
- #address-cells = <1>;
- #size-cells = <1>;
-
- barebox@0 {
- label = "barebox";
- reg = <0x0 0x300000>;
- };
- };
-};
diff --git a/arch/arm/boards/qemu-virt/.gitignore b/arch/arm/boards/qemu-virt/.gitignore
new file mode 100644
index 0000000000..5d65b54bf1
--- /dev/null
+++ b/arch/arm/boards/qemu-virt/.gitignore
@@ -0,0 +1 @@
+*.dtb*
diff --git a/arch/arm/boards/qemu-virt/Makefile b/arch/arm/boards/qemu-virt/Makefile
index dcfc2937d3..8451c7832d 100644
--- a/arch/arm/boards/qemu-virt/Makefile
+++ b/arch/arm/boards/qemu-virt/Makefile
@@ -1 +1,2 @@
obj-y += board.o
+obj-y += overlay-of-flash.dtb.o
diff --git a/arch/arm/boards/qemu-virt/board.c b/arch/arm/boards/qemu-virt/board.c
index 3aeea1a017..9d8c90eb5b 100644
--- a/arch/arm/boards/qemu-virt/board.c
+++ b/arch/arm/boards/qemu-virt/board.c
@@ -5,7 +5,41 @@
*/
#include <common.h>
#include <init.h>
+#include <of.h>
#include <asm/system_info.h>
+#include <asm/barebox-arm.h>
+
+extern char __dtb_overlay_of_flash_start[];
+
+static int replace_dtb(void) {
+ struct device_node *overlay;
+ void *fdt;
+ struct device_node *root;
+
+ fdt = barebox_arm_boot_dtb();
+ if (fdt)
+ pr_debug("using boarddata provided DTB\n");
+
+ if (!fdt) {
+ pr_debug("No DTB found\n");
+ return 0;
+ }
+
+ root = of_unflatten_dtb(fdt);
+
+ if (!of_device_is_compatible(root, "linux,dummy-virt")) {
+ of_delete_node(root);
+ return 0;
+ }
+
+ overlay = of_unflatten_dtb(__dtb_overlay_of_flash_start);
+ of_overlay_apply_tree(root, overlay);
+ barebox_register_of(root);
+
+ return 0;
+}
+
+pure_initcall(replace_dtb);
static int virt_probe(struct device_d *dev)
{
diff --git a/arch/arm/boards/qemu-virt/overlay-of-flash.dts b/arch/arm/boards/qemu-virt/overlay-of-flash.dts
new file mode 100644
index 0000000000..e00dc5d7e2
--- /dev/null
+++ b/arch/arm/boards/qemu-virt/overlay-of-flash.dts
@@ -0,0 +1,97 @@
+/dts-v1/;
+/plugin/;
+/ {
+ fragment@0 {
+ target-path = "/flash@0";
+ __overlay__ {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "initramfs";
+ reg = <0x0 0x3c00000>;
+ };
+
+ environment_flash: partition@3c00000 {
+ label = "barebox-environment";
+ reg = <0x3c00000 0x200000>;
+ };
+
+ backend_state_flash: partition@3e00000 {
+ label = "barebox-state";
+ reg = <0x3e00000 0x200000>;
+ };
+ };
+ };
+ };
+ fragment@1 {
+ target-path="/";
+ __overlay__ {
+ chosen {
+ environment {
+ compatible = "barebox,environment";
+ device-path = "/flash@0/partitions/partition@3c00000";
+ };
+ };
+ aliases {
+ state = "/state";
+ };
+
+ state {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "barebox,state";
+ magic = <0x290cf8c6>;
+ backend-type = "raw";
+ backend = < &backend_state_flash >;
+ backend-stridesize = <0x200>;
+
+ bootstate {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ system0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@0 {
+ reg = <0x0 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@4 {
+ reg = <0x4 0x4>;
+ type = "uint32";
+ default = <20>;
+ };
+ };
+
+ system1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@8 {
+ reg = <0x8 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@c {
+ reg = <0xc 0x4>;
+ type = "uint32";
+ default = <21>;
+ };
+ };
+
+ last_chosen@10 {
+ reg = <0x10 0x4>;
+ type = "uint32";
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/configs/vexpress_defconfig b/arch/arm/configs/vexpress_defconfig
index f17af2bb95..760e39b440 100644
--- a/arch/arm/configs/vexpress_defconfig
+++ b/arch/arm/configs/vexpress_defconfig
@@ -50,6 +50,7 @@ CONFIG_NET=y
CONFIG_NET_NFS=y
CONFIG_NET_NETCONSOLE=y
CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_OF_OVERLAY=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_DRIVER_NET_SMC91111=y
# CONFIG_SPI is not set
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 9d301f7ae8..557c9653f4 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -11,5 +11,6 @@ config MACH_VIRT
bool "QEMU virt"
select ARM_PSCI_CLIENT
select BOARD_ARM_GENERIC_DT
+ select OF_OVERLAY
endif
diff --git a/arch/mips/dts/ar9331-dptechnics-dpt-module.dts b/arch/mips/dts/ar9331-dptechnics-dpt-module.dts
index cbaf5ab39e..24ce0d0d67 100644
--- a/arch/mips/dts/ar9331-dptechnics-dpt-module.dts
+++ b/arch/mips/dts/ar9331-dptechnics-dpt-module.dts
@@ -7,6 +7,8 @@
};
chosen {
+ stdout-path = &uart;
+
environment {
compatible = "barebox,environment";
device-path = &spiflash, "partname:barebox-environment";
diff --git a/arch/mips/dts/ar9331-okud-max9331.dts b/arch/mips/dts/ar9331-okud-max9331.dts
index 53350899f9..3b93bee93b 100644
--- a/arch/mips/dts/ar9331-okud-max9331.dts
+++ b/arch/mips/dts/ar9331-okud-max9331.dts
@@ -17,6 +17,8 @@
};
chosen {
+ stdout-path = &uart;
+
environment {
compatible = "barebox,environment";
device-path = &spiflash, "partname:barebox-environment";
diff --git a/arch/mips/dts/ar9331-openembed-som9331-board.dts b/arch/mips/dts/ar9331-openembed-som9331-board.dts
index ff9d25e352..4736332f8f 100644
--- a/arch/mips/dts/ar9331-openembed-som9331-board.dts
+++ b/arch/mips/dts/ar9331-openembed-som9331-board.dts
@@ -33,6 +33,8 @@
chosen {
+ stdout-path = &uart;
+
environment {
compatible = "barebox,environment";
device-path = &spiflash, "partname:barebox-environment";
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 3205bbc3c3..6763bbc6f5 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -372,7 +372,7 @@ struct resource *dev_get_resource_by_name(struct device_d *dev,
return ERR_PTR(-ENOENT);
}
-void __iomem *dev_request_mem_region_by_name(struct device_d *dev, const char *name)
+struct resource *dev_request_mem_resource_by_name(struct device_d *dev, const char *name)
{
struct resource *res;
@@ -380,7 +380,15 @@ void __iomem *dev_request_mem_region_by_name(struct device_d *dev, const char *n
if (IS_ERR(res))
return ERR_CAST(res);
- res = request_iomem_region(dev_name(dev), res->start, res->end);
+ return request_iomem_region(dev_name(dev), res->start, res->end);
+}
+EXPORT_SYMBOL(dev_request_mem_resource_by_name);
+
+void __iomem *dev_request_mem_region_by_name(struct device_d *dev, const char *name)
+{
+ struct resource *res;
+
+ res = dev_request_mem_resource_by_name(dev, name);
if (IS_ERR(res))
return ERR_CAST(res);
diff --git a/drivers/eeprom/at24.c b/drivers/eeprom/at24.c
index 568aa02a4c..8c04c5684b 100644
--- a/drivers/eeprom/at24.c
+++ b/drivers/eeprom/at24.c
@@ -112,6 +112,7 @@ static struct platform_device_id at24_ids[] = {
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
+ { "24cs64", AT24_DEVICE_MAGIC(16, AT24_FLAG_ADDR16) },
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index affa31ae2c..80d2394f4b 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -52,7 +52,7 @@ static struct mdio_gpio_info *mdio_gpio_of_get_info(struct device_d *dev)
ret = of_get_gpio_flags(dev->device_node, 0, &flags);
if (ret < 0) {
- dev_dbg(dev, "failed to get MDC inforamtion from DT\n");
+ dev_dbg(dev, "failed to get MDC information from DT\n");
goto free_info;
}
@@ -61,7 +61,7 @@ static struct mdio_gpio_info *mdio_gpio_of_get_info(struct device_d *dev)
ret = of_get_gpio_flags(dev->device_node, 1, &flags);
if (ret < 0) {
- dev_dbg(dev, "failed to get MDIO inforamtion from DT\n");
+ dev_dbg(dev, "failed to get MDIO information from DT\n");
goto free_info;
}
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index eb47378258..9c6218c2c4 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -58,6 +58,9 @@ static int of_overlay_apply(struct device_node *target,
if (of_prop_cmp(prop->name, "name") == 0)
continue;
+ if (of_prop_cmp(prop->name, "phandle") == 0)
+ target->phandle = be32_to_cpup(prop->value);
+
err = of_set_property(target, prop->name, prop->value,
prop->length, true);
if (err)
diff --git a/include/driver.h b/include/driver.h
index e2886d051d..0d43b36148 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -215,6 +215,11 @@ void __iomem *dev_request_mem_region(struct device_d *dev, int num);
struct resource *dev_request_mem_resource(struct device_d *dev, int num);
/*
+ * exlusively request resource 'name' for a device
+ */
+struct resource *dev_request_mem_resource_by_name(struct device_d *dev, const char *name);
+
+/*
* exlusively request register base 'num' for a device
* will return NULL on error
* only used on platform like at91 where the Ressource address collision with
diff --git a/include/linux/math64.h b/include/linux/math64.h
index 71dd6d7109..e8b737e70e 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_MATH64_H
#define _LINUX_MATH64_H
@@ -6,10 +7,16 @@
#if BITS_PER_LONG == 64
-#define div64_long(x,y) div64_s64((x),(y))
+#define div64_long(x, y) div64_s64((x), (y))
+#define div64_ul(x, y) div64_u64((x), (y))
/**
* div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
+ * @remainder: pointer to unsigned 32bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
*
* This is commonly provided by 32bit archs to provide an optimized 64bit
* divide.
@@ -20,8 +27,13 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
return dividend / divisor;
}
-/**
+/*
* div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 32bit divisor
+ * @remainder: pointer to signed 32bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
*/
static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
{
@@ -29,16 +41,38 @@ static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
return dividend / divisor;
}
-/**
+/*
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 64bit divisor
+ * @remainder: pointer to unsigned 64bit remainder
+ *
+ * Return: sets ``*remainder``, then returns dividend / divisor
+ */
+static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/*
* div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 64bit divisor
+ *
+ * Return: dividend / divisor
*/
static inline u64 div64_u64(u64 dividend, u64 divisor)
{
return dividend / divisor;
}
-/**
+/*
* div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 64bit divisor
+ *
+ * Return: dividend / divisor
*/
static inline s64 div64_s64(s64 dividend, s64 divisor)
{
@@ -47,7 +81,8 @@ static inline s64 div64_s64(s64 dividend, s64 divisor)
#elif BITS_PER_LONG == 32
-#define div64_long(x,y) div_s64((x),(y))
+#define div64_long(x, y) div_s64((x), (y))
+#define div64_ul(x, y) div_u64((x), (y))
#ifndef div_u64_rem
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
@@ -61,6 +96,10 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
#endif
+#ifndef div64_u64_rem
+extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder);
+#endif
+
#ifndef div64_u64
extern u64 div64_u64(u64 dividend, u64 divisor);
#endif
@@ -73,6 +112,8 @@ extern s64 div64_s64(s64 dividend, s64 divisor);
/**
* div_u64 - unsigned 64bit divide with 32bit divisor
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 32bit divisor
*
* This is the most common 64bit divide and should be used if possible,
* as many 32bit archs can optimize this variant better than a full 64bit
@@ -88,6 +129,8 @@ static inline u64 div_u64(u64 dividend, u32 divisor)
/**
* div_s64 - signed 64bit divide with 32bit divisor
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 32bit divisor
*/
#ifndef div_s64
static inline s64 div_s64(s64 dividend, s32 divisor)
@@ -99,6 +142,164 @@ static inline s64 div_s64(s64 dividend, s32 divisor)
u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
+#ifndef mul_u32_u32
+/*
+ * Many a GCC version messes this up and generates a 64x64 mult :-(
+ */
+static inline u64 mul_u32_u32(u32 a, u32 b)
+{
+ return (u64)a * b;
+}
+#endif
+
+#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
+
+#ifndef mul_u64_u32_shr
+static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift)
+{
+ return (u64)(((unsigned __int128)a * mul) >> shift);
+}
+#endif /* mul_u64_u32_shr */
+
+#ifndef mul_u64_u64_shr
+static inline u64 mul_u64_u64_shr(u64 a, u64 mul, unsigned int shift)
+{
+ return (u64)(((unsigned __int128)a * mul) >> shift);
+}
+#endif /* mul_u64_u64_shr */
+
+#else
+
+#ifndef mul_u64_u32_shr
+static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift)
+{
+ u32 ah, al;
+ u64 ret;
+
+ al = a;
+ ah = a >> 32;
+
+ ret = mul_u32_u32(al, mul) >> shift;
+ if (ah)
+ ret += mul_u32_u32(ah, mul) << (32 - shift);
+
+ return ret;
+}
+#endif /* mul_u64_u32_shr */
+
+#ifndef mul_u64_u64_shr
+static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift)
+{
+ union {
+ u64 ll;
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 high, low;
+#else
+ u32 low, high;
+#endif
+ } l;
+ } rl, rm, rn, rh, a0, b0;
+ u64 c;
+
+ a0.ll = a;
+ b0.ll = b;
+
+ rl.ll = mul_u32_u32(a0.l.low, b0.l.low);
+ rm.ll = mul_u32_u32(a0.l.low, b0.l.high);
+ rn.ll = mul_u32_u32(a0.l.high, b0.l.low);
+ rh.ll = mul_u32_u32(a0.l.high, b0.l.high);
+
+ /*
+ * Each of these lines computes a 64-bit intermediate result into "c",
+ * starting at bits 32-95. The low 32-bits go into the result of the
+ * multiplication, the high 32-bits are carried into the next step.
+ */
+ rl.l.high = c = (u64)rl.l.high + rm.l.low + rn.l.low;
+ rh.l.low = c = (c >> 32) + rm.l.high + rn.l.high + rh.l.low;
+ rh.l.high = (c >> 32) + rh.l.high;
+
+ /*
+ * The 128-bit result of the multiplication is in rl.ll and rh.ll,
+ * shift it right and throw away the high part of the result.
+ */
+ if (shift == 0)
+ return rl.ll;
+ if (shift < 64)
+ return (rl.ll >> shift) | (rh.ll << (64 - shift));
+ return rh.ll >> (shift & 63);
+}
+#endif /* mul_u64_u64_shr */
+
+#endif
+
+#ifndef mul_u64_u32_div
+static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor)
+{
+ union {
+ u64 ll;
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 high, low;
+#else
+ u32 low, high;
+#endif
+ } l;
+ } u, rl, rh;
+
+ u.ll = a;
+ rl.ll = mul_u32_u32(u.l.low, mul);
+ rh.ll = mul_u32_u32(u.l.high, mul) + rl.l.high;
+
+ /* Bits 32-63 of the result will be in rh.l.low. */
+ rl.l.high = do_div(rh.ll, divisor);
+
+ /* Bits 0-31 of the result will be in rl.l.low. */
+ do_div(rl.ll, divisor);
+
+ rl.l.high = rh.l.low;
+ return rl.ll;
+}
+#endif /* mul_u64_u32_div */
+
+u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
+
+#define DIV64_U64_ROUND_UP(ll, d) \
+ ({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); })
+
+/**
+ * DIV64_U64_ROUND_CLOSEST - unsigned 64bit divide with 64bit divisor rounded to nearest integer
+ * @dividend: unsigned 64bit dividend
+ * @divisor: unsigned 64bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 64bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV64_U64_ROUND_CLOSEST(dividend, divisor) \
+ ({ u64 _tmp = (divisor); div64_u64((dividend) + _tmp / 2, _tmp); })
+
+/*
+ * DIV_S64_ROUND_CLOSEST - signed 64bit divide with 32bit divisor rounded to nearest integer
+ * @dividend: signed 64bit dividend
+ * @divisor: signed 32bit divisor
+ *
+ * Divide signed 64bit dividend by signed 32bit divisor
+ * and round to closest integer.
+ *
+ * Return: dividend / divisor rounded to nearest integer
+ */
+#define DIV_S64_ROUND_CLOSEST(dividend, divisor)( \
+{ \
+ s64 __x = (dividend); \
+ s32 __d = (divisor); \
+ ((__x > 0) == (__d > 0)) ? \
+ div_s64((__x + (__d / 2)), __d) : \
+ div_s64((__x - (__d / 2)), __d); \
+} \
+)
+
static __always_inline u32
__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
{
diff --git a/lib/Makefile b/lib/Makefile
index ba6af6f2ab..9c6f4133d7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -25,6 +25,7 @@ obj-y += cmdlinepart.o
obj-y += recursive_action.o
obj-y += make_directory.o
obj-y += math.o
+obj-y += math/
obj-$(CONFIG_XXHASH) += xxhash.o
obj-$(CONFIG_BZLIB) += decompress_bunzip2.o
obj-$(CONFIG_ZLIB) += decompress_inflate.o zlib_inflate/
diff --git a/lib/math/Makefile b/lib/math/Makefile
new file mode 100644
index 0000000000..3341a8e474
--- /dev/null
+++ b/lib/math/Makefile
@@ -0,0 +1 @@
+obj-y += div64.o
diff --git a/lib/math/div64.c b/lib/math/div64.c
new file mode 100644
index 0000000000..386497592b
--- /dev/null
+++ b/lib/math/div64.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
+ *
+ * Based on former do_div() implementation from asm-parisc/div64.h:
+ * Copyright (C) 1999 Hewlett-Packard Co
+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ *
+ * Generic C version of 64bit/32bit division and modulo, with
+ * 64bit result and 32bit remainder.
+ *
+ * The fast case for (n>>32 == 0) is handled inline by do_div().
+ *
+ * Code generated for this function might be very inefficient
+ * for some CPUs. __div64_32() can be overridden by linking arch-specific
+ * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S
+ * or by defining a preprocessor macro in arch/include/asm/div64.h.
+ */
+
+#include <linux/bitops.h>
+#include <module.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/log2.h>
+
+/* Not needed on 64bit architectures */
+#if BITS_PER_LONG == 32
+
+#ifndef __div64_32
+uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
+{
+ uint64_t rem = *n;
+ uint64_t b = base;
+ uint64_t res, d = 1;
+ uint32_t high = rem >> 32;
+
+ /* Reduce the thing a bit first */
+ res = 0;
+ if (high >= base) {
+ high /= base;
+ res = (uint64_t) high << 32;
+ rem -= (uint64_t) (high*base) << 32;
+ }
+
+ while ((int64_t)b > 0 && b < rem) {
+ b = b+b;
+ d = d+d;
+ }
+
+ do {
+ if (rem >= b) {
+ rem -= b;
+ res += d;
+ }
+ b >>= 1;
+ d >>= 1;
+ } while (d);
+
+ *n = res;
+ return rem;
+}
+EXPORT_SYMBOL(__div64_32);
+#endif
+
+/**
+ * div_s64_rem - signed 64bit divide with 64bit divisor and remainder
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ * @remainder: 64bit remainder
+ */
+#ifndef div_s64_rem
+s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+ u64 quotient;
+
+ if (dividend < 0) {
+ quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
+ *remainder = -*remainder;
+ if (divisor > 0)
+ quotient = -quotient;
+ } else {
+ quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
+ if (divisor < 0)
+ quotient = -quotient;
+ }
+ return quotient;
+}
+EXPORT_SYMBOL(div_s64_rem);
+#endif
+
+/**
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ * @remainder: 64bit remainder
+ *
+ * This implementation is a comparable to algorithm used by div64_u64.
+ * But this operation, which includes math for calculating the remainder,
+ * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
+ * systems.
+ */
+#ifndef div64_u64_rem
+u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+ u32 high = divisor >> 32;
+ u64 quot;
+
+ if (high == 0) {
+ u32 rem32;
+ quot = div_u64_rem(dividend, divisor, &rem32);
+ *remainder = rem32;
+ } else {
+ int n = fls(high);
+ quot = div_u64(dividend >> n, divisor >> n);
+
+ if (quot != 0)
+ quot--;
+
+ *remainder = dividend - quot * divisor;
+ if (*remainder >= divisor) {
+ quot++;
+ *remainder -= divisor;
+ }
+ }
+
+ return quot;
+}
+EXPORT_SYMBOL(div64_u64_rem);
+#endif
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ *
+ * This implementation is a modified version of the algorithm proposed
+ * by the book 'Hacker's Delight'. The original source and full proof
+ * can be found here and is available for use without restriction.
+ *
+ * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt'
+ */
+#ifndef div64_u64
+u64 div64_u64(u64 dividend, u64 divisor)
+{
+ u32 high = divisor >> 32;
+ u64 quot;
+
+ if (high == 0) {
+ quot = div_u64(dividend, divisor);
+ } else {
+ int n = fls(high);
+ quot = div_u64(dividend >> n, divisor >> n);
+
+ if (quot != 0)
+ quot--;
+ if ((dividend - quot * divisor) >= divisor)
+ quot++;
+ }
+
+ return quot;
+}
+EXPORT_SYMBOL(div64_u64);
+#endif
+
+/**
+ * div64_s64 - signed 64bit divide with 64bit divisor
+ * @dividend: 64bit dividend
+ * @divisor: 64bit divisor
+ */
+#ifndef div64_s64
+s64 div64_s64(s64 dividend, s64 divisor)
+{
+ s64 quot, t;
+
+ quot = div64_u64(abs(dividend), abs(divisor));
+ t = (dividend ^ divisor) >> 63;
+
+ return (quot ^ t) - t;
+}
+EXPORT_SYMBOL(div64_s64);
+#endif
+
+#endif /* BITS_PER_LONG == 32 */
+
+/*
+ * Iterative div/mod for use when dividend is not expected to be much
+ * bigger than divisor.
+ */
+u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
+{
+ return __iter_div_u64_rem(dividend, divisor, remainder);
+}
+EXPORT_SYMBOL(iter_div_u64_rem);
+
+#ifndef mul_u64_u64_div_u64
+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);
+}
+#endif