From 9b9c4dfd46a19b7d743dc23ecb4d28784fed5c73 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 2 Feb 1999 21:14:44 +0000 Subject: New file. Based on the i386 version. --- .../exec/libnetworking/netinet/in_cksum_powerpc.c | 202 +++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 c/src/exec/libnetworking/netinet/in_cksum_powerpc.c (limited to 'c/src/exec') diff --git a/c/src/exec/libnetworking/netinet/in_cksum_powerpc.c b/c/src/exec/libnetworking/netinet/in_cksum_powerpc.c new file mode 100644 index 0000000000..8e0a417163 --- /dev/null +++ b/c/src/exec/libnetworking/netinet/in_cksum_powerpc.c @@ -0,0 +1,202 @@ +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * This implementation is the PowerPC version. + * + * $Id$ + */ + +#include /* for puts */ + +#undef ADDCARRY +#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);} + +/* + * Thanks to gcc we don't have to guess + * which registers contain sum & w. + */ + +#define LDTMP(n) tmp = *((u_int *)((u_char *)w + n)) + +#define ADD(n) \ + LDTMP(n); \ + __asm__ volatile("addc %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define ADDC(n) \ + LDTMP(n); \ + __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define MOP \ + tmp = 0; \ + __asm__ volatile("adde %0,%0,%2" : "=r" (sum) : "0" (sum), "r" (tmp)) + +#define LOAD(n) junk = (u_char) *((volatile u_char *) w + n) + + +int +in_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_short *w; + register unsigned sum = 0; + register unsigned tmp; + register int mlen = 0; + int byte_swapped = 0; + union { char c[2]; u_short s; } su; + + for (;m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * The first byte of this mbuf is the continuation + * of a word spanning between this mbuf and the + * last mbuf. + */ + + /* su.c[0] is already saved when scanning previous + * mbuf. sum was REDUCEd when we found mlen == -1 + */ + su.c[1] = *(u_char *)w; + sum += su.s; + w = (u_short *)((char *)w + 1); + mlen = m->m_len - 1; + len--; + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to long boundary so we do longword aligned + * memory operations + */ + if (3 & (int) w) { + REDUCE; + if ((1 & (int) w) && (mlen > 0)) { + sum <<= 8; + su.c[0] = *(char *)w; + w = (u_short *)((char *)w + 1); + mlen--; + byte_swapped = 1; + } + if ((2 & (int) w) && (mlen >= 2)) { + sum += *w++; + mlen -= 2; + } + } + /* + * Advance to a cache line boundary. + */ + if (4 & (int) w && mlen >= 4) { + ADD(0); + MOP; + w += 2; + mlen -= 4; + } + if (8 & (int) w && mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to make overhead from + * branches &c small. + */ + mlen -= 1; + while ((mlen -= 32) >= 0) { + u_char junk; + /* + * Add with carry 16 words and fold in the last + * carry by adding a 0 with carry. + * + * The early ADD(16) and the LOAD(32) are intended + * to help get the data into the cache. + */ + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + LOAD(32); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + } + mlen += 32 + 1; + if (mlen >= 32) { + ADD(16); + ADDC(0); + ADDC(4); + ADDC(8); + ADDC(12); + ADDC(20); + ADDC(24); + ADDC(28); + MOP; + w += 16; + mlen -= 32; + } + if (mlen >= 16) { + ADD(0); + ADDC(4); + ADDC(8); + ADDC(12); + MOP; + w += 8; + mlen -= 16; + } + if (mlen >= 8) { + ADD(0); + ADDC(4); + MOP; + w += 4; + mlen -= 8; + } + if (mlen == 0 && byte_swapped == 0) + continue; /* worth 1% maybe ?? */ + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + if (byte_swapped) { + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + su.c[1] = *(char *)w; + sum += su.s; + mlen = 0; + } else + mlen = -1; + } else if (mlen == -1) + /* + * This mbuf has odd number of bytes. + * There could be a word split betwen + * this mbuf and the next mbuf. + * Save the last byte (to prepend to next mbuf). + */ + su.c[0] = *(char *)w; + } + + if (len) + puts("cksum: out of data"); + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte is shifted left by 8 bits) */ + su.c[1] = 0; + sum += su.s; + } + REDUCE; + return (~sum & 0xffff); +} -- cgit v1.2.3