From: Arnd Bergmann <arnd@arndb.de>
To: Mike Frysinger <vapier.adi@gmail.com>
Cc: linux-kernel@vger.kernel.org,
uclinux-dist-devel@blackfin.uclinux.org,
Michal Simek <monstr@monstr.eu>, Paul Mundt <lethal@linux-sh.org>
Subject: Re: [PATCH 05/17] Blackfin: convert to generic checksum code
Date: Fri, 19 Jun 2009 11:05:37 +0200 [thread overview]
Message-ID: <200906191105.37732.arnd@arndb.de> (raw)
In-Reply-To: <8bd0f97a0906181819u25df402fxfd535030fd180e87@mail.gmail.com>
On Friday 19 June 2009, Mike Frysinger wrote:
> On Mon, Jun 15, 2009 at 07:04, Arnd Bergmann wrote:
> > On Sunday 14 June 2009, Mike Frysinger wrote:
> >> The Blackfin port only implemented an optimized version of the
> >> csum_tcpudp_nofold function, so convert everything else to the new
> >> generic code.
> >>
> >> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
> >
> > Have you tested this one well? I was as careful as possible with the
> > version I added, but it was basically only tested on microblaze, which
> > has a different endianess from blackfin. Some areas of the code may be
> > sensitive to this.
>
> i did some tests and it looks like do_csum() is broken :(
Thanks for testing. Indeed it turns out to be an endian-problem with
the handling of the last byte:
> here's the input:
> do_csum({ 0xff 0xfb 0x01 }, 3)
>
> and here's the output:
> Blackfin: 0xfc00
> generic: 0xfcff
>
> if i run the two funcs on my x86, i see similar behavior. the
> attached csum-test.c contains the csum code from lib/checksum.c and
> arch/blackfin/lib/checksum.c and shows the problem.
x86 and blackfin are both little-endian, so your variant is correct
there. They add the 0x01 to the low byte of the 16-bit word, while
on big-endian machines, you have to add it to the high byte.
> -mike
> csum-test.c
> #include <stdio.h>
>
> static inline unsigned short gen_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 int gen_do_csum(const unsigned char *buff, int len)
> {
> ...
> if (len & 1)
> result += (*buff << 8);
On little-endian, this needs to be
if (len & 1)
result += *buff;
> static unsigned short bf_do_csum(const unsigned char *buff, int len)
> {
> ...
> if (len > 0)
> sum += *buff;
Same problem, on big-endian this would need to be
if (len > 0)
sum += (*buff << 8);
The bug potentially also exists in arch/sh/lib64/c-checksum.c, which only
works on little-endian machines, while the sh architecture code appears
dual-endian. Paul, is your lib64/c-checksum.c implementation potentially
run on big-endian machines, or is sh64 guaranteed to be little-endian?
I've committed the patch below now.
Arnd <><
---
>From e01fed86629737809c46dcb8b807347e84640b70 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Fri, 19 Jun 2009 10:41:19 +0200
Subject: [PATCH] lib/checksum.c: fix endianess bug
The new generic checksum code has a small dependency on endianess and
worked only on big-endian systems. I could not find a nice efficient
way to express this, so I added an #ifdef. Using
'result += le16_to_cpu(*buff);' would have worked as well, but
would be slightly less efficient on big-endian systems and IMHO
would not be clearer.
Also fix a bug that prevents this from working on 64-bit machines.
If you have a 64-bit CPU and want to use the generic checksum
code, you should probably do some more optimizations anyway, but
at least the code should not break.
Reported-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
lib/checksum.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/lib/checksum.c b/lib/checksum.c
index 12e5a1c..4a1c84a 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -71,7 +71,7 @@ static unsigned int do_csum(const unsigned char *buff, int len)
if (count) {
unsigned long carry = 0;
do {
- unsigned long w = *(unsigned long *) buff;
+ unsigned long w = *(unsigned int *) buff;
count--;
buff += 4;
result += carry;
@@ -87,7 +87,11 @@ static unsigned int do_csum(const unsigned char *buff, int len)
}
}
if (len & 1)
+#ifdef __LITTLE_ENDIAN
+ result += *buff;
+#else
result += (*buff << 8);
+#endif
result = from32to16(result);
if (odd)
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
--
1.6.3.1
next prev parent reply other threads:[~2009-06-19 9:07 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-14 12:01 [PATCH 00/17] Blackfin arch conversion to asm-generic Mike Frysinger
2009-06-14 12:01 ` [PATCH 01/17] Blackfin: use common test_bit() rather than __test_bit() Mike Frysinger
2009-06-14 12:01 ` [PATCH 02/17] Blackfin: pull in asm/io.h in ksyms for prototypes Mike Frysinger
2009-06-14 12:01 ` [PATCH 03/17] Blackfin: only build irqpanic.c when needed Mike Frysinger
2009-06-14 12:01 ` [PATCH 04/17] Blackfin: convert asm/ioctls.h to asm-generic/ioctls.h Mike Frysinger
2009-06-14 12:01 ` [PATCH 05/17] Blackfin: convert to generic checksum code Mike Frysinger
2009-06-15 11:04 ` Arnd Bergmann
2009-06-16 10:03 ` Mike Frysinger
2009-06-19 1:19 ` Mike Frysinger
2009-06-19 9:05 ` Arnd Bergmann [this message]
2009-06-19 10:42 ` Mike Frysinger
2009-06-19 12:33 ` Arnd Bergmann
2009-06-19 13:12 ` Mike Frysinger
2009-06-23 21:14 ` Arnd Bergmann
2009-06-23 21:53 ` Mike Frysinger
2009-06-23 22:06 ` Arnd Bergmann
2009-06-23 22:11 ` Mike Frysinger
2009-09-19 19:08 ` Mike Frysinger
2009-06-14 12:01 ` [PATCH 06/17] Blackfin: convert shm/sysv/ipc to asm-generic Mike Frysinger
2009-06-14 12:01 ` [PATCH 07/17] Blackfin: convert user/elf " Mike Frysinger
2009-06-14 12:01 ` [PATCH 08/17] Blackfin: convert socket/poll " Mike Frysinger
2009-06-14 12:01 ` [PATCH 09/17] Blackfin: convert simple headers " Mike Frysinger
2009-06-14 12:01 ` [PATCH 10/17] Blackfin: convert dma/pci " Mike Frysinger
2009-06-15 11:37 ` Arnd Bergmann
2009-06-16 10:00 ` Mike Frysinger
2009-06-14 12:01 ` [PATCH 11/17] Blackfin: convert termios " Mike Frysinger
2009-06-14 12:01 ` [PATCH 12/17] Blackfin: convert locking primitives " Mike Frysinger
2009-06-14 12:01 ` [PATCH 13/17] Blackfin: convert signal/mmap " Mike Frysinger
2009-06-14 12:01 ` [PATCH 14/17] Blackfin: convert irq/process " Mike Frysinger
2009-06-14 12:01 ` [PATCH 15/17] Blackfin: convert types " Mike Frysinger
2009-06-14 12:01 ` [PATCH 16/17] Blackfin: convert page/tlb " Mike Frysinger
2009-06-14 12:01 ` [PATCH 17/17] Blackfin: convert uaccess " Mike Frysinger
2009-06-15 11:42 ` [PATCH 00/17] Blackfin arch conversion " Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200906191105.37732.arnd@arndb.de \
--to=arnd@arndb.de \
--cc=lethal@linux-sh.org \
--cc=linux-kernel@vger.kernel.org \
--cc=monstr@monstr.eu \
--cc=uclinux-dist-devel@blackfin.uclinux.org \
--cc=vapier.adi@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.