On 29 September 2017 at 23:34, James Hogan <[email protected]> wrote:
> Hi Marcin,
>
> On Wed, Sep 27, 2017 at 02:18:36PM +0200, Marcin Nowakowski wrote:
>> This module registers crc32 and crc32c algorithms that use the
>> optional CRC32[bhwd] and CRC32C[bhwd] instructions in MIPSr6 cores.
>>
>> Signed-off-by: Marcin Nowakowski <[email protected]>
>> Cc: [email protected]
>> Cc: Herbert Xu <[email protected]>
>> Cc: "David S. Miller" <[email protected]>
>>
>> ---
>> arch/mips/Kconfig | 4 +
>> arch/mips/Makefile | 3 +
>> arch/mips/crypto/Makefile | 5 +
>> arch/mips/crypto/crc32-mips.c | 361
>> ++++++++++++++++++++++++++++++++++++++++++
>> crypto/Kconfig | 9 ++
>> 5 files changed, 382 insertions(+)
>> create mode 100644 arch/mips/crypto/Makefile
>> create mode 100644 arch/mips/crypto/crc32-mips.c
>>
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index cb7fcc4..0f96812 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -2036,6 +2036,7 @@ config CPU_MIPSR6
>> select CPU_HAS_RIXI
>> select HAVE_ARCH_BITREVERSE
>> select MIPS_ASID_BITS_VARIABLE
>> + select MIPS_CRC_SUPPORT
>> select MIPS_SPRAM
>>
>> config EVA
>> @@ -2503,6 +2504,9 @@ config MIPS_ASID_BITS
>> config MIPS_ASID_BITS_VARIABLE
>> bool
>>
>> +config MIPS_CRC_SUPPORT
>> + bool
>> +
>> #
>> # - Highmem only makes sense for the 32-bit kernel.
>> # - The current highmem code will only work properly on physically indexed
>> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
>> index a96d97a..aa77536 100644
>> --- a/arch/mips/Makefile
>> +++ b/arch/mips/Makefile
>> @@ -216,6 +216,8 @@ cflags-$(toolchain-msa) +=
>> -DTOOLCHAIN_SUPPORTS_MSA
>> endif
>> toolchain-virt := $(call
>> cc-option-yn,$(mips-cflags) -mvirt)
>> cflags-$(toolchain-virt) += -DTOOLCHAIN_SUPPORTS_VIRT
>> +toolchain-crc := $(call
>> cc-option-yn,$(mips-cflags) -Wa$(comma)-mcrc)
>> +cflags-$(toolchain-crc) += -DTOOLCHAIN_SUPPORTS_CRC
>>
>> #
>> # Firmware support
>> @@ -324,6 +326,7 @@ libs-y += arch/mips/math-emu/
>> # See arch/mips/Kbuild for content of core part of the kernel
>> core-y += arch/mips/
>>
>> +drivers-$(CONFIG_MIPS_CRC_SUPPORT) += arch/mips/crypto/
>> drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
>>
>> # suspend and hibernation support
>> diff --git a/arch/mips/crypto/Makefile b/arch/mips/crypto/Makefile
>> new file mode 100644
>> index 0000000..665c725
>> --- /dev/null
>> +++ b/arch/mips/crypto/Makefile
>> @@ -0,0 +1,5 @@
>> +#
>> +# Makefile for MIPS crypto files..
>> +#
>> +
>> +obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32-mips.o
>> diff --git a/arch/mips/crypto/crc32-mips.c b/arch/mips/crypto/crc32-mips.c
>> new file mode 100644
>> index 0000000..dfa8bb1
>> --- /dev/null
>> +++ b/arch/mips/crypto/crc32-mips.c
>> @@ -0,0 +1,361 @@
>> +/*
>> + * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions
>> + *
>> + * Module based on arm64/crypto/crc32-arm.c
>> + *
>> + * Copyright (C) 2014 Linaro Ltd <[email protected]>
>> + * Copyright (C) 2017 Imagination Technologies, Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/unaligned/access_ok.h>
>> +#include <linux/cpufeature.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/string.h>
>> +
>> +#include <crypto/internal/hash.h>
>> +
>> +enum crc_op_size {
>> + b, h, w, d,
>> +};
>> +
>> +enum crc_type {
>> + crc32,
>> + crc32c,
>> +};
>> +
>> +#ifdef TOOLCHAIN_SUPPORTS_CRC
>> +
>> +#define _CRC32(crc, value, size, type) \
>> +do { \
>> + __asm__ __volatile__( \
>> + ".set push\n\t" \
>> + ".set crc\n\t" \
>> + #type #size " %0, %1, %0\n\t" \
>> + ".set pop\n\t" \
>
> Technically the \n\t on the last line is redundant.
>
>> + : "+r" (crc) \
>> + : "r" (value) \
>> +); \
>> +} while(0)
>> +
>> +#define CRC_REGISTER
>> +
>> +#else /* TOOLCHAIN_SUPPORTS_CRC */
>> +/*
>> + * Crc argument is currently ignored and the assembly below assumes
>> + * the crc is stored in $2. As the register number is encoded in the
>> + * instruction we can't let the compiler chose the register it wants.
>> + * An alternative is to change the code to do
>> + * move $2, %0
>> + * crc32
>> + * move %0, $2
>> + * but that adds unnecessary operations that the crc32 operation is
>> + * designed to avoid. This issue can go away once the assembler
>> + * is extended to support this operation and the compiler can make
>> + * the right register choice automatically
>> + */
>> +
>> +#define _CRC32(crc, value, size, type)
>> \
>> +do {
>> \
>> + __asm__ __volatile__(
>> \
>> + ".set push\n\t"
>> \
>> + ".set noat\n\t"
>> \
>> + "move $at, %1\n\t"
>> \
>> + "# " #type #size " %0, $at, %0\n\t"
>> \
>> + _ASM_INSN_IF_MIPS(0x7c00000f | (2 << 16) | (1 << 21) | (%2 << 6) | (%3
>> << 8)) \
>> + _ASM_INSN32_IF_MM(0x00000030 | (1 << 16) | (2 << 21) | (%2 << 14) |
>> (%3 << 3)) \
>
> You should explicitly include <asm/mipsregs.h> for these macros.
>
>> + ".set pop\n\t"
>> \
>> + : "+r" (crc)
>> \
>> + : "r" (value), "i" (size), "i" (type)
>> \
>> +);
>> \
>> +} while(0)
>> +
>> +#define CRC_REGISTER __asm__("$2")
>> +#endif /* !TOOLCHAIN_SUPPORTS_CRC */
>> +
>> +#define CRC32(crc, value, size) \
>> + _CRC32(crc, value, size, crc32)
>> +
>> +#define CRC32C(crc, value, size) \
>> + _CRC32(crc, value, size, crc32c)
>> +
>> +static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
>> +{
>> + s64 length = len;
>
> The need for 64-bit signed length is unfortunate. Do you get decent
> assembly and comparable/better performance on 32-bit if you just use len
> and only decrement it in the loops? i.e.
>
> - while ((length -= sizeof(uXX)) >= 0) {
> + while (len >= sizeof(uXX)) {
> register uXX value = get_unaligned_leXX(p);
>
> CRC32(crc, value, XX);
> p += sizeof(uXX);
> + len -= sizeof(uXX);
> }
>
> That would be more readable too IMHO.
or maybe just do some pointer arithmetic like
const u8 *end = p + len;
while ((end - p) >= sizeof(uXX)) {
register uXX value = get_unaligned_leXX(p);
CRC32(crc, value, XX);
p += sizeof(uXX);
}
Regards
Jonas