186144Stmm/*- 286144Stmm * Copyright (c) 1990 The Regents of the University of California. 386144Stmm * All rights reserved. 486144Stmm * 586144Stmm * Redistribution and use in source and binary forms, with or without 686144Stmm * modification, are permitted provided that the following conditions 786144Stmm * are met: 886144Stmm * 1. Redistributions of source code must retain the above copyright 986144Stmm * notice, this list of conditions and the following disclaimer. 1086144Stmm * 2. Redistributions in binary form must reproduce the above copyright 1186144Stmm * notice, this list of conditions and the following disclaimer in the 1286144Stmm * documentation and/or other materials provided with the distribution. 1386144Stmm * 4. Neither the name of the University nor the names of its contributors 1486144Stmm * may be used to endorse or promote products derived from this software 1586144Stmm * without specific prior written permission. 1686144Stmm * 1786144Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1886144Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1986144Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2086144Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2186144Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2286144Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2386144Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2486144Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2586144Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2686144Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2786144Stmm * SUCH DAMAGE. 2886144Stmm */ 2986144Stmm/*- 3086144Stmm * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>. 3186144Stmm * All rights reserved. 3286144Stmm * 3386144Stmm * Redistribution and use in source and binary forms, with or without 3486144Stmm * modification, are permitted provided that the following conditions 3586144Stmm * are met: 3686144Stmm * 1. Redistributions of source code must retain the above copyright 3786144Stmm * notice, this list of conditions and the following disclaimer. 3886144Stmm * 2. Redistributions in binary form must reproduce the above copyright 3986144Stmm * notice, this list of conditions and the following disclaimer in the 4086144Stmm * documentation and/or other materials provided with the distribution. 4186144Stmm * 4286144Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4386144Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4486144Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4586144Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 4686144Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 4786144Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 4886144Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 4986144Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 5086144Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 5186144Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5286144Stmm * 5386144Stmm * from tahoe: in_cksum.c 1.2 86/01/05 5486144Stmm * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 5586144Stmm * from: FreeBSD: src/sys/i386/i386/in_cksum.c,v 1.22 2000/11/25 5686144Stmm */ 5786144Stmm 58180298Smarius#include <sys/cdefs.h> 59180298Smarius__FBSDID("$FreeBSD: releng/10.3/sys/sparc64/sparc64/in_cksum.c 180299 2008-07-05 15:44:56Z marius $"); 60180298Smarius 6186144Stmm#include <sys/param.h> 6286144Stmm#include <sys/systm.h> 6386144Stmm#include <sys/mbuf.h> 6486144Stmm 6586144Stmm#include <netinet/in.h> 6686144Stmm#include <netinet/in_systm.h> 6786144Stmm#include <netinet/ip.h> 6886144Stmm 6986144Stmm#include <machine/in_cksum.h> 7086144Stmm 7186144Stmm/* 7286144Stmm * Checksum routine for Internet Protocol family headers. 7386144Stmm * 7486144Stmm * This routine is very heavily used in the network 7586144Stmm * code and should be modified for each CPU to be as fast as possible. 7686144Stmm * 77180298Smarius * This implementation is a sparc64 version. Most code was taken over 78180298Smarius * and adapted from the i386. Some optimizations were changed to achieve 79180298Smarius * (hopefully) better performance. 80180298Smarius * This uses 64-bit loads, but 32-bit additions due to the lack of a 64-bit 8186144Stmm * add-with-carry operation. 8286144Stmm */ 8386144Stmm 8486144Stmm/* 8586144Stmm * REDUCE() is actually not used that frequently... maybe a C implementation 8686144Stmm * would suffice. 8786144Stmm */ 88180299Smarius#define REDUCE(sum, tmp) __asm( \ 89180298Smarius "sll %2, 16, %1\n" \ 90180298Smarius "addcc %2, %1, %0\n" \ 91180298Smarius "srl %0, 16, %0\n" \ 92180299Smarius "addc %0, 0, %0" : "=r" (sum), "=&r" (tmp) : "0" (sum) : "cc") 9386144Stmm 9486144Stmm/* 95180298Smarius * Note that some of these macros depend on the flags being preserved 96180299Smarius * between calls, thus they have to be used within a single __asm(). 9786144Stmm */ 98180299Smarius#define LD64_ADD32(n, mod) \ 99180298Smarius "ldx [%3 + " #n "], %1\n" \ 100180298Smarius "add" #mod " %2, %1, %0\n" \ 101180298Smarius "srlx %1, 32, %1\n" \ 102180299Smarius "addccc %0, %1, %0\n" 10386144Stmm 104180299Smarius#define LD32_ADD32(n, mod) \ 105180298Smarius "lduw [%3 + " #n "], %1\n" \ 106180299Smarius "add" #mod " %2, %1, %0\n" 10786144Stmm 108180299Smarius#define MOP(sum, tmp, addr) \ 109180299Smarius "addc %2, 0, %0" \ 110180299Smarius : "=r" (sum), "=&r" (tmp) : "0" (sum), "r" (addr) : "cc" 11186144Stmm 11286144Stmmu_short 11386144Stmmin_cksum_skip(struct mbuf *m, int len, int skip) 11486144Stmm{ 11586144Stmm u_short *w; 11686144Stmm unsigned long tmp, sum = 0; 11786144Stmm int mlen = 0; 11886144Stmm int byte_swapped = 0; 11986144Stmm u_short su = 0; 12086144Stmm 12186144Stmm len -= skip; 12286144Stmm for (; skip > 0 && m != NULL; m = m->m_next) { 12386144Stmm if (m->m_len > skip) { 12486144Stmm mlen = m->m_len - skip; 12586144Stmm w = (u_short *)(mtod(m, u_char *) + skip); 12686144Stmm goto skip_start; 12786144Stmm } else 12886144Stmm skip -= m->m_len; 12986144Stmm } 13086144Stmm 13186144Stmm for (; m != NULL && len > 0; m = m->m_next) { 13286144Stmm if (m->m_len == 0) 13386144Stmm continue; 13486144Stmm w = mtod(m, u_short *); 13586144Stmm if (mlen == -1) { 13686144Stmm /* 13786144Stmm * The first byte of this mbuf is the continuation 13886144Stmm * of a word spanning between this mbuf and the 13986144Stmm * last mbuf. 14086144Stmm * 14186144Stmm * The high order byte of su is already saved when 14286144Stmm * scanning previous mbuf. sum was REDUCEd when we 14386144Stmm * found mlen == -1 14486144Stmm */ 14586144Stmm sum += su | *(u_char *)w; 14686144Stmm w = (u_short *)((u_char *)w + 1); 14786144Stmm mlen = m->m_len - 1; 14886144Stmm len--; 14986144Stmm } else 15086144Stmm mlen = m->m_len; 15186144Stmmskip_start: 15286144Stmm if (len < mlen) 15386144Stmm mlen = len; 15486144Stmm len -= mlen; 15586144Stmm /* 15686144Stmm * Force to a 8-byte boundary first so that we can use 15786144Stmm * LD64_ADD32. 15886144Stmm */ 15986144Stmm if (((u_long)w & 7) != 0) { 16086144Stmm REDUCE(sum, tmp); 16186144Stmm if (((u_long)w & 1) != 0 && mlen >= 1) { 16286144Stmm sum <<= 8; 16386144Stmm su = *(u_char *)w << 8; 16486144Stmm w = (u_short *)((u_char *)w + 1); 16586144Stmm mlen--; 16686144Stmm byte_swapped = 1; 16786144Stmm } 16886144Stmm if (((u_long)w & 2) != 0 && mlen >= 2) { 16986144Stmm sum += *w++; 17086144Stmm mlen -= 2; 17186144Stmm } 17286144Stmm if (((u_long)w & 4) != 0 && mlen >= 4) { 173180299Smarius __asm( 174180299Smarius LD32_ADD32(0, cc) 175180299Smarius MOP(sum, tmp, w) 176180299Smarius ); 17786144Stmm w += 2; 17886144Stmm mlen -= 4; 17986144Stmm } 18086144Stmm } 18186144Stmm /* 18286144Stmm * Do as much of the checksum as possible 64 bits at at time. 18386144Stmm * In fact, this loop is unrolled to make overhead from 18486144Stmm * branches &c small. 18586144Stmm */ 18686144Stmm for (; mlen >= 64; mlen -= 64) { 187180299Smarius __asm( 188180299Smarius LD64_ADD32(0, cc) 189180299Smarius LD64_ADD32(8, ccc) 190180299Smarius LD64_ADD32(16, ccc) 191180299Smarius LD64_ADD32(24, ccc) 192180299Smarius LD64_ADD32(32, ccc) 193180299Smarius LD64_ADD32(40, ccc) 194180299Smarius LD64_ADD32(48, ccc) 195180299Smarius LD64_ADD32(56, ccc) 196180299Smarius MOP(sum, tmp, w) 197180299Smarius ); 19886144Stmm w += 32; 19986144Stmm } 20086144Stmm if (mlen >= 32) { 201180299Smarius __asm( 202180299Smarius LD64_ADD32(0, cc) 203180299Smarius LD64_ADD32(8, ccc) 204180299Smarius LD64_ADD32(16, ccc) 205180299Smarius LD64_ADD32(24, ccc) 206180299Smarius MOP(sum, tmp, w) 207180299Smarius ); 20886144Stmm w += 16; 20986144Stmm mlen -= 32; 21086144Stmm } 21186144Stmm if (mlen >= 16) { 212180299Smarius __asm( 213180299Smarius LD64_ADD32(0, cc) 214180299Smarius LD64_ADD32(8, ccc) 215180299Smarius MOP(sum, tmp, w) 216180299Smarius ); 21786144Stmm w += 8; 21886144Stmm mlen -= 16; 21986144Stmm } 22086144Stmm if (mlen >= 8) { 221180299Smarius __asm( 222180299Smarius LD64_ADD32(0, cc) 223180299Smarius MOP(sum, tmp, w) 224180299Smarius ); 22586144Stmm w += 4; 22686144Stmm mlen -= 8; 22786144Stmm } 22886144Stmm REDUCE(sum, tmp); 22986144Stmm while ((mlen -= 2) >= 0) 23086144Stmm sum += *w++; 23186144Stmm if (byte_swapped) { 23286144Stmm sum <<= 8; 23386144Stmm byte_swapped = 0; 23486144Stmm if (mlen == -1) { 23586144Stmm su |= *(u_char *)w; 23686144Stmm sum += su; 23786144Stmm mlen = 0; 23886144Stmm } else 23986144Stmm mlen = -1; 24086144Stmm } else if (mlen == -1) { 24186144Stmm /* 24286144Stmm * This mbuf has odd number of bytes. 243180298Smarius * There could be a word split between 24486144Stmm * this mbuf and the next mbuf. 24586144Stmm * Save the last byte (to prepend to next mbuf). 24686144Stmm */ 24786144Stmm su = *(u_char *)w << 8; 24886144Stmm } 24986144Stmm } 25086144Stmm 25186144Stmm if (len) 25286144Stmm printf("%s: out of data by %d\n", __func__, len); 25386144Stmm if (mlen == -1) { 254180298Smarius /* 255180298Smarius * The last mbuf has odd # of bytes. Follow the 256180298Smarius * standard (the odd byte is shifted left by 8 bits). 257180298Smarius */ 25886144Stmm sum += su & 0xff00; 25986144Stmm } 26086144Stmm REDUCE(sum, tmp); 26186144Stmm return (~sum & 0xffff); 26286144Stmm} 263