root/lib/crc/powerpc/crc32.h
// SPDX-License-Identifier: GPL-2.0-only
#include <asm/simd.h>
#include <asm/switch_to.h>
#include <linux/cpufeature.h>
#include <linux/jump_label.h>
#include <linux/preempt.h>
#include <linux/uaccess.h>

#define VMX_ALIGN               16
#define VMX_ALIGN_MASK          (VMX_ALIGN-1)

#define VECTOR_BREAKPOINT       512

static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_vec_crypto);

#define crc32_le_arch crc32_le_base /* not implemented on this arch */
#define crc32_be_arch crc32_be_base /* not implemented on this arch */

u32 __crc32c_vpmsum(u32 crc, const u8 *p, size_t len);

static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len)
{
        unsigned int prealign;
        unsigned int tail;

        if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) ||
            !static_branch_likely(&have_vec_crypto) ||
            unlikely(!may_use_simd()))
                return crc32c_base(crc, p, len);

        if ((unsigned long)p & VMX_ALIGN_MASK) {
                prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK);
                crc = crc32c_base(crc, p, prealign);
                len -= prealign;
                p += prealign;
        }

        if (len & ~VMX_ALIGN_MASK) {
                preempt_disable();
                pagefault_disable();
                enable_kernel_altivec();
                crc = __crc32c_vpmsum(crc, p, len & ~VMX_ALIGN_MASK);
                disable_kernel_altivec();
                pagefault_enable();
                preempt_enable();
        }

        tail = len & VMX_ALIGN_MASK;
        if (tail) {
                p += len & ~VMX_ALIGN_MASK;
                crc = crc32c_base(crc, p, tail);
        }

        return crc;
}

#define crc32_mod_init_arch crc32_mod_init_arch
static void crc32_mod_init_arch(void)
{
        if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
            (cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO))
                static_branch_enable(&have_vec_crypto);
}

static inline u32 crc32_optimizations_arch(void)
{
        if (static_key_enabled(&have_vec_crypto))
                return CRC32C_OPTIMIZATION;
        return 0;
}