arch/riscv/lib/csum.c

Source file repositories/reference/linux-study-clean/arch/riscv/lib/csum.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/lib/csum.c
Extension
.c
Size
7529 bytes
Lines
282
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

riscv_has_extension_likely(RISCV_ISA_EXT_ZBB)) {
		unsigned long fold_temp;

		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);
	}

	sum += ror64(sum, 32);
	sum >>= 32;
	return csum_fold((__force __wsum)sum);
}
EXPORT_SYMBOL(csum_ipv6_magic);
#endif /* !CONFIG_32BIT */

#ifdef CONFIG_32BIT
#define OFFSET_MASK 3
#elif CONFIG_64BIT
#define OFFSET_MASK 7
#endif

static inline __no_sanitize_address unsigned long
do_csum_common(const unsigned long *ptr, const unsigned long *end,
	       unsigned long data)
{
	unsigned int shift;
	unsigned long csum = 0, carry = 0;

	/*
	 * 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.
 */
static inline __no_sanitize_address unsigned int
do_csum_with_alignment(const unsigned char *buff, int len)
{
	unsigned int offset, shift;
	unsigned long csum, data;
	const unsigned long *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 = (unsigned long)buff & OFFSET_MASK;
	kasan_check_read(buff, len);
	ptr = (const unsigned long *)(buff - offset);

	/*
	 * Clear the most significant bytes that were over-read if buff was not
	 * aligned.
	 */

Annotation

Implementation Notes