From 075a46a049d4ec16925139d69b4473499fd14122 Mon Sep 17 00:00:00 2001 From: Richard Kuo Date: Mon, 31 Oct 2011 18:38:04 -0500 Subject: Hexagon: Add checksum functions Signed-off-by: Richard Kuo Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Signed-off-by: Linus Torvalds --- arch/hexagon/lib/checksum.c | 203 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 arch/hexagon/lib/checksum.c (limited to 'arch/hexagon/lib') diff --git a/arch/hexagon/lib/checksum.c b/arch/hexagon/lib/checksum.c new file mode 100644 index 000000000000..93005522d52b --- /dev/null +++ b/arch/hexagon/lib/checksum.c @@ -0,0 +1,203 @@ +/* + * Checksum functions for Hexagon + * + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* This was derived from arch/alpha/lib/checksum.c */ + + +#include +#include + +#include +#include +#include +#include + + +/* Vector value operations */ +#define SIGN(x, y) ((0x8000ULL*x)<> 32); + /* 33 to 32 */ + result = (result & 0xffffffffUL) + (result >> 32); + return (__force __wsum)result; +} +EXPORT_SYMBOL(csum_tcpudp_nofold); + +/* + * Do a 64-bit checksum on an arbitrary memory area.. + * + * This isn't a great routine, but it's not _horrible_ either. The + * inner loop could be unrolled a bit further, and there are better + * ways to do the carry, but this is reasonable. + */ + +/* optimized HEXAGON intrinsic version, with over read fixed */ +unsigned int do_csum(const void *voidptr, int len) +{ + u64 sum0, sum1, x0, x1, *ptr8_o, *ptr8_e, *ptr8; + int i, start, mid, end, mask; + const char *ptr = voidptr; + unsigned short *ptr2; + unsigned int *ptr4; + + if (len <= 0) + return 0; + + start = 0xF & (16-(((int) ptr) & 0xF)) ; + mask = 0x7fffffffUL >> HEXAGON_R_cl0_R(len); + start = start & mask ; + + mid = len - start; + end = mid & 0xF; + mid = mid>>4; + sum0 = mid << 18; + sum1 = 0; + + if (start & 1) + sum0 += (u64) (ptr[0] << 8); + ptr2 = (unsigned short *) &ptr[start & 1]; + if (start & 2) + sum1 += (u64) ptr2[0]; + ptr4 = (unsigned int *) &ptr[start & 3]; + if (start & 4) { + sum0 = HEXAGON_P_vrmpyhacc_PP(sum0, + VR_NEGATE(0, 0, 1, 1)^((u64)ptr4[0]), + VR_SELECT(0, 0, 1, 1)); + sum0 += VR_SELECT(0, 0, 1, 0); + } + ptr8 = (u64 *) &ptr[start & 7]; + if (start & 8) { + sum1 = HEXAGON_P_vrmpyhacc_PP(sum1, + VR_NEGATE(1, 1, 1, 1)^(ptr8[0]), + VR_SELECT(1, 1, 1, 1)); + sum1 += VR_CARRY(0, 0, 1, 0); + } + ptr8_o = (u64 *) (ptr + start); + ptr8_e = (u64 *) (ptr + start + 8); + + if (mid) { + x0 = *ptr8_e; ptr8_e += 2; + x1 = *ptr8_o; ptr8_o += 2; + if (mid > 1) + for (i = 0; i < mid-1; i++) { + sum0 = HEXAGON_P_vrmpyhacc_PP(sum0, + x0^VR_NEGATE(1, 1, 1, 1), + VR_SELECT(1, 1, 1, 1)); + sum1 = HEXAGON_P_vrmpyhacc_PP(sum1, + x1^VR_NEGATE(1, 1, 1, 1), + VR_SELECT(1, 1, 1, 1)); + x0 = *ptr8_e; ptr8_e += 2; + x1 = *ptr8_o; ptr8_o += 2; + } + sum0 = HEXAGON_P_vrmpyhacc_PP(sum0, x0^VR_NEGATE(1, 1, 1, 1), + VR_SELECT(1, 1, 1, 1)); + sum1 = HEXAGON_P_vrmpyhacc_PP(sum1, x1^VR_NEGATE(1, 1, 1, 1), + VR_SELECT(1, 1, 1, 1)); + } + + ptr4 = (unsigned int *) &ptr[start + (mid * 16) + (end & 8)]; + if (end & 4) { + sum1 = HEXAGON_P_vrmpyhacc_PP(sum1, + VR_NEGATE(0, 0, 1, 1)^((u64)ptr4[0]), + VR_SELECT(0, 0, 1, 1)); + sum1 += VR_SELECT(0, 0, 1, 0); + } + ptr2 = (unsigned short *) &ptr[start + (mid * 16) + (end & 12)]; + if (end & 2) + sum0 += (u64) ptr2[0]; + + if (end & 1) + sum1 += (u64) ptr[start + (mid * 16) + (end & 14)]; + + ptr8 = (u64 *) &ptr[start + (mid * 16)]; + if (end & 8) { + sum0 = HEXAGON_P_vrmpyhacc_PP(sum0, + VR_NEGATE(1, 1, 1, 1)^(ptr8[0]), + VR_SELECT(1, 1, 1, 1)); + sum0 += VR_CARRY(0, 0, 1, 0); + } + sum0 = HEXAGON_P_vrmpyh_PP((sum0+sum1)^VR_NEGATE(0, 0, 0, 1), + VR_SELECT(0, 0, 1, 1)); + sum0 += VR_NEGATE(0, 0, 0, 1); + sum0 = HEXAGON_P_vrmpyh_PP(sum0, VR_SELECT(0, 0, 1, 1)); + + if (start & 1) + sum0 = (sum0 << 8) | (0xFF & (sum0 >> 8)); + + return 0xFFFF & sum0; +} + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ +__wsum +csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} -- cgit v1.2.2