diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2021-01-19 05:41:44 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-01-19 05:41:44 +0100 |
commit | 5fb76871a15151cb725b2d11814f4236429a8634 (patch) | |
tree | 8fca8f8151cb1b60bc2b6f9d134e8c76c16ef09a | |
parent | 83ec121f239b6af42a408ea75930e3733c27c79a (diff) | |
parent | ff8b098a4ad26688a8f2a853a864903b47f240d6 (diff) | |
download | barebox-5fb76871a15151cb725b2d11814f4236429a8634.tar.gz barebox-5fb76871a15151cb725b2d11814f4236429a8634.tar.xz |
Merge branch 'for-next/misc'
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 |