linux-stable/drivers/staging/octeon/ethernet-defines.h
David Daney a620c16326 Staging: octeon-ethernet: Fix race freeing transmit buffers.
The existing code had the following race:

Thread-1                       Thread-2

inc/read in_use
                               inc/read in_use
inc tx_free_list[qos].len
                               inc tx_free_list[qos].len

The actual in_use value was incremented twice, but thread-1 is going
to free memory based on its stale value, and will free one too many
times.  The result is that memory is freed back to the kernel while
its packet is still in the transmit buffer.  If the memory is
overwritten before it is transmitted, the hardware will put a valid
checksum on it and send it out (just like it does with good packets).
If by chance the TCP flags are clobbered but not the addresses or
ports, the result can be a broken TCP stream.

The fix is to track the number of freed packets in a single location
(a Fetch-and-Add Unit register).  That way it can never get out of sync
with itself.

We try to free up to MAX_SKB_TO_FREE (currently 10) buffers at a time.
If fewer are available we adjust the free count with the difference.
The action of claiming buffers to free is atomic so two threads cannot
claim the same buffers.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2009-06-24 18:34:41 +01:00

136 lines
5 KiB
C

/**********************************************************************
* Author: Cavium Networks
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2007 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
**********************************************************************/
/*
* A few defines are used to control the operation of this driver:
* CONFIG_CAVIUM_RESERVE32
* This kernel config options controls the amount of memory configured
* in a wired TLB entry for all processes to share. If this is set, the
* driver will use this memory instead of kernel memory for pools. This
* allows 32bit userspace application to access the buffers, but also
* requires all received packets to be copied.
* CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
* This kernel config option allows the user to control the number of
* packet and work queue buffers allocated by the driver. If this is zero,
* the driver uses the default from below.
* USE_SKBUFFS_IN_HW
* Tells the driver to populate the packet buffers with kernel skbuffs.
* This allows the driver to receive packets without copying them. It also
* means that 32bit userspace can't access the packet buffers.
* USE_32BIT_SHARED
* This define tells the driver to allocate memory for buffers from the
* 32bit sahred region instead of the kernel memory space.
* USE_HW_TCPUDP_CHECKSUM
* Controls if the Octeon TCP/UDP checksum engine is used for packet
* output. If this is zero, the kernel will perform the checksum in
* software.
* USE_MULTICORE_RECEIVE
* Process receive interrupts on multiple cores. This spreads the network
* load across the first 8 processors. If ths is zero, only one core
* processes incomming packets.
* USE_ASYNC_IOBDMA
* Use asynchronous IO access to hardware. This uses Octeon's asynchronous
* IOBDMAs to issue IO accesses without stalling. Set this to zero
* to disable this. Note that IOBDMAs require CVMSEG.
* REUSE_SKBUFFS_WITHOUT_FREE
* Allows the TX path to free an skbuff into the FPA hardware pool. This
* can significantly improve performance for forwarding and bridging, but
* may be somewhat dangerous. Checks are made, but if any buffer is reused
* without the proper Linux cleanup, the networking stack may have very
* bizarre bugs.
*/
#ifndef __ETHERNET_DEFINES_H__
#define __ETHERNET_DEFINES_H__
#include "cvmx-config.h"
#define OCTEON_ETHERNET_VERSION "1.9"
#ifndef CONFIG_CAVIUM_RESERVE32
#define CONFIG_CAVIUM_RESERVE32 0
#endif
#if CONFIG_CAVIUM_RESERVE32
#define USE_32BIT_SHARED 1
#define USE_SKBUFFS_IN_HW 0
#define REUSE_SKBUFFS_WITHOUT_FREE 0
#else
#define USE_32BIT_SHARED 0
#define USE_SKBUFFS_IN_HW 1
#ifdef CONFIG_NETFILTER
#define REUSE_SKBUFFS_WITHOUT_FREE 0
#else
#define REUSE_SKBUFFS_WITHOUT_FREE 1
#endif
#endif
/* Max interrupts per second per core */
#define INTERRUPT_LIMIT 10000
/* Don't limit the number of interrupts */
/*#define INTERRUPT_LIMIT 0 */
#define USE_HW_TCPUDP_CHECKSUM 1
#define USE_MULTICORE_RECEIVE 1
/* Enable Random Early Dropping under load */
#define USE_RED 1
#define USE_ASYNC_IOBDMA (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
/*
* Allow SW based preamble removal at 10Mbps to workaround PHYs giving
* us bad preambles.
*/
#define USE_10MBPS_PREAMBLE_WORKAROUND 1
/*
* Use this to have all FPA frees also tell the L2 not to write data
* to memory.
*/
#define DONT_WRITEBACK(x) (x)
/* Use this to not have FPA frees control L2 */
/*#define DONT_WRITEBACK(x) 0 */
/* Maximum number of packets to process per interrupt. */
#define MAX_RX_PACKETS 120
/* Maximum number of SKBs to try to free per xmit packet. */
#define MAX_SKB_TO_FREE 10
#define MAX_OUT_QUEUE_DEPTH 1000
#ifndef CONFIG_SMP
#undef USE_MULTICORE_RECEIVE
#define USE_MULTICORE_RECEIVE 0
#endif
#define IP_PROTOCOL_TCP 6
#define IP_PROTOCOL_UDP 0x11
#define FAU_NUM_PACKET_BUFFERS_TO_FREE (CVMX_FAU_REG_END - sizeof(uint32_t))
#define TOTAL_NUMBER_OF_PORTS (CVMX_PIP_NUM_INPUT_PORTS+1)
#endif /* __ETHERNET_DEFINES_H__ */