Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759841AbYFZMwz (ORCPT ); Thu, 26 Jun 2008 08:52:55 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754831AbYFZMh1 (ORCPT ); Thu, 26 Jun 2008 08:37:27 -0400 Received: from 238.225.broadband7.iol.cz ([88.102.225.238]:20857 "EHLO monstr.eu" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1758566AbYFZMhX (ORCPT ); Thu, 26 Jun 2008 08:37:23 -0400 From: monstr@seznam.cz To: linux-kernel@vger.kernel.org Cc: arnd@arndb.de, linux-arch@vger.kernel.org, stephen.neuendorffer@xilinx.com, John.Linn@xilinx.com, john.williams@petalogix.com, matthew@wil.cx, will.newton@gmail.com, drepper@redhat.com, microblaze-uclinux@itee.uq.edu.au, grant.likely@secretlab.ca, linuxppc-dev@ozlabs.org, vapier.adi@gmail.com, alan@lxorguk.ukuu.org.uk, hpa@zytor.com, Michal Simek Subject: [PATCH 19/60] microblaze_v4: checksum support Date: Thu, 26 Jun 2008 14:29:48 +0200 Message-Id: <1214483429-32360-20-git-send-email-monstr@seznam.cz> X-Mailer: git-send-email 1.5.4.GIT In-Reply-To: <1214483429-32360-19-git-send-email-monstr@seznam.cz> References: <1214483429-32360-1-git-send-email-monstr@seznam.cz> <1214483429-32360-2-git-send-email-monstr@seznam.cz> <1214483429-32360-3-git-send-email-monstr@seznam.cz> <1214483429-32360-4-git-send-email-monstr@seznam.cz> <1214483429-32360-5-git-send-email-monstr@seznam.cz> <1214483429-32360-6-git-send-email-monstr@seznam.cz> <1214483429-32360-7-git-send-email-monstr@seznam.cz> <1214483429-32360-8-git-send-email-monstr@seznam.cz> <1214483429-32360-9-git-send-email-monstr@seznam.cz> <1214483429-32360-10-git-send-email-monstr@seznam.cz> <1214483429-32360-11-git-send-email-monstr@seznam.cz> <1214483429-32360-12-git-send-email-monstr@seznam.cz> <1214483429-32360-13-git-send-email-monstr@seznam.cz> <1214483429-32360-14-git-send-email-monstr@seznam.cz> <1214483429-32360-15-git-send-email-monstr@seznam.cz> <1214483429-32360-16-git-send-email-monstr@seznam.cz> <1214483429-32360-17-git-send-email-monstr@seznam.cz> <1214483429-32360-18-git-send-email-monstr@seznam.cz> <1214483429-32360-19-git-send-email-monstr@seznam.cz> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8991 Lines: 321 From: Michal Simek Signed-off-by: Michal Simek --- include/asm-generic/checksum.h | 101 ++++++++++++++++++++++ include/asm-microblaze/checksum.h | 1 + lib/Makefile | 2 + lib/checksum.c | 166 +++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 0 deletions(-) create mode 100644 include/asm-generic/checksum.h create mode 100644 include/asm-microblaze/checksum.h create mode 100644 lib/checksum.c diff --git a/include/asm-generic/checksum.h b/include/asm-generic/checksum.h new file mode 100644 index 0000000..b40f0f8 --- /dev/null +++ b/include/asm-generic/checksum.h @@ -0,0 +1,101 @@ +/* + * include/asm-generic/checksum.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Atmark Techno, Inc. + */ + +#ifndef _ASM_GENERIC_CHECKSUM_H +#define _ASM_GENERIC_CHECKSUM_H + +#include + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char *buff, int len, + unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *csum_err); + +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy((src), (dst), (len), (sum)) + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + * + */ +extern unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl); + +/* + * Fold a partial checksum + */ +static inline unsigned int csum_fold(unsigned int sum) +{ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + return ~sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned int +csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + __asm__("add %0, %4, %1\n\t" + "addc %0, %4, %2\n\t" + "addc %0, %4, %3\n\t" + "addc %0, %4, r0\n\t" + : "=d" (sum) + : "d" (saddr), "d" (daddr), "d" (len + proto), + "0"(sum)); + + return sum; +} + +static inline unsigned short int +csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +extern unsigned short ip_compute_csum(const unsigned char *buff, int len); + +#endif /* _ASM_GENERIC_CHECKSUM_H */ diff --git a/include/asm-microblaze/checksum.h b/include/asm-microblaze/checksum.h new file mode 100644 index 0000000..adbb5e6 --- /dev/null +++ b/include/asm-microblaze/checksum.h @@ -0,0 +1 @@ +#include diff --git a/lib/Makefile b/lib/Makefile index 74b0cfb..6f48c04 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -72,6 +72,8 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o obj-$(CONFIG_HAVE_LMB) += lmb.o +obj-$(CONFIG_GENERIC_CSUM) += checksum.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/checksum.c b/lib/checksum.c new file mode 100644 index 0000000..0060873 --- /dev/null +++ b/lib/checksum.c @@ -0,0 +1,166 @@ +/* + * arch/microblaze/lib/checksum.c + * + * Copyright (C) 2008 Michal Simek + * + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Andreas Schwab, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: + * Fixed some nasty bugs, causing some horrible crashes. + * A: At some points, the sum (%0) was used as + * length-counter instead of the length counter + * (%1). Thanks to Roman Hodek for pointing this out. + * B: GCC seems to mess up if one uses too many + * data-registers to hold input values and one tries to + * specify d0 and d1 as scratch registers. Letting gcc choose these + * registers itself solves the problem. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access + kills, so most of the assembly has to go. */ + +#include +#include +#include + +static inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 16-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static unsigned long do_csum(const unsigned char *buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += (*buff << 8); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) +{ + return ~do_csum(iph, ihl*4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return result; +} +EXPORT_SYMBOL(csum_partial); + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(const unsigned char *buff, int len) +{ + return ~do_csum(buff, len); +} +EXPORT_SYMBOL(ip_compute_csum); + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ +unsigned int +csum_partial_copy_from_user(const char __user *src, char *dst, int len, + int sum, int *csum_err) +{ + if (csum_err) + *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ +unsigned int +csum_partial_copy(const char *src, char *dst, int len, int sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy); -- 1.5.4.GIT -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/