vmxnet3-only/ 0000755 0000000 0000000 00000000000 12025727030 012135 5 ustar root root vmxnet3-only/autoconf/ 0000755 0000000 0000000 00000000000 12025727027 013761 5 ustar root root vmxnet3-only/autoconf/geninclude.c 0000444 0000000 0000000 00000002264 12025727027 016244 0 ustar root root /*********************************************************
* Copyright (C) 2003 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#include
#ifdef CONFIG_X86_VOYAGER
APATH/mach-voyager
#endif
#ifdef CONFIG_X86_VISWS
APATH/mach-visws
#endif
#ifdef CONFIG_X86_NUMAQ
APATH/mach-numaq
#endif
#ifdef CONFIG_X86_BIGSMP
APATH/mach-bigsmp
#endif
#ifdef CONFIG_X86_SUMMIT
APATH/mach-summit
#endif
#ifdef CONFIG_X86_GENERICARCH
APATH/mach-generic
#endif
APATH/mach-default
vmxnet3-only/autoconf/skblin.c 0000444 0000000 0000000 00000002570 12025727027 015411 0 ustar root root /*********************************************************
* Copyright (C) 2006 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* Detect whether skb_linearize takes one or two arguments.
*/
#include
#include
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
/*
* Since 2.6.18 all kernels have single-argument skb_linearize. For
* older kernels use autodetection. Not using autodetection on newer
* kernels saves us from compile failure on some post 2.6.18 kernels
* which do not have selfcontained skbuff.h.
*/
#include
int test_skb_linearize(struct sk_buff *skb)
{
return skb_linearize(skb);
}
#endif
vmxnet3-only/vm_basic_types.h 0000444 0000000 0000000 00000056242 12025727027 015332 0 ustar root root /*********************************************************
* Copyright (C) 1998-2008 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
*
* vm_basic_types.h --
*
* basic data types.
*/
#ifndef _VM_BASIC_TYPES_H_
#define _VM_BASIC_TYPES_H_
#define INCLUDE_ALLOW_USERLEVEL
#define INCLUDE_ALLOW_VMMEXT
#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_VMMON
#define INCLUDE_ALLOW_VMNIXMOD
#define INCLUDE_ALLOW_VMKERNEL
#define INCLUDE_ALLOW_VMKDRIVERS
#define INCLUDE_ALLOW_VMK_MODULE
#define INCLUDE_ALLOW_DISTRIBUTE
#define INCLUDE_ALLOW_VMCORE
#define INCLUDE_ALLOW_VMIROM
#include "includeCheck.h"
/* STRICT ANSI means the Xserver build and X defines Bool differently. */
#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
typedef char Bool;
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define IsBool(x) (((x) & ~1) == 0)
#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0)
/*
* Macros __i386__ and __ia64 are intrinsically defined by GCC
*/
#ifdef __i386__
#define VM_I386
#endif
#ifdef _WIN64
#define __x86_64__
#endif
#ifdef __x86_64__
#define VM_X86_64
#define VM_I386
#define vm_x86_64 (1)
#else
#define vm_x86_64 (0)
#endif
#ifdef _WIN32
/* safe assumption for a while */
#define VM_I386
#endif
#ifdef _MSC_VER
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#pragma warning (3 :4505) // unreferenced local function
#pragma warning (disable :4018) // signed/unsigned mismatch
#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
#pragma warning (disable :4305) // truncation from 'const int' to 'short'
#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
#pragma warning (disable :4267) // truncation of 'size_t'
#if !defined VMX86_DEVEL // XXX until we clean up all the code -- edward
#pragma warning (disable :4133) // incompatible types - from 'struct VM *' to 'int *'
#pragma warning (disable :4047) // differs in levels of indirection
#endif
#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning (disable :4142) // benign redefinition of type
#elif __GNUC__
/* The Xserver source compiles with -ansi -pendantic */
#ifndef __STRICT_ANSI__
#if defined(VM_X86_64)
typedef unsigned long uint64;
typedef long int64;
#else
typedef unsigned long long uint64;
typedef long long int64;
#endif
#elif __FreeBSD__
typedef unsigned long long uint64;
typedef long long int64;
#endif
#else
#error - Need compiler define for int64/uint64
#endif
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
typedef int int32;
typedef short int16;
typedef char int8;
/*
* FreeBSD (for the tools build) unconditionally defines these in
* sys/inttypes.h so don't redefine them if this file has already
* been included. [greg]
*
* This applies to Solaris as well.
*/
/*
* Before trying to do the includes based on OS defines, see if we can use
* feature-based defines to get as much functionality as possible
*/
#ifdef HAVE_INTTYPES_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_SYS_INTTYPES_H
#include
#endif
#ifdef HAVE_STDINT_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#if !defined(USING_AUTOCONF)
# if defined(__FreeBSD__) || defined(sun)
# ifdef KLD_MODULE
# include
# else
# if (BSD_VERSION >= 50)
# include
# include
# else
# include
# endif
# endif
# elif defined __APPLE__
# if KERNEL
# include
# include /* mostly for size_t */
# include
# else
# include
# include
# include
# include
# endif
# else
# if !defined(__intptr_t_defined) && !defined(intptr_t)
# define __intptr_t_defined
# define intptr_t intptr_t
# ifdef VM_I386
# ifdef VM_X86_64
typedef int64 intptr_t;
# else
typedef int32 intptr_t;
# endif
# endif
# endif
# ifndef _STDINT_H
# ifdef VM_I386
# ifdef VM_X86_64
typedef uint64 uintptr_t;
# else
typedef uint32 uintptr_t;
# endif
# endif
# endif
# endif
#endif
/*
* Time
* XXX These should be cleaned up. -- edward
*/
typedef int64 VmTimeType; /* Time in microseconds */
typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */
typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */
/*
* Printf format specifiers for size_t and 64-bit number.
* Use them like this:
* printf("%"FMT64"d\n", big);
*
* FMTH is for handles/fds.
*/
#ifdef _MSC_VER
#define FMT64 "I64"
#ifdef VM_X86_64
#define FMTSZ "I64"
#define FMTPD "I64"
#define FMTH "I64"
#else
#define FMTSZ "I"
#define FMTPD "I"
#define FMTH "I"
#endif
#elif __GNUC__
#define FMTH ""
#if defined(N_PLAT_NLM) || defined(sun) || \
(defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
/*
* Why (__FreeBSD__ + 0)? See bug 141008.
* Yes, we really need to test both (__FreeBSD__ + 0) and
* ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from
* ((__FreeBSD__ + 0) < 5).
*/
#ifdef VM_X86_64
#define FMTSZ "l"
#define FMTPD "l"
#else
#define FMTSZ ""
#define FMTPD ""
#endif
#elif defined(__linux__) \
|| (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
|| (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
|| (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
/* BSD/Darwin, Linux */
#define FMTSZ "z"
#define FMTPD "t"
#else
/* Systems with a pre-C99 libc */
#define FMTSZ "Z"
#ifdef VM_X86_64
#define FMTPD "l"
#else
#define FMTPD ""
#endif
#endif
#ifdef VM_X86_64
#define FMT64 "l"
#elif defined(sun) || defined(__APPLE__) || defined(__FreeBSD__)
#define FMT64 "ll"
#else
#define FMT64 "L"
#endif
#else
#error - Need compiler define for FMT64 and FMTSZ
#endif
/*
* Suffix for 64-bit constants. Use it like this:
* CONST64(0x7fffffffffffffff) for signed or
* CONST64U(0x7fffffffffffffff) for unsigned.
*
* 2004.08.30(thutt):
* The vmcore/asm64/gen* programs are compiled as 32-bit
* applications, but must handle 64 bit constants. If the
* 64-bit-constant defining macros are already defined, the
* definition will not be overwritten.
*/
#if !defined(CONST64) || !defined(CONST64U)
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
#define CONST64U(c) c##uL
#else
#define CONST64(c) c##LL
#define CONST64U(c) c##uLL
#endif
#else
#error - Need compiler define for CONST64
#endif
#endif
/*
* Use CONST3264/CONST3264U if you want a constant to be
* treated as a 32-bit number on 32-bit compiles and
* a 64-bit number on 64-bit compiles. Useful in the case
* of shifts, like (CONST3264U(1) << x), where x could be
* more than 31 on a 64-bit compile.
*/
#ifdef VM_X86_64
#define CONST3264(a) CONST64(a)
#define CONST3264U(a) CONST64U(a)
#else
#define CONST3264(a) (a)
#define CONST3264U(a) (a)
#endif
#define MIN_INT32 ((int32)0x80000000)
#define MAX_INT32 ((int32)0x7fffffff)
#define MIN_UINT32 ((uint32)0)
#define MAX_UINT32 ((uint32)0xffffffff)
#define MIN_INT64 (CONST64(0x8000000000000000))
#define MAX_INT64 (CONST64(0x7fffffffffffffff))
#define MIN_UINT64 (CONST64U(0))
#define MAX_UINT64 (CONST64U(0xffffffffffffffff))
typedef uint8 *TCA; /* Pointer into TC (usually). */
/*
* Type big enough to hold an integer between 0..100
*/
typedef uint8 Percent;
#define AsPercent(v) ((Percent)(v))
#define CHOOSE_PERCENT AsPercent(101)
typedef uintptr_t VA;
typedef uintptr_t VPN;
typedef uint64 PA;
typedef uint32 PPN;
typedef uint64 PhysMemOff;
typedef uint64 PhysMemSize;
/* The Xserver source compiles with -ansi -pendantic */
#ifndef __STRICT_ANSI__
typedef uint64 BA;
#endif
typedef uint32 BPN;
typedef uint32 PageNum;
typedef unsigned MemHandle;
typedef int32 World_ID;
#define INVALID_WORLD_ID ((World_ID)0)
typedef World_ID User_CartelID;
#define INVALID_CARTEL_ID INVALID_WORLD_ID
typedef User_CartelID User_SessionID;
#define INVALID_SESSION_ID INVALID_CARTEL_ID
typedef User_CartelID User_CartelGroupID;
#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID
typedef uint32 Worldlet_ID;
#define INVALID_WORLDLET_ID ((Worldlet_ID)0)
/* world page number */
typedef uint32 WPN;
/* The Xserver source compiles with -ansi -pendantic */
#ifndef __STRICT_ANSI__
typedef uint64 MA;
typedef uint32 MPN;
#endif
/*
* This type should be used for variables that contain sector
* position/quantity.
*/
typedef uint64 SectorType;
/*
* Linear address
*/
typedef uintptr_t LA;
typedef uintptr_t LPN;
#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT)
#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT)
#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1)
#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1)
#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1)
/* Valid bits in a LPN. */
#define LPN_MASK LAST_LPN
#define LPN_MASK32 LAST_LPN32
#define LPN_MASK64 LAST_LPN64
/*
* On 64 bit platform, address and page number types default
* to 64 bit. When we need to represent a 32 bit address, we use
* types defined below.
*
* On 32 bit platform, the following types are the same as the
* default types.
*/
typedef uint32 VA32;
typedef uint32 VPN32;
typedef uint32 LA32;
typedef uint32 LPN32;
typedef uint32 PA32;
typedef uint32 PPN32;
typedef uint32 MA32;
typedef uint32 MPN32;
/*
* On 64 bit platform, the following types are the same as the
* default types.
*/
typedef uint64 VA64;
typedef uint64 VPN64;
typedef uint64 LA64;
typedef uint64 LPN64;
typedef uint64 PA64;
typedef uint64 PPN64;
typedef uint64 MA64;
typedef uint64 MPN64;
/*
* VA typedefs for user world apps.
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
typedef UserVA32 UserVA;
#else
typedef void * UserVA;
#endif
/*
* Maximal possible PPN value (errors too) that PhysMem can handle.
* Must be at least as large as MAX_PPN which is the maximum PPN
* for any region other than buserror.
*/
#define PHYSMEM_MAX_PPN ((PPN)0xffffffff)
#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */
#define INVALID_PPN ((PPN)0xffffffff)
#define INVALID_BPN ((BPN) 0x1fffffff)
#define INVALID_MPN ((MPN)-1)
#define MEMREF_MPN ((MPN)-2)
#define RESERVED_MPN ((MPN) 0)
/* Support 43 bits of address space. */
#define MAX_MPN ((MPN)0x7fffffff)
#define INVALID_LPN ((LPN)-1)
#define INVALID_VPN ((VPN)-1)
#define INVALID_LPN64 ((LPN64)-1)
#define INVALID_PAGENUM ((PageNum)-1)
#define INVALID_WPN ((WPN) -1)
/*
* Format modifier for printing VA, LA, and VPN.
* Use them like this: Log("%#"FMTLA"x\n", laddr)
*/
#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__
# define FMTLA "l"
# define FMTVA "l"
# define FMTVPN "l"
#else
# define FMTLA ""
# define FMTVA ""
# define FMTVPN ""
#endif
#define EXTERN extern
#define CONST const
#ifndef INLINE
# ifdef _MSC_VER
# define INLINE __inline
# else
# define INLINE inline
# endif
#endif
/*
* Annotation for data that may be exported into a DLL and used by other
* apps that load that DLL and import the data.
*/
#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA)
# define VMX86_EXTERN_DATA extern __declspec(dllimport)
#else // !_WIN32
# define VMX86_EXTERN_DATA extern
#endif
#if defined(_WIN32) && !defined(VMX86_NO_THREADS)
#define THREADSPECIFIC __declspec(thread)
#else
#define THREADSPECIFIC
#endif
/*
* Due to the wonderful "registry redirection" feature introduced in
* 64-bit Windows, if you access any key under HKLM\Software in 64-bit
* code, you need to open/create/delete that key with
* VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code.
*/
#ifdef _WIN32
#ifdef _WIN64
#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY
#else
#define VMW_KEY_WOW64_32KEY 0x0
#endif
#endif
/*
* Consider the following reasons functions are inlined:
*
* 1) inlined for performance reasons
* 2) inlined because it's a single-use function
*
* Functions which meet only condition 2 should be marked with this
* inline macro; It is not critical to be inlined (but there is a
* code-space & runtime savings by doing so), so when other callers
* are added the inline-ness should be removed.
*/
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
/*
* Starting at version 3.3, gcc does not always inline functions marked
* 'inline' (it depends on their size). To force gcc to do so, one must use the
* extra __always_inline__ attribute.
*/
# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__))
# if defined(VMM) \
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1))
# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \
monitor size change?)
# endif
#else
# define INLINE_SINGLE_CALLER INLINE
#endif
/*
* Used when a hard guaranteed of no inlining is needed. Very few
* instances need this since the absence of INLINE is a good hint
* that gcc will not do inlining.
*/
#if defined(__GNUC__) && defined(VMM)
#define ABSOLUTELY_NOINLINE __attribute__((__noinline__))
#endif
/*
* Attributes placed on function declarations to tell the compiler
* that the function never returns.
*/
#ifdef _MSC_VER
#define NORETURN __declspec(noreturn)
#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
#define NORETURN __attribute__((__noreturn__))
#else
#define NORETURN
#endif
/*
* GCC 3.2 inline asm needs the + constraint for input/ouput memory operands.
* Older GCCs don't know about it --hpreg
*/
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
# define VM_ASM_PLUS 1
#else
# define VM_ASM_PLUS 0
#endif
/*
* Branch prediction hints:
* LIKELY(exp) - Expression exp is likely TRUE.
* UNLIKELY(exp) - Expression exp is likely FALSE.
* Usage example:
* if (LIKELY(excCode == EXC_NONE)) {
* or
* if (UNLIKELY(REAL_MODE(vc))) {
*
* We know how to predict branches on gcc3 and later (hopefully),
* all others we don't so we do nothing.
*/
#if (__GNUC__ >= 3)
/*
* gcc3 uses __builtin_expect() to inform the compiler of an expected value.
* We use this to inform the static branch predictor. The '!!' in LIKELY
* will convert any !=0 to a 1.
*/
#define LIKELY(_exp) __builtin_expect(!!(_exp), 1)
#define UNLIKELY(_exp) __builtin_expect((_exp), 0)
#else
#define LIKELY(_exp) (_exp)
#define UNLIKELY(_exp) (_exp)
#endif
/*
* GCC's argument checking for printf-like functions
* This is conditional until we have replaced all `"%x", void *'
* with `"0x%08x", (uint32) void *'. Note that %p prints different things
* on different platforms. Argument checking is enabled for the
* vmkernel, which has already been cleansed.
*
* fmtPos is the position of the format string argument, beginning at 1
* varPos is the position of the variable argument, beginning at 1
*/
#if defined(__GNUC__)
# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
#else
# define PRINTF_DECL(fmtPos, varPos)
#endif
#if defined(__GNUC__)
# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
#else
# define SCANF_DECL(fmtPos, varPos)
#endif
/*
* UNUSED_PARAM should surround the parameter name and type declaration,
* e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))"
*
*/
#ifndef UNUSED_PARAM
# if defined(__GNUC__)
# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__))
# else
# define UNUSED_PARAM(_parm) _parm
# endif
#endif
/*
* REGPARM defaults to REGPARM3, i.e., a requent that gcc
* puts the first three arguments in registers. (It is fine
* if the function has fewer than three args.) Gcc only.
* Syntactically, put REGPARM where you'd put INLINE or NORETURN.
*/
#if defined(__GNUC__)
# define REGPARM0 __attribute__((regparm(0)))
# define REGPARM1 __attribute__((regparm(1)))
# define REGPARM2 __attribute__((regparm(2)))
# define REGPARM3 __attribute__((regparm(3)))
# define REGPARM REGPARM3
#else
# define REGPARM0
# define REGPARM1
# define REGPARM2
# define REGPARM3
# define REGPARM
#endif
/*
* ALIGNED specifies minimum alignment in "n" bytes.
*/
#ifdef __GNUC__
#define ALIGNED(n) __attribute__((__aligned__(n)))
#else
#define ALIGNED(n)
#endif
/*
***********************************************************************
* STRUCT_OFFSET_CHECK -- */ /**
*
* \brief Check if the actual offsef of a member in a structure
* is what is expected
*
*
* \param[in] STRUCT Structure the member is a part of.
* \param[in] MEMBER Member to check the offset of.
* \param[in] OFFSET Expected offset of MEMBER in STRUCTURE.
* \param[in] DEBUG_EXTRA Additional bytes to be added to OFFSET to
* compensate for extra info in debug builds.
*
***********************************************************************
*/
#ifdef VMX86_DEBUG
#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == (OFFSET + DEBUG_EXTRA))
#else
#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == OFFSET)
#endif
/*
***********************************************************************
* STRUCT_SIZE_CHECK -- */ /**
*
* \brief Check if the actual size of a structure is what is expected
*
*
* \param[in] STRUCT Structure whose size is to be checked.
* \param[in] SIZE Expected size of STRUCT.
* \param[in] DEBUG_EXTRA Additional bytes to be added to SIZE to
* compensate for extra info in debug builds.
*
***********************************************************************
*/
#ifdef VMX86_DEBUG
#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
ASSERT_ON_COMPILE(sizeof(STRUCT) == (SIZE + DEBUG_EXTRA))
#else
#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
ASSERT_ON_COMPILE(sizeof(STRUCT) == SIZE)
#endif
/*
* __func__ is a stringified function name that is part of the C99 standard. The block
* below defines __func__ on older systems where the compiler does not support that
* macro.
*/
#if defined(__GNUC__) \
&& ((__GNUC__ == 2 && __GNUC_MINOR < 96) \
|| (__GNUC__ < 2))
# define __func__ __FUNCTION__
#endif
/*
* Once upon a time, this was used to silence compiler warnings that
* get generated when the compiler thinks that a function returns
* when it is marked noreturn. Don't do it. Use NOT_REACHED().
*/
#define INFINITE_LOOP() do { } while (1)
/*
* On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
* is defined. Use the same logic here so we don't define it twice. [greg]
*/
#ifdef __FreeBSD__
# ifdef _BSD_SIZE_T_
# undef _BSD_SIZE_T_
# ifdef VM_I386
# ifdef VM_X86_64
typedef uint64 size_t;
# else
typedef uint32 size_t;
# endif
# endif /* VM_I386 */
# endif
# ifdef _BSD_SSIZE_T_
# undef _BSD_SSIZE_T_
# define _SSIZE_T
# define __ssize_t_defined
# define _SSIZE_T_DECLARED
# ifdef VM_I386
# ifdef VM_X86_64
typedef int64 ssize_t;
# else
typedef int32 ssize_t;
# endif
# endif /* VM_I386 */
# endif
#else
# ifndef _SIZE_T
# define _SIZE_T
# ifdef VM_I386
# ifdef VM_X86_64
typedef uint64 size_t;
# else
typedef uint32 size_t;
# endif
# endif /* VM_I386 */
# endif
# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \
!defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)
# define _SSIZE_T
# define __ssize_t_defined
# define _SSIZE_T_DECLARED
# ifdef VM_I386
# ifdef VM_X86_64
typedef int64 ssize_t;
# else
typedef int32 ssize_t;
# endif
# endif /* VM_I386 */
# endif
#endif
/*
* Format modifier for printing pid_t. On sun the pid_t is a ulong, but on
* Linux it's an int.
* Use this like this: printf("The pid is %"FMTPID".\n", pid);
*/
#ifdef sun
# ifdef VM_X86_64
# define FMTPID "d"
# else
# define FMTPID "lu"
# endif
#else
# define FMTPID "d"
#endif
/*
* Format modifier for printing uid_t. On sun the uid_t is a ulong, but on
* Linux it's an int.
* Use this like this: printf("The uid is %"FMTUID".\n", uid);
*/
#ifdef sun
# ifdef VM_X86_64
# define FMTUID "u"
# else
# define FMTUID "lu"
# endif
#else
# define FMTUID "u"
#endif
/*
* Format modifier for printing mode_t. On sun the mode_t is a ulong, but on
* Linux it's an int.
* Use this like this: printf("The mode is %"FMTMODE".\n", mode);
*/
#ifdef sun
# ifdef VM_X86_64
# define FMTMODE "o"
# else
# define FMTMODE "lo"
# endif
#else
# define FMTMODE "o"
#endif
/*
* Format modifier for printing time_t. Most platforms define a time_t to be
* a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
* size quantity. Refer to the definition of FMTSZ to see why we need silly
* preprocessor arithmetic.
* Use this like this: printf("The mode is %"FMTTIME".\n", time);
*/
#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
# define FMTTIME FMTSZ"d"
#else
# define FMTTIME "ld"
#endif
/*
* Define MXSemaHandle here so both vmmon and vmx see this definition.
*/
#ifdef _WIN32
typedef uintptr_t MXSemaHandle;
#else
typedef int MXSemaHandle;
#endif
/*
* Define type for poll device handles.
*/
#ifdef _WIN32
typedef uintptr_t PollDevHandle;
#else
typedef int PollDevHandle;
#endif
/*
* Define the utf16_t type.
*/
#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED)
typedef wchar_t utf16_t;
#else
typedef uint16 utf16_t;
#endif
#endif /* _VM_BASIC_TYPES_H_ */
vmxnet3-only/vm_device_version.h 0000444 0000000 0000000 00000016114 12025727027 016023 0 ustar root root /*********************************************************
* Copyright (C) 1998 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef VM_DEVICE_VERSION_H
#define VM_DEVICE_VERSION_H
#define INCLUDE_ALLOW_USERLEVEL
#define INCLUDE_ALLOW_VMMEXT
#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_VMKERNEL
#define INCLUDE_ALLOW_VMCORE
#include "includeCheck.h"
#ifdef _WIN32
#include "guiddef.h"
#endif
/* Our own PCI IDs
* VMware SVGA II (Unified VGA)
* VMware SVGA (PCI Accelerator)
* VMware vmxnet (Idealized NIC)
* VMware vmxscsi (Abortive idealized SCSI controller)
* VMware chipset (Subsystem ID for our motherboards)
* VMware e1000 (Subsystem ID)
* VMware vmxnet3 (Uniform Pass Through NIC)
*/
#define PCI_VENDOR_ID_VMWARE 0x15AD
#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
#define PCI_DEVICE_ID_VMWARE_NET 0x0720
#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976
#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */
#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */
#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770
#define PCI_DEVICE_ID_VMWARE_1394 0x0780
#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790
#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0
#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
/* The hypervisor device might grow. Please leave room
* for 7 more subfunctions.
*/
#define PCI_DEVICE_ID_VMWARE_HYPER 0x0800
#define PCI_DEVICE_ID_VMWARE_VMI 0x0801
#define PCI_DEVICE_VMI_CLASS 0x05
#define PCI_DEVICE_VMI_SUBCLASS 0x80
#define PCI_DEVICE_VMI_INTERFACE 0x00
#define PCI_DEVICE_VMI_REVISION 0x01
/* From linux/pci_ids.h:
* AMD Lance Ethernet controller
* BusLogic SCSI controller
* Ensoniq ES1371 sound controller
*/
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_VLANCE 0x2000
#define PCI_VENDOR_ID_BUSLOGIC 0x104B
#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
#define PCI_VENDOR_ID_ENSONIQ 0x1274
#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
/* From linux/pci_ids.h:
* Intel 82439TX (430 HX North Bridge)
* Intel 82371AB (PIIX4 South Bridge)
* Intel 82443BX (440 BX North Bridge and AGP Bridge)
* Intel 82545EM (e1000, server adapter, single port)
* Intel 82546EB (e1000, server adapter, dual port)
*/
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_82443BX 0x7190
#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */
#define PCI_DEVICE_ID_INTEL_82545EM 0x100f
#define PCI_DEVICE_ID_INTEL_82546EB 0x1010
/************* Strings for IDE Identity Fields **************************/
#define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */
#define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */
/* No longer than 40 Bytes */
#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive"
#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive"
#define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */
#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */
#define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */
#define IDE_NUM_INTERFACES 2 /* support for two interfaces */
#define IDE_DRIVES_PER_IF 2
/************* Strings for SCSI Identity Fields **************************/
#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive"
#define SCSI_DISK_VENDOR_NAME COMPANY_NAME
#define SCSI_DISK_REV_LEVEL "1.0"
#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive"
#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME
#define SCSI_CDROM_REV_LEVEL "1.0"
/************* SCSI implementation limits ********************************/
#define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering
#define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16
#define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS
#define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1)
#define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2)
/************* Strings for the VESA BIOS Identity Fields *****************/
#define VBE_OEM_STRING COMPANY_NAME " SVGA"
#define VBE_VENDOR_NAME COMPANY_NAME
#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME
/************* PCI implementation limits ********************************/
#define PCI_MAX_BRIDGES 15
/************* Ethernet implementation limits ***************************/
#define MAX_ETHERNET_CARDS 10
/************* PCI Passthrough implementation limits ********************/
#define MAX_PCI_PASSTHRU_DEVICES 2
/************* USB implementation limits ********************************/
#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127
/************* Strings for Host USB Driver *******************************/
#ifdef _WIN32
/*
* Globally unique ID for the VMware device interface. Define INITGUID before including
* this header file to instantiate the variable.
*/
DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES,
0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65);
/*
* Globally unique ID for the VMware device setup class.
*/
DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES,
0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56);
/*
* This string defines the device ID string of a VMware USB device.
* The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the
* hexadecimal representations of the vendor and product ids, respectively.
*
* The official vendor ID for VMware, Inc. is 0x0E0F.
* The product id for USB generic devices is 0x0001.
*/
#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001"
#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR))
#ifdef UNICODE
#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices"
#define USB_PNP_DRIVER_NAME L"vmusb"
#else
#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices"
#define USB_PNP_DRIVER_NAME "vmusb"
#endif
#endif
#endif /* VM_DEVICE_VERSION_H */
vmxnet3-only/vmware_pack_init.h 0000444 0000000 0000000 00000003644 12025727027 015643 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __VMWARE_PACK_INIT_H__
# define __VMWARE_PACK_INIT_H__
/*
* vmware_pack_init.h --
*
* Platform-independent code to make the compiler pack (i.e. have them
* occupy the smallest possible space) structure definitions. The following
* constructs are known to work --hpreg
*
* #include "vmware_pack_begin.h"
* struct foo {
* ...
* }
* #include "vmware_pack_end.h"
* ;
*
* typedef
* #include "vmware_pack_begin.h"
* struct foo {
* ...
* }
* #include "vmware_pack_end.h"
* foo;
*/
#ifdef _MSC_VER
/*
* MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is
* not balanced within 1 included file. That is annoying because our scheme
* is based on the pairing being balanced between 2 included files.
*
* So we disable this warning, but this is safe because the compiler will also
* emit warning 4161 when there is more pops than pushes within 1 main
* file --hpreg
*/
# pragma warning(disable:4103)
#elif __GNUC__
#else
# error Compiler packing...
#endif
#endif /* __VMWARE_PACK_INIT_H__ */
vmxnet3-only/vmware_pack_begin.h 0000444 0000000 0000000 00000002444 12025727027 015761 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmware_pack_begin.h --
*
* Begin of structure packing. See vmware_pack_init.h for details.
*
* Note that we do not use the following construct in this include file,
* because we want to emit the code every time the file is included --hpreg
*
* #ifndef foo
* # define foo
* ...
* #endif
*
*/
#include "vmware_pack_init.h"
#ifdef _MSC_VER
# pragma pack(push, 1)
#elif __GNUC__
#else
# error Compiler packing...
#endif
vmxnet3-only/vmware_pack_end.h 0000444 0000000 0000000 00000002470 12025727027 015442 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmware_pack_end.h --
*
* End of structure packing. See vmware_pack_init.h for details.
*
* Note that we do not use the following construct in this include file,
* because we want to emit the code every time the file is included --hpreg
*
* #ifndef foo
* # define foo
* ...
* #endif
*
*/
#include "vmware_pack_init.h"
#ifdef _MSC_VER
# pragma pack(pop)
#elif __GNUC__
__attribute__((__packed__))
#else
# error Compiler packing...
#endif
vmxnet3-only/vmnet_def.h 0000444 0000000 0000000 00000006154 12025727027 014267 0 ustar root root /*********************************************************
* Copyright (C) 2004 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmnet_def.h
*
* - definitions which are (mostly) not vmxnet or vlance specific
*/
#ifndef _VMNET_DEF_H_
#define _VMNET_DEF_H_
#define INCLUDE_ALLOW_USERLEVEL
#define INCLUDE_ALLOW_VMMEXT
#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_VMK_MODULE
#define INCLUDE_ALLOW_VMKERNEL
#define INCLUDE_ALLOW_DISTRIBUTE
#define INCLUDE_ALLOW_VMNIXMOD
#include "includeCheck.h"
/*
* capabilities - not all of these are implemented in the virtual HW
* (eg VLAN support is in the virtual switch) so even vlance
* can use them
*/
#define VMNET_CAP_SG 0x0001 /* Can do scatter-gather transmits. */
#define VMNET_CAP_IP4_CSUM 0x0002 /* Can checksum only TCP/UDP over IPv4. */
#define VMNET_CAP_HW_CSUM 0x0004 /* Can checksum all packets. */
#define VMNET_CAP_HIGH_DMA 0x0008 /* Can DMA to high memory. */
#define VMNET_CAP_TOE 0x0010 /* Supports TCP/IP offload. */
#define VMNET_CAP_TSO 0x0020 /* Supports TCP Segmentation offload */
#define VMNET_CAP_SW_TSO 0x0040 /* Supports SW TCP Segmentation */
#define VMNET_CAP_VMXNET_APROM 0x0080 /* Vmxnet APROM support */
#define VMNET_CAP_HW_TX_VLAN 0x0100 /* Can we do VLAN tagging in HW */
#define VMNET_CAP_HW_RX_VLAN 0x0200 /* Can we do VLAN untagging in HW */
#define VMNET_CAP_SW_VLAN 0x0400 /* Can we do VLAN tagging/untagging in SW */
#define VMNET_CAP_WAKE_PCKT_RCV 0x0800 /* Can wake on network packet recv? */
#define VMNET_CAP_ENABLE_INT_INLINE 0x1000 /* Enable Interrupt Inline */
#define VMNET_CAP_ENABLE_HEADER_COPY 0x2000 /* copy header for vmkernel */
#define VMNET_CAP_TX_CHAIN 0x4000 /* Guest can use multiple tx entries for a pkt */
#define VMNET_CAP_RX_CHAIN 0x8000 /* a pkt can span multiple rx entries */
#define VMNET_CAP_LPD 0x10000 /* large pkt delivery */
#define VMNET_CAP_BPF 0x20000 /* BPF Support in VMXNET Virtual Hardware */
#define VMNET_CAP_SG_SPAN_PAGES 0x40000 /* Can do scatter-gather span multiple pages transmits. */
#define VMNET_CAP_IP6_CSUM 0x80000 /* Can do IPv6 csum offload. */
#define VMNET_CAP_TSO6 0x100000 /* Can do TSO segmentation offload for IPv6 pkts. */
#define VMNET_CAP_TSO256k 0x200000 /* Can do TSO segmentation offload for pkts up to 256kB. */
#endif // _VMNET_DEF_H_
vmxnet3-only/includeCheck.h 0000444 0000000 0000000 00000010246 12025727027 014676 0 ustar root root /*********************************************************
* Copyright (C) 1998 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* includeCheck.h --
*
* Restrict include file use.
*
* In every .h file, define one or more of these
*
* INCLUDE_ALLOW_VMX
* INCLUDE_ALLOW_USERLEVEL
* INCLUDE_ALLOW_VMMEXT
* INCLUDE_ALLOW_VMCORE
* INCLUDE_ALLOW_MODULE
* INCLUDE_ALLOW_VMNIXMOD
* INCLUDE_ALLOW_VMKERNEL
* INCLUDE_ALLOW_DISTRIBUTE
* INCLUDE_ALLOW_VMK_MODULE
* INCLUDE_ALLOW_VMKDRIVERS
* INCLUDE_ALLOW_VMIROM
*
* Then include this file.
*
* Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially
* be distributed in source form along with GPLed code. Ensure
* that this is acceptable.
*/
/*
* Declare a VMCORE-only variable to help classify object
* files. The variable goes in the common block and does
* not create multiple definition link-time conflicts.
*/
#if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \
defined linux && !defined MODULE && \
!defined COMPILED_WITH_VMCORE
#define COMPILED_WITH_VMCORE compiled_with_vmcore
#ifdef ASM
.comm compiled_with_vmcore, 0
#else
asm(".comm compiled_with_vmcore, 0");
#endif /* ASM */
#endif
#if defined VMCORE && \
!(defined VMX86_VMX || defined VMM || \
defined MONITOR_APP || defined VMMON)
#error "Makefile problem: VMCORE without VMX86_VMX or \
VMM or MONITOR_APP or MODULE."
#endif
#if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE
#error "The surrounding include file is not allowed in vmcore."
#endif
#undef INCLUDE_ALLOW_VMCORE
#if defined VMX86_VMX && !defined VMCORE && \
!(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL)
#error "The surrounding include file is not allowed in the VMX."
#endif
#undef INCLUDE_ALLOW_VMX
#if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \
!defined INCLUDE_ALLOW_USERLEVEL
#error "The surrounding include file is not allowed at userlevel."
#endif
#undef INCLUDE_ALLOW_USERLEVEL
#if defined VMM && !defined VMCORE && \
!defined INCLUDE_ALLOW_VMMEXT
#error "The surrounding include file is not allowed in the monitor."
#endif
#undef INCLUDE_ALLOW_VMMEXT
#if defined MODULE && !defined VMKERNEL_MODULE && !defined VMNIXMOD && \
!defined VMMON && !defined INCLUDE_ALLOW_MODULE
#error "The surrounding include file is not allowed in driver modules."
#endif
#undef INCLUDE_ALLOW_MODULE
#if defined VMMON && !defined INCLUDE_ALLOW_VMMON
#error "The surrounding include file is not allowed in vmmon."
#endif
#undef INCLUDE_ALLOW_VMMON
#if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL
#error "The surrounding include file is not allowed in the vmkernel."
#endif
#undef INCLUDE_ALLOW_VMKERNEL
#if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE
#error "The surrounding include file is not allowed in GPL code."
#endif
#undef INCLUDE_ALLOW_DISTRIBUTE
#if defined VMKERNEL_MODULE && !defined VMKERNEL && \
!defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS
#error "The surrounding include file is not allowed in vmkernel modules."
#endif
#undef INCLUDE_ALLOW_VMK_MODULE
#undef INCLUDE_ALLOW_VMKDRIVERS
#if defined VMNIXMOD && !defined INCLUDE_ALLOW_VMNIXMOD
#ifndef VMNIXMOD_VM
#error "The surrounding include file is not allowed in vmnixmod."
#endif
#endif
#undef INCLUDE_ALLOW_VMNIXMOD
#if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM
#error "The surrounding include file is not allowed in vmirom."
#endif
#undef INCLUDE_ALLOW_VMIROM
vmxnet3-only/vmxnet3_defs.h 0000444 0000000 0000000 00000043057 12025727027 014730 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmxnet3_defs.h --
*
* Definitions shared by device emulation and guest drivers for
* VMXNET3 NIC
*/
#ifndef _VMXNET3_DEFS_H_
#define _VMXNET3_DEFS_H_
#define INCLUDE_ALLOW_USERLEVEL
#define INCLUDE_ALLOW_VMKERNEL
#define INCLUDE_ALLOW_VMMEXT
#define INCLUDE_ALLOW_VMCORE
#define INCLUDE_ALLOW_MODULE
#include "includeCheck.h"
#include "upt1_defs.h"
/* all registers are 32 bit wide */
/* BAR 1 */
#define VMXNET3_REG_VRRS 0x0 /* Vmxnet3 Revision Report Selection */
#define VMXNET3_REG_UVRS 0x8 /* UPT Version Report Selection */
#define VMXNET3_REG_DSAL 0x10 /* Driver Shared Address Low */
#define VMXNET3_REG_DSAH 0x18 /* Driver Shared Address High */
#define VMXNET3_REG_CMD 0x20 /* Command */
#define VMXNET3_REG_MACL 0x28 /* MAC Address Low */
#define VMXNET3_REG_MACH 0x30 /* MAC Address High */
#define VMXNET3_REG_ICR 0x38 /* Interrupt Cause Register */
#define VMXNET3_REG_ECR 0x40 /* Event Cause Register */
/* BAR 0 */
#define VMXNET3_REG_IMR 0x0 /* Interrupt Mask Register */
#define VMXNET3_REG_TXPROD 0x600 /* Tx Producer Index */
#define VMXNET3_REG_RXPROD 0x800 /* Rx Producer Index for ring 1 */
#define VMXNET3_REG_RXPROD2 0xA00 /* Rx Producer Index for ring 2 */
#define VMXNET3_PT_REG_SIZE 4096 /* BAR 0 */
#define VMXNET3_VD_REG_SIZE 4096 /* BAR 1 */
#define VMXNET3_REG_ALIGN 8 /* All registers are 8-byte aligned. */
#define VMXNET3_REG_ALIGN_MASK 0x7
/* I/O Mapped access to registers */
#define VMXNET3_IO_TYPE_PT 0
#define VMXNET3_IO_TYPE_VD 1
#define VMXNET3_IO_ADDR(type, reg) (((type) << 24) | ((reg) & 0xFFFFFF))
#define VMXNET3_IO_TYPE(addr) ((addr) >> 24)
#define VMXNET3_IO_REG(addr) ((addr) & 0xFFFFFF)
typedef enum {
VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET,
VMXNET3_CMD_QUIESCE_DEV,
VMXNET3_CMD_RESET_DEV,
VMXNET3_CMD_UPDATE_RX_MODE,
VMXNET3_CMD_UPDATE_MAC_FILTERS,
VMXNET3_CMD_UPDATE_VLAN_FILTERS,
VMXNET3_CMD_UPDATE_RSSIDT,
VMXNET3_CMD_UPDATE_IML,
VMXNET3_CMD_UPDATE_PMCFG,
VMXNET3_CMD_UPDATE_FEATURE,
VMXNET3_CMD_FIRST_GET = 0xF00D0000,
VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
VMXNET3_CMD_GET_STATS,
VMXNET3_CMD_GET_LINK,
VMXNET3_CMD_GET_PERM_MAC_LO,
VMXNET3_CMD_GET_PERM_MAC_HI,
VMXNET3_CMD_GET_DID_LO,
VMXNET3_CMD_GET_DID_HI,
VMXNET3_CMD_GET_DEV_EXTRA_INFO,
VMXNET3_CMD_GET_CONF_INTR
} Vmxnet3_Cmd;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_TxDesc {
uint64 addr;
uint32 len:14;
uint32 gen:1; /* generation bit */
uint32 rsvd:1;
uint32 dtype:1; /* descriptor type */
uint32 ext1:1;
uint32 msscof:14; /* MSS, checksum offset, flags */
uint32 hlen:10; /* header len */
uint32 om:2; /* offload mode */
uint32 eop:1; /* End Of Packet */
uint32 cq:1; /* completion request */
uint32 ext2:1;
uint32 ti:1; /* VLAN Tag Insertion */
uint32 tci:16; /* Tag to Insert */
}
#include "vmware_pack_end.h"
Vmxnet3_TxDesc;
/* TxDesc.OM values */
#define VMXNET3_OM_NONE 0
#define VMXNET3_OM_CSUM 2
#define VMXNET3_OM_TSO 3
/* fields in TxDesc we access w/o using bit fields */
#define VMXNET3_TXD_EOP_SHIFT 12
#define VMXNET3_TXD_CQ_SHIFT 13
#define VMXNET3_TXD_GEN_SHIFT 14
#define VMXNET3_TXD_CQ (1 << VMXNET3_TXD_CQ_SHIFT)
#define VMXNET3_TXD_EOP (1 << VMXNET3_TXD_EOP_SHIFT)
#define VMXNET3_TXD_GEN (1 << VMXNET3_TXD_GEN_SHIFT)
#define VMXNET3_HDR_COPY_SIZE 128
typedef
#include "vmware_pack_begin.h"
struct vmxnet3_TxDataDesc {
uint8 data[VMXNET3_HDR_COPY_SIZE];
}
#include "vmware_pack_end.h"
Vmxnet3_TxDataDesc;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_TxCompDesc {
uint32 txdIdx:12; /* Index of the EOP TxDesc */
uint32 ext1:20;
uint32 ext2;
uint32 ext3;
uint32 rsvd:24;
uint32 type:7; /* completion type */
uint32 gen:1; /* generation bit */
}
#include "vmware_pack_end.h"
Vmxnet3_TxCompDesc;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxDesc {
uint64 addr;
uint32 len:14;
uint32 btype:1; /* Buffer Type */
uint32 dtype:1; /* Descriptor type */
uint32 rsvd:15;
uint32 gen:1; /* Generation bit */
uint32 ext1;
}
#include "vmware_pack_end.h"
Vmxnet3_RxDesc;
/* values of RXD.BTYPE */
#define VMXNET3_RXD_BTYPE_HEAD 0 /* head only */
#define VMXNET3_RXD_BTYPE_BODY 1 /* body only */
/* fields in RxDesc we access w/o using bit fields */
#define VMXNET3_RXD_BTYPE_SHIFT 14
#define VMXNET3_RXD_GEN_SHIFT 31
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxCompDesc {
uint32 rxdIdx:12; /* Index of the RxDesc */
uint32 ext1:2;
uint32 eop:1; /* End of Packet */
uint32 sop:1; /* Start of Packet */
uint32 rqID:10; /* rx queue/ring ID */
uint32 rssType:4; /* RSS hash type used */
uint32 cnc:1; /* Checksum Not Calculated */
uint32 ext2:1;
uint32 rssHash; /* RSS hash value */
uint32 len:14; /* data length */
uint32 err:1; /* Error */
uint32 ts:1; /* Tag is stripped */
uint32 tci:16; /* Tag stripped */
uint32 csum:16;
uint32 tuc:1; /* TCP/UDP Checksum Correct */
uint32 udp:1; /* UDP packet */
uint32 tcp:1; /* TCP packet */
uint32 ipc:1; /* IP Checksum Correct */
uint32 v6:1; /* IPv6 */
uint32 v4:1; /* IPv4 */
uint32 frg:1; /* IP Fragment */
uint32 fcs:1; /* Frame CRC correct */
uint32 type:7; /* completion type */
uint32 gen:1; /* generation bit */
}
#include "vmware_pack_end.h"
Vmxnet3_RxCompDesc;
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
#define VMXNET3_RCD_TUC_SHIFT 16
#define VMXNET3_RCD_IPC_SHIFT 19
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
#define VMXNET3_RCD_TYPE_SHIFT 56
#define VMXNET3_RCD_GEN_SHIFT 63
/* csum OK for TCP/UDP pkts over IP */
#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | 1 << VMXNET3_RCD_IPC_SHIFT)
/* value of RxCompDesc.rssType */
#define VMXNET3_RCD_RSS_TYPE_NONE 0
#define VMXNET3_RCD_RSS_TYPE_IPV4 1
#define VMXNET3_RCD_RSS_TYPE_TCPIPV4 2
#define VMXNET3_RCD_RSS_TYPE_IPV6 3
#define VMXNET3_RCD_RSS_TYPE_TCPIPV6 4
/* a union for accessing all cmd/completion descriptors */
typedef union Vmxnet3_GenericDesc {
uint64 qword[2];
uint32 dword[4];
uint16 word[8];
Vmxnet3_TxDesc txd;
Vmxnet3_RxDesc rxd;
Vmxnet3_TxCompDesc tcd;
Vmxnet3_RxCompDesc rcd;
} Vmxnet3_GenericDesc;
#define VMXNET3_INIT_GEN 1
/* Max size of a single tx buffer */
#define VMXNET3_MAX_TX_BUF_SIZE (1 << 14)
/* # of tx desc needed for a tx buffer size */
#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / VMXNET3_MAX_TX_BUF_SIZE)
/* max # of tx descs for a non-tso pkt */
#define VMXNET3_MAX_TXD_PER_PKT 16
/* Max size of a single rx buffer */
#define VMXNET3_MAX_RX_BUF_SIZE ((1 << 14) - 1)
/* Minimum size of a type 0 buffer */
#define VMXNET3_MIN_T0_BUF_SIZE 128
#define VMXNET3_MAX_CSUM_OFFSET 1024
/* Ring base address alignment */
#define VMXNET3_RING_BA_ALIGN 512
#define VMXNET3_RING_BA_MASK (VMXNET3_RING_BA_ALIGN - 1)
/* Ring size must be a multiple of 32 */
#define VMXNET3_RING_SIZE_ALIGN 32
#define VMXNET3_RING_SIZE_MASK (VMXNET3_RING_SIZE_ALIGN - 1)
/* Max ring size */
#define VMXNET3_TX_RING_MAX_SIZE 4096
#define VMXNET3_TC_RING_MAX_SIZE 4096
#define VMXNET3_RX_RING_MAX_SIZE 4096
#define VMXNET3_RC_RING_MAX_SIZE 8192
/* a list of reasons for queue stop */
#define VMXNET3_ERR_NOEOP 0x80000000 /* cannot find the EOP desc of a pkt */
#define VMXNET3_ERR_TXD_REUSE 0x80000001 /* reuse a TxDesc before tx completion */
#define VMXNET3_ERR_BIG_PKT 0x80000002 /* too many TxDesc for a pkt */
#define VMXNET3_ERR_DESC_NOT_SPT 0x80000003 /* descriptor type not supported */
#define VMXNET3_ERR_SMALL_BUF 0x80000004 /* type 0 buffer too small */
#define VMXNET3_ERR_STRESS 0x80000005 /* stress option firing in vmkernel */
#define VMXNET3_ERR_SWITCH 0x80000006 /* mode switch failure */
#define VMXNET3_ERR_TXD_INVALID 0x80000007 /* invalid TxDesc */
/* completion descriptor types */
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
#define VMXNET3_GOS_BITS_UNK 0 /* unknown */
#define VMXNET3_GOS_BITS_32 1
#define VMXNET3_GOS_BITS_64 2
#define VMXNET3_GOS_TYPE_UNK 0 /* unknown */
#define VMXNET3_GOS_TYPE_LINUX 1
#define VMXNET3_GOS_TYPE_WIN 2
#define VMXNET3_GOS_TYPE_SOLARIS 3
#define VMXNET3_GOS_TYPE_FREEBSD 4
#define VMXNET3_GOS_TYPE_PXE 5
/* All structures in DriverShared are padded to multiples of 8 bytes */
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_GOSInfo {
uint32 gosBits: 2; /* 32-bit or 64-bit? */
uint32 gosType: 4; /* which guest */
uint32 gosVer: 16; /* gos version */
uint32 gosMisc: 10; /* other info about gos */
}
#include "vmware_pack_end.h"
Vmxnet3_GOSInfo;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_DriverInfo {
uint32 version; /* driver version */
Vmxnet3_GOSInfo gos;
uint32 vmxnet3RevSpt; /* vmxnet3 revision supported */
uint32 uptVerSpt; /* upt version supported */
}
#include "vmware_pack_end.h"
Vmxnet3_DriverInfo;
#define VMXNET3_REV1_MAGIC 0xbabefee1
/*
* QueueDescPA must be 128 bytes aligned. It points to an array of
* Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
* The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
* Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
*/
#define VMXNET3_QUEUE_DESC_ALIGN 128
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_MiscConf {
Vmxnet3_DriverInfo driverInfo;
uint64 uptFeatures;
uint64 ddPA; /* driver data PA */
uint64 queueDescPA; /* queue descriptor table PA */
uint32 ddLen; /* driver data len */
uint32 queueDescLen; /* queue descriptor table len, in bytes */
uint32 mtu;
uint16 maxNumRxSG;
uint8 numTxQueues;
uint8 numRxQueues;
uint32 reserved[4];
}
#include "vmware_pack_end.h"
Vmxnet3_MiscConf;
typedef
#include "vmware_pack_begin.h"
struct vmxnet3_TxQueueConf {
uint64 txRingBasePA;
uint64 dataRingBasePA;
uint64 compRingBasePA;
uint64 ddPA; /* driver data */
uint64 reserved;
uint32 txRingSize; /* # of tx desc */
uint32 dataRingSize; /* # of data desc */
uint32 compRingSize; /* # of comp desc */
uint32 ddLen; /* size of driver data */
uint8 intrIdx;
uint8 _pad[7];
}
#include "vmware_pack_end.h"
Vmxnet3_TxQueueConf;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxQueueConf {
uint64 rxRingBasePA[2];
uint64 compRingBasePA;
uint64 ddPA; /* driver data */
uint64 reserved;
uint32 rxRingSize[2]; /* # of rx desc */
uint32 compRingSize; /* # of rx comp desc */
uint32 ddLen; /* size of driver data */
uint8 intrIdx;
uint8 _pad[7];
}
#include "vmware_pack_end.h"
Vmxnet3_RxQueueConf;
enum vmxnet3_intr_mask_mode {
VMXNET3_IMM_AUTO = 0,
VMXNET3_IMM_ACTIVE = 1,
VMXNET3_IMM_LAZY = 2
};
enum vmxnet3_intr_type {
VMXNET3_IT_AUTO = 0,
VMXNET3_IT_INTX = 1,
VMXNET3_IT_MSI = 2,
VMXNET3_IT_MSIX = 3
};
#define VMXNET3_MAX_TX_QUEUES 8
#define VMXNET3_MAX_RX_QUEUES 16
/* addition 1 for events */
#define VMXNET3_MAX_INTRS 25
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_IntrConf {
Bool autoMask;
uint8 numIntrs; /* # of interrupts */
uint8 eventIntrIdx;
uint8 modLevels[VMXNET3_MAX_INTRS]; /* moderation level for each intr */
uint32 reserved[3];
}
#include "vmware_pack_end.h"
Vmxnet3_IntrConf;
/* one bit per VLAN ID, the size is in the units of uint32 */
#define VMXNET3_VFT_SIZE (4096 / (sizeof(uint32) * 8))
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_QueueStatus {
Bool stopped;
uint8 _pad[3];
uint32 error;
}
#include "vmware_pack_end.h"
Vmxnet3_QueueStatus;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_TxQueueCtrl {
uint32 txNumDeferred;
uint32 txThreshold;
uint64 reserved;
}
#include "vmware_pack_end.h"
Vmxnet3_TxQueueCtrl;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxQueueCtrl {
Bool updateRxProd;
uint8 _pad[7];
uint64 reserved;
}
#include "vmware_pack_end.h"
Vmxnet3_RxQueueCtrl;
#define VMXNET3_RXM_UCAST 0x01 /* unicast only */
#define VMXNET3_RXM_MCAST 0x02 /* multicast passing the filters */
#define VMXNET3_RXM_BCAST 0x04 /* broadcast only */
#define VMXNET3_RXM_ALL_MULTI 0x08 /* all multicast */
#define VMXNET3_RXM_PROMISC 0x10 /* promiscuous */
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxFilterConf {
uint32 rxMode; /* VMXNET3_RXM_xxx */
uint16 mfTableLen; /* size of the multicast filter table */
uint16 _pad1;
uint64 mfTablePA; /* PA of the multicast filters table */
uint32 vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
}
#include "vmware_pack_end.h"
Vmxnet3_RxFilterConf;
#define VMXNET3_PM_MAX_FILTERS 6
#define VMXNET3_PM_MAX_PATTERN_SIZE 128
#define VMXNET3_PM_MAX_MASK_SIZE (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
#define VMXNET3_PM_WAKEUP_MAGIC 0x01 /* wake up on magic pkts */
#define VMXNET3_PM_WAKEUP_FILTER 0x02 /* wake up on pkts matching filters */
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_PM_PktFilter {
uint8 maskSize;
uint8 patternSize;
uint8 mask[VMXNET3_PM_MAX_MASK_SIZE];
uint8 pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
uint8 pad[6];
}
#include "vmware_pack_end.h"
Vmxnet3_PM_PktFilter;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_PMConf {
uint16 wakeUpEvents; /* VMXNET3_PM_WAKEUP_xxx */
uint8 numFilters;
uint8 pad[5];
Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
}
#include "vmware_pack_end.h"
Vmxnet3_PMConf;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_VariableLenConfDesc {
uint32 confVer;
uint32 confLen;
uint64 confPA;
}
#include "vmware_pack_end.h"
Vmxnet3_VariableLenConfDesc;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_DSDevRead {
/* read-only region for device, read by dev in response to a SET cmd */
Vmxnet3_MiscConf misc;
Vmxnet3_IntrConf intrConf;
Vmxnet3_RxFilterConf rxFilterConf;
Vmxnet3_VariableLenConfDesc rssConfDesc;
Vmxnet3_VariableLenConfDesc pmConfDesc;
uint64 reserved[2];
}
#include "vmware_pack_end.h"
Vmxnet3_DSDevRead;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_TxQueueDesc {
Vmxnet3_TxQueueCtrl ctrl;
Vmxnet3_TxQueueConf conf;
/* Driver read after a GET command */
Vmxnet3_QueueStatus status;
UPT1_TxStats stats;
uint8 _pad[88]; /* 128 aligned */
}
#include "vmware_pack_end.h"
Vmxnet3_TxQueueDesc;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_RxQueueDesc {
Vmxnet3_RxQueueCtrl ctrl;
Vmxnet3_RxQueueConf conf;
/* Driver read after a GET command */
Vmxnet3_QueueStatus status;
UPT1_RxStats stats;
uint8 _pad[88]; /* 128 aligned */
}
#include "vmware_pack_end.h"
Vmxnet3_RxQueueDesc;
typedef
#include "vmware_pack_begin.h"
struct Vmxnet3_DriverShared {
uint32 magic;
uint32 pad; /* make devRead start at 64-bit boundaries */
Vmxnet3_DSDevRead devRead;
uint32 ecr;
uint32 reserved[5];
}
#include "vmware_pack_end.h"
Vmxnet3_DriverShared;
#define VMXNET3_ECR_RQERR (1 << 0)
#define VMXNET3_ECR_TQERR (1 << 1)
#define VMXNET3_ECR_LINK (1 << 2)
#define VMXNET3_ECR_DIC (1 << 3)
#define VMXNET3_ECR_DEBUG (1 << 4)
/* flip the gen bit of a ring */
#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
/* only use this if moving the idx won't affect the gen bit */
#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
do {\
(idx)++;\
if (UNLIKELY((idx) == (ring_size))) {\
(idx) = 0;\
}\
} while (0)
#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
vfTable[vid >> 5] |= (1 << (vid & 31))
#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
vfTable[vid >> 5] &= ~(1 << (vid & 31))
#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
#define VMXNET3_MAX_MTU 9000
#define VMXNET3_MIN_MTU 60
#define VMXNET3_LINK_UP (10000 << 16 | 1) // 10 Gbps, up
#define VMXNET3_LINK_DOWN 0
#endif /* _VMXNET3_DEFS_H_ */
vmxnet3-only/upt1_defs.h 0000444 0000000 0000000 00000011561 12025727027 014210 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/* upt1_defs.h
*
* Definitions for UPTv1
*/
#ifndef _UPT1_DEFS_H
#define _UPT1_DEFS_H
#define UPT1_MAX_TX_QUEUES 64
#define UPT1_MAX_RX_QUEUES 64
#define UPT1_MAX_INTRS (UPT1_MAX_TX_QUEUES + UPT1_MAX_RX_QUEUES)
typedef
#include "vmware_pack_begin.h"
struct UPT1_RingDesc {
uint64 basePA; /* physical addr of the ring */
uint16 size; /* # of descriptors */
uint16 prodIdx; /* index of the descriptor the producer of the ring
* will write to next */
uint16 consIdx; /* index of the descriptor the consumer of the ring
* will read next */
uint16 pad;
}
#include "vmware_pack_end.h"
UPT1_RingDesc;
typedef
#include "vmware_pack_begin.h"
struct UPT1_TxStats {
uint64 TSOPktsTxOK; /* TSO pkts post-segmentation */
uint64 TSOBytesTxOK;
uint64 ucastPktsTxOK;
uint64 ucastBytesTxOK;
uint64 mcastPktsTxOK;
uint64 mcastBytesTxOK;
uint64 bcastPktsTxOK;
uint64 bcastBytesTxOK;
uint64 pktsTxError;
uint64 pktsTxDiscard;
}
#include "vmware_pack_end.h"
UPT1_TxStats;
typedef
#include "vmware_pack_begin.h"
struct UPT1_TxQueueState {
UPT1_RingDesc txRing;
UPT1_RingDesc dataRing;
UPT1_RingDesc compRing;
uint8 tcGen; /* value of the TCGEN register */
uint8 intrIdx; /* which MSI/MSI-X vector to use for the tx queue */
Bool stopped; /* is the queue stopped? */
uint8 pad;
uint32 error; /* error code if the queue is stopped due to error */
UPT1_TxStats stats; /* stats for the tx queue */
}
#include "vmware_pack_end.h"
UPT1_TxQueueState;
typedef
#include "vmware_pack_begin.h"
struct UPT1_RxStats {
uint64 LROPktsRxOK; /* LRO pkts */
uint64 LROBytesRxOK; /* bytes from LRO pkts */
/* the following counters are for pkts from the wire, i.e., pre-LRO */
uint64 ucastPktsRxOK;
uint64 ucastBytesRxOK;
uint64 mcastPktsRxOK;
uint64 mcastBytesRxOK;
uint64 bcastPktsRxOK;
uint64 bcastBytesRxOK;
uint64 pktsRxOutOfBuf;
uint64 pktsRxError;
}
#include "vmware_pack_end.h"
UPT1_RxStats;
typedef
#include "vmware_pack_begin.h"
struct UPT1_RxQueueState {
UPT1_RingDesc rxRing[2];
UPT1_RingDesc compRing;
uint8 rcGen; /* value of the RCGEN register */
uint8 intrIdx; /* which MSI/MSI-X vector to use for the rx queue */
Bool stopped; /* is the queue stopped? */
uint8 pad;
uint32 error; /* error code if the queue is stopped due to error */
UPT1_RxStats stats; /* stats for the rx queue */
}
#include "vmware_pack_end.h"
UPT1_RxQueueState;
/* physical dev intr type */
typedef enum {
UPT1_IT_MSI = 1,
UPT1_IT_MSIX
} UPT1_IntrType;
/* interrupt moderation level */
#define UPT1_IML_NONE 0 /* no interrupt moderation */
#define UPT1_IML_HIGHEST 7 /* least intr generated */
#define UPT1_IML_ADAPTIVE 8 /* adpative intr moderation */
typedef struct UPT1_IntrState {
UPT1_IntrType type;
Bool autoMask;
uint8 numIntrs; /* # of MSI/MSI-X vectors allocated */
uint8 *modLevels; /* interrupt moderation level */
uint8 *imr; /* IMR register values */
} UPT1_IntrState;
/* values for UPT1_RSSConf.hashFunc */
#define UPT1_RSS_HASH_TYPE_NONE 0x0
#define UPT1_RSS_HASH_TYPE_IPV4 0x01
#define UPT1_RSS_HASH_TYPE_TCP_IPV4 0x02
#define UPT1_RSS_HASH_TYPE_IPV6 0x04
#define UPT1_RSS_HASH_TYPE_TCP_IPV6 0x08
#define UPT1_RSS_HASH_FUNC_NONE 0x0
#define UPT1_RSS_HASH_FUNC_TOEPLITZ 0x01
#define UPT1_RSS_MAX_KEY_SIZE 40
#define UPT1_RSS_MAX_IND_TABLE_SIZE 128
typedef
#include "vmware_pack_begin.h"
struct UPT1_RSSConf {
uint16 hashType;
uint16 hashFunc;
uint16 hashKeySize;
uint16 indTableSize;
uint8 hashKey[UPT1_RSS_MAX_KEY_SIZE];
uint8 indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
}
#include "vmware_pack_end.h"
UPT1_RSSConf;
/* features */
#define UPT1_F_RXCSUM 0x0001 /* rx csum verification */
#define UPT1_F_RSS 0x0002
#define UPT1_F_RXVLAN 0x0004 /* VLAN tag stripping */
#define UPT1_F_LRO 0x0008
#endif
vmxnet3-only/compat_ethtool.h 0000444 0000000 0000000 00000003306 12025727027 015335 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef _COMPAT_ETHTOOL_H
#define _COMPAT_ETHTOOL_H
/*
* ethtool is a userspace utility for getting and setting ethernet device
* settings. Kernel support for it was first published in 2.4.0-test11, but
* only in 2.4.15 were the ethtool_value struct and the ETHTOOL_GLINK ioctl
* added to ethtool.h (together, because the ETHTOOL_GLINK ioctl expects a
* single value response).
*
* Likewise, ioctls for getting and setting TSO were published in 2.4.22.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
# include
# ifndef ETHTOOL_GLINK
# define ETHTOOL_GLINK 0x0a
typedef struct {
__u32 cmd;
__u32 data;
} compat_ethtool_value;
# else
typedef struct ethtool_value compat_ethtool_value;
# endif
# ifndef ETHTOOL_GTSO
# define ETHTOOL_GTSO 0x1E
# define ETHTOOL_STSO 0x1F
# endif
#endif
#endif /* _COMPAT_ETHTOOL_H */
vmxnet3-only/compat_init.h 0000444 0000000 0000000 00000002355 12025727027 014625 0 ustar root root /*********************************************************
* Copyright (C) 1999 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* compat_init.h: Initialization compatibility wrappers.
*/
#ifndef __COMPAT_INIT_H__
#define __COMPAT_INIT_H__
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0)
#include
#endif
#ifndef module_init
#define module_init(x) int init_module(void) { return x(); }
#endif
#ifndef module_exit
#define module_exit(x) void cleanup_module(void) { x(); }
#endif
#endif /* __COMPAT_INIT_H__ */
vmxnet3-only/compat_interrupt.h 0000444 0000000 0000000 00000003573 12025727027 015721 0 ustar root root /*********************************************************
* Copyright (C) 2003 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_INTERRUPT_H__
# define __COMPAT_INTERRUPT_H__
#include
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69)
/*
* We cannot just define irqreturn_t, as some 2.4.x kernels have
* typedef void irqreturn_t; for "increasing" backward compatibility.
*/
typedef void compat_irqreturn_t;
#define COMPAT_IRQ_NONE
#define COMPAT_IRQ_HANDLED
#define COMPAT_IRQ_RETVAL(x)
#else
typedef irqreturn_t compat_irqreturn_t;
#define COMPAT_IRQ_NONE IRQ_NONE
#define COMPAT_IRQ_HANDLED IRQ_HANDLED
#define COMPAT_IRQ_RETVAL(x) IRQ_RETVAL(x)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
#define COMPAT_IRQF_DISABLED SA_INTERRUPT
#define COMPAT_IRQF_SHARED SA_SHIRQ
#else
#define COMPAT_IRQF_DISABLED IRQF_DISABLED
#define COMPAT_IRQF_SHARED IRQF_SHARED
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp, struct pt_regs *regs)
#else
#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp)
#endif
#endif /* __COMPAT_INTERRUPT_H__ */
vmxnet3-only/compat_module.h 0000444 0000000 0000000 00000004372 12025727027 015150 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* compat_module.h --
*/
#ifndef __COMPAT_MODULE_H__
# define __COMPAT_MODULE_H__
#include
/*
* Modules wishing to use the GPL license are required to include a
* MODULE_LICENSE definition in their module source as of 2.4.10.
*/
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(license)
#endif
/*
* To make use of our own home-brewed MODULE_INFO, we need macros to
* concatenate two expressions to "__mod_", and and to convert an
* expression into a string. I'm sure we've got these in our codebase,
* but I'd rather not introduce such a dependency in a compat header.
*/
#ifndef __module_cat
#define __module_cat_1(a, b) __mod_ ## a ## b
#define __module_cat(a, b) __module_cat_1(a, b)
#endif
#ifndef __stringify
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
#endif
/*
* MODULE_INFO was born in 2.5.69.
*/
#ifndef MODULE_INFO
#define MODULE_INFO(tag, info) \
static const char __module_cat(tag, __LINE__)[] \
__attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info
#endif
/*
* MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx"
* string to the module's version, but that was removed in 2.6.10, so we'll
* ignore it in our wrapper.
*/
#ifndef MODULE_VERSION
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
#endif
#endif /* __COMPAT_MODULE_H__ */
vmxnet3-only/compat_netdevice.h 0000444 0000000 0000000 00000017671 12025727027 015637 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_NETDEVICE_H__
# define __COMPAT_NETDEVICE_H__
#include
#include
#include
#include
/*
* The enet_statistics structure moved from linux/if_ether.h to
* linux/netdevice.h and is renamed net_device_stats in 2.1.25 --hpreg
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 25)
# include
# define net_device_stats enet_statistics
#endif
/* The netif_rx_ni() API appeared in 2.4.8 --hpreg */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8)
# define netif_rx_ni netif_rx
#endif
/* The device struct was renamed net_device in 2.3.14 --hpreg */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)
# define net_device device
#endif
/*
* SET_MODULE_OWNER appeared sometime during 2.3.x. It was setting
* dev->owner = THIS_MODULE until 2.5.70, where netdevice refcounting
* was completely changed. SET_MODULE_OWNER was nop for whole
* 2.6.x series, and finally disappeared in 2.6.24.
*
* MOD_xxx_USE_COUNT wrappers are here, as they must be mutually
* exclusive with SET_MODULE_OWNER call.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0)
# define COMPAT_NETDEV_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
# define COMPAT_NETDEV_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
#else
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# define COMPAT_SET_MODULE_OWNER(dev) SET_MODULE_OWNER(dev)
# else
# define COMPAT_SET_MODULE_OWNER(dev) do {} while (0)
# endif
# define COMPAT_NETDEV_MOD_INC_USE_COUNT do {} while (0)
# define COMPAT_NETDEV_MOD_DEC_USE_COUNT do {} while (0)
#endif
/*
* SET_NETDEV_DEV appeared sometime during 2.5.x, and later was
* crossported to various 2.4.x kernels (as dummy macro).
*/
#ifdef SET_NETDEV_DEV
# define COMPAT_SET_NETDEV_DEV(dev, pdev) SET_NETDEV_DEV(dev, pdev)
#else
# define COMPAT_SET_NETDEV_DEV(dev, pdev) do {} while (0)
#endif
/*
* Build alloc_etherdev API on the top of init_etherdev. For 2.0.x kernels
* we must provide dummy init method, otherwise register_netdev does
* nothing.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0)
int
vmware_dummy_init(struct net_device *dev)
{
return 0;
}
#endif
static inline struct net_device*
compat_alloc_etherdev(int priv_size)
{
struct net_device* dev;
int size = sizeof *dev + priv_size;
/*
* The name is dynamically allocated before 2.4.0, but
* is an embedded array in later kernels.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
size += sizeof("ethXXXXXXX");
#endif
dev = kmalloc(size, GFP_KERNEL);
if (dev) {
memset(dev, 0, size);
if (priv_size) {
dev->priv = dev + 1;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
dev->name = (char *)(dev + 1) + priv_size;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0)
dev->init = vmware_dummy_init;
#endif
if (init_etherdev(dev, 0) != dev) {
kfree(dev);
dev = NULL;
}
}
return dev;
}
#else
#define compat_alloc_etherdev(sz) alloc_etherdev(sz)
#endif
/*
* alloc_netdev and free_netdev are there since 2.4.23. Their use is mandatory
* since 2.6.24.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)
static inline struct net_device *
compat_alloc_netdev(int priv_size,
const char *mask,
void (*setup)(struct net_device *))
{
struct net_device *dev;
int netdev_size = sizeof *dev;
int alloc_size;
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
netdev_size += IFNAMSIZ;
# endif
alloc_size = netdev_size + priv_size;
dev = kmalloc(alloc_size, GFP_KERNEL);
if (dev) {
memset(dev, 0, alloc_size);
dev->priv = (char*)dev + netdev_size;
setup(dev);
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
dev->name = (char*)(dev + 1);
# endif
strcpy(dev->name, mask);
}
return dev;
}
# define compat_free_netdev(dev) kfree(dev)
#else
# define compat_alloc_netdev(size, mask, setup) alloc_netdev(size, mask, setup)
# define compat_free_netdev(dev) free_netdev(dev)
#endif
/* netdev_priv() appeared in 2.6.3 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)
# define compat_netdev_priv(netdev) (netdev)->priv
#else
# define compat_netdev_priv(netdev) netdev_priv(netdev)
#endif
#if defined(NETDEV_TX_OK)
# define COMPAT_NETDEV_TX_OK NETDEV_TX_OK
# define COMPAT_NETDEV_TX_BUSY NETDEV_TX_BUSY
#else
# define COMPAT_NETDEV_TX_OK 0
# define COMPAT_NETDEV_TX_BUSY 1
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
static inline void
compat_netif_start_queue(struct device *dev)
{
clear_bit(0, &dev->tbusy);
}
static inline void
compat_netif_stop_queue(struct device *dev)
{
set_bit(0, &dev->tbusy);
}
static inline int
compat_netif_queue_stopped(struct device *dev)
{
return test_bit(0, &dev->tbusy);
}
static inline void
compat_netif_wake_queue(struct device *dev)
{
clear_bit(0, &dev->tbusy);
mark_bh(NET_BH);
}
static inline int
compat_netif_running(struct device *dev)
{
return dev->start == 0;
}
static inline int
compat_netif_carrier_ok(struct device *dev)
{
return 1;
}
static inline void
compat_netif_carrier_on(struct device *dev)
{
}
static inline void
compat_netif_carrier_off(struct device *dev)
{
}
#else
#define compat_netif_start_queue(dev) netif_start_queue(dev)
#define compat_netif_stop_queue(dev) netif_stop_queue(dev)
#define compat_netif_queue_stopped(dev) netif_queue_stopped(dev)
#define compat_netif_wake_queue(dev) netif_wake_queue(dev)
#define compat_netif_running(dev) netif_running(dev)
#define compat_netif_carrier_ok(dev) netif_carrier_ok(dev)
#define compat_netif_carrier_on(dev) netif_carrier_on(dev)
#define compat_netif_carrier_off(dev) netif_carrier_off(dev)
#endif
/* unregister_netdevice_notifier was not safe prior to 2.6.17 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \
!defined(ATOMIC_NOTIFIER_INIT)
/* pre 2.6.17 and not patched */
static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb) {
int err;
rtnl_lock();
err = unregister_netdevice_notifier(nb);
rtnl_unlock();
return err;
}
#else
/* post 2.6.17 or patched */
#define compat_unregister_netdevice_notifier(_nb) \
unregister_netdevice_notifier(_nb);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
#define compat_netif_napi_add(dev, napi, poll, quota) \
netif_napi_add(dev, napi, poll, quota)
#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev, napi)
#define compat_napi_enable(dev, napi) napi_enable(napi)
#define compat_napi_disable(dev, napi) napi_disable(napi)
#else
struct napi_struct {
int dummy;
};
#define compat_netif_napi_add(dev, napi, pollcb, quota) \
do { \
(dev)->poll = (pollcb); \
(dev)->weight = (quota);\
} while (0)
#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev)
#define compat_napi_enable(dev, napi) netif_poll_enable(dev)
#define compat_napi_disable(dev, napi) netif_poll_disable(dev)
#endif
#endif /* __COMPAT_NETDEVICE_H__ */
vmxnet3-only/compat_ioport.h 0000444 0000000 0000000 00000004041 12025727027 015170 0 ustar root root /*********************************************************
* Copyright (C) 2003 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_IOPORT_H__
# define __COMPAT_IOPORT_H__
#include
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
static inline void *
compat_request_region(unsigned long start, unsigned long len, const char *name)
{
if (check_region(start, len)) {
return NULL;
}
request_region(start, len, name);
return (void*)1;
}
#else
#define compat_request_region(start, len, name) request_region(start, len, name)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 7)
/* mmap io support starts from 2.3.7, fail the call for kernel prior to that */
static inline void *
compat_request_mem_region(unsigned long start, unsigned long len, const char *name)
{
return NULL;
}
static inline void
compat_release_mem_region(unsigned long start, unsigned long len)
{
return;
}
#else
#define compat_request_mem_region(start, len, name) request_mem_region(start, len, name)
#define compat_release_mem_region(start, len) release_mem_region(start, len)
#endif
/* these two macro defs are needed by compat_pci_request_region */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15)
# define IORESOURCE_IO 0x00000100
# define IORESOURCE_MEM 0x00000200
#endif
#endif /* __COMPAT_IOPORT_H__ */
vmxnet3-only/compat_pci.h 0000444 0000000 0000000 00000041575 12025727027 014444 0 ustar root root /*********************************************************
* Copyright (C) 1999 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* compat_pci.h: PCI compatibility wrappers.
*/
#ifndef __COMPAT_PCI_H__
#define __COMPAT_PCI_H__
#include "compat_ioport.h"
#include
#ifndef KERNEL_2_1
# include
#endif
/* 2.0.x has useless struct pci_dev; remap it to our own */
#ifndef KERNEL_2_1
#define pci_dev vmw_pci_driver_instance
#endif
/* 2.0/2.2 does not have pci driver API */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
struct vmw_pci_driver_instance {
struct vmw_pci_driver_instance *next;
void *driver_data;
struct pci_driver *pcidrv;
#ifdef KERNEL_2_1
struct pci_dev *pcidev;
#else
unsigned char bus;
unsigned char devfn;
unsigned int irq;
#endif
};
#endif
/* 2.0 has pcibios_* calls only... We have to provide pci_* compatible wrappers. */
#ifndef KERNEL_2_1
static inline int
pci_read_config_byte(struct pci_dev *pdev, // IN: PCI slot
unsigned char where, // IN: Byte to read
u8 *value) // OUT: Value read
{
return pcibios_read_config_byte(pdev->bus, pdev->devfn, where, value);
}
static inline int
pci_read_config_dword(struct pci_dev *pdev, // IN: PCI slot
unsigned char where, // IN: Dword to read
u32 *value) // OUT: Value read
{
return pcibios_read_config_dword(pdev->bus, pdev->devfn, where, value);
}
static inline int
pci_write_config_dword(struct pci_dev *pdev, // IN: PCI slot
unsigned char where, // IN: Dword to write
u32 value) // IN: Value to write
{
return pcibios_write_config_dword(pdev->bus, pdev->devfn, where, value);
}
#endif
/*
*-----------------------------------------------------------------------------
*
* compat_pci_name --
*
* Return human readable PCI slot name. Note that some implementations
* return a pointer to the static storage, so returned value may be
* overwritten by subsequent calls to this function.
*
* Results:
* Returns pointer to the string with slot name.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
#define compat_pci_name(pdev) pci_name(pdev)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
#define compat_pci_name(pdev) (pdev)->slot_name
#elif defined(KERNEL_2_1)
static inline const char*
compat_pci_name(struct pci_dev* pdev)
{
static char slot_name[12];
sprintf(slot_name, "%02X:%02X.%X", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
return slot_name;
}
#else
static inline const char*
compat_pci_name(struct pci_dev* pdev)
{
static char slot_name[12];
sprintf(slot_name, "%02X:%02X.%X", pdev->bus,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
return slot_name;
}
#endif
/* pci_resource_start comes in 4 flavors - 2.0, 2.2, early 2.3, 2.4+ */
#ifndef KERNEL_2_1
static inline unsigned long
compat_pci_resource_start(struct pci_dev *pdev,
unsigned int index)
{
u32 addr;
if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) {
printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n",
index, compat_pci_name(pdev));
return ~0UL;
}
if (addr & PCI_BASE_ADDRESS_SPACE) {
return addr & PCI_BASE_ADDRESS_IO_MASK;
} else {
return addr & PCI_BASE_ADDRESS_MEM_MASK;
}
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1)
# define compat_pci_resource_start(dev, index) \
(((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \
? ((dev)->base_address[index] & PCI_BASE_ADDRESS_IO_MASK) \
: ((dev)->base_address[index] & PCI_BASE_ADDRESS_MEM_MASK))
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)
# define compat_pci_resource_start(dev, index) \
((dev)->resource[index].start)
#else
# define compat_pci_resource_start(dev, index) \
pci_resource_start(dev, index)
#endif
/* since 2.3.15, a new set of s/w res flags IORESOURCE_ is introduced,
* we fake them by returning either IORESOURCE_{IO, MEM} prior to 2.3.15 since
* this is what compat_pci_request_region uses
*/
#ifndef KERNEL_2_1
static inline unsigned long
compat_pci_resource_flags(struct pci_dev *pdev,
unsigned int index)
{
u32 addr;
if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) {
printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n",
index, compat_pci_name(pdev));
return ~0UL;
}
if (addr & PCI_BASE_ADDRESS_SPACE) {
return IORESOURCE_IO;
} else {
return IORESOURCE_MEM;
}
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1)
# define compat_pci_resource_flags(dev, index) \
(((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \
? IORESOURCE_IO: IORESOURCE_MEM)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15)
/* IORESOURCE_xxx appeared in 2.3.15 and is set in resource[].flags */
# define compat_pci_resource_flags(dev, index) ((dev)->resource[index].flags)
#else
# define compat_pci_resource_flags(dev, index) pci_resource_flags(dev, index)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
static inline unsigned long
compat_pci_resource_len(struct pci_dev *pdev, // IN
unsigned int index) // IN
{
u32 addr, mask;
unsigned char reg = PCI_BASE_ADDRESS_0 + index * 4;
if (pci_read_config_dword(pdev, reg, &addr) || addr == 0xFFFFFFFF) {
return 0;
}
pci_write_config_dword(pdev, reg, 0xFFFFFFFF);
pci_read_config_dword(pdev, reg, &mask);
pci_write_config_dword(pdev, reg, addr);
if (mask == 0 || mask == 0xFFFFFFFF) {
return 0;
}
if (addr & PCI_BASE_ADDRESS_SPACE) {
return 65536 - (mask & PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
} else {
return -(mask & PCI_BASE_ADDRESS_MEM_MASK);
}
}
#else
#define compat_pci_resource_len(dev, index) pci_resource_len(dev, index)
#endif
/* pci_request_region appears in 2.4.20 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20)
static inline int
compat_pci_request_region(struct pci_dev *pdev, int bar, char *name)
{
if (compat_pci_resource_len(pdev, bar) == 0) {
return 0;
}
if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
if (!compat_request_region(compat_pci_resource_start(pdev, bar),
compat_pci_resource_len(pdev, bar),
name)) {
return -EBUSY;
}
} else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
if (!compat_request_mem_region(compat_pci_resource_start(pdev, bar),
compat_pci_resource_len(pdev, bar),
name)) {
return -EBUSY;
}
}
return 0;
}
static inline void
compat_pci_release_region(struct pci_dev *pdev, int bar)
{
if (compat_pci_resource_len(pdev, bar) != 0) {
if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
release_region(compat_pci_resource_start(pdev, bar),
compat_pci_resource_len(pdev, bar));
} else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
compat_release_mem_region(compat_pci_resource_start(pdev, bar),
compat_pci_resource_len(pdev, bar));
}
}
}
#else
#define compat_pci_request_region(pdev, bar, name) pci_request_region(pdev, bar, name)
#define compat_pci_release_region(pdev, bar) pci_release_region(pdev, bar)
#endif
/* pci_request_regions appeears in 2.4.3 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)
static inline int
compat_pci_request_regions(struct pci_dev *pdev, char *name)
{
int i;
for (i = 0; i < 6; i++) {
if (compat_pci_request_region(pdev, i, name)) {
goto release;
}
}
return 0;
release:
while (--i >= 0) {
compat_pci_release_region(pdev, i);
}
return -EBUSY;
}
static inline void
compat_pci_release_regions(struct pci_dev *pdev)
{
int i;
for (i = 0; i < 6; i++) {
compat_pci_release_region(pdev, i);
}
}
#else
#define compat_pci_request_regions(pdev, name) pci_request_regions(pdev, name)
#define compat_pci_release_regions(pdev) pci_release_regions(pdev)
#endif
/* pci_enable_device is available since 2.4.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
#define compat_pci_enable_device(pdev) (0)
#else
#define compat_pci_enable_device(pdev) pci_enable_device(pdev)
#endif
/* pci_set_master is available since 2.2.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0)
#define compat_pci_set_master(pdev) (0)
#else
#define compat_pci_set_master(pdev) pci_set_master(pdev)
#endif
/* pci_disable_device is available since 2.4.4 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 4)
#define compat_pci_disable_device(pdev) do {} while (0)
#else
#define compat_pci_disable_device(pdev) pci_disable_device(pdev)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
/*
* Devices supported by particular pci driver. While 2.4+ kernels
* can do match on subsystem and class too, we support match on
* vendor/device IDs only.
*/
struct pci_device_id {
unsigned int vendor, device;
unsigned long driver_data;
};
#define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev)
/* PCI driver */
struct pci_driver {
const char *name;
const struct pci_device_id *id_table;
int (*probe)(struct pci_dev* dev, const struct pci_device_id* id);
void (*remove)(struct pci_dev* dev);
};
/*
* Note that this is static variable. Maybe everything below should be in
* separate compat_pci.c file, but currently only user of this file is vmxnet,
* and vmxnet has only one file, so it is fine. Also with vmxnet all
* functions below are called just once, so difference between 'inline' and
* separate compat_pci.c should be very small.
*/
static struct vmw_pci_driver_instance *pci_driver_instances = NULL;
#ifdef KERNEL_2_1
#define vmw_pci_device(instance) (instance)->pcidev
#else
#define vmw_pci_device(instance) (instance)
#endif
/*
*-----------------------------------------------------------------------------
*
* pci_register_driver --
*
* Create driver instances for all matching PCI devices in the box.
*
* Results:
* Returns 0 for success, negative error value for failure.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static inline int
pci_register_driver(struct pci_driver *drv)
{
const struct pci_device_id *chipID;
for (chipID = drv->id_table; chipID->vendor; chipID++) {
#ifdef KERNEL_2_1
struct pci_dev *pdev;
for (pdev = NULL;
(pdev = pci_find_device(chipID->vendor, chipID->device, pdev)) != NULL; ) {
#else
int adapter;
unsigned char bus, devfn, irq;
for (adapter = 0;
pcibios_find_device(chipID->vendor, chipID->device, adapter,
&bus, &devfn) == 0;
adapter++) {
#endif
struct vmw_pci_driver_instance *pdi;
int err;
pdi = kmalloc(sizeof *pdi, GFP_KERNEL);
if (!pdi) {
printk(KERN_ERR "Not enough memory.\n");
break;
}
pdi->pcidrv = drv;
#ifdef KERNEL_2_1
pdi->pcidev = pdev;
#else
pdi->bus = bus;
pdi->devfn = devfn;
if (pci_read_config_byte(pdi, PCI_INTERRUPT_LINE, &irq)) {
pdi->irq = -1;
} else {
pdi->irq = irq;
}
#endif
pdi->driver_data = NULL;
pdi->next = pci_driver_instances;
pci_driver_instances = pdi;
err = drv->probe(vmw_pci_device(pdi), chipID);
if (err) {
pci_driver_instances = pdi->next;
kfree(pdi);
}
}
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* compat_pci_unregister_driver --
*
* Shut down PCI driver - unbind all device instances from driver.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static inline void
pci_unregister_driver(struct pci_driver *drv)
{
struct vmw_pci_driver_instance **ppdi;
ppdi = &pci_driver_instances;
while (1) {
struct vmw_pci_driver_instance *pdi = *ppdi;
if (!pdi) {
break;
}
if (pdi->pcidrv == drv) {
drv->remove(vmw_pci_device(pdi));
*ppdi = pdi->next;
kfree(pdi);
} else {
ppdi = &pdi->next;
}
}
}
#else
/* provide PCI_DEVICE for early 2.4.x kernels */
#ifndef PCI_DEVICE
#define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
#endif
#endif
/* provide dummy MODULE_DEVICE_TABLE for 2.0/2.2 */
#ifndef MODULE_DEVICE_TABLE
#define MODULE_DEVICE_TABLE(bus, devices)
#endif
/*
*-----------------------------------------------------------------------------
*
* pci_set_drvdata --
*
* Set per-device driver's private data.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
/*
*-----------------------------------------------------------------------------
*
* pci_get_drvdata --
*
* Retrieve per-device driver's private data.
*
* Results:
* per-device driver's data previously set by pci_set_drvdata,
* or NULL on failure.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
#ifndef KERNEL_2_1
/* 2.0.x is simple, we have driver_data directly in pci_dev */
#define pci_set_drvdata(pdev, data) do { (pdev)->driver_data = (data); } while (0)
#define pci_get_drvdata(pdev) (pdev)->driver_data
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
/* 2.2.x is trickier, we have to find driver instance first */
static inline void
pci_set_drvdata(struct pci_dev *pdev, void* data)
{
struct vmw_pci_driver_instance *pdi;
for (pdi = pci_driver_instances; pdi; pdi = pdi->next) {
if (pdi->pcidev == pdev) {
pdi->driver_data = data;
return;
}
}
printk(KERN_ERR "pci_set_drvdata issued for unknown device %p\n", pdev);
}
static inline void *
pci_get_drvdata(struct pci_dev *pdev)
{
struct vmw_pci_driver_instance *pdi;
for (pdi = pci_driver_instances; pdi; pdi = pdi->next) {
if (pdi->pcidev == pdev) {
return pdi->driver_data;
}
}
printk(KERN_ERR "pci_get_drvdata issued for unknown device %p\n", pdev);
return NULL;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
# define PCI_DMA_BIDIRECTIONAL 0
# define PCI_DMA_TODEVICE 1
# define PCI_DMA_FROMDEVICE 2
# define PCI_DMA_NONE 3
#endif
/*
* Power Management related compat wrappers.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
# define compat_pci_save_state(pdev) pci_save_state((pdev), NULL)
# define compat_pci_restore_state(pdev) pci_restore_state((pdev), NULL)
#else
# define compat_pci_save_state(pdev) pci_save_state((pdev))
# define compat_pci_restore_state(pdev) pci_restore_state((pdev))
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
# define pm_message_t u32
# define compat_pci_choose_state(pdev, state) (state)
# define PCI_D0 0
# define PCI_D3hot 3
#else
# define compat_pci_choose_state(pdev, state) pci_choose_state((pdev), (state))
#endif
/* 2.6.14 changed the PCI shutdown callback */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
# define COMPAT_PCI_SHUTDOWN(func) .driver = { .shutdown = (func), }
# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct device *(var))
# define COMPAT_PCI_TO_DEV(dev) (to_pci_dev(dev))
#else
# define COMPAT_PCI_SHUTDOWN(func) .shutdown = (func)
# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct pci_dev *(var))
# define COMPAT_PCI_TO_DEV(dev) (dev)
#endif
#endif /* __COMPAT_PCI_H__ */
vmxnet3-only/compat_skbuff.h 0000444 0000000 0000000 00000014465 12025727030 015141 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_SKBUFF_H__
# define __COMPAT_SKBUFF_H__
#include
/*
* When transition from mac/nh/h to skb_* accessors was made, also SKB_WITH_OVERHEAD
* was introduced.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) || \
(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 21) && defined(SKB_WITH_OVERHEAD))
#define compat_skb_mac_header(skb) skb_mac_header(skb)
#define compat_skb_network_header(skb) skb_network_header(skb)
#define compat_skb_network_offset(skb) skb_network_offset(skb)
#define compat_skb_transport_header(skb) skb_transport_header(skb)
#define compat_skb_transport_offset(skb) skb_transport_offset(skb)
#define compat_skb_network_header_len(skb) skb_network_header_len(skb)
#define compat_skb_tail_pointer(skb) skb_tail_pointer(skb)
#define compat_skb_end_pointer(skb) skb_end_pointer(skb)
#define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb))
#define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb))
#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb)
#define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off)
#define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off)
#else
#define compat_skb_mac_header(skb) (skb)->mac.raw
#define compat_skb_network_header(skb) (skb)->nh.raw
#define compat_skb_network_offset(skb) ((skb)->nh.raw - (skb)->data)
#define compat_skb_transport_header(skb) (skb)->h.raw
#define compat_skb_transport_offset(skb) ((skb)->h.raw - (skb)->data)
#define compat_skb_network_header_len(skb) ((skb)->h.raw - (skb)->nh.raw)
#define compat_skb_tail_pointer(skb) (skb)->tail
#define compat_skb_end_pointer(skb) (skb)->end
#define compat_skb_ip_header(skb) (skb)->nh.iph
#define compat_skb_tcp_header(skb) (skb)->h.th
#define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data)
#define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off))
#define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off))
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) || defined(VMW_SKB_LINEARIZE_2618)
# define compat_skb_linearize(skb) skb_linearize((skb))
#else
# if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0)
# define compat_skb_linearize(skb) __skb_linearize((skb), GFP_ATOMIC)
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
# define compat_skb_linearize(skb) skb_linearize((skb), GFP_ATOMIC)
# else
static inline int
compat_skb_linearize(struct sk_buff *skb)
{
return 0;
}
# endif
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#define compat_skb_csum_offset(skb) (skb)->csum_offset
#else
#define compat_skb_csum_offset(skb) (skb)->csum
#endif
/*
* Note that compat_skb_csum_start() has semantic different from kernel's csum_start:
* kernel's skb->csum_start is offset between start of checksummed area and start of
* complete skb buffer, while our compat_skb_csum_start(skb) is offset from start
* of packet itself.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
#define compat_skb_csum_start(skb) ((skb)->csum_start - skb_headroom(skb))
#else
#define compat_skb_csum_start(skb) compat_skb_transport_offset(skb)
#endif
#if defined(NETIF_F_GSO) /* 2.6.18 and upwards */
#define compat_skb_mss(skb) (skb_shinfo(skb)->gso_size)
#else
#define compat_skb_mss(skb) (skb_shinfo(skb)->tso_size)
#endif
/* used by both received pkts and outgoing ones */
#define VM_CHECKSUM_UNNECESSARY CHECKSUM_UNNECESSARY
/* csum status of received pkts */
#if defined(CHECKSUM_COMPLETE)
# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_COMPLETE
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW)
# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_HW
#else
# define VM_RX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL
#endif
/* csum status of outgoing pkts */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW)
# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_HW
#else
# define VM_TX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0))
# define compat_kfree_skb(skb, type) kfree_skb(skb, type)
# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb, type)
# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb, type)
# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb, type)
#else
# define compat_kfree_skb(skb, type) kfree_skb(skb)
# define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb)
# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb)
# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb)
# else
# define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb_any(skb)
# define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb_irq(skb)
# endif
#endif
#ifndef NET_IP_ALIGN
# define COMPAT_NET_IP_ALIGN 2
#else
# define COMPAT_NET_IP_ALIGN NET_IP_ALIGN
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
# define compat_skb_headlen(skb) skb_headlen(skb)
# define compat_pskb_may_pull(skb, len) pskb_may_pull(skb, len)
#else
# define compat_skb_headlen(skb) (skb)->len
# define compat_pskb_may_pull(skb, len) 1
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
# define compat_skb_header_cloned(skb) skb_header_cloned(skb)
#else
# define compat_skb_header_cloned(skb) 0
#endif
#endif /* __COMPAT_SKBUFF_H__ */
vmxnet3-only/compat_slab.h 0000444 0000000 0000000 00000006653 12025727030 014602 0 ustar root root /*********************************************************
* Copyright (C) 2005 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_SLAB_H__
# define __COMPAT_SLAB_H__
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0)
# include
#else
# include
#endif
/*
* Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache
* structure. Prior to 2.6.15, this structure was called kmem_cache_s, and
* afterwards it was renamed to kmem_cache. Here we keep things simple and use
* the accepted typedef until it became deprecated, at which point we switch
* over to the kmem_cache name.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
# define compat_kmem_cache struct kmem_cache
#else
# define compat_kmem_cache kmem_cache_t
#endif
/*
* Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags,
* constructor, and destructor. Then for some time kernel was asserting that
* destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5
* arguments - destructor is gone.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR)
#define compat_kmem_cache_create(name, size, align, flags, ctor) \
kmem_cache_create(name, size, align, flags, ctor, NULL)
#else
#define compat_kmem_cache_create(name, size, align, flags, ctor) \
kmem_cache_create(name, size, align, flags, ctor)
#endif
/*
* Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to
* prepare (aka "this"), from which cache it came, and some unused flags. After
* 2.6.23 flags were removed, and order of "this" and cache parameters was swapped...
* Since 2.6.27-rc2 everything is different again, and ctor has only one argument.
*
* HAS_3_ARGS has precedence over HAS_2_ARGS if both are defined.
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS)
# define VMW_KMEMCR_CTOR_HAS_3_ARGS
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && !defined(VMW_KMEMCR_CTOR_HAS_2_ARGS)
# define VMW_KMEMCR_CTOR_HAS_2_ARGS
#endif
#if defined(VMW_KMEMCR_CTOR_HAS_3_ARGS)
typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long);
#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg, \
compat_kmem_cache *cache, \
unsigned long flags
#elif defined(VMW_KMEMCR_CTOR_HAS_2_ARGS)
typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *);
#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) compat_kmem_cache *cache, \
void *arg
#else
typedef void compat_kmem_cache_ctor(void *);
#define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg
#endif
#endif /* __COMPAT_SLAB_H__ */
vmxnet3-only/compat_spinlock.h 0000444 0000000 0000000 00000004606 12025727030 015477 0 ustar root root /*********************************************************
* Copyright (C) 2005 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_SPINLOCK_H__
# define __COMPAT_SPINLOCK_H__
/*
* The spin_lock() API appeared in 2.1.25 in asm/smp_lock.h
* It moved in 2.1.30 to asm/spinlock.h
* It moved again in 2.3.18 to linux/spinlock.h
*
* --hpreg
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 18)
# include
#else
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 30)
# include
# else
typedef struct {} spinlock_t;
# define spin_lock_init(lock)
# define spin_lock(lock)
# define spin_unlock(lock)
# define spin_lock_irqsave(lock, flags) do { \
save_flags(flags); \
cli(); \
spin_lock(lock); \
} while (0)
# define spin_unlock_irqrestore(lock, flags) do { \
spin_unlock(lock); \
restore_flags(flags); \
} while (0)
# endif
#endif
/*
* Preempt support was added during 2.5.x development cycle, and later
* it was backported to 2.4.x. In 2.4.x backport these definitions
* live in linux/spinlock.h, that's why we put them here (in 2.6.x they
* are defined in linux/preempt.h which is included by linux/spinlock.h).
*/
#ifdef CONFIG_PREEMPT
#define compat_preempt_disable() preempt_disable()
#define compat_preempt_enable() preempt_enable()
#else
#define compat_preempt_disable() do { } while (0)
#define compat_preempt_enable() do { } while (0)
#endif
#endif /* __COMPAT_SPINLOCK_H__ */
vmxnet3-only/compat_timer.h 0000444 0000000 0000000 00000006070 12025727030 014772 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_TIMER_H__
# define __COMPAT_TIMER_H__
/*
* The del_timer_sync() API appeared in 2.3.43
* It became reliable in 2.4.0-test3
*
* --hpreg
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
# define compat_del_timer_sync(timer) del_timer_sync(timer)
#else
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)
/* 2.3.43 removed asm/softirq.h's reference to bh_base. */
# include
# endif
# include
static inline int
compat_del_timer_sync(struct timer_list *timer) // IN
{
int wasPending;
start_bh_atomic();
wasPending = del_timer(timer);
end_bh_atomic();
return wasPending;
}
#endif
/*
* The msleep_interruptible() API appeared in 2.6.9.
* It is based on the msleep() API, which appeared in 2.4.29.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
# include
# define compat_msleep_interruptible(msecs) msleep_interruptible(msecs)
# define compat_msleep(msecs) msleep(msecs)
#else
# include
/*
* msecs_to_jiffies appeared in 2.6.7/2.4.29. For earlier kernels,
* fall back to slow-case code (we don't use this operation
* enough to need the performance).
*/
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 29) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7))
# define msecs_to_jiffies(msecs) (((msecs) * HZ + 999) / 1000)
# endif
/*
* set_current_state appeared in 2.2.18.
*/
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
# define set_current_state(a) do { current->state = (a); } while(0)
# endif
static inline void
compat_msleep_interruptible(unsigned long msecs) // IN
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(msecs) + 1);
}
static inline void
compat_msleep(unsigned long msecs) // IN
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(msecs) + 1);
}
#endif
/*
* There is init_timer_deferrable() since 2.6.22.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
# define compat_init_timer_deferrable(timer) init_timer_deferrable(timer)
#else
# define compat_init_timer_deferrable(timer) init_timer(timer)
#endif
#endif /* __COMPAT_TIMER_H__ */
vmxnet3-only/compat_version.h 0000444 0000000 0000000 00000006165 12025727030 015344 0 ustar root root /*********************************************************
* Copyright (C) 1998 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_VERSION_H__
# define __COMPAT_VERSION_H__
#define INCLUDE_ALLOW_VMMON
#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_VMCORE
#define INCLUDE_ALLOW_VMNIXMOD
#define INCLUDE_ALLOW_DISTRIBUTE
#include "includeCheck.h"
#ifndef __linux__
# error "linux-version.h"
#endif
#include
/* Appeared in 2.1.90 --hpreg */
#ifndef KERNEL_VERSION
# define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#endif
/*
* Distinguish relevant classes of Linux kernels.
*
* The convention is that version X defines all
* the KERNEL_Y symbols where Y <= X.
*
* XXX Do not add more definitions here. This way of doing things does not
* scale, and we are going to phase it out soon --hpreg
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0)
# define KERNEL_2_1
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0)
# define KERNEL_2_2
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1)
# define KERNEL_2_3_1
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15)
/* new networking */
# define KERNEL_2_3_15
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25)
/* new procfs */
# define KERNEL_2_3_25
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29)
/* even newer procfs */
# define KERNEL_2_3_29
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43)
/* softnet changes */
# define KERNEL_2_3_43
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47)
/* more softnet changes */
# define KERNEL_2_3_47
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99)
/* name in netdevice struct is array and not pointer */
# define KERNEL_2_3_99
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
/* New 'owner' member at the beginning of struct file_operations */
# define KERNEL_2_4_0
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8)
/* New netif_rx_ni() --hpreg */
# define KERNEL_2_4_8
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
/* New vmap() */
# define KERNEL_2_4_22
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2)
/* New kdev_t, major()/minor() API --hpreg */
# define KERNEL_2_5_2
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
/* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */
# define KERNEL_2_5_5
#endif
#endif /* __COMPAT_VERSION_H__ */
vmxnet3-only/compat_highmem.h 0000444 0000000 0000000 00000002557 12025727030 015276 0 ustar root root /*********************************************************
* Copyright (C) 2002 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_HIGHMEM_H__
# define __COMPAT_HIGHMEM_H__
/*
* BIGMEM (4 GB) support appeared in 2.3.16: kmap() API added
* HIGHMEM (4 GB + 64 GB) support appeared in 2.3.23: kmap() API modified
* In 2.3.27, kmap() API modified again
*
* --hpreg
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 27)
# include
#else
/* For page_address --hpreg */
# include
# define kmap(_page) (void*)page_address(_page)
# define kunmap(_page)
#endif
#endif /* __COMPAT_HIGHMEM_H__ */
vmxnet3-only/compat_workqueue.h 0000444 0000000 0000000 00000014311 12025727030 015676 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef __COMPAT_WORKQUEUE_H__
# define __COMPAT_WORKQUEUE_H__
#include
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)
# include
#endif
/*
*
* Work queues and delayed work queues.
*
* Prior to 2.5.41, the notion of work queues did not exist. Taskqueues are
* used for work queues and timers are used for delayed work queues.
*
* After 2.6.20, normal work structs ("work_struct") and delayed work
* ("delayed_work") structs were separated so that the work_struct could be
* slimmed down. The interface was also changed such that the address of the
* work_struct itself is passed in as the argument to the work function. This
* requires that one embed the work struct in the larger struct containing the
* information necessary to complete the work and use container_of() to obtain
* the address of the containing structure.
*
* Users of these macros should embed a compat_work or compat_delayed_work in
* a larger structure, then specify the larger structure as the _data argument
* for the initialization functions, specify the work function to take
* a compat_work_arg or compat_delayed_work_arg, then use the appropriate
* _GET_DATA macro to obtain the reference to the structure passed in as _data.
* An example is below.
*
*
* typedef struct WorkData {
* int data;
* compat_work work;
* } WorkData;
*
*
* void
* WorkFunc(compat_work_arg data)
* {
* WorkData *workData = COMPAT_WORK_GET_DATA(data, WorkData, work);
*
* ...
* }
*
*
* {
* WorkData *workData = kmalloc(sizeof *workData, GFP_EXAMPLE);
* if (!workData) {
* return -ENOMEM;
* }
*
* COMPAT_INIT_WORK(&workData->work, WorkFunc, workData);
* compat_schedule_work(&workData->work);
* }
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 41) /* { */
typedef struct tq_struct compat_work;
typedef struct compat_delayed_work {
struct tq_struct work;
struct timer_list timer;
} compat_delayed_work;
typedef void * compat_work_arg;
typedef void * compat_delayed_work_arg;
/*
* Delayed work queues need to run at some point in the future in process
* context, but task queues don't support delaying the task one is scheduling.
* Timers allow us to delay the execution of our work queue until the future,
* but timer handlers run in bottom-half context. As such, we use both a timer
* and task queue and use the timer handler below to schedule the task in
* process context immediately. The timer lets us delay execution, and the
* task queue lets us run in process context.
*
* Note that this is similar to how delayed_work is implemented with work
* queues in later kernel versions.
*/
static inline void
__compat_delayed_work_timer(unsigned long arg)
{
compat_delayed_work *dwork = (compat_delayed_work *)arg;
if (dwork) {
schedule_task(&dwork->work);
}
}
# define COMPAT_INIT_WORK(_work, _func, _data) \
INIT_LIST_HEAD(&(_work)->list); \
(_work)->sync = 0; \
(_work)->routine = _func; \
(_work)->data = _data
# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \
COMPAT_INIT_WORK(&(_work)->work, _func, _data); \
init_timer(&(_work)->timer); \
(_work)->timer.expires = 0; \
(_work)->timer.function = __compat_delayed_work_timer; \
(_work)->timer.data = (unsigned long)_work
# define compat_schedule_work(_work) \
schedule_task(_work)
# define compat_schedule_delayed_work(_work, _delay) \
(_work)->timer.expires = jiffies + _delay; \
add_timer(&(_work)->timer)
# define COMPAT_WORK_GET_DATA(_p, _type) \
(_type *)(_p)
# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \
(_type *)(_p)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) /* } { */
typedef struct work_struct compat_work;
typedef struct work_struct compat_delayed_work;
typedef void * compat_work_arg;
typedef void * compat_delayed_work_arg;
# define COMPAT_INIT_WORK(_work, _func, _data) \
INIT_WORK(_work, _func, _data)
# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \
INIT_WORK(_work, _func, _data)
# define compat_schedule_work(_work) \
schedule_work(_work)
# define compat_schedule_delayed_work(_work, _delay) \
schedule_delayed_work(_work, _delay)
# define COMPAT_WORK_GET_DATA(_p, _type) \
(_type *)(_p)
# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \
(_type *)(_p)
#else /* } Linux >= 2.6.20 { */
typedef struct work_struct compat_work;
typedef struct delayed_work compat_delayed_work;
typedef struct work_struct * compat_work_arg;
typedef struct work_struct * compat_delayed_work_arg;
# define COMPAT_INIT_WORK(_work, _func, _data) \
INIT_WORK(_work, _func)
# define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \
INIT_DELAYED_WORK(_work, _func)
# define compat_schedule_work(_work) \
schedule_work(_work)
# define compat_schedule_delayed_work(_work, _delay) \
schedule_delayed_work(_work, _delay)
# define COMPAT_WORK_GET_DATA(_p, _type) \
container_of(_p, _type, work)
# define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \
container_of(_p, _type, _member.work)
#endif /* } */
#endif /* __COMPAT_WORKQUEUE_H__ */
vmxnet3-only/driver-config.h 0000444 0000000 0000000 00000004250 12025727030 015043 0 ustar root root /*********************************************************
* Copyright (C) 1998 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* Sets the proper defines from the Linux header files
*
* This file must be included before the inclusion of any kernel header file,
* with the exception of linux/autoconf.h and linux/version.h --hpreg
*/
#ifndef __VMX_CONFIG_H__
#define __VMX_CONFIG_H__
#define INCLUDE_ALLOW_VMCORE
#define INCLUDE_ALLOW_VMMON
#define INCLUDE_ALLOW_MODULE
#define INCLUDE_ALLOW_VMNIXMOD
#include "includeCheck.h"
#include
#include "compat_version.h"
/*
* We rely on Kernel Module support. Check here.
*/
#ifndef CONFIG_MODULES
# error "No Module support in this kernel. Please configure with CONFIG_MODULES"
#endif
/*
* 2.2 kernels still use __SMP__ (derived from CONFIG_SMP
* in the main Makefile), so we do it here.
*/
#ifdef CONFIG_SMP
# define __SMP__ 1
#endif
#if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1)
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
/*
* MODVERSIONS might be already defined when using kernel's Makefiles.
*/
# ifndef MODVERSIONS
# define MODVERSIONS
# endif
# include
# endif
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
/*
* Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h.
*/
# include
# define _STDINT_H 1
#endif
#ifndef __KERNEL__
# define __KERNEL__
#endif
#endif
vmxnet3-only/vmxnet3.c 0000444 0000000 0000000 00000377102 12025727030 013715 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmxnet3.c --
*
* Linux driver for VMXNET3 NIC
* XXX:
* + invoke request_irq after device is activated
*/
#include "driver-config.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
#error "vmxnet3 driver is not supported on kernels earlier than 2.6"
#endif
#include "compat_module.h"
//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
#include
//#endif
#include "compat_slab.h"
#include "compat_spinlock.h"
#include "compat_ioport.h"
#include "compat_pci.h"
#include "compat_init.h"
#include "compat_timer.h"
#include "compat_netdevice.h"
#include "compat_skbuff.h"
#include "compat_interrupt.h"
#include "compat_workqueue.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "vm_basic_types.h"
#include "vmnet_def.h"
#include "vm_device_version.h"
#include "vmxnet3_version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VMXNET3_NO_NAPI)
# define VMXNET3_NAPI
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
# define VMXNET3_NEW_NAPI
#endif
#endif
#include "vmxnet3_int.h"
#ifdef VLAN_GROUP_ARRAY_SPLIT_PARTS
# define compat_vlan_group_get_device(vlan_grp, vid) vlan_group_get_device(vlan_grp, vid)
# define compat_vlan_group_set_device(vlan_grp, vid, dev) vlan_group_set_device(vlan_grp, vid, dev)
#else
# define compat_vlan_group_get_device(vlan_grp, vid) ((vlan_grp)->vlan_devices[(vid)])
# define compat_vlan_group_set_device(vlan_grp, vid, dev) ((vlan_grp)->vlan_devices[(vid)] = (dev))
#endif
#ifdef VMX86_DEBUG
# define VMXNET3_ASSERT(cond) BUG_ON(!(cond))
#else
# define VMXNET3_ASSERT(cond) do {} while (0)
#endif
#ifdef VMXNET3_DO_LOG
# define VMXNET3_LOG(msg...) printk(KERN_ERR msg)
#else
# define VMXNET3_LOG(msg...)
#endif
#ifdef VMXNET3_NAPI
# ifdef VMX86_DEBUG
# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING"-NAPI(debug)"
# else
# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING"-NAPI"
# endif
#else
# ifdef VMX86_DEBUG
# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING"(debug)"
# else
# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING
# endif
#endif
static char vmxnet3_driver_name[] = "vmxnet3";
#define VMXNET3_DRIVER_DESC "VMware vmxnet3 virtual NIC driver"
static const struct pci_device_id vmxnet3_pciid_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMXNET3)},
{0}
};
static void vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter);
static int vmxnet3_probe_device(struct pci_dev *pdev, const struct pci_device_id *id);
static void vmxnet3_remove_device(struct pci_dev *pdev);
#ifdef CONFIG_PM
static int vmxnet3_suspend(struct pci_dev *pdev, pm_message_t state);
static int vmxnet3_resume(struct pci_dev *pdev);
#endif
static int vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter);
#ifdef VMXNET3_NAPI
static int vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter,
int quota);
#else
static int vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter);
#endif
static inline Bool vmxnet3_tq_stopped(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter);
static inline void vmxnet3_tq_start(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter);
static inline void vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter);
static inline void vmxnet3_tq_wake(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter);
static struct pci_driver vmxnet3_driver = {
.name = vmxnet3_driver_name,
.id_table = vmxnet3_pciid_table,
.probe = vmxnet3_probe_device,
.remove = vmxnet3_remove_device,
#ifdef CONFIG_PM
.suspend = vmxnet3_suspend,
.resume = vmxnet3_resume,
#endif
};
static int disable_lro = 0;
/*
*----------------------------------------------------------------------------
*
* vmxnet3_enable_intr/vmxnet3_disable_intr --
*
* Enable/Disable the given intr
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_enable_intr(struct vmxnet3_adapter *adapter, unsigned intr_idx)
{
VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_IMR + intr_idx * 8, 0);
}
static inline void
vmxnet3_disable_intr(struct vmxnet3_adapter *adapter, unsigned intr_idx)
{
VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_IMR + intr_idx * 8, 1);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_enable_all_intrs/vmxnet3_disable_all_intrs--
*
* Enable/Disable all intrs used by the device
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_enable_all_intrs(struct vmxnet3_adapter *adapter)
{
int i;
for (i = 0; i < adapter->intr.num_intrs; i++) {
vmxnet3_enable_intr(adapter, i);
}
}
static void
vmxnet3_disable_all_intrs(struct vmxnet3_adapter *adapter)
{
int i;
for (i = 0; i < adapter->intr.num_intrs; i++) {
vmxnet3_disable_intr(adapter, i);
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_ack_events --
*
* Ack the events we received.
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static INLINE void
vmxnet3_ack_events(struct vmxnet3_adapter *adapter, uint32 events)
{
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_ECR, events);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_check_link --
*
* Check link state.
*
* Results:
* None.
*
* Side effects:
* May start or stop the tx queue.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_check_link(struct vmxnet3_adapter *adapter)
{
uint32 ret;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
adapter->link_speed = ret >> 16;
if (ret & 1) { /* Link is up. */
printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n", adapter->netdev->name,
adapter->link_speed);
if (!netif_carrier_ok(adapter->netdev)) {
netif_carrier_on(adapter->netdev);
}
vmxnet3_tq_start(&adapter->tx_queue, adapter);
} else {
printk(KERN_INFO "%s: NIC Link is Down\n", adapter->netdev->name);
if (netif_carrier_ok(adapter->netdev)) {
netif_carrier_off(adapter->netdev);
}
vmxnet3_tq_stop(&adapter->tx_queue, adapter);
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_process_events --
*
* process events indicated in ECR
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_process_events(struct vmxnet3_adapter *adapter)
{
uint32 events = adapter->shared->ecr;
if (events) {
vmxnet3_ack_events(adapter, events);
if (events & VMXNET3_ECR_LINK) {
vmxnet3_check_link(adapter);
}
if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_QUEUE_STATUS);
if (adapter->tqd_start->status.stopped) {
printk(KERN_ERR "%s: tq error 0x%x\n", adapter->netdev->name,
adapter->tqd_start->status.error);
}
if (adapter->rqd_start->status.stopped) {
printk(KERN_ERR "%s: rq error 0x%x\n", adapter->netdev->name,
adapter->rqd_start->status.error);
}
compat_schedule_work(&adapter->work);
}
}
}
#ifdef VMXNET3_NAPI
/*
*----------------------------------------------------------------------------
*
* vmxnet3_do_poll --
*
* The actual polling function.
*
* Results:
* void
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_do_poll(struct vmxnet3_adapter *adapter, int budget,
int *txd_done, int *rxd_done)
{
if (UNLIKELY(adapter->shared->ecr)) {
vmxnet3_process_events(adapter);
}
*txd_done = vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
*rxd_done = vmxnet3_rq_rx_complete(&adapter->rx_queue, adapter, budget);
}
#ifdef VMXNET3_NEW_NAPI
/*
*----------------------------------------------------------------------------
*
* vmxnet3_poll --
*
* new NAPI polling function
*
* Result:
* # of the NAPI credit consumed (# of rx descriptors processed)
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_poll(struct napi_struct *napi, int budget)
{
struct vmxnet3_adapter *adapter = container_of(napi, struct vmxnet3_adapter, napi);
int rxd_done, txd_done;
struct net_device *netdev = adapter->netdev;
vmxnet3_do_poll(adapter, budget, &txd_done, &rxd_done);
if (rxd_done < budget) {
netif_rx_complete(netdev, napi);
vmxnet3_enable_intr(adapter, 0);
}
return rxd_done;
}
#else
/*
*----------------------------------------------------------------------------
*
* vmxnet3_poll --
*
* NAPI polling function
*
* Result:
* 0: napi is done
* 1: continue polling
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_poll(struct net_device *poll_dev, int *budget)
{
int rxd_done, txd_done, quota;
struct vmxnet3_adapter *adapter = poll_dev->priv;
quota = min(*budget, poll_dev->quota);
vmxnet3_do_poll(adapter, quota, &txd_done, &rxd_done);
*budget -= rxd_done;
poll_dev->quota -= rxd_done;
if (rxd_done < quota) {
netif_rx_complete(poll_dev);
vmxnet3_enable_intr(adapter, 0);
return 0;
}
return 1; /* not done */
}
#endif
#endif
/*
*----------------------------------------------------------------------------
*
* vmxnet3_intr --
*
* vmxnet3 intr handler, the same version for all intr types
*
* Result:
* whether or not the intr is handled
*
*----------------------------------------------------------------------------
*/
static compat_irqreturn_t
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
vmxnet3_intr(int irq, void *dev_id, struct pt_regs * regs)
#else
vmxnet3_intr(int irq, void *dev_id)
#endif
{
struct net_device *dev = dev_id;
struct vmxnet3_adapter *adapter = dev->priv;
if (UNLIKELY(adapter->intr.type == VMXNET3_IT_INTX)) {
uint32 icr = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
if (UNLIKELY(icr == 0)) {
/* not ours */
return COMPAT_IRQ_NONE;
}
}
#ifdef VMXNET3_NAPI
/* disable intr if needed */
if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE) {
vmxnet3_disable_intr(adapter, 0);
}
compat_netif_rx_schedule(dev, &adapter->napi);
#else
vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
vmxnet3_rq_rx_complete(&adapter->rx_queue, adapter);
if (UNLIKELY(adapter->shared->ecr)) {
vmxnet3_process_events(adapter);
}
vmxnet3_enable_intr(adapter, 0);
#endif
return COMPAT_IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
*----------------------------------------------------------------------------
*
* vmxnet3_netpoll --
*
* netpoll callback.
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_netpoll(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
int irq;
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
irq = adapter->intr.msix_entries[0].vector;
} else
#endif
{
irq = adapter->pdev->irq;
}
disable_irq(irq);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
vmxnet3_intr(irq, netdev, NULL);
#else
vmxnet3_intr(irq, netdev);
#endif
enable_irq(irq);
}
#endif
/*
*----------------------------------------------------------------------------
*
* vmxnet3_request_irqs --
*
* based on adapter->intr.type, register the intr handler
*
* Result:
* 0 or error code
*
* Side-effects:
* 1. event_intr_idx and intr_idx for different comp rings are updated
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
{
int err;
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
/* we only use 1 MSI-X vector */
err = request_irq(adapter->intr.msix_entries[0].vector,
vmxnet3_intr, 0, adapter->netdev->name, adapter->netdev);
if (err) {
printk(KERN_ERR "Failed to request irq for MSIX, %s, error %d\n",
adapter->netdev->name, err);
}
} else if (adapter->intr.type == VMXNET3_IT_MSI) {
err = request_irq(adapter->pdev->irq, vmxnet3_intr, 0,
adapter->netdev->name, adapter->netdev);
if (err) {
printk(KERN_ERR "Failed to request irq for MSI, %s, error %d\n",
adapter->netdev->name, err);
}
} else {
#endif
VMXNET3_ASSERT(adapter->intr.type == VMXNET3_IT_INTX);
err = request_irq(adapter->pdev->irq, vmxnet3_intr, COMPAT_IRQF_SHARED,
adapter->netdev->name, adapter->netdev);
if (err) {
printk(KERN_ERR "Failed to request irq, %s, error %d\n",
adapter->netdev->name, err);
}
#ifdef CONFIG_PCI_MSI
}
#endif
if (!err) {
int i;
/* init our intr settings */
for (i = 0; i < adapter->intr.num_intrs; i++) {
adapter->intr.mod_levels[i] = UPT1_IML_ADAPTIVE;
}
/* next setup intr index for all intr sources */
adapter->tx_queue.comp_ring.intr_idx = 0;
adapter->rx_queue.comp_ring.intr_idx = 0;
adapter->intr.event_intr_idx = 0;
printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors allocated\n",
adapter->netdev->name, adapter->intr.type,
adapter->intr.mask_mode, adapter->intr.num_intrs);
}
return err;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_free_irqs --
*
* free IRQs allocated
*
* Result:
* None
*
* Side-effects:
* None
*----------------------------------------------------------------------------
*/
static void
vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
{
VMXNET3_ASSERT(adapter->intr.type != VMXNET3_IT_AUTO &&
adapter->intr.num_intrs > 0);
switch (adapter->intr.type) {
#ifdef CONFIG_PCI_MSI
case VMXNET3_IT_MSIX:
{
int i;
for (i = 0; i < adapter->intr.num_intrs; i++) {
free_irq(adapter->intr.msix_entries[i].vector, adapter->netdev);
}
break;
}
case VMXNET3_IT_MSI:
free_irq(adapter->pdev->irq, adapter->netdev);
break;
#endif
case VMXNET3_IT_INTX:
free_irq(adapter->pdev->irq, adapter->netdev);
break;
default:
VMXNET3_ASSERT(FALSE);
}
}
static inline Bool
vmxnet3_tq_stopped(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
return compat_netif_queue_stopped(adapter->netdev);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_start/stop/wake --
*
* Request the stack to start/stop/wake the tq. This only deals with the OS side,
* it does NOT handle the device side
*
* Result:
* None
*
* Side-effects:
* None
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_tq_start(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
tq->stopped = FALSE;
compat_netif_start_queue(adapter->netdev);
}
static inline void
vmxnet3_tq_wake(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
tq->stopped = FALSE;
compat_netif_wake_queue(adapter->netdev);
}
static inline void
vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
tq->stopped = TRUE;
tq->num_stop++;
compat_netif_stop_queue(adapter->netdev);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_map_pkt --
*
* map the tx buffer and set up ONLY TXD.{addr, len, gen} based on the mapping.
* It sets the other fields of the descriptors to 0.
*
* Result:
* None
*
* Side-effects:
* 1. the corresponding buf_info entries are upated,
* 2. ring indices are advanced
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_map_pkt(struct sk_buff *skb,
struct vmxnet3_tx_ctx *ctx,
struct vmxnet3_tx_queue *tq,
struct pci_dev *pdev)
{
uint32 dw2, len;
char *buf;
int i;
Vmxnet3_GenericDesc *gdesc;
struct vmxnet3_tx_buf_info *tbi = NULL;
VMXNET3_ASSERT(ctx->copy_size <= compat_skb_headlen(skb));
/* use the previous gen bit for the SOP desc */
dw2 = (tq->tx_ring.gen ^ 0x1) << VMXNET3_TXD_GEN_SHIFT;
ctx->sop_txd = tq->tx_ring.base + tq->tx_ring.next2fill;
gdesc = ctx->sop_txd; // both loops below can be skipped
/* no need to map the buffer if headers are copied */
if (ctx->copy_size) {
VMXNET3_ASSERT(ctx->sop_txd->txd.gen != tq->tx_ring.gen);
ctx->sop_txd->txd.addr = tq->data_ring.basePA +
tq->tx_ring.next2fill * sizeof(Vmxnet3_TxDataDesc);
ctx->sop_txd->dword[2] = dw2 | ctx->copy_size;
ctx->sop_txd->dword[3] = 0;
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_NONE;
VMXNET3_LOG("txd[%u]: 0x%"FMT64"x 0x%x 0x%x\n", tq->tx_ring.next2fill,
ctx->sop_txd->txd.addr, ctx->sop_txd->dword[2],
ctx->sop_txd->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
/* use the right gen for non-SOP desc */
dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
}
/* linear part can use multiple tx desc if it's big */
len = compat_skb_headlen(skb) - ctx->copy_size;
buf = skb->data + ctx->copy_size;
while (len) {
uint32 buf_size;
buf_size = len > VMXNET3_MAX_TX_BUF_SIZE ? VMXNET3_MAX_TX_BUF_SIZE : len;
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_SINGLE;
tbi->dma_addr = pci_map_single(pdev, buf,
buf_size, PCI_DMA_TODEVICE);
tbi->len = buf_size; /* this automatically convert 2^14 to 0 */
gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
VMXNET3_ASSERT(gdesc->txd.gen != tq->tx_ring.gen);
gdesc->txd.addr = tbi->dma_addr;
gdesc->dword[2] = dw2 | buf_size;
gdesc->dword[3] = 0;
VMXNET3_LOG("txd[%u]: 0x%"FMT64"x 0x%x 0x%x\n", tq->tx_ring.next2fill,
gdesc->txd.addr, gdesc->dword[2], gdesc->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
len -= buf_size;
buf += buf_size;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_PAGE;
tbi->dma_addr = pci_map_page(pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
tbi->len = frag->size;
gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
VMXNET3_ASSERT(gdesc->txd.gen != tq->tx_ring.gen);
gdesc->txd.addr = tbi->dma_addr;
gdesc->dword[2] = dw2 | frag->size;
gdesc->dword[3] = 0;
VMXNET3_LOG("txd[%u]: %"FMT64"u %u %u\n", tq->tx_ring.next2fill,
gdesc->txd.addr, gdesc->dword[2], gdesc->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
}
ctx->eop_txd = gdesc;
/* set the last buf_info for the pkt */
tbi->skb = skb;
tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_parse_and_copy_hdr --
*
* parse and copy relevant protocol headers:
* For a tso pkt, relevant headers are L2/3/4 including options
* For a pkt requesting csum offloading, they are L2/3 and may include L4
* if it's a TCP/UDP pkt
*
* The implementation works only when h/w vlan insertion is used, see PR
* 171928
*
* Result:
* -1: error happens during parsing
* 0: protocol headers parsed, but too big to be copied
* 1: protocol headers parsed and copied
*
* Side-effects:
* 1. related *ctx fields are updated.
* 2. ctx->copy_size is # of bytes copied
* 3. the portion copied is guaranteed to be in the linear part
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_parse_and_copy_hdr(struct sk_buff *skb,
struct vmxnet3_tx_queue *tq,
struct vmxnet3_tx_ctx *ctx)
{
Vmxnet3_TxDataDesc *tdd;
if (ctx->mss) {
ctx->eth_ip_hdr_size = compat_skb_transport_offset(skb);
ctx->l4_hdr_size = compat_skb_tcp_header(skb)->doff * 4;
ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size;
} else {
unsigned int pull_size;
if (skb->ip_summed == VM_TX_CHECKSUM_PARTIAL) {
ctx->eth_ip_hdr_size = compat_skb_transport_offset(skb);
if (ctx->ipv4) {
if (compat_skb_ip_header(skb)->protocol == IPPROTO_TCP) {
pull_size = ctx->eth_ip_hdr_size + sizeof(struct tcphdr);
if (UNLIKELY(!compat_pskb_may_pull(skb, pull_size))) {
goto err;
}
ctx->l4_hdr_size = compat_skb_tcp_header(skb)->doff * 4;
} else if (compat_skb_ip_header(skb)->protocol == IPPROTO_UDP) {
ctx->l4_hdr_size = sizeof(struct udphdr);
} else {
ctx->l4_hdr_size = 0;
}
} else {
// for simplicity, don't copy L4 headers
ctx->l4_hdr_size = 0;
}
ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size;
} else {
ctx->eth_ip_hdr_size = 14;
ctx->l4_hdr_size = 0;
/* copy as much as allowed */
ctx->copy_size = min((unsigned int)VMXNET3_HDR_COPY_SIZE, skb_headlen(skb));
}
/* make sure headers are accessible directly */
if (UNLIKELY(!compat_pskb_may_pull(skb, ctx->copy_size))) {
goto err;
}
}
if (UNLIKELY(ctx->copy_size > VMXNET3_HDR_COPY_SIZE)) {
tq->stats.oversized_hdr++;
ctx->copy_size = 0;
return 0;
}
tdd = tq->data_ring.base + tq->tx_ring.next2fill;
VMXNET3_ASSERT(ctx->copy_size <= compat_skb_headlen(skb));
memcpy(tdd->data, skb->data, ctx->copy_size);
VMXNET3_LOG("copy %u bytes to dataRing[%u]\n", ctx->copy_size, tq->tx_ring.next2fill);
return 1;
err:
return -1;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_prepare_tso --
*
* Fix pkt headers for tso
*
* Result:
* None
*
* Side-effects:
* ip hdr and tcp hdr are changed
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_prepare_tso(struct sk_buff *skb,
struct vmxnet3_tx_ctx *ctx)
{
if (ctx->ipv4) {
struct iphdr *iph = compat_skb_ip_header(skb);
iph->check = 0;
compat_skb_tcp_header(skb)->check = ~csum_tcpudp_magic(iph->saddr,
iph->daddr,
0,
IPPROTO_TCP,
0);
#ifdef NETIF_F_TSO6
} else {
struct ipv6hdr *iph = (struct ipv6hdr*)compat_skb_network_header(skb);
compat_skb_tcp_header(skb)->check = ~csum_ipv6_magic(&iph->saddr,
&iph->daddr,
0,
IPPROTO_TCP,
0);
#endif
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_xmit --
*
* transmit a pkt thru a given tq
*
* Result:
* COMPAT_NETDEV_TX_OK: descriptors are setup successfully
* COMPAT_NETDEV_TX_OK: error occured, the pkt is dropped
* COMPAT_NETDEV_TX_BUSY: tx ring is full, queue is stopped
*
* Side-effects:
* 1. tx ring may be changed
* 2. tq stats may be updated accordingly
* 3. shared->txNumDeferred may be updated
*----------------------------------------------------------------------------
*/
static int
vmxnet3_tq_xmit(struct sk_buff *skb,
struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter,
struct net_device *netdev)
{
int ret;
uint32 count;
unsigned long flags;
struct vmxnet3_tx_ctx ctx;
Vmxnet3_GenericDesc *gdesc;
/* conservatively estimate # of descriptors to use */
count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + skb_shinfo(skb)->nr_frags + 1;
ctx.ipv4 = (skb->protocol == __constant_ntohs(ETH_P_IP));
ctx.mss = compat_skb_mss(skb);
if (ctx.mss) {
if (compat_skb_header_cloned(skb)) {
if (UNLIKELY(pskb_expand_head(skb, 0, 0, GFP_ATOMIC) != 0)) {
tq->stats.drop_tso++;
goto drop_pkt;
}
tq->stats.copy_skb_header++;
}
vmxnet3_prepare_tso(skb, &ctx);
} else {
if (UNLIKELY(count > VMXNET3_MAX_TXD_PER_PKT)) {
/* non-tso pkts must not use more than VMXNET3_MAX_TXD_PER_PKT entries */
if (compat_skb_linearize(skb) != 0) {
tq->stats.drop_too_many_frags++;
goto drop_pkt;
}
tq->stats.linearized++;
/* recalculate the # of descriptors to use */
count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1;
}
}
ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx);
if (ret >= 0) {
VMXNET3_ASSERT(ret > 0 || ctx.copy_size == 0);
/* hdrs parsed, check against other limits */
if (ctx.mss) {
if (UNLIKELY(ctx.eth_ip_hdr_size + ctx.l4_hdr_size > VMXNET3_MAX_TX_BUF_SIZE)) {
goto hdr_too_big;
}
} else {
if (skb->ip_summed == VM_TX_CHECKSUM_PARTIAL) {
if (UNLIKELY(ctx.eth_ip_hdr_size + compat_skb_csum_offset(skb) >
VMXNET3_MAX_CSUM_OFFSET)) {
goto hdr_too_big;
}
}
}
} else {
tq->stats.drop_hdr_inspect_err++;
goto drop_pkt;
}
spin_lock_irqsave(&tq->tx_lock, flags);
if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
tq->stats.tx_ring_full++;
VMXNET3_LOG("tx queue stopped on %s, next2comp %u next2fill %u\n",
adapter->netdev->name, tq->tx_ring.next2comp, tq->tx_ring.next2fill);
vmxnet3_tq_stop(tq, adapter);
spin_unlock_irqrestore(&tq->tx_lock, flags);
return COMPAT_NETDEV_TX_BUSY;
}
/* fill tx descs related to addr & len */
vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev);
/* setup the EOP desc */
ctx.eop_txd->dword[3] = VMXNET3_TXD_CQ | VMXNET3_TXD_EOP;
/* setup the SOP desc */
gdesc = ctx.sop_txd;
if (ctx.mss) {
gdesc->txd.hlen = ctx.eth_ip_hdr_size + ctx.l4_hdr_size;
gdesc->txd.om = VMXNET3_OM_TSO;
gdesc->txd.msscof = ctx.mss;
tq->shared->txNumDeferred += (skb->len - gdesc->txd.hlen + ctx.mss - 1) / ctx.mss;
} else {
if (skb->ip_summed == VM_TX_CHECKSUM_PARTIAL) {
gdesc->txd.hlen = ctx.eth_ip_hdr_size;
gdesc->txd.om = VMXNET3_OM_CSUM;
gdesc->txd.msscof = ctx.eth_ip_hdr_size + compat_skb_csum_offset(skb);
} else {
gdesc->txd.om = 0;
gdesc->txd.msscof = 0;
}
tq->shared->txNumDeferred ++;
}
if (vlan_tx_tag_present(skb)) {
gdesc->txd.ti = 1;
gdesc->txd.tci = vlan_tx_tag_get(skb);
}
wmb();
/* finally flips the GEN bit of the SOP desc */
gdesc->dword[2] ^= VMXNET3_TXD_GEN;
VMXNET3_LOG("txd[%u]: SOP 0x%"FMT64"x 0x%x 0x%x\n",
(uint32)((Vmxnet3_GenericDesc *)ctx.sop_txd - tq->tx_ring.base),
gdesc->txd.addr, gdesc->dword[2], gdesc->dword[3]);
spin_unlock_irqrestore(&tq->tx_lock, flags);
if (tq->shared->txNumDeferred >= tq->shared->txThreshold) {
tq->shared->txNumDeferred = 0;
VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_TXPROD, tq->tx_ring.next2fill);
}
netdev->trans_start = jiffies;
return COMPAT_NETDEV_TX_OK;
hdr_too_big:
tq->stats.drop_oversized_hdr++;
drop_pkt:
tq->stats.drop_total++;
compat_dev_kfree_skb(skb, FREE_WRITE);
return COMPAT_NETDEV_TX_OK;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_xmit_frame --
*
* called by the stack to tx a pkt
*
* Result:
* COMPAT_NETDEV_TX_OK if the pkt is sent or dropped
* COMPAT_NETDEV_TX_BUSY if the pkt has to be requeued
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
struct vmxnet3_tx_queue *tq = &adapter->tx_queue;
return vmxnet3_tq_xmit(skb, tq, adapter, netdev);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_unmap_tx_buf --
*
* unmap, if necessay, the given tx buffer
*
* Result:
* None
*
* Side-effects:
* 1. tbi->map_type is reset to VMXNET3_MAP_NONE
*
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
struct pci_dev *pdev)
{
if (tbi->map_type == VMXNET3_MAP_SINGLE) {
pci_unmap_single(pdev,
tbi->dma_addr,
tbi->len,
PCI_DMA_TODEVICE);
} else if (tbi->map_type == VMXNET3_MAP_PAGE) {
pci_unmap_page(pdev,
tbi->dma_addr,
tbi->len,
PCI_DMA_TODEVICE);
} else {
VMXNET3_ASSERT(tbi->map_type == VMXNET3_MAP_NONE);
}
tbi->map_type = VMXNET3_MAP_NONE; /* to help debugging */
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_unmap_pkt --
*
* handle tx completion for a pkt. Basically undo vmxnet3_map_pkt().
* @eop_idx is the index of the eop desc in the tx ring for the pkt
*
* Result:
* # of tx descs that this pkt used
*
* Side-effects:
* 1. mappings are freed
* 2. buf_info[] are updated
* 3. tx_ring.{avail, next2comp} are updated.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_unmap_pkt(uint32 eop_idx,
struct vmxnet3_tx_queue *tq,
struct pci_dev *pdev)
{
struct sk_buff *skb;
int entries = 0;
/* no out of order completion */
VMXNET3_ASSERT(tq->buf_info[eop_idx].sop_idx == tq->tx_ring.next2comp);
VMXNET3_ASSERT(tq->tx_ring.base[eop_idx].txd.eop == 1);
VMXNET3_LOG("tx complete [%u %u]\n", tq->tx_ring.next2comp, eop_idx);
skb = tq->buf_info[eop_idx].skb;
VMXNET3_ASSERT(skb != NULL);
tq->buf_info[eop_idx].skb = NULL;
VMXNET3_INC_RING_IDX_ONLY(eop_idx, tq->tx_ring.size);
while (tq->tx_ring.next2comp != eop_idx) {
vmxnet3_unmap_tx_buf(tq->buf_info + tq->tx_ring.next2comp, pdev);
/* update next2comp w/o tx_lock. Since we are marking more, instead of
* less, tx ring entries avail, the worst case is that the tx routine
* incorrectly re-queues a pkt due to insufficient tx ring entries.
*/
vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
entries ++;
}
compat_dev_kfree_skb_any(skb, FREE_WRITE);
return entries;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_tx_complete --
*
* process tx completion for the given tx queue
*
* Result:
* # of tx ring entries completed
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
int completed = 0;
Vmxnet3_GenericDesc *gdesc;
gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
while (gdesc->tcd.gen == tq->comp_ring.gen) {
completed += vmxnet3_unmap_pkt(gdesc->tcd.txdIdx, tq, adapter->pdev);
vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring);
gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
}
if (completed) {
spin_lock(&tq->tx_lock);
if (UNLIKELY(vmxnet3_tq_stopped(tq, adapter) &&
vmxnet3_cmd_ring_desc_avail(&tq->tx_ring) >
VMXNET3_WAKE_QUEUE_THRESHOLD(tq) &&
compat_netif_carrier_ok(adapter->netdev))) {
vmxnet3_tq_wake(tq, adapter);
}
spin_unlock(&tq->tx_lock);
}
return completed;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_cleanup --
*
* unmap tx buffers, free pkts, and reset ring indices and gen
*
* Result:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
while (tq->tx_ring.next2comp != tq->tx_ring.next2fill) {
struct vmxnet3_tx_buf_info *tbi;
Vmxnet3_GenericDesc *gdesc;
tbi = tq->buf_info + tq->tx_ring.next2comp;
gdesc = tq->tx_ring.base + tq->tx_ring.next2comp;
vmxnet3_unmap_tx_buf(tbi, adapter->pdev);
if (tbi->skb) {
compat_dev_kfree_skb_any(tbi->skb, FREE_WRITE);
tbi->skb = NULL;
}
vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
}
/* sanity check */
#ifdef VMX86_DEBUG
{
/* verify all buffers are indeed unmapped and freed */
int i;
for (i = 0; i < tq->tx_ring.size; i++) {
VMXNET3_ASSERT(tq->buf_info[i].skb == NULL &&
tq->buf_info[i].map_type == VMXNET3_MAP_NONE);
}
}
#endif
tq->tx_ring.gen = VMXNET3_INIT_GEN;
tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0;
tq->comp_ring.gen = VMXNET3_INIT_GEN;
tq->comp_ring.next2proc = 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_destroy --
*
* free rings and buf_info for the tx queue. There must be no pending pkt
* in the tx ring.
*
* Result:
* None
*
* Side-effects:
* the .base fields of all rings and buf_info will be set to NULL
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
if (tq->tx_ring.base) {
pci_free_consistent(adapter->pdev,
tq->tx_ring.size * sizeof(Vmxnet3_TxDesc),
tq->tx_ring.base, tq->tx_ring.basePA);
tq->tx_ring.base = NULL;
}
if (tq->data_ring.base) {
pci_free_consistent(adapter->pdev,
tq->data_ring.size * sizeof(Vmxnet3_TxDataDesc),
tq->data_ring.base, tq->data_ring.basePA);
tq->data_ring.base = NULL;
}
if (tq->comp_ring.base) {
pci_free_consistent(adapter->pdev,
tq->comp_ring.size * sizeof(Vmxnet3_TxCompDesc),
tq->comp_ring.base, tq->comp_ring.basePA);
tq->comp_ring.base = NULL;
}
if (tq->buf_info) {
kfree(tq->buf_info);
tq->buf_info = NULL;
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_init --
*
* reset all internal states and rings for a tx queue
*
* Result:
* None
*
* Side-effects:
* 1. contents of the rings are reset to 0
* 2. indices and gen of rings are reset
* 3. bookkeeping data is reset
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
int i;
/* reset the tx ring contents to 0 and reset the tx ring states */
memset(tq->tx_ring.base, 0, tq->tx_ring.size * sizeof(Vmxnet3_TxDesc));
tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0;
tq->tx_ring.gen = VMXNET3_INIT_GEN;
memset(tq->data_ring.base, 0, tq->data_ring.size * sizeof(Vmxnet3_TxDataDesc));
/* reset the tx comp ring contents to 0 and reset the comp ring states */
memset(tq->comp_ring.base, 0, tq->comp_ring.size * sizeof(Vmxnet3_TxCompDesc));
tq->comp_ring.next2proc = 0;
tq->comp_ring.gen = VMXNET3_INIT_GEN;
/* reset the bookkeeping data */
memset(tq->buf_info, 0, sizeof(tq->buf_info[0]) * tq->tx_ring.size);
for (i = 0; i < tq->tx_ring.size; i++) {
tq->buf_info[i].map_type = VMXNET3_MAP_NONE;
}
/* stats are not reset */
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tq_create --
*
* allocate and initialize rings for the tx queue, also allocate and
* initialize buf_info
*
* Result:
* 0 on success, negative errno on failure.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
VMXNET3_ASSERT(tq->tx_ring.size > 0 &&
tq->data_ring.size == tq->tx_ring.size);
VMXNET3_ASSERT((tq->tx_ring.size & VMXNET3_RING_SIZE_MASK) == 0);
VMXNET3_ASSERT(!tq->tx_ring.base && !tq->data_ring.base &&
!tq->comp_ring.base && !tq->buf_info);
tq->tx_ring.base = pci_alloc_consistent(adapter->pdev,
tq->tx_ring.size * sizeof(Vmxnet3_TxDesc),
&tq->tx_ring.basePA);
if (!tq->tx_ring.base) {
printk(KERN_ERR "%s: failed to allocate tx ring\n", adapter->netdev->name);
goto err;
}
tq->data_ring.base = pci_alloc_consistent(adapter->pdev,
tq->data_ring.size * sizeof(Vmxnet3_TxDataDesc),
&tq->data_ring.basePA);
if (!tq->data_ring.base) {
printk(KERN_ERR "%s: failed to allocate data ring\n", adapter->netdev->name);
goto err;
}
tq->comp_ring.base = pci_alloc_consistent(adapter->pdev,
tq->comp_ring.size * sizeof(Vmxnet3_TxCompDesc),
&tq->comp_ring.basePA);
if (!tq->comp_ring.base) {
printk(KERN_ERR "%s: failed to allocate tx comp ring\n", adapter->netdev->name);
goto err;
}
tq->buf_info = kmalloc(sizeof(tq->buf_info[0]) * tq->tx_ring.size, GFP_KERNEL);
if (!tq->buf_info) {
printk(KERN_ERR "%s: failed to allocate tx bufinfo\n", adapter->netdev->name);
goto err;
}
return 0;
err:
vmxnet3_tq_destroy(tq, adapter);
return -ENOMEM;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_alloc_rx_buf --
*
* starting from ring->next2fill, allocate rx buffers for the given ring
* of the rx queue and update the rx desc. stop after @num_to_alloc buffers
* are allocated or allocation fails
*
* Result:
* returns # of buffers allocated
*
* Side-effects:
* 1. rx descs are updated
* 2. ring->{gen, next2fill} are updated
* 3. uncommitted[ring_idx] is incremented
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq,
uint32 ring_idx,
int num_to_alloc,
struct vmxnet3_adapter *adapter)
{
int num_allocated = 0;
struct vmxnet3_rx_buf_info *rbi_base = rq->buf_info[ring_idx];
struct vmxnet3_cmd_ring *ring = &rq->rx_ring[ring_idx];
uint32 val;
while (num_allocated < num_to_alloc) {
struct vmxnet3_rx_buf_info *rbi;
Vmxnet3_GenericDesc *gd;
rbi = rbi_base + ring->next2fill;
gd = ring->base + ring->next2fill;
if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
if (rbi->skb == NULL) {
rbi->skb = dev_alloc_skb(rbi->len + COMPAT_NET_IP_ALIGN);
if (UNLIKELY(rbi->skb == NULL)) {
rq->stats.rx_buf_alloc_failure++;
break;
}
skb_reserve(rbi->skb, COMPAT_NET_IP_ALIGN);
rbi->skb->dev = adapter->netdev;
rbi->dma_addr = pci_map_single(adapter->pdev, rbi->skb->data,
rbi->len, PCI_DMA_FROMDEVICE);
} else {
/* rx buffer skipped by the device */
}
val = VMXNET3_RXD_BTYPE_HEAD << VMXNET3_RXD_BTYPE_SHIFT;
} else {
VMXNET3_ASSERT(rbi->buf_type == VMXNET3_RX_BUF_PAGE &&
rbi->len == PAGE_SIZE);
if (rbi->page == NULL) {
rbi->page = alloc_page(GFP_ATOMIC);
if (UNLIKELY(rbi->page == NULL)) {
rq->stats.rx_buf_alloc_failure++;
break;
}
rbi->dma_addr = pci_map_page(adapter->pdev, rbi->page, 0,
PAGE_SIZE, PCI_DMA_FROMDEVICE);
} else {
/* rx buffers skipped by the device */
}
val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT;
}
VMXNET3_ASSERT(rbi->dma_addr != 0);
gd->rxd.addr = rbi->dma_addr;
wmb();
gd->dword[2] = (ring->gen << VMXNET3_RXD_GEN_SHIFT) | val | rbi->len;
num_allocated ++;
vmxnet3_cmd_ring_adv_next2fill(ring);
}
rq->uncommitted[ring_idx] += num_allocated;
VMXNET3_LOG("alloc_rx_buf: %d allocated, next2fill %u, next2comp %u, uncommited %u\n",
num_allocated, ring->next2fill, ring->next2comp,
rq->uncommitted[ring_idx]);
/* so that the device can distinguish a full ring and an empty ring */
VMXNET3_ASSERT(num_allocated == 0 || ring->next2fill != ring->next2comp);
return num_allocated;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_append_frag --
*
* Append a frag to the speicified skb. It assumes the skb still has space
* to accommodate the frag. It only increments skb->data_len
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_append_frag(struct sk_buff *skb,
Vmxnet3_RxCompDesc *rcd,
struct vmxnet3_rx_buf_info *rbi)
{
struct skb_frag_struct *frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags;
VMXNET3_ASSERT(skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS);
frag->page = rbi->page;
frag->page_offset = 0;
frag->size = rcd->len;
skb->data_len += frag->size;
skb_shinfo(skb)->nr_frags ++;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rx_csum --
*
* called to process csum related bits in the EOP RCD descriptor
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static inline void
vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
struct sk_buff *skb,
Vmxnet3_GenericDesc *gdesc)
{
if (!gdesc->rcd.cnc && adapter->rxcsum) {
/* typical case: TCP/UDP over IP and both csums are correct */
if ((gdesc->dword[3] & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) {
skb->ip_summed = VM_CHECKSUM_UNNECESSARY;
VMXNET3_ASSERT((gdesc->rcd.tcp || gdesc->rcd.udp) &&
(gdesc->rcd.v4 || gdesc->rcd.v6) &&
!gdesc->rcd.frg);
} else {
if (gdesc->rcd.csum) {
skb->csum = htons(gdesc->rcd.csum);
skb->ip_summed = VM_RX_CHECKSUM_PARTIAL;
} else {
skb->ip_summed = CHECKSUM_NONE;
}
}
} else {
skb->ip_summed = CHECKSUM_NONE;
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rx_error --
*
* called when ERR bit is set for a received pkt
*
* Result:
* none
*
* Side-effects:
* 1. up the stat counters
* 2. free the pkt
* 3. reset ctx->skb
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_rx_error(struct vmxnet3_rx_queue *rq,
Vmxnet3_RxCompDesc *rcd,
struct vmxnet3_rx_ctx *ctx)
{
rq->stats.drop_err++;
if (!rcd->fcs) {
rq->stats.drop_fcs++;
}
rq->stats.drop_total++;
compat_dev_kfree_skb_irq(ctx->skb, FREE_WRITE);
ctx->skb = NULL;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_rx_complete --
*
* process the rx completion ring of the given rx queue. Quota specified the
* max # of rx completion entries to be processed
*
* Result:
* # of rx descs completed
*
* Side-effects:
* None
*----------------------------------------------------------------------------
*/
static int
#ifdef VMXNET3_NAPI
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter,
int quota)
#else
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
#endif
{
static uint32 rxprod_reg[2] = {VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2};
uint32 num_rxd = 0;
Vmxnet3_RxCompDesc *rcd;
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
rcd = &rq->comp_ring.base[rq->comp_ring.next2proc].rcd;
while (rcd->gen == rq->comp_ring.gen) {
struct vmxnet3_rx_buf_info *rbi;
struct sk_buff *skb;
int num_to_alloc;
Vmxnet3_RxDesc *rxd;
uint32 idx, ring_idx;
#ifdef VMXNET3_NAPI
if (num_rxd >= quota) {
/* we may stop even before we see the EOP desc of the current pkt */
break;
}
num_rxd++;
#endif
idx = rcd->rxdIdx;
ring_idx = rcd->rqID == rq->qid ? 0 : 1;
rxd = &rq->rx_ring[ring_idx].base[idx].rxd;
rbi = rq->buf_info[ring_idx] + idx;
VMXNET3_ASSERT(rcd->len <= rxd->len);
VMXNET3_ASSERT(rxd->addr == rbi->dma_addr && rxd->len == rbi->len);
if (rcd->sop) { /* first buf of the pkt */
VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
rcd->rqID == rq->qid);
VMXNET3_ASSERT(rbi->buf_type == VMXNET3_RX_BUF_SKB);
VMXNET3_ASSERT(ctx->skb == NULL && rbi->skb != NULL);
if (UNLIKELY(rcd->len == 0)) {
/* Pretend the rx buffer is skipped. */
VMXNET3_ASSERT(rcd->sop && rcd->eop);
VMXNET3_LOG("rxRing[%u][%u] 0 length\n", ring_idx, idx);
goto rcd_done;
}
ctx->skb = rbi->skb;
rbi->skb = NULL;
skb_put(ctx->skb, rcd->len);
pci_unmap_single(adapter->pdev,
rbi->dma_addr,
rbi->len,
PCI_DMA_FROMDEVICE);
} else {
VMXNET3_ASSERT(ctx->skb != NULL);
/* non SOP buffer must be type 1 in most cases */
if (rbi->buf_type == VMXNET3_RX_BUF_PAGE) {
VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_BODY);
if (rcd->len) {
vmxnet3_append_frag(ctx->skb, rcd, rbi);
pci_unmap_page(adapter->pdev,
rbi->dma_addr,
rbi->len,
PCI_DMA_FROMDEVICE);
rbi->page = NULL;
}
} else {
/* the only time a non-SOP buffer is type 0 is when it's EOP and
* error flag is raised
*/
if (UNLIKELY(rcd->err && rcd->eop)) {
/* pretend this buffer is skipped by the device.
* dont chain it and don't reset rbi->skb to NULL
*/
VMXNET3_LOG("Err EOP is type 0 from ring[%u].rxd[%u]\n", ring_idx, idx);
} else {
/* bug in the device */
VMXNET3_ASSERT(FALSE);
}
}
}
skb = ctx->skb;
if (rcd->eop) {
skb->len += skb->data_len;
skb->truesize += skb->data_len;
if (UNLIKELY(rcd->err)) {
vmxnet3_rx_error(rq, rcd, ctx);
goto rcd_done;
}
vmxnet3_rx_csum(adapter, skb, (Vmxnet3_GenericDesc*)rcd);
skb->protocol = eth_type_trans(skb, adapter->netdev);
#ifdef VMXNET3_NAPI
if (UNLIKELY(adapter->vlan_grp && rcd->ts)) {
vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rcd->tci);
} else {
netif_receive_skb(skb);
}
#else
if (UNLIKELY(adapter->vlan_grp && rcd->ts)) {
vlan_hwaccel_rx(skb, adapter->vlan_grp, rcd->tci);
} else {
netif_rx(skb);
}
#endif
adapter->netdev->last_rx = jiffies;
ctx->skb = NULL;
}
rcd_done:
/* device may skip some rx descs */
rq->rx_ring[ring_idx].next2comp = idx;
VMXNET3_INC_RING_IDX_ONLY(rq->rx_ring[ring_idx].next2comp,
rq->rx_ring[ring_idx].size);
/* refill rx buffers from time to time to avoid starving the h/w */
num_to_alloc = vmxnet3_cmd_ring_desc_avail(rq->rx_ring + ring_idx);
if (UNLIKELY(num_to_alloc > VMXNET3_RX_ALLOC_THRESHOLD(rq, ring_idx, adapter))) {
vmxnet3_rq_alloc_rx_buf(rq, ring_idx, num_to_alloc, adapter);
/* if needed, update the register */
if (UNLIKELY(rq->shared->updateRxProd)) {
VMXNET3_WRITE_BAR0_REG(adapter, rxprod_reg[ring_idx] + rq->qid * 8,
rq->rx_ring[ring_idx].next2fill);
rq->uncommitted[ring_idx] = 0;
}
}
vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
rcd = &rq->comp_ring.base[rq->comp_ring.next2proc].rcd;
}
return num_rxd;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_cleanup --
*
* Unmap and free the rx buffers allocated to the rx queue. Other resources
* are NOT freed. This is the counterpart of vmxnet3_rq_init()
*
* the content of the rx rings must still be valid when we are invoked
*
* Result:
* None
*
* Side-effects:
* 1. indices and gen of each ring are reset to the initial value
* 2. buf_info[] and buf_info2[] are cleared.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
uint32 i, ring_idx;
Vmxnet3_RxDesc *rxd;
for (ring_idx = 0; ring_idx < 2; ring_idx++) {
for (i = 0; i < rq->rx_ring[ring_idx].size; i++) {
rxd = &rq->rx_ring[ring_idx].base[i].rxd;
if (rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
rq->buf_info[ring_idx][i].skb) {
pci_unmap_single(adapter->pdev,
rxd->addr,
rxd->len,
PCI_DMA_FROMDEVICE);
compat_dev_kfree_skb(rq->buf_info[ring_idx][i].skb, FREE_WRITE);
rq->buf_info[ring_idx][i].skb = NULL;
} else if (rxd->btype == VMXNET3_RXD_BTYPE_BODY &&
rq->buf_info[ring_idx][i].page) {
pci_unmap_page(adapter->pdev,
rxd->addr,
rxd->len,
PCI_DMA_FROMDEVICE);
put_page(rq->buf_info[ring_idx][i].page);
rq->buf_info[ring_idx][i].page = NULL;
}
}
rq->rx_ring[ring_idx].gen = VMXNET3_INIT_GEN;
rq->rx_ring[ring_idx].next2fill = rq->rx_ring[ring_idx].next2comp = 0;
rq->uncommitted[ring_idx] = 0;
}
rq->comp_ring.gen = VMXNET3_INIT_GEN;
rq->comp_ring.next2proc = 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_destroy --
*
* Free rings and buf_info for the rx queue. The rx buffers must have
* ALREADY been freed.
*
* Result:
* None
*
* Side-effects:
* the .base fields of all rings will be set to NULL
*----------------------------------------------------------------------------
*/
static void
vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
int i;
#ifdef VMX86_DEBUG
/* all rx buffers must have already been freed */
{
int j;
for (i = 0; i < 2; i++) {
if (rq->buf_info[i]) {
for (j = 0; j < rq->rx_ring[i].size; j++) {
VMXNET3_ASSERT(rq->buf_info[i][j].page == NULL);
}
}
}
}
#endif
if (rq->buf_info[0]) {
kfree(rq->buf_info[0]);
}
for (i = 0; i < 2; i++) {
if (rq->rx_ring[i].base) {
pci_free_consistent(adapter->pdev,
rq->rx_ring[i].size * sizeof(Vmxnet3_RxDesc),
rq->rx_ring[i].base, rq->rx_ring[i].basePA);
rq->rx_ring[i].base = NULL;
}
rq->buf_info[i] = NULL;
}
if (rq->comp_ring.base) {
pci_free_consistent(adapter->pdev,
rq->comp_ring.size * sizeof(Vmxnet3_RxCompDesc),
rq->comp_ring.base, rq->comp_ring.basePA);
rq->comp_ring.base = NULL;
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_init --
*
* initialize buf_info, allocate rx buffers and fill the rx rings. On
* failure, the rx buffers already allocated are NOT freed
*
* Result:
* 0 on success or error code
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
int i;
VMXNET3_ASSERT(adapter->rx_buf_per_pkt > 0 &&
rq->rx_ring[0].size % adapter->rx_buf_per_pkt == 0);
/* initialize buf_info */
for (i = 0; i < rq->rx_ring[0].size; i++) {
VMXNET3_ASSERT(rq->buf_info[0][i].skb == NULL);
if (i % adapter->rx_buf_per_pkt == 0) { /* 1st buf for a pkt is skbuff */
rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_SKB;
rq->buf_info[0][i].len = adapter->skb_buf_size;
} else { /* subsequent bufs for a pkt is frag */
rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_PAGE;
rq->buf_info[0][i].len = PAGE_SIZE;
}
}
for (i = 0; i < rq->rx_ring[1].size; i++) {
VMXNET3_ASSERT(rq->buf_info[1][i].page == NULL);
rq->buf_info[1][i].buf_type = VMXNET3_RX_BUF_PAGE;
rq->buf_info[1][i].len = PAGE_SIZE;
}
/* reset internal state and allocate buffers for both rings */
for (i = 0; i < 2; i++) {
rq->rx_ring[i].next2fill = rq->rx_ring[i].next2comp = 0;
rq->uncommitted[i] = 0;
memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size * sizeof(Vmxnet3_RxDesc));
rq->rx_ring[i].gen = VMXNET3_INIT_GEN;
}
if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1, adapter) == 0) {
// at least has 1 rx buffer for the 1st ring
return -ENOMEM;
}
vmxnet3_rq_alloc_rx_buf(rq, 1, rq->rx_ring[1].size - 1, adapter);
/* reset the comp ring */
rq->comp_ring.next2proc = 0;
memset(rq->comp_ring.base, 0, rq->comp_ring.size * sizeof(Vmxnet3_RxCompDesc));
rq->comp_ring.gen = VMXNET3_INIT_GEN;
/* reset rxctx */
rq->rx_ctx.skb = NULL;
/* stats are not reset */
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_rq_create --
*
* allocate and initialize two cmd rings and the completion ring for the
* given rx queue. Also allocate and initialize buf_info.
* rx buffers are NOT allocated
*
* Result:
* 0 on success, negative errno on failure
*----------------------------------------------------------------------------
*/
static int
vmxnet3_rq_create(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
int i;
size_t sz;
struct vmxnet3_rx_buf_info *bi;
VMXNET3_ASSERT(rq->rx_ring[0].size % adapter->rx_buf_per_pkt == 0);
for (i = 0; i < 2; i++) {
VMXNET3_ASSERT((rq->rx_ring[i].size & VMXNET3_RING_SIZE_MASK) == 0);
VMXNET3_ASSERT(rq->rx_ring[i].base == NULL);
sz = rq->rx_ring[i].size * sizeof(Vmxnet3_RxDesc);
rq->rx_ring[i].base = pci_alloc_consistent(adapter->pdev,
sz,
&rq->rx_ring[i].basePA);
if (!rq->rx_ring[i].base) {
printk(KERN_ERR "%s: failed to allocate rx ring %d\n", adapter->netdev->name, i);
goto err;
}
}
sz = rq->comp_ring.size * sizeof(Vmxnet3_RxCompDesc);
VMXNET3_ASSERT(rq->comp_ring.base == NULL);
rq->comp_ring.base = pci_alloc_consistent(adapter->pdev,
sz,
&rq->comp_ring.basePA);
if (!rq->comp_ring.base) {
printk(KERN_ERR "%s: failed to allocate rx comp ring\n", adapter->netdev->name);
goto err;
}
VMXNET3_ASSERT(!rq->buf_info[0] && !rq->buf_info[1]);
sz = sizeof(struct vmxnet3_rx_buf_info) * (rq->rx_ring[0].size + rq->rx_ring[1].size);
bi = kmalloc(sz, GFP_KERNEL);
if (!bi) {
printk(KERN_ERR "%s: failed to allocate rx bufinfo\n", adapter->netdev->name);
goto err;
}
memset(bi, 0, sz);
rq->buf_info[0] = bi;
rq->buf_info[1] = bi + rq->rx_ring[0].size;
return 0;
err:
vmxnet3_rq_destroy(rq, adapter);
return -ENOMEM;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_vlan_features --
*
* Inherit net_device features from real device to VLAN device.
*
* Results:
* None.
*
* Side effects:
* Modifies VLAN net_device's features.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_vlan_features(struct vmxnet3_adapter *adapter, // IN:
uint16_t vid, // IN:
Bool allvids) // IN:
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
struct net_device *v_netdev;
if (adapter->vlan_grp) {
if (allvids) {
for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
v_netdev = compat_vlan_group_get_device(adapter->vlan_grp, vid);
if (v_netdev) {
v_netdev->features |= adapter->netdev->features;
compat_vlan_group_set_device(adapter->vlan_grp, vid, v_netdev);
}
}
} else {
v_netdev = compat_vlan_group_get_device(adapter->vlan_grp, vid);
if (v_netdev) {
v_netdev->features |= adapter->netdev->features;
compat_vlan_group_set_device(adapter->vlan_grp, vid, v_netdev);
}
}
}
#endif
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_vlan_rx_register --
*
* Called to enable/disable VLAN stripping.
*
* Result:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
Vmxnet3_DriverShared *shared = adapter->shared;
uint32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
if (grp) {
// add vlan rx stripping.
if (adapter->netdev->features & NETIF_F_HW_VLAN_RX) {
int i;
Vmxnet3_DSDevRead *devRead = &shared->devRead;
adapter->vlan_grp = grp;
/* update FEATURES to device */
devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE);
/*
* Clear entire vfTable; then enable untagged pkts.
* Note: setting one entry in vfTable to non-zero turns on VLAN rx filtering.
*/
for (i = 0; i < VMXNET3_VFT_SIZE; i++) {
//
vfTable[i] = 0;
}
VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_VLAN_FILTERS);
} else {
printk(KERN_ERR "%s: vlan_rx_register when device has no NETIF_F_HW_VLAN_RX\n",
netdev->name);
}
} else {
// remove vlan rx stripping.
Vmxnet3_DSDevRead *devRead = &shared->devRead;
adapter->vlan_grp = NULL;
if (devRead->misc.uptFeatures & UPT1_F_RXVLAN) {
int i;
for (i = 0; i < VMXNET3_VFT_SIZE; i++) {
// clear entire vfTable; this also disables VLAN rx filtering
vfTable[i] = 0;
}
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_VLAN_FILTERS);
/* update FEATURES to device */
devRead->misc.uptFeatures &= ~UPT1_F_RXVLAN;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE);
}
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_restore_vlan --
*
* Setup driverShared.devRead.rxFilter.vfTable
*
* Result:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_restore_vlan(struct vmxnet3_adapter *adapter)
{
if (adapter->vlan_grp) {
uint16 vid;
uint32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
Bool activeVlan = FALSE;
for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
if (compat_vlan_group_get_device(adapter->vlan_grp, vid)) {
VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
activeVlan = TRUE;
}
}
if (activeVlan) {
/* continue to allow untagged pkts */
VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
}
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_vlan_rx_add_vid --
*
* Called to add a VLAN ID.
*
* Result:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
uint32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
vmxnet3_vlan_features(adapter, vid, FALSE);
VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_VLAN_FILTERS);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_vlan_rx_kill_vid --
*
* Called to remove a VLAN ID.
*
* Result:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
uint32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_VLAN_FILTERS);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_copy_mc --
*
* Allocate a buffer and copy into the mcast list.
* It returns NULL if the mcast list exceeds the limit.
*
* Result:
* The addr of the allocated buffer or NULL.
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static uint8 *
vmxnet3_copy_mc(struct net_device *netdev)
{
uint8 *buf = NULL;
uint32 sz = netdev->mc_count * ETH_ALEN;
/* Vmxnet3_RxFilterConf.mfTableLen is uint16. */
if (sz <= 0xffff) {
/* We may be called with BH disabled */
buf = kmalloc(sz, GFP_ATOMIC);
if (buf) {
int i;
struct dev_mc_list *mc = netdev->mc_list;
for (i = 0; i < netdev->mc_count; i++) {
VMXNET3_ASSERT(mc);
memcpy(buf + i * ETH_ALEN, mc->dmi_addr, ETH_ALEN);
mc = mc->next;
}
}
}
return buf;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_mc --
*
* Called to change rx mode as well as multicast list.
*
* Result:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_set_mc(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
Vmxnet3_RxFilterConf *rxConf = &adapter->shared->devRead.rxFilterConf;
uint8 *new_table = NULL;
uint32 new_mode = VMXNET3_RXM_UCAST;
if (netdev->flags & IFF_PROMISC) {
new_mode |= VMXNET3_RXM_PROMISC;
}
if (netdev->flags & IFF_BROADCAST) {
new_mode |= VMXNET3_RXM_BCAST;
}
if (netdev->flags & IFF_ALLMULTI) {
new_mode |= VMXNET3_RXM_ALL_MULTI;
} else {
if (netdev->mc_count > 0) {
new_table = vmxnet3_copy_mc(netdev);
if (new_table) {
new_mode |= VMXNET3_RXM_MCAST;
rxConf->mfTableLen = netdev->mc_count * ETH_ALEN;
rxConf->mfTablePA = virt_to_phys(new_table);
} else {
printk(KERN_INFO "%s: failed to copy mcast list, setting ALL_MULTI\n",
netdev->name);
new_mode |= VMXNET3_RXM_ALL_MULTI;
}
}
}
if (!(new_mode & VMXNET3_RXM_MCAST)) {
rxConf->mfTableLen = 0;
rxConf->mfTablePA = 0;
}
if (new_mode != rxConf->rxMode) {
rxConf->rxMode = new_mode;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_RX_MODE);
}
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_MAC_FILTERS);
if (new_table) {
kfree(new_table);
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_activate_dev --
*
* put the vNIC into an operational state. After this function finishes, the
* adapter is fully functional. It does the following:
*
* 1. initialize tq and rq
* 2. fill rx rings with rx buffers
* 3. setup intr
* 4. setup driver_shared
* 5. activate the dev
* 6. signal the stack that the vNIC is ready to tx/rx
* 7. enable intrs for the vNIC
*
* Result:
* 0 if the vNIC is in operation state
* error code if any intermediate step fails.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
{
int err;
uint32 ret;
VMXNET3_LOG("%s: skb_buf_size %d, rx_buf_per_pkt %d, ring sizes %u %u %u\n",
adapter->netdev->name,
adapter->skb_buf_size, adapter->rx_buf_per_pkt,
adapter->tx_queue.tx_ring.size,
adapter->rx_queue.rx_ring[0].size,
adapter->rx_queue.rx_ring[1].size);
vmxnet3_tq_init(&adapter->tx_queue, adapter);
err = vmxnet3_rq_init(&adapter->rx_queue, adapter);
if (err) {
printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
adapter->netdev->name, err);
goto rq_err;
}
err = vmxnet3_request_irqs(adapter);
if (err) {
printk(KERN_ERR "Failed to setup irq for %s: error %d\n",
adapter->netdev->name, err);
goto irq_err;
}
vmxnet3_setup_driver_shared(adapter);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAL, VMXNET3_GET_ADDR_LO(adapter->shared_pa));
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH, VMXNET3_GET_ADDR_HI(adapter->shared_pa));
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_ACTIVATE_DEV);
ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
if (ret != 0) {
printk(KERN_ERR "Failed to activate dev %s: error %u\n",
adapter->netdev->name, ret);
err = -EINVAL;
goto activate_err;
}
VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD,
adapter->rx_queue.rx_ring[0].next2fill);
VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD2,
adapter->rx_queue.rx_ring[1].next2fill);
/* Apply the rx filter settins last. */
vmxnet3_set_mc(adapter->netdev);
/*
* Check link state when first activating device. It will start the tx queue
* if the link is up.
*/
vmxnet3_check_link(adapter);
#ifdef VMXNET3_NAPI
compat_napi_enable(adapter->netdev, &adapter->napi);
#endif
vmxnet3_enable_all_intrs(adapter);
clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
return 0;
activate_err:
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAL, 0);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH, 0);
vmxnet3_free_irqs(adapter);
irq_err:
rq_err:
/* free up buffers we allocated */
vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
return err;
}
static void
vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
{
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_quiesce_dev --
*
* stop the device. After this function returns, the adapter stop pkt tx/rx
* and won't generate intrs. The stack won't try to xmit pkts through us,
* nor will it poll us for pkts. It does the following:
*
* 1. ask the vNIC to quiesce
* 2. disable the vNIC from generating intrs
* 3. free intr
* 4. stop the stack from xmiting pkts thru us and polling
* 5. free rx buffers
* 6. tx complete pkts pending
*
* Result:
* 0 on success
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
{
if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state)) {
printk(KERN_INFO "%s: already quiesced\n", adapter->netdev->name);
return 0;
}
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
vmxnet3_disable_all_intrs(adapter);
#ifdef VMXNET3_NAPI
compat_napi_disable(adapter->netdev, &adapter->napi);
#endif
netif_tx_disable(adapter->netdev);
adapter->link_speed = 0;
netif_carrier_off(adapter->netdev);
/* TODO: force tx completion */
vmxnet3_tq_cleanup(&adapter->tx_queue, adapter);
vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
vmxnet3_free_irqs(adapter);
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_write_mac_addr --
*
* Write the given MAC address to the device register
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, uint8 *mac)
{
uint32 tmp;
tmp = *(uint32*)mac;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_MACL, tmp);
tmp = (mac[5] << 8) | mac[4];
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_MACH, tmp);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_mac_addr --
*
* Change the current MAC address
*
* Result:
* 0 on success
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_mac_addr(struct net_device *netdev, void *p)
{
struct sockaddr *addr = p;
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
vmxnet3_write_mac_addr(adapter, addr->sa_data);
return 0;
}
/* ==================== initialization and cleanup routines ============ */
/*
*----------------------------------------------------------------------------
*
* vmxnet3_alloc_pci_resources --
*
* allocate pci resources
*
* Result:
* 0 on success or error code
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, Bool *dma64)
{
int err;
unsigned long mmio_start, mmio_len;
struct pci_dev *pdev = adapter->pdev;
err = compat_pci_enable_device(pdev);
if (err) {
printk(KERN_ERR "Failed to enable adapter %s: error %d\n",
compat_pci_name(pdev), err);
return err;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6)
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
printk(KERN_ERR "pci_set_consistent_dma_mask failed for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
goto err_set_mask;
}
*dma64 = TRUE;
} else {
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
printk(KERN_ERR "pci_set_dma_mask failed for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
goto err_set_mask;
}
*dma64 = FALSE;
}
#else
*dma64 = TRUE;
#endif
err = compat_pci_request_regions(pdev, vmxnet3_driver_name);
if (err) {
printk(KERN_ERR "Failed to request region for adapter %s: error %d\n",
compat_pci_name(pdev), err);
goto err_set_mask;
}
compat_pci_set_master(pdev);
mmio_start = compat_pci_resource_start(pdev, 0);
mmio_len = compat_pci_resource_len(pdev, 0);
adapter->hw_addr0 = ioremap(mmio_start, mmio_len);
if (!adapter->hw_addr0) {
printk(KERN_ERR "Failed to map bar0 for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
goto err_ioremap;
}
mmio_start = compat_pci_resource_start(pdev, 1);
mmio_len = compat_pci_resource_len(pdev, 1);
adapter->hw_addr1 = ioremap(mmio_start, mmio_len);
if (!adapter->hw_addr1) {
printk(KERN_ERR "Failed to map bar1 for adapter %s\n",
compat_pci_name(pdev));
err = -EIO;
goto err_bar1;
}
return 0;
err_bar1:
iounmap(adapter->hw_addr0);
err_ioremap:
compat_pci_release_regions(pdev);
err_set_mask:
compat_pci_disable_device(pdev);
return err;
}
static void
vmxnet3_free_pci_resources(struct vmxnet3_adapter *adapter)
{
VMXNET3_ASSERT(adapter->pdev);
iounmap(adapter->hw_addr0);
iounmap(adapter->hw_addr1);
compat_pci_release_regions(adapter->pdev);
compat_pci_disable_device(adapter->pdev);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_setup_driver_shared --
*
* Set up driver_shared based on settings in adapter.
*
* Result:
* 1. the whole driver_shared area is wiped out and re-initialized
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
{
Vmxnet3_DriverShared *shared = adapter->shared;
Vmxnet3_DSDevRead *devRead = &shared->devRead;
Vmxnet3_TxQueueConf *tqc;
Vmxnet3_RxQueueConf *rqc;
int i;
memset(shared, 0, sizeof(*shared));
/* driver settings */
shared->magic = VMXNET3_REV1_MAGIC;
devRead->misc.driverInfo.version = VMXNET3_DRIVER_VERSION_NUM;
devRead->misc.driverInfo.gos.gosBits = sizeof(void*) == 4 ? VMXNET3_GOS_BITS_32 :
VMXNET3_GOS_BITS_64;
devRead->misc.driverInfo.gos.gosType = VMXNET3_GOS_TYPE_LINUX;
devRead->misc.driverInfo.vmxnet3RevSpt = 1;
devRead->misc.driverInfo.uptVerSpt = 1;
devRead->misc.ddPA = virt_to_phys(adapter);
devRead->misc.ddLen = sizeof(struct vmxnet3_adapter);
/* set up feature flags */
if (adapter->rxcsum) {
devRead->misc.uptFeatures |= UPT1_F_RXCSUM;
}
if (adapter->lro) {
devRead->misc.uptFeatures |= UPT1_F_LRO;
devRead->misc.maxNumRxSG = 1 + MAX_SKB_FRAGS;
}
if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX)
&& adapter->vlan_grp) {
devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
}
devRead->misc.mtu = adapter->netdev->mtu;
devRead->misc.queueDescPA = adapter->queue_desc_pa;
devRead->misc.queueDescLen = sizeof(Vmxnet3_TxQueueDesc) +
sizeof(Vmxnet3_RxQueueDesc);
/* tx queue settings */
VMXNET3_ASSERT(adapter->tx_queue.tx_ring.base != NULL);
devRead->misc.numTxQueues = 1;
tqc = &adapter->tqd_start->conf;
tqc->txRingBasePA = adapter->tx_queue.tx_ring.basePA;
tqc->dataRingBasePA = adapter->tx_queue.data_ring.basePA;
tqc->compRingBasePA = adapter->tx_queue.comp_ring.basePA;
tqc->ddPA = virt_to_phys(adapter->tx_queue.buf_info);
tqc->txRingSize = adapter->tx_queue.tx_ring.size;
tqc->dataRingSize = adapter->tx_queue.data_ring.size;
tqc->compRingSize = adapter->tx_queue.comp_ring.size;
tqc->ddLen = sizeof(struct vmxnet3_tx_buf_info) *
tqc->txRingSize;
tqc->intrIdx = adapter->tx_queue.comp_ring.intr_idx;
/* rx queue settings */
devRead->misc.numRxQueues = 1;
rqc = &adapter->rqd_start->conf;
rqc->rxRingBasePA[0] = adapter->rx_queue.rx_ring[0].basePA;
rqc->rxRingBasePA[1] = adapter->rx_queue.rx_ring[1].basePA;
rqc->compRingBasePA = adapter->rx_queue.comp_ring.basePA;
rqc->ddPA = virt_to_phys(adapter->rx_queue.buf_info);
rqc->rxRingSize[0] = adapter->rx_queue.rx_ring[0].size;
rqc->rxRingSize[1] = adapter->rx_queue.rx_ring[1].size;
rqc->compRingSize = adapter->rx_queue.comp_ring.size;
rqc->ddLen = sizeof(struct vmxnet3_rx_buf_info) *
(rqc->rxRingSize[0] + rqc->rxRingSize[1]);
rqc->intrIdx = adapter->rx_queue.comp_ring.intr_idx;
/* intr settings */
devRead->intrConf.autoMask = adapter->intr.mask_mode == VMXNET3_IMM_AUTO;
devRead->intrConf.numIntrs = adapter->intr.num_intrs;
for (i = 0; i < adapter->intr.num_intrs; i++) {
devRead->intrConf.modLevels[i] = adapter->intr.mod_levels[i];
}
devRead->intrConf.eventIntrIdx = adapter->intr.event_intr_idx;
/* rx filter settings */
devRead->rxFilterConf.rxMode = 0;
vmxnet3_restore_vlan(adapter);
/* the rest are already zeroed */
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_adjust_rx_ring_size --
*
* calc the # of buffers for a pkt based on mtu, then adjust the size of the
* 1st rx ring accordingly
*
* Result:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
{
size_t sz;
if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE - VMXNET3_MAX_ETH_HDR_SIZE) {
adapter->skb_buf_size = adapter->netdev->mtu + VMXNET3_MAX_ETH_HDR_SIZE;
if (adapter->skb_buf_size < VMXNET3_MIN_T0_BUF_SIZE) {
adapter->skb_buf_size = VMXNET3_MIN_T0_BUF_SIZE;
}
adapter->rx_buf_per_pkt = 1;
} else {
adapter->skb_buf_size = VMXNET3_MAX_SKB_BUF_SIZE;
sz = adapter->netdev->mtu - VMXNET3_MAX_SKB_BUF_SIZE + VMXNET3_MAX_ETH_HDR_SIZE;
adapter->rx_buf_per_pkt = 1 + (sz + PAGE_SIZE - 1) / PAGE_SIZE;
}
/*
* for simplicity, force the ring0 size to be a multiple of
* rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN
*/
sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
adapter->rx_queue.rx_ring[0].size =
(adapter->rx_queue.rx_ring[0].size + sz - 1) / sz * sz;
adapter->rx_queue.rx_ring[0].size = min_t(uint32, adapter->rx_queue.rx_ring[0].size,
VMXNET3_RX_RING_MAX_SIZE / sz * sz);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_create_queues --
*
* Create the specified number of tx queues and rx queues. On failure, it
* destroys the queues created.
*
* Results:
* 0 on success, errno value on failure.
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
uint32 tx_ring_size,
uint32 rx_ring_size,
uint32 rx_ring2_size)
{
int err;
adapter->tx_queue.tx_ring.size = tx_ring_size;
adapter->tx_queue.data_ring.size = tx_ring_size;
adapter->tx_queue.comp_ring.size = tx_ring_size;
adapter->tx_queue.shared = &adapter->tqd_start->ctrl;
adapter->tx_queue.stopped = TRUE;
err = vmxnet3_tq_create(&adapter->tx_queue, adapter);
if (err) {
return err;
}
adapter->rx_queue.rx_ring[0].size = rx_ring_size;
adapter->rx_queue.rx_ring[1].size = rx_ring2_size;
vmxnet3_adjust_rx_ring_size(adapter);
adapter->rx_queue.comp_ring.size = adapter->rx_queue.rx_ring[0].size +
adapter->rx_queue.rx_ring[1].size;
adapter->rx_queue.qid = 0;
adapter->rx_queue.qid2 = 1;
adapter->rx_queue.shared = &adapter->rqd_start->ctrl;
err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
if (err) {
vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
}
return err;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_open --
*
* called when the interface is brought up
*
* Result:
* 0 on success, negative errno value on failure
*
* Side-effects:
* setup rings, allocate necessary resources, request for IRQs, configure
* the device. The device is functional after this function finishes
* successfully.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_open(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter;
int err;
adapter = compat_netdev_priv(netdev);
spin_lock_init(&adapter->tx_queue.tx_lock);
err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE,
VMXNET3_DEF_RX_RING_SIZE, VMXNET3_DEF_RX_RING_SIZE);
if (err) {
goto queue_err;
}
err = vmxnet3_activate_dev(adapter);
if (err) {
goto activate_err;
}
COMPAT_NETDEV_MOD_INC_USE_COUNT;
return 0;
activate_err:
vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
queue_err:
return err;
}
static int
vmxnet3_close(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
/*
* Reset_work may be in the middle of resetting the device, wait for its
* completion.
*/
while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state)) {
compat_msleep(1);
}
vmxnet3_quiesce_dev(adapter);
vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
COMPAT_NETDEV_MOD_DEC_USE_COUNT;
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_force_close --
*
* called to forcibly close the device when the driver failed to re-activate it.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_force_close(struct vmxnet3_adapter *adapter)
{
/*
* we must clear VMXNET3_STATE_BIT_RESETTING, otherwise
* vmxnet3_close() will deadlock.
*/
VMXNET3_ASSERT(!test_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state));
#ifdef VMXNET3_NAPI
/* we need to enable NAPI, otherwise dev_close will deadlock */
compat_napi_enable(adapter->netdev, &adapter->napi);
#endif
dev_close(adapter->netdev);
}
static int
vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
int err = 0;
if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU) {
return -EINVAL;
}
if (new_mtu > 1500 && !adapter->jumbo_frame) {
return -EINVAL;
}
netdev->mtu = new_mtu;
/*
* Reset_work may be in the middle of resetting the device, wait for its
* completion.
*/
while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state)) {
compat_msleep(1);
}
if (compat_netif_running(netdev)) {
vmxnet3_quiesce_dev(adapter);
vmxnet3_reset_dev(adapter);
/* we need to re-create the rx queue based on the new mtu */
vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
vmxnet3_adjust_rx_ring_size(adapter);
adapter->rx_queue.comp_ring.size = adapter->rx_queue.rx_ring[0].size +
adapter->rx_queue.rx_ring[1].size;
err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
if (err) {
printk(KERN_ERR "%s: failed to re-create rx queue, error %d. Closing it.\n",
netdev->name, err);
goto out;
}
err = vmxnet3_activate_dev(adapter);
if (err) {
printk(KERN_ERR "%s: failed to re-activate, error %d. Closing it\n",
netdev->name, err);
goto out;
}
}
out:
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
if (err) {
vmxnet3_force_close(adapter);
}
return err;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_declare_features --
*
* set netdev->features based on the device's capabilities
*
* Result:
* None
*
* Side-effects:
* netdev->features is set
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_declare_features(struct vmxnet3_adapter *adapter, Bool dma64)
{
struct net_device *netdev = adapter->netdev;
netdev->features = NETIF_F_SG |
NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER |
NETIF_F_TSO;
printk(KERN_INFO "features: sg csum vlan jf tso");
adapter->rxcsum = TRUE;
adapter->jumbo_frame = TRUE;
#ifdef NETIF_F_TSO6
netdev->features |= NETIF_F_TSO6;
printk(" tsoIPv6");
#endif
if (!disable_lro) {
adapter->lro = TRUE;
printk(" lro");
}
if (dma64) {
netdev->features |= NETIF_F_HIGHDMA;
printk(" highDMA");
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
netdev->vlan_features = netdev->features;
#endif
printk("\n");
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_read_mac_addr --
*
* Read the current MAC address from the device and store into @mac
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, uint8 *mac)
{
uint32 tmp;
tmp = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACL);
*(uint32*)mac = tmp;
tmp = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACH);
mac[4] = tmp & 0xff;
mac[5] = (tmp >> 8) & 0xff;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_rx_csum --
*
* Ethtool callback to return whether or not the dev verifies rx csum
*
* Result:
* 1 if the device verifies rx csum and 0 otherwise
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static uint32
vmxnet3_get_rx_csum(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
return adapter->rxcsum;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_rx_csum --
*
* Ethtool callback to change if rx csum verification should be done
*
* Result:
* 0 on success
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_rx_csum(struct net_device *netdev, uint32 val)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
if (adapter->rxcsum != val) {
adapter->rxcsum = val;
if (compat_netif_running(netdev)) {
if (val) {
adapter->shared->devRead.misc.uptFeatures |= UPT1_F_RXCSUM;
} else {
adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_RXCSUM;
}
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE);
}
}
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_tx_csum --
*
* Ethtool op to return whether or not tx csum offload is enabled
*
* Result:
* 1 if tx csum offload is currently used and 0 otherwise
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static uint32
vmxnet3_get_tx_csum(struct net_device *netdev)
{
return (netdev->features & NETIF_F_HW_CSUM) != 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_tx_csum --
*
* Ethtool op to change if tx csum offloading should be used or not
*
* Result:
* 0 on success
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_tx_csum(struct net_device *netdev, uint32 val)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
if (val) {
netdev->features |= NETIF_F_HW_CSUM;
} else {
netdev->features &= ~ NETIF_F_HW_CSUM;
}
vmxnet3_vlan_features(adapter, 0, TRUE);
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_sg --
*
* Ethtool op to change Scatter/gather IO feature.
*
* Results:
* 0 on success.
*
* Side effects:
* Change SG feature on any VLAN interfaces associated with netdev.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_sg(struct net_device *netdev, uint32 val)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
ethtool_op_set_sg(netdev, val);
vmxnet3_vlan_features(adapter, 0, TRUE);
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_tso --
*
* Ethtool op to change TCP Segmentation Offload feature.
*
* Results:
* 0 on success.
*
* Side effects:
* Change TSO feature on any VLAN interfaces associated with netdev.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_tso(struct net_device *netdev, uint32 val)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
ethtool_op_set_tso(netdev, val);
vmxnet3_vlan_features(adapter, 0, TRUE);
return 0;
}
/* per tq stats maintained by the device */
static const struct vmxnet3_stat_desc
vmxnet3_tq_dev_stats[] = {
/* description, offset */
{ "TSO pkts tx", offsetof(UPT1_TxStats, TSOPktsTxOK) },
{ "TSO bytes tx", offsetof(UPT1_TxStats, TSOBytesTxOK) },
{ "ucast pkts tx", offsetof(UPT1_TxStats, ucastPktsTxOK) },
{ "ucast bytes tx", offsetof(UPT1_TxStats, ucastBytesTxOK) },
{ "mcast pkts tx", offsetof(UPT1_TxStats, mcastPktsTxOK) },
{ "mcast bytes tx", offsetof(UPT1_TxStats, mcastBytesTxOK) },
{ "bcast pkts tx", offsetof(UPT1_TxStats, bcastPktsTxOK) },
{ "bcast bytes tx", offsetof(UPT1_TxStats, bcastBytesTxOK) },
{ "pkts tx err", offsetof(UPT1_TxStats, pktsTxError) },
{ "pkts tx discard", offsetof(UPT1_TxStats, pktsTxDiscard) },
};
/* per tq stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_tq_driver_stats[] = {
/* description, offset */
{ "drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats, drop_total) },
{ " too many frags", offsetof(struct vmxnet3_tq_driver_stats, drop_too_many_frags) },
{ " giant hdr", offsetof(struct vmxnet3_tq_driver_stats, drop_oversized_hdr) },
{ " hdr err", offsetof(struct vmxnet3_tq_driver_stats, drop_hdr_inspect_err) },
{ " tso", offsetof(struct vmxnet3_tq_driver_stats, drop_tso) },
{ "ring full", offsetof(struct vmxnet3_tq_driver_stats, tx_ring_full) },
{ "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats, linearized) },
{ "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats, copy_skb_header) },
{ "giant hdr", offsetof(struct vmxnet3_tq_driver_stats, oversized_hdr) },
};
/* per rq stats maintained by the device */
static const struct vmxnet3_stat_desc
vmxnet3_rq_dev_stats[] = {
{ "LRO pkts rx", offsetof(UPT1_RxStats, LROPktsRxOK) },
{ "LRO byte rx", offsetof(UPT1_RxStats, LROBytesRxOK) },
{ "ucast pkts rx", offsetof(UPT1_RxStats, ucastPktsRxOK) },
{ "ucast bytes rx", offsetof(UPT1_RxStats, ucastBytesRxOK) },
{ "mcast pkts rx", offsetof(UPT1_RxStats, mcastPktsRxOK) },
{ "mcast bytes rx", offsetof(UPT1_RxStats, mcastBytesRxOK) },
{ "bcast pkts rx", offsetof(UPT1_RxStats, bcastPktsRxOK) },
{ "bcast bytes rx", offsetof(UPT1_RxStats, bcastBytesRxOK) },
{ "pkts rx out of buf", offsetof(UPT1_RxStats, pktsRxOutOfBuf) },
{ "pkts rx err", offsetof(UPT1_RxStats, pktsRxError) },
};
/* per rq stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_rq_driver_stats[] = {
/* description, offset */
{ "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats, drop_total) },
{ " err", offsetof(struct vmxnet3_rq_driver_stats, drop_err) },
{ " fcs", offsetof(struct vmxnet3_rq_driver_stats, drop_fcs) },
{ "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats, rx_buf_alloc_failure) },
};
/* gloabl stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_global_stats[] = {
/* description, offset */
{ "tx timeout count", offsetof(struct vmxnet3_adapter, tx_timeout_count) }
};
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_stats --
*
* Collect the device and driver statistics and present in the
* net_device_stats format.
*
* Results:
* Pointer to the net_device_stats struct in the adapter.
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static struct net_device_stats*
vmxnet3_get_stats(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter;
struct vmxnet3_tq_driver_stats *drvTxStats;
struct vmxnet3_rq_driver_stats *drvRxStats;
UPT1_TxStats *devTxStats;
UPT1_RxStats *devRxStats;
adapter = compat_netdev_priv(netdev);
/* Collect the dev stats into the shared area */
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
/* Assuming that we have a single queue device */
devTxStats = &adapter->tqd_start->stats;
devRxStats = &adapter->rqd_start->stats;
/* Get access to the driver stats per queue */
drvTxStats = &adapter->tx_queue.stats;
drvRxStats = &adapter->rx_queue.stats;
memset(&adapter->net_stats, 0, sizeof(adapter->net_stats));
adapter->net_stats.rx_packets = devRxStats->ucastPktsRxOK +
devRxStats->mcastPktsRxOK +
devRxStats->bcastPktsRxOK;
adapter->net_stats.tx_packets = devTxStats->ucastPktsTxOK +
devTxStats->mcastPktsTxOK +
devTxStats->bcastPktsTxOK;
adapter->net_stats.rx_bytes = devRxStats->ucastBytesRxOK +
devRxStats->mcastBytesRxOK +
devRxStats->bcastBytesRxOK;
adapter->net_stats.tx_bytes = devTxStats->ucastBytesTxOK +
devTxStats->mcastBytesTxOK +
devTxStats->bcastBytesTxOK;
adapter->net_stats.rx_errors = devRxStats->pktsRxError;
adapter->net_stats.tx_errors = devTxStats->pktsTxError;
adapter->net_stats.rx_dropped = drvRxStats->drop_total;
adapter->net_stats.tx_dropped = drvTxStats->drop_total;
adapter->net_stats.multicast = devRxStats->mcastPktsRxOK;
return &adapter->net_stats;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_stats_count --
*
* Return the number of counters we will return in vmxnet3_get_ethtool_stats.
* Assume each counter is uint64
*
* Result:
* # of counters we will return in vmxnet3_get_ethtool_stats
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_get_stats_count(struct net_device *netdev)
{
return ARRAY_SIZE(vmxnet3_tq_dev_stats) +
ARRAY_SIZE(vmxnet3_tq_driver_stats) +
ARRAY_SIZE(vmxnet3_rq_dev_stats) +
ARRAY_SIZE(vmxnet3_rq_driver_stats) +
ARRAY_SIZE(vmxnet3_global_stats);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_regs_len --
*
* Return the size of buffer needed to dump registers.
*
* Result:
* The number of bytes needed.
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_get_regs_len(struct net_device *netdev)
{
return 20 * sizeof(uint32);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_drvinfo --
*
* Ethtool callback to return driver information
*
* Result:
* None
*
* Side-effects:
* 1. *drvinfo is updated
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
strncpy(drvinfo->driver, vmxnet3_driver_name, sizeof(drvinfo->driver));
drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';
strncpy(drvinfo->version, VMXNET3_DRIVER_VERSION_REPORT, sizeof(drvinfo->version));
drvinfo->driver[sizeof(drvinfo->version) - 1] = '\0';
strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
drvinfo->fw_version[sizeof(drvinfo->fw_version) - 1] = '\0';
strncpy(drvinfo->bus_info, compat_pci_name(adapter->pdev), ETHTOOL_BUSINFO_LEN);
drvinfo->n_stats = vmxnet3_get_stats_count(netdev);
drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
drvinfo->regdump_len = vmxnet3_get_regs_len(netdev);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_strings --
*
* Return the description strings for the counters returned by
* vmxnet3_get_ethtool_stats.
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_strings(struct net_device *netdev,
u32 stringset,
u8 *buf)
{
if (stringset == ETH_SS_STATS) {
int i;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
memcpy(buf, vmxnet3_tq_dev_stats[i].desc, ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) {
memcpy(buf, vmxnet3_tq_driver_stats[i].desc, ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
memcpy(buf, vmxnet3_rq_dev_stats[i].desc, ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
memcpy(buf, vmxnet3_rq_driver_stats[i].desc, ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
memcpy(buf, vmxnet3_global_stats[i].desc, ETH_GSTRING_LEN);
buf += ETH_GSTRING_LEN;
}
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_ethtool_stats --
*
* Return the values of the maintained counters in 'buf'
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats,
u64 *buf)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
uint8 *base;
int i;
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
/* this does assume each counter is 64-bit wide */
base = (uint8*)&adapter->tqd_start->stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
*buf++ = *(uint64*)(base + vmxnet3_tq_dev_stats[i].offset);
}
base = (uint8*)&adapter->tx_queue.stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) {
*buf++ = *(uint64*)(base + vmxnet3_tq_driver_stats[i].offset);
}
base = (uint8*)&adapter->rqd_start->stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
*buf++ = *(uint64*)(base + vmxnet3_rq_dev_stats[i].offset);
}
base = (uint8*)&adapter->rx_queue.stats;
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
*buf++ = *(uint64*)(base + vmxnet3_rq_driver_stats[i].offset);
}
base = (uint8*)adapter;
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
*buf++ = *(uint64*)(base + vmxnet3_global_stats[i].offset);
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_regs --
*
* Dump out the register values.
*
* Result:
* None
*
* Side-effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
uint32 *buf = p;
memset(p, 0, vmxnet3_get_regs_len(netdev));
regs->version = 1;
/* Update vmxnet3_get_regs_len if we want to dump more registers */
/* make each ring use multiple of 16 bytes */
buf[0] = adapter->tx_queue.tx_ring.next2fill;
buf[1] = adapter->tx_queue.tx_ring.next2comp;
buf[2] = adapter->tx_queue.tx_ring.gen;
buf[3] = 0;
buf[4] = adapter->tx_queue.comp_ring.next2proc;
buf[5] = adapter->tx_queue.comp_ring.gen;
buf[6] = adapter->tx_queue.stopped;
buf[7] = 0;
buf[8] = adapter->rx_queue.rx_ring[0].next2fill;
buf[9] = adapter->rx_queue.rx_ring[0].next2comp;
buf[10] = adapter->rx_queue.rx_ring[0].gen;
buf[11] = 0;
buf[12] = adapter->rx_queue.rx_ring[1].next2fill;
buf[13] = adapter->rx_queue.rx_ring[1].next2comp;
buf[14] = adapter->rx_queue.rx_ring[1].gen;
buf[15] = 0;
buf[16] = adapter->rx_queue.comp_ring.next2proc;
buf[17] = adapter->rx_queue.comp_ring.gen;
buf[18] = 0;
buf[19] = 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_wol --
*
* Report whether Wake-on-Lan is enabled.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
wol->supported = WAKE_UCAST | WAKE_ARP | WAKE_MAGIC;
wol->wolopts = adapter->wol;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_wol --
*
* Turn Wake-on-Lan on or off.
*
* Results:
* 0 on success, errno on failure.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
if (wol->wolopts & (WAKE_PHY | WAKE_MCAST | WAKE_BCAST |
WAKE_MAGICSECURE)) {
return -EOPNOTSUPP;
}
adapter->wol = wol->wolopts;
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_settings --
*
* Get device-specific settings.
*
* Results:
* 0 on success, errno on failure.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_get_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
ecmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full |
SUPPORTED_TP;
ecmd->advertising = ADVERTISED_TP;
ecmd->port = PORT_TP;
ecmd->transceiver = XCVR_INTERNAL;
if (adapter->link_speed) {
ecmd->speed = adapter->link_speed;
ecmd->duplex = DUPLEX_FULL;
} else {
ecmd->speed = -1;
ecmd->duplex = -1;
}
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_get_ringparam --
*
* Get ring sizes
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *param)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE;
param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE;
param->rx_mini_max_pending = 0;
param->rx_jumbo_max_pending = 0;
param->rx_pending = adapter->rx_queue.rx_ring[0].size;
param->tx_pending = adapter->tx_queue.tx_ring.size;
param->rx_mini_pending = 0;
param->rx_jumbo_pending = 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_set_ringparam --
*
* Set ring sizes
*
* Results:
* 0 on success or errno.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *param)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
uint32 new_tx_ring_size, new_rx_ring_size;
uint32 sz;
int err = 0;
if (param->tx_pending == 0 || param->tx_pending > VMXNET3_TX_RING_MAX_SIZE) {
printk(KERN_ERR "%s: invalid tx ring size %u\n", netdev->name, param->tx_pending);
return -EINVAL;
}
if (param->rx_pending == 0 || param->rx_pending > VMXNET3_RX_RING_MAX_SIZE) {
printk(KERN_ERR "%s: invalid rx ring size %u\n", netdev->name, param->rx_pending);
return -EINVAL;
}
/* round it up to a multiple of VMXNET3_RING_SIZE_ALIGN */
new_tx_ring_size = (param->tx_pending + VMXNET3_RING_SIZE_MASK) &
~VMXNET3_RING_SIZE_MASK;
new_tx_ring_size = min_t(uint32, new_tx_ring_size, VMXNET3_TX_RING_MAX_SIZE);
VMXNET3_ASSERT(new_tx_ring_size <= VMXNET3_TX_RING_MAX_SIZE);
VMXNET3_ASSERT(new_tx_ring_size % VMXNET3_RING_SIZE_ALIGN == 0);
/* ring0 has to be a multiple of rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN */
sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
new_rx_ring_size = (param->rx_pending + sz - 1) / sz * sz;
new_rx_ring_size = min_t(uint32, new_rx_ring_size,
VMXNET3_RX_RING_MAX_SIZE / sz * sz);
VMXNET3_ASSERT(new_rx_ring_size <= VMXNET3_RX_RING_MAX_SIZE);
VMXNET3_ASSERT(new_rx_ring_size % sz == 0);
if (new_tx_ring_size == adapter->tx_queue.tx_ring.size &&
new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) {
return 0;
}
/*
* Reset_work may be in the middle of resetting the device, wait for its
* completion.
*/
while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state)) {
compat_msleep(1);
}
if (compat_netif_running(netdev)) {
vmxnet3_quiesce_dev(adapter);
vmxnet3_reset_dev(adapter);
/* recreate the rx queue and the tx queue based on the new sizes */
vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size,
VMXNET3_DEF_RX_RING_SIZE);
if (err) {
/* failed, most likely because of OOM, try the default size */
printk(KERN_ERR "%s: failed to apply new sizes, try the default ones\n",
netdev->name);
err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE,
VMXNET3_DEF_RX_RING_SIZE, VMXNET3_DEF_RX_RING_SIZE);
if (err) {
printk(KERN_ERR "%s: failed to create queues with default sizes. Closing it\n",
netdev->name);
goto out;
}
}
err = vmxnet3_activate_dev(adapter);
if (err) {
printk(KERN_ERR "%s: failed to re-activate, error %d. Closing it\n",
netdev->name, err);
goto out;
}
}
out:
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
if (err) {
vmxnet3_force_close(adapter);
}
return err;
}
static struct ethtool_ops
vmxnet3_ethtool_ops = {
.get_settings = vmxnet3_get_settings,
.get_drvinfo = vmxnet3_get_drvinfo,
.get_regs_len = vmxnet3_get_regs_len,
.get_regs = vmxnet3_get_regs,
.get_wol = vmxnet3_get_wol,
.set_wol = vmxnet3_set_wol,
.get_link = ethtool_op_get_link,
.get_rx_csum = vmxnet3_get_rx_csum,
.set_rx_csum = vmxnet3_set_rx_csum,
.get_tx_csum = vmxnet3_get_tx_csum,
.set_tx_csum = vmxnet3_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = vmxnet3_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = vmxnet3_set_tso,
.get_strings = vmxnet3_get_strings,
.get_stats_count = vmxnet3_get_stats_count,
.get_ethtool_stats = vmxnet3_get_ethtool_stats,
.get_ringparam = vmxnet3_get_ringparam,
.set_ringparam = vmxnet3_set_ringparam,
};
/*
*----------------------------------------------------------------------------
*
* vmxnet3_alloc_intr_resources --
*
* read the intr configuration, pick the intr type, and enable MSI/MSI-X if
* needed.
*
* Results:
* None
*
* Side effects:
* adapter->intr.{type, mask_mode, num_intr} are modified
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
{
uint32 cfg;
/* intr settings */
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_CONF_INTR);
cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
adapter->intr.type = cfg & 0x3;
adapter->intr.mask_mode = (cfg >> 2) & 0x3;
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_AUTO) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
/* start with MSI-X */
adapter->intr.type = VMXNET3_IT_MSIX;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
adapter->intr.type = VMXNET3_IT_MSI;
#else
adapter->intr.type = VMXNET3_IT_INTX;
#endif
}
if (adapter->intr.type == VMXNET3_IT_MSIX) {
int err;
adapter->intr.msix_entries[0].entry = 0;
err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
VMXNET3_LINUX_MAX_MSIX_VECT);
if (!err) {
adapter->intr.num_intrs = 1;
return;
}
printk(KERN_INFO "Failed to enable MSI-X for %s, error %d, try MSI\n",
adapter->netdev->name, err);
adapter->intr.type = VMXNET3_IT_MSI;
}
if (adapter->intr.type == VMXNET3_IT_MSI) {
int err;
err = pci_enable_msi(adapter->pdev);
if (!err) {
adapter->intr.num_intrs = 1;
return;
}
printk(KERN_INFO "Failed to enable MSI for %s, error %d, use INTx\n",
adapter->netdev->name, err);
adapter->intr.type = VMXNET3_IT_INTX;
}
#else
adapter->intr.type = VMXNET3_IT_INTX;
#endif
/* INT-X related setting */
adapter->intr.num_intrs = 1;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_free_intr_resources --
*
* disable MSI/MSI-X if previously enabled
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_free_intr_resources(struct vmxnet3_adapter *adapter)
{
#ifdef CONFIG_PCI_MSI
if (adapter->intr.type == VMXNET3_IT_MSIX) {
pci_disable_msix(adapter->pdev);
} else if (adapter->intr.type == VMXNET3_IT_MSI) {
pci_disable_msi(adapter->pdev);
} else
#endif
{
VMXNET3_ASSERT(adapter->intr.type == VMXNET3_IT_INTX);
}
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_tx_timeout --
*
* Called when the stack detects a Tx hang.
*
* Results:
* None
*
* Side effects:
* schedule a job to reset the device
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_tx_timeout(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
adapter->tx_timeout_count++;
printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
compat_schedule_work(&adapter->work);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_reset_work --
*
* Reset the device
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_reset_work(compat_work_arg data)
{
struct vmxnet3_adapter *adapter;
adapter = COMPAT_WORK_GET_DATA(data, struct vmxnet3_adapter);
/* if another thread is resetting the device, no need to proceed */
if (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state)) {
printk(KERN_INFO "%s: resetting already in progress\n", adapter->netdev->name);
return;
}
/* if the device is closed, we must leave it alone */
if (netif_running(adapter->netdev)) {
printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
vmxnet3_quiesce_dev(adapter);
vmxnet3_reset_dev(adapter);
vmxnet3_activate_dev(adapter);
} else {
printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
}
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_probe_device --
*
* initialize a vmxnet3 device
*
* Result:
* 0 on success, negative errno code otherwise
*
* Side-effects:
* Initialize the h/w and allocate necessary resources
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_probe_device(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int err;
Bool dma64 = FALSE; /* stupid gcc */
uint32 ver;
struct net_device *netdev;
struct vmxnet3_adapter *adapter;
uint8 mac[ETH_ALEN];
netdev = compat_alloc_etherdev(sizeof(struct vmxnet3_adapter));
if (!netdev) {
printk(KERN_ERR "Failed to alloc ethernet device for adapter %s\n",
compat_pci_name(pdev));
return -ENOMEM;
}
pci_set_drvdata(pdev, netdev);
adapter = compat_netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->shared = pci_alloc_consistent(adapter->pdev,
sizeof(Vmxnet3_DriverShared),
&adapter->shared_pa);
if (!adapter->shared) {
printk(KERN_ERR "Failed to allocate memory for %s\n", compat_pci_name(pdev));
err = -ENOMEM;
goto err_alloc_shared;
}
adapter->tqd_start = pci_alloc_consistent(adapter->pdev,
sizeof(Vmxnet3_TxQueueDesc) + sizeof(Vmxnet3_RxQueueDesc),
&adapter->queue_desc_pa);
if (!adapter->tqd_start) {
printk(KERN_ERR "Failed to allocate memory for %s\n", compat_pci_name(pdev));
err = -ENOMEM;
goto err_alloc_queue_desc;
}
adapter->rqd_start = (Vmxnet3_RxQueueDesc *)(adapter->tqd_start + 1);
adapter->pm_conf = kmalloc(sizeof(Vmxnet3_PMConf), GFP_KERNEL);
if (adapter->pm_conf == NULL) {
printk(KERN_ERR "Failed to allocate memory for %s\n", compat_pci_name(pdev));
err = -ENOMEM;
goto err_alloc_pm;
}
err = vmxnet3_alloc_pci_resources(adapter, &dma64);
if (err < 0) {
goto err_alloc_pci;
}
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
if (ver & 1) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
} else {
printk(KERN_ERR "Incompatible h/w version (0x%x) for adapter %s\n",
ver, compat_pci_name(pdev));
err = -EBUSY;
goto err_ver;
}
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
if (ver & 1) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_UVRS, 1);
} else {
printk(KERN_ERR "Incompatible upt version (0x%x) for adapter %s\n",
ver, compat_pci_name(pdev));
err = -EBUSY;
goto err_ver;
}
vmxnet3_declare_features(adapter, dma64);
vmxnet3_alloc_intr_resources(adapter);
vmxnet3_read_mac_addr(adapter, mac);
memcpy(netdev->dev_addr, mac, netdev->addr_len);
netdev->open = vmxnet3_open;
netdev->stop = vmxnet3_close;
netdev->hard_start_xmit = vmxnet3_xmit_frame;
netdev->set_mac_address = vmxnet3_set_mac_addr;
netdev->change_mtu = vmxnet3_change_mtu;
netdev->get_stats = vmxnet3_get_stats;
SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops);
netdev->tx_timeout = vmxnet3_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
COMPAT_INIT_WORK(&adapter->work, vmxnet3_reset_work, adapter);
#ifdef VMXNET3_NAPI
compat_netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64);
#endif
netdev->set_multicast_list = vmxnet3_set_mc;
netdev->vlan_rx_register = vmxnet3_vlan_rx_register;
netdev->vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid;
netdev->vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = vmxnet3_netpoll;
#endif
COMPAT_SET_MODULE_OWNER(netdev);
COMPAT_SET_NETDEV_DEV(netdev, &pdev->dev);
err = register_netdev(netdev);
if (err) {
printk(KERN_ERR "Failed to register adapter %s\n", compat_pci_name(pdev));
goto err_register;
}
set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
return 0;
err_register:
vmxnet3_free_intr_resources(adapter);
err_ver:
vmxnet3_free_pci_resources(adapter);
err_alloc_pci:
kfree(adapter->pm_conf);
err_alloc_pm:
pci_free_consistent(adapter->pdev,
sizeof(Vmxnet3_TxQueueDesc) + sizeof(Vmxnet3_RxQueueDesc),
adapter->tqd_start, adapter->queue_desc_pa);
err_alloc_queue_desc:
pci_free_consistent(adapter->pdev, sizeof(Vmxnet3_DriverShared),
adapter->shared, adapter->shared_pa);
err_alloc_shared:
pci_set_drvdata(pdev, NULL);
compat_free_netdev(netdev);
return err;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_remove_device --
*
* Called by the PCI subsystem to release a device
*
* Result:
* None
*
* Side-effects:
* unregister the adapter with the kernel and free resources
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_remove_device(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
flush_scheduled_work();
unregister_netdev(netdev);
vmxnet3_free_intr_resources(adapter);
vmxnet3_free_pci_resources(adapter);
kfree(adapter->pm_conf);
pci_free_consistent(adapter->pdev,
sizeof(Vmxnet3_TxQueueDesc) + sizeof(Vmxnet3_RxQueueDesc),
adapter->tqd_start, adapter->queue_desc_pa);
pci_free_consistent(adapter->pdev, sizeof(Vmxnet3_DriverShared),
adapter->shared, adapter->shared_pa);
compat_free_netdev(netdev);
}
#ifdef CONFIG_PM
/*
*----------------------------------------------------------------------------
*
* vmxnet3_suspend --
*
* Called by the PCI subsystem to save device state before suspending
* system.
*
* Results:
* 0 on success, errno on failure.
*
* Side effects:
* May programs the wake-up filters if configured to do so.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
Vmxnet3_PMConf *pmConf;
struct ethhdr *ehdr;
struct arphdr *ahdr;
uint8 *arpreq;
struct in_device *in_dev;
struct in_ifaddr *ifa;
int i = 0;
if (!compat_netif_running(netdev)) {
return 0;
}
netif_device_detach(netdev);
netif_stop_queue(netdev);
/* Create wake-up filters. */
pmConf = adapter->pm_conf;
memset(pmConf, 0, sizeof (*pmConf));
if (adapter->wol & WAKE_UCAST) {
pmConf->filters[i].patternSize = ETH_ALEN;
pmConf->filters[i].maskSize = 1;
memcpy(pmConf->filters[i].pattern, netdev->dev_addr, ETH_ALEN);
pmConf->filters[i].mask[0] = 0x3F; // LSB ETH_ALEN bits
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
}
if (adapter->wol & WAKE_ARP) {
in_dev = in_dev_get(netdev);
if (!in_dev) {
VMXNET3_LOG("Cannot program WoL ARP filter for %s: IPv4 not enabled.\n",
netdev->name);
goto skip_arp;
}
ifa = (struct in_ifaddr *)in_dev->ifa_list;
if (!ifa) {
VMXNET3_LOG("Cannot program WoL ARP filter for %s: no IPv4 address.\n",
netdev->name);
in_dev_put(in_dev);
goto skip_arp;
}
pmConf->filters[i].patternSize = ETH_HLEN + // Ethernet header
sizeof(struct arphdr) + // ARP header
2 * ETH_ALEN + // 2 Ethernet addresses
2 * sizeof (uint32); // 2 IPv4 addresses
pmConf->filters[i].maskSize =
(pmConf->filters[i].patternSize - 1) / 8 + 1;
/* ETH_P_ARP in Ethernet header. */
ehdr = (struct ethhdr *)pmConf->filters[i].pattern;
ehdr->h_proto = htons(ETH_P_ARP);
/* ARPOP_REQUEST in ARP header. */
ahdr = (struct arphdr *)&pmConf->filters[i].pattern[ETH_HLEN];
ahdr->ar_op = htons(ARPOP_REQUEST);
arpreq = (uint8 *)(ahdr + 1);
/* The Unicast IPv4 address in 'tip' field. */
arpreq += 2 * ETH_ALEN + sizeof(uint32);
*(uint32 *)arpreq = ifa->ifa_address;
/* The mask for the relevant bits. */
pmConf->filters[i].mask[0] = 0x00;
pmConf->filters[i].mask[1] = 0x30; // ETH_P_ARP
pmConf->filters[i].mask[2] = 0x30; // ARPOP_REQUEST
pmConf->filters[i].mask[3] = 0x00;
pmConf->filters[i].mask[4] = 0xC0; // IPv4 TIP
pmConf->filters[i].mask[5] = 0x03; // IPv4 TIP
in_dev_put(in_dev);
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
}
skip_arp:
if (adapter->wol & WAKE_MAGIC) {
pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_MAGIC;
}
pmConf->numFilters = i;
adapter->shared->devRead.pmConfDesc.confVer = 1;
adapter->shared->devRead.pmConfDesc.confLen = sizeof(*pmConf);
adapter->shared->devRead.pmConfDesc.confPA = virt_to_phys(pmConf);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_PMCFG);
compat_pci_save_state(pdev);
pci_enable_wake(pdev, compat_pci_choose_state(pdev, state), adapter->wol);
compat_pci_disable_device(pdev);
pci_set_power_state(pdev, compat_pci_choose_state(pdev, state));
return 0;
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_resume --
*
* Called by the PCI subsystem to restore device state when resuming the
* system.
*
* Results:
* 0 on success, errno on failure.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------------
*/
static int
vmxnet3_resume(struct pci_dev *pdev)
{
int err;
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev);
Vmxnet3_PMConf *pmConf;
if (!compat_netif_running(netdev)) {
return 0;
}
/* Destroy wake-up filters. */
pmConf = adapter->pm_conf;
memset(pmConf, 0, sizeof (*pmConf));
adapter->shared->devRead.pmConfDesc.confVer = 1;
adapter->shared->devRead.pmConfDesc.confLen = sizeof(*pmConf);
adapter->shared->devRead.pmConfDesc.confPA = virt_to_phys(pmConf);
netif_device_attach(netdev);
pci_set_power_state(pdev, PCI_D0);
compat_pci_restore_state(pdev);
err = compat_pci_enable_device(pdev);
if (err != 0) {
return err;
}
pci_enable_wake(pdev, PCI_D0, 0);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_PMCFG);
return 0;
}
#endif
/*
*----------------------------------------------------------------------------
*
* vmxnet3_init_module --
*
* Called when the driver is loaded
*
* Result:
* 0 on success, negative errno value on error
*
* Side-effects:
* register ourselves with the pci system, and claim devices
*
*----------------------------------------------------------------------------
*/
static int __init
vmxnet3_init_module(void)
{
printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC, VMXNET3_DRIVER_VERSION_REPORT);
return pci_register_driver(&vmxnet3_driver);
}
/*
*----------------------------------------------------------------------------
*
* vmxnet3_exit_module --
*
* Called when the driver is to be unloaded
*
* Result:
* None
*
* Side-effects:
* unregister ourselves with the pci system
*
*----------------------------------------------------------------------------
*/
static void
vmxnet3_exit_module(void)
{
pci_unregister_driver(&vmxnet3_driver);
}
module_init(vmxnet3_init_module);
module_exit(vmxnet3_exit_module);
MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION(VMXNET3_DRIVER_DESC);
MODULE_LICENSE("GPL v2");
MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING);
/*
* Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
* with them and mark their kernel modules as externally supported via a
* change to the module header. If this isn't done, the module will not load
* by default (i.e., neither mkinitrd nor modprobe will accept it).
*/
MODULE_INFO(supported, "external");
module_param(disable_lro, int, 0);
vmxnet3-only/vmxnet3_int.h 0000444 0000000 0000000 00000017323 12025727030 014570 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
#ifndef _VMXNET3_INT_H
#define _VMXNET3_INT_H
#define INCLUDE_ALLOW_MODULE
#include "includeCheck.h"
#include "vmxnet3_defs.h"
typedef struct vmxnet3_cmd_ring {
Vmxnet3_GenericDesc *base;
uint32 size;
uint32 next2fill;
uint32 next2comp;
uint8 gen;
dma_addr_t basePA;
} Vmxnet3_CmdRing;
static INLINE void
vmxnet3_cmd_ring_adv_next2fill(struct vmxnet3_cmd_ring *ring)
{
ring->next2fill++;
if (UNLIKELY(ring->next2fill == ring->size)) {
ring->next2fill = 0;
VMXNET3_FLIP_RING_GEN(ring->gen);
}
}
static INLINE void
vmxnet3_cmd_ring_adv_next2comp(struct vmxnet3_cmd_ring *ring)
{
VMXNET3_INC_RING_IDX_ONLY(ring->next2comp, ring->size);
}
static INLINE int
vmxnet3_cmd_ring_desc_avail(struct vmxnet3_cmd_ring *ring)
{
return (ring->next2comp > ring->next2fill ? 0 : ring->size) +
ring->next2comp - ring->next2fill - 1;
}
typedef struct vmxnet3_comp_ring {
Vmxnet3_GenericDesc *base;
uint32 size;
uint32 next2proc;
uint8 gen;
uint8 intr_idx;
dma_addr_t basePA;
} Vmxnet3_CompRing;
static INLINE void
vmxnet3_comp_ring_adv_next2proc(struct vmxnet3_comp_ring *ring)
{
ring->next2proc++;
if (UNLIKELY(ring->next2proc == ring->size)) {
ring->next2proc = 0;
VMXNET3_FLIP_RING_GEN(ring->gen);
}
}
struct vmxnet3_tx_data_ring {
Vmxnet3_TxDataDesc *base;
uint32 size;
dma_addr_t basePA;
};
enum vmxnet3_buf_map_type {
VMXNET3_MAP_INVALID = 0,
VMXNET3_MAP_NONE,
VMXNET3_MAP_SINGLE,
VMXNET3_MAP_PAGE,
};
struct vmxnet3_tx_buf_info {
uint32 map_type;
uint16 len;
uint16 sop_idx;
dma_addr_t dma_addr;
struct sk_buff *skb;
};
struct vmxnet3_tq_driver_stats {
uint64 drop_total; /* # of pkts dropped by the driver, the
* counters below track droppings due to
* different reasons
*/
uint64 drop_too_many_frags;
uint64 drop_oversized_hdr;
uint64 drop_hdr_inspect_err;
uint64 drop_tso;
uint64 tx_ring_full;
uint64 linearized; /* # of pkts linearized */
uint64 copy_skb_header; /* # of times we have to copy skb header */
uint64 oversized_hdr;
};
struct vmxnet3_tx_ctx {
Bool ipv4;
uint16 mss;
uint32 eth_ip_hdr_size; /* only valid for pkts requesting tso or csum offloading */
uint32 l4_hdr_size; /* only valid if mss != 0 */
uint32 copy_size; /* # of bytes copied into the data ring */
Vmxnet3_GenericDesc *sop_txd;
Vmxnet3_GenericDesc *eop_txd;
};
struct vmxnet3_tx_queue {
spinlock_t tx_lock;
struct vmxnet3_cmd_ring tx_ring;
struct vmxnet3_tx_buf_info *buf_info;
struct vmxnet3_tx_data_ring data_ring;
struct vmxnet3_comp_ring comp_ring;
Vmxnet3_TxQueueCtrl *shared;
struct vmxnet3_tq_driver_stats stats;
Bool stopped;
int num_stop; /* # of time queue is stopped */
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
enum vmxnet3_rx_buf_type {
VMXNET3_RX_BUF_NONE = 0,
VMXNET3_RX_BUF_SKB = 1,
VMXNET3_RX_BUF_PAGE = 2
};
struct vmxnet3_rx_buf_info {
enum vmxnet3_rx_buf_type buf_type;
uint16 len;
union {
struct sk_buff *skb;
struct page *page;
};
dma_addr_t dma_addr;
};
struct vmxnet3_rx_ctx {
struct sk_buff *skb;
uint32 sop_idx;
};
struct vmxnet3_rq_driver_stats {
uint64 drop_total;
uint64 drop_err;
uint64 drop_fcs;
uint64 rx_buf_alloc_failure;
};
struct vmxnet3_rx_queue {
struct vmxnet3_cmd_ring rx_ring[2];
struct vmxnet3_comp_ring comp_ring;
struct vmxnet3_rx_ctx rx_ctx;
uint32 qid; /* rqID in RCD for buffer from 1st ring */
uint32 qid2; /* rqID in RCD for buffer from 2nd ring */
uint32 uncommitted[2]; /* # of buffers allocated since last RXPROD update */
struct vmxnet3_rx_buf_info *buf_info[2];
Vmxnet3_RxQueueCtrl *shared;
struct vmxnet3_rq_driver_stats stats;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define VMXNET3_LINUX_MAX_MSIX_VECT 1
struct vmxnet3_intr {
enum vmxnet3_intr_mask_mode mask_mode;
enum vmxnet3_intr_type type; /* MSI-X, MSI, or INTx? */
uint8 num_intrs; /* # of intr vectors */
uint8 event_intr_idx; /* idx of the intr vector for event */
uint8 mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
#ifdef CONFIG_PCI_MSI
struct msix_entry msix_entries[VMXNET3_LINUX_MAX_MSIX_VECT];
#endif
};
#define VMXNET3_STATE_BIT_RESETTING 0
#define VMXNET3_STATE_BIT_QUIESCED 1
struct vmxnet3_adapter {
struct vmxnet3_tx_queue tx_queue;
struct vmxnet3_rx_queue rx_queue;
#ifdef VMXNET3_NAPI
struct napi_struct napi;
#endif
struct vlan_group *vlan_grp;
struct vmxnet3_intr intr;
struct Vmxnet3_DriverShared *shared;
struct Vmxnet3_PMConf *pm_conf;
struct Vmxnet3_TxQueueDesc *tqd_start; /* first tx queue desc */
struct Vmxnet3_RxQueueDesc *rqd_start; /* first rx queue desc */;
struct net_device *netdev;
struct net_device_stats net_stats;
struct pci_dev *pdev;
uint8 *hw_addr0; /* for BAR 0 */
uint8 *hw_addr1; /* for BAR 1 */
/* feature control */
Bool rxcsum;
Bool lro;
Bool jumbo_frame;
/* rx buffer related */
unsigned skb_buf_size;
int rx_buf_per_pkt; /* only apply to the 1st ring */
dma_addr_t shared_pa;
dma_addr_t queue_desc_pa;
/* Wake-on-LAN */
uint32 wol;
/* Link speed */
uint32 link_speed; /* in mbps */
uint64 tx_timeout_count;
compat_work work;
unsigned long state; /* VMXNET3_STATE_BIT_xxx */
};
struct vmxnet3_stat_desc {
char desc[ETH_GSTRING_LEN];
int offset;
};
#define VMXNET3_WRITE_BAR0_REG(adapter, reg, val) \
writel((val), (adapter)->hw_addr0 + (reg))
#define VMXNET3_READ_BAR0_REG(adapter, reg) \
readl((adapter)->hw_addr0 + (reg))
#define VMXNET3_WRITE_BAR1_REG(adapter, reg, val) \
writel((val), (adapter)->hw_addr1 + (reg))
#define VMXNET3_READ_BAR1_REG(adapter, reg) \
readl((adapter)->hw_addr1 + (reg))
#define VMXNET3_WAKE_QUEUE_THRESHOLD(tq) (5)
#define VMXNET3_RX_ALLOC_THRESHOLD(rq, ring_idx, adapter) \
((rq)->rx_ring[ring_idx].size >> 3)
#define VMXNET3_GET_ADDR_LO(dma) ((uint32)(dma))
#define VMXNET3_GET_ADDR_HI(dma) ((uint32)(((uint64)(dma)) >> 32))
/* must be a multiple of VMXNET3_RING_SIZE_ALIGN */
#define VMXNET3_DEF_TX_RING_SIZE 512
#define VMXNET3_DEF_RX_RING_SIZE 256
/* FIXME: what's the right value for this? */
#define VMXNET3_MAX_ETH_HDR_SIZE 22
#define VMXNET3_MAX_SKB_BUF_SIZE (3*1024)
#endif
vmxnet3-only/vmxnet3_version.h 0000444 0000000 0000000 00000002436 12025727030 015462 0 ustar root root /*********************************************************
* Copyright (C) 2007 VMware, Inc. All rights reserved.
*
* 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 version 2 and no later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*********************************************************/
/*
* vmxnet3_version.h --
*
* Version definitions for the Linux vmxnet3 driver.
*/
#ifndef _VMXNET3_VERSION_H_
#define _VMXNET3_VERSION_H_
#define VMXNET3_DRIVER_VERSION 1.0.0.32
#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,0,32
#define VMXNET3_DRIVER_VERSION_STRING "1.0.0.32"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
#define VMXNET3_DRIVER_VERSION_NUM 0x01000020
#endif /* _VMXNET3_VERSION_H_ */
vmxnet3-only/Makefile.kernel 0000444 0000000 0000000 00000002435 12025727030 015056 0 ustar root root #!/usr/bin/make -f
##########################################################
# Copyright (C) 2008 VMware, Inc. All rights reserved.
#
# 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 version 2 and no later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
##########################################################
####
#### VMware vmxnet3 Makefile to be distributed externally
####
INCLUDE := -I.
EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE)
EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/autoconf/skblin.c, -DVMW_SKB_LINEARIZE_2618, )
obj-m += $(DRIVER).o
clean:
rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \
Module.symvers Modules.symvers Module.markers modules.order \
$(foreach dir,./,$(addprefix $(dir),.*.cmd .*.o.flags *.o)))
vmxnet3-only/Makefile.normal 0000444 0000000 0000000 00000005117 12025727030 015066 0 ustar root root #!/usr/bin/make -f
##########################################################
# Copyright (C) 1998 VMware, Inc. All rights reserved.
#
# 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 version 2 and no later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
##########################################################
####
#### VMware vmxnet3 Makefile to be distributed externally
####
vm_check_build = $(shell if $(CC) $(CC_OPTS) $(INCLUDE) -Werror -S -o /dev/null -xc $(1) \
> /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi)
DRIVERNAME = $(DRIVER)-$(VM_UNAME)
ifneq (,$(filter x86_64%, $(shell $(CC) -dumpmachine)))
MACHINE := x86_64
else
MACHINE := x386
endif
####
#### You must compile with at least -O level of optimization
#### or the module won't load.
#### If desparate, I think that bringing in might
#### suffice.
####
CC_WARNINGS := -Wall -Wstrict-prototypes
# Don't use -pipe or egcs-2.91.66 (shipped with RedHat) will die
CC_KFLAGS := -D__KERNEL__ -fno-strength-reduce -fno-omit-frame-pointer \
-fno-common -DKBUILD_MODNAME=$(DRIVER)
CC_KFLAGS += $(call vm_check_gcc,-falign-loops=2 -falign-jumps=2 -falign-functions=2, \
-malign-loops=2 -malign-jumps=2 -malign-functions=2)
CC_KFLAGS += $(call vm_check_gcc,-fno-strict-aliasing,)
ifeq ($(MACHINE),x86_64)
CC_KFLAGS += -mno-red-zone -mcmodel=kernel
else
# Gcc 3.0 deprecates -m486 --hpreg
CC_KFLAGS += -DCPU=586 $(call check_gcc,-march=i586,-m486)
endif
CC_OPTS := -g3 -O2 -DMODULE $(GLOBAL_DEFS) $(CC_KFLAGS) $(CC_WARNINGS)
INCLUDE := -I$(HEADER_DIR)
INCLUDE += $(shell $(CC) $(CC_OPTS) $(INCLUDE) \
-E $(SRCROOT)/autoconf/geninclude.c \
| sed -n -e 's!^APATH!-I$(HEADER_DIR)/asm!p')
CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/skblin.c, -DVMW_SKB_LINEARIZE_2618, )
OBJS := vmxnet3.o
CFLAGS := $(CC_OPTS) $(INCLUDE)
LIBS :=
default: all
all: $(DRIVERNAME)
$(DRIVERNAME): $(OBJS)
$(LD) -r -o $@ $^
$(DRIVER) ../$(DRIVER).o: $(DRIVERNAME)
cp -f $< $@
auto-build: ../$(DRIVER).o
clean:
rm -f $(DRIVERNAME) ../$(DRIVERNAME) $(DRIVER) $(OBJS)
.SILENT:
vmxnet3-only/README 0000444 0000000 0000000 00000000736 12025727027 013027 0 ustar root root The files in this directory are the source files for the VMware
3rd Generation Virtual Ethernet Adapter driver. In order to build,
make certain the Makefile is correct, especially about whether or
not your system is multi-processor or not, and then just type:
make
from this directory. A copy of the module will be left in 'vmxnet3.o',
which can then be installed in /lib/modules//net.
If you have any problems or questions, send mail to support@vmware.com
vmxnet3-only/Makefile 0000444 0000000 0000000 00000007265 12025727030 013605 0 ustar root root #!/usr/bin/make -f
##########################################################
# Copyright (C) 1998 VMware, Inc. All rights reserved.
#
# 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 version 2 and no later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
##########################################################
####
#### VMware kernel module Makefile to be distributed externally
####
####
#### SRCROOT _must_ be a relative path.
####
SRCROOT = .
VM_UNAME = $(shell uname -r)
# Header directory for the running kernel
HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include
BUILD_DIR = $(HEADER_DIR)/..
DRIVER := vmxnet3
PRODUCT := @PRODUCT@
# Grep program
GREP = /bin/grep
vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi)
ifndef VM_KBUILD
VM_KBUILD := no
ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes)
ifneq ($(call vm_check_file,$(BUILD_DIR)/Rules.make), yes)
VM_KBUILD := 26
endif
endif
export VM_KBUILD
endif
ifndef VM_KBUILD_SHOWN
ifeq ($(VM_KBUILD), no)
VM_DUMMY := $(shell echo >&2 "Using standalone build system.")
else
ifeq ($(VM_KBUILD), 24)
VM_DUMMY := $(shell echo >&2 "Using 2.4.x kernel build system.")
else
VM_DUMMY := $(shell echo >&2 "Using 2.6.x kernel build system.")
endif
endif
VM_KBUILD_SHOWN := yes
export VM_KBUILD_SHOWN
endif
ifneq ($(VM_KBUILD), no)
VMCCVER := $(shell $(CC) -dumpversion)
# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles...
ifeq ($(VERSION),)
ifeq ($(VM_KBUILD), 24)
DRIVER_KO := $(DRIVER).o
else
DRIVER_KO := $(DRIVER).ko
endif
.PHONY: $(DRIVER_KO)
auto-build: $(DRIVER_KO)
cp -f $< $(SRCROOT)/../$(DRIVER).o
# $(DRIVER_KO) is a phony target, so compare file times explicitly
$(DRIVER): $(DRIVER_KO)
if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi
# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler
VM_CCVER := $(VMCCVER)
export VM_CCVER
VM_CC := $(CC)
export VM_CC
MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES))
#
# Define a setup target that gets built before the actual driver.
# This target may not be used at all, but if it is then it will be defined
# in Makefile.kernel
#
prebuild:: ;
postbuild:: ;
$(DRIVER_KO): prebuild
make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
endif
vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
$(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
-DKBUILD_BASENAME=\"$(DRIVER)\" \
-Werror -S -o /dev/null -xc $(1) \
> /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi)
CC_WARNINGS := -Wall -Wstrict-prototypes
CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD
ifdef VMX86_DEVEL
CC_OPTS += -DVMX86_DEVEL
endif
ifdef VMX86_DEBUG
CC_OPTS += -DVMX86_DEBUG
endif
include $(SRCROOT)/Makefile.kernel
ifdef TOPDIR
ifeq ($(VM_KBUILD), 24)
O_TARGET := $(DRIVER).o
obj-y := $($(DRIVER)-y)
include $(TOPDIR)/Rules.make
endif
endif
else
include $(SRCROOT)/Makefile.normal
endif
#.SILENT:
vmxnet3-only/COPYING 0000444 0000000 0000000 00000043103 12025727027 013175 0 ustar root root GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.