On 29 September 2017 at 23:34, James Hogan <james.ho...@imgtec.com> 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 <marcin.nowakow...@imgtec.com>
>> Cc: linux-crypto@vger.kernel.org
>> Cc: Herbert Xu <herb...@gondor.apana.org.au>
>> Cc: "David S. Miller" <da...@davemloft.net>
>>
>> ---
>>  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 <yazen.ghan...@linaro.org>
>> + * 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

Reply via email to