/* Default version is sufficient for 32 bit */ #ifndef CONFIG_32BIT
__sum16 csum_ipv6_magic(conststruct in6_addr *saddr, conststruct in6_addr *daddr,
__u32 len, __u8 proto, __wsum csum)
{ unsignedint ulen, uproto; unsignedlong sum = (__force unsignedlong)csum;
sum += (__force unsignedlong)saddr->s6_addr32[0];
sum += (__force unsignedlong)saddr->s6_addr32[1];
sum += (__force unsignedlong)saddr->s6_addr32[2];
sum += (__force unsignedlong)saddr->s6_addr32[3];
sum += (__force unsignedlong)daddr->s6_addr32[0];
sum += (__force unsignedlong)daddr->s6_addr32[1];
sum += (__force unsignedlong)daddr->s6_addr32[2];
sum += (__force unsignedlong)daddr->s6_addr32[3];
ulen = (__force unsignedint)htonl((unsignedint)len);
sum += ulen;
uproto = (__force unsignedint)htonl(proto);
sum += uproto;
if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB)) { unsignedlong fold_temp;
/* * Zbb is likely available when the kernel is compiled with Zbb * support, so nop when Zbb is available and jump when Zbb is * not available.
*/ asmgoto(ALTERNATIVE("j %l[no_zbb]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
:
:
:
: no_zbb); asm(".option push \n\
.option arch,+zbb \n\
rori %[fold_temp], %[sum], 32 \n\
add %[sum], %[fold_temp], %[sum] \n\
srli %[sum], %[sum], 32 \n\ not %[fold_temp], %[sum] \n\
roriw %[sum], %[sum], 16 \n\
subw %[sum], %[fold_temp], %[sum] \n\
.option pop"
: [sum] "+r" (sum), [fold_temp] "=&r" (fold_temp)); return (__force __sum16)(sum >> 16);
}
no_zbb:
sum += ror64(sum, 32);
sum >>= 32; return csum_fold((__force __wsum)sum);
}
EXPORT_SYMBOL(csum_ipv6_magic); #endif/* !CONFIG_32BIT */
/* * Do 32-bit reads on RV32 and 64-bit reads otherwise. This should be * faster than doing 32-bit reads on architectures that support larger * reads.
*/ while (ptr < end) {
csum += data;
carry += csum < data;
data = *(ptr++);
}
/* * Perform alignment (and over-read) bytes on the tail if any bytes * leftover.
*/
shift = ((long)ptr - (long)end) * 8; #ifdef __LITTLE_ENDIAN
data = (data << shift) >> shift; #else
data = (data >> shift) << shift; #endif
csum += data;
carry += csum < data;
csum += carry;
csum += csum < carry;
return csum;
}
/* * Algorithm accounts for buff being misaligned. * If buff is not aligned, will over-read bytes but not use the bytes that it * shouldn't. The same thing will occur on the tail-end of the read.
*/ staticinline __no_sanitize_address unsignedint
do_csum_with_alignment(constunsignedchar *buff, int len)
{ unsignedint offset, shift; unsignedlong csum, data; constunsignedlong *ptr, *end;
/* * Align address to closest word (double word on rv64) that comes before * buff. This should always be in the same page and cache line. * Directly call KASAN with the alignment we will be using.
*/
offset = (unsignedlong)buff & OFFSET_MASK;
kasan_check_read(buff, len);
ptr = (constunsignedlong *)(buff - offset);
/* * Clear the most significant bytes that were over-read if buff was not * aligned.
*/
shift = offset * 8;
data = *(ptr++); #ifdef __LITTLE_ENDIAN
data = (data >> shift) << shift; #else
data = (data << shift) >> shift; #endif
end = (constunsignedlong *)(buff + len);
csum = do_csum_common(ptr, end, data);
#ifdef CC_HAS_ASM_GOTO_TIED_OUTPUT if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB)) { unsignedlong fold_temp;
/* * Zbb is likely available when the kernel is compiled with Zbb * support, so nop when Zbb is available and jump when Zbb is * not available.
*/ asmgoto(ALTERNATIVE("j %l[no_zbb]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
:
:
:
: no_zbb);
/* * Does not perform alignment, should only be used if machine has fast * misaligned accesses, or when buff is known to be aligned.
*/ staticinline __no_sanitize_address unsignedint
do_csum_no_alignment(constunsignedchar *buff, int len)
{ unsignedlong csum, data; constunsignedlong *ptr, *end;
ptr = (constunsignedlong *)(buff);
data = *(ptr++);
if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB)) { unsignedlong fold_temp;
/* * Zbb is likely available when the kernel is compiled with Zbb * support, so nop when Zbb is available and jump when Zbb is * not available.
*/ asmgoto(ALTERNATIVE("j %l[no_zbb]", "nop", 0,
RISCV_ISA_EXT_ZBB, 1)
:
:
:
: no_zbb);
/* * Perform a checksum on an arbitrary memory address. * Will do a light-weight address alignment if buff is misaligned, unless * cpu supports fast misaligned accesses.
*/ unsignedint do_csum(constunsignedchar *buff, int len)
{ if (unlikely(len <= 0)) return 0;
/* * Significant performance gains can be seen by not doing alignment * on machines with fast misaligned accesses. * * There is some duplicate code between the "with_alignment" and * "no_alignment" implmentations, but the overlap is too awkward to be * able to fit in one function without introducing multiple static * branches. The largest chunk of overlap was delegated into the * do_csum_common function.
*/ if (has_fast_unaligned_accesses() || (((unsignedlong)buff & OFFSET_MASK) == 0)) return do_csum_no_alignment(buff, len);
return do_csum_with_alignment(buff, len);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.