OpenNetVM mTCP Module Code Cleanup (#4)

This change updates mTCP from their master branch and cleans up the OpenNetVM module.  The ONVM module is reorganized to match the DPDK module.  This includes:

  - Removed the command line arguments for running epserver
    + This removes the extra arg passing between methods
    + Moved the ONVM arguments to `epserver.conf`
  - Added configure options to build mtcp with the ONVM library
  - Added preprocessor macros to build ONVM specific code on-demand

Commit log:

* - IP defrag module for dpdk integrated (partly derived from ip_reassembly/ example code).
	-> Currently disabled... because I need some testing suite that can fragment IP datagrams
- Cleaned up the Makefile.in scripts.

* - Fixed an ICMP-related bug that was accidentally introduced when hw-chksumming was implemented.
- Cleaned up the Makefile.in script
- Cleaned up dpdk_module.c file.

* - Applied fixes for suspect snippets identified by Coverity.
- Added IP_DEFRAG warning.

* - More fixes.

* Adding coverity badge.
- Needs more code fixing :S

* - Minor fixes.

* - Minor error checks.

* - More & more fixes.

* - Forgot to check in these files.

* - More error checking.

* - Added more DPDK-capable Ethernet controllers which makes mOS/mTCP compatible
  with certain 1/10 Gbps NICs (e.g. X540T1, I211 and many, many others). Ack
  to Juhyung.
- Small coverity related fix.

* tcp: handle ack with payload correctly in SYN_RECV state

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* uses -m64 for x86_64 only to avoid compile error on other ARCHs

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* add a generic ip_fast_csum for non-x86 platform

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* - Stats bug that does not appear in kernel version <= 4.1.. but appears in linux-4.4.
	--> Always, always do copy_from_user() for user-space buffers before accessing
		them in kernel module. This one was hard to catch!
	--> Ack to Jaehyong for initially reporting the problem.

* - Adding partial support for i40e.
	--> Still working on mtcp_init_rss() function for i40e.
	--> Server-side applications should work fine with mTCP.

* - Removed redundant printk lines (in igbuio.c).
- mtcp_init_rss() for i40e fixed.
	--> According to xl710 controller data sheet, the secret key should be 52 bytes long
		--> Intel 10 Gbps nic controllers previously relied on 40 bytes RSK
		--> See http://www.intel.co.kr/content/dam/www/public/us/en/documents/datasheets/xl710-10-40-controller-datasheet.pdf
		    section 7.1.10.1 for details.
- Made the code backward compatible with linux-3.x
	--> Previous code changes were made in linux-4.4.x
- Added logic to unmap the pci address when driver (igb_uio) is deregistered.
	--> Now igb_uio-registered devices can be re-attached to i40e devices back and forth.

* - Resovles issue# 67.

* fix the bug in cofiguring mTCP when running ab (issue 124)

ref:#124

* reset errno to 0 before calling strtol (resolves issue 128)

ref:#128

* - Make sure that even non-TCP packets are uniformly distributed across cores.

* Fix unused return value for copy_from_user(). (issue# 132)

* add support for configuring discrete ports (resolves issue 125)

ref:#125

* make backlog a command option (resolves the issue 136)

ref:#136

* - Small update.

* - Patch suggested by 	gchen-viosoft.

* - Small patch to make it work for linux-4.2

* - Removed the MAX_CPUS restriction.
- Make sure that hyperthreading is disabled before setting up mTCP
- igb_uio driver will maintain netdev stats for up to 128 queues.

* - Removed a statistics-related bug in epwget.c
- Removed a race condition in cleaning up context resources during termination of application.

* - Revised MAX_CPUs macro setup.

* - Forgot to update README.md file.

* - Small optimization related to CPU RSS calculation (rss-side)
	-> Thanks Ilwoo

* - Small fixes (thanks to YoungGyoun Moon)

* - Made it compatible with linux kernel versions >= 4.11.0

* - Updating travis configuration file slightly.

* - Updating travis configuration file slightly.
- Updating Id.

* - Small typo in travis file.

* - Small update to the tcp sent window logic

* - Slight updates to the README/README.md files.

* - Resolved issue #51

* Update from eunyoung14/mtcp (#3)

* - IP defrag module for dpdk integrated (partly derived from ip_reassembly/ example code).
	-> Currently disabled... because I need some testing suite that can fragment IP datagrams
- Cleaned up the Makefile.in scripts.

* - Fixed an ICMP-related bug that was accidentally introduced when hw-chksumming was implemented.
- Cleaned up the Makefile.in script
- Cleaned up dpdk_module.c file.

* - Applied fixes for suspect snippets identified by Coverity.
- Added IP_DEFRAG warning.

* - More fixes.

* Adding coverity badge.
- Needs more code fixing :S

* - Minor fixes.

* - Minor error checks.

* - More & more fixes.

* - Forgot to check in these files.

* - More error checking.

* - Added more DPDK-capable Ethernet controllers which makes mOS/mTCP compatible
  with certain 1/10 Gbps NICs (e.g. X540T1, I211 and many, many others). Ack
  to Juhyung.
- Small coverity related fix.

* tcp: handle ack with payload correctly in SYN_RECV state

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* uses -m64 for x86_64 only to avoid compile error on other ARCHs

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* add a generic ip_fast_csum for non-x86 platform

Signed-off-by: Jianbo Liu <jianbo.liu@linaro.org>

* - Stats bug that does not appear in kernel version <= 4.1.. but appears in linux-4.4.
	--> Always, always do copy_from_user() for user-space buffers before accessing
		them in kernel module. This one was hard to catch!
	--> Ack to Jaehyong for initially reporting the problem.

* - Adding partial support for i40e.
	--> Still working on mtcp_init_rss() function for i40e.
	--> Server-side applications should work fine with mTCP.

* - Removed redundant printk lines (in igbuio.c).
- mtcp_init_rss() for i40e fixed.
	--> According to xl710 controller data sheet, the secret key should be 52 bytes long
		--> Intel 10 Gbps nic controllers previously relied on 40 bytes RSK
		--> See http://www.intel.co.kr/content/dam/www/public/us/en/documents/datasheets/xl710-10-40-controller-datasheet.pdf
		    section 7.1.10.1 for details.
- Made the code backward compatible with linux-3.x
	--> Previous code changes were made in linux-4.4.x
- Added logic to unmap the pci address when driver (igb_uio) is deregistered.
	--> Now igb_uio-registered devices can be re-attached to i40e devices back and forth.

* - Resovles issue# 67.

* fix the bug in cofiguring mTCP when running ab (issue 124)

ref:#124

* reset errno to 0 before calling strtol (resolves issue 128)

ref:#128

* - Make sure that even non-TCP packets are uniformly distributed across cores.

* Fix unused return value for copy_from_user(). (issue# 132)

* add support for configuring discrete ports (resolves issue 125)

ref:#125

* make backlog a command option (resolves the issue 136)

ref:#136

* - Small update.

* - Patch suggested by 	gchen-viosoft.

* - Small patch to make it work for linux-4.2

* - Removed the MAX_CPUS restriction.
- Make sure that hyperthreading is disabled before setting up mTCP
- igb_uio driver will maintain netdev stats for up to 128 queues.

* - Removed a statistics-related bug in epwget.c
- Removed a race condition in cleaning up context resources during termination of application.

* - Revised MAX_CPUs macro setup.

* - Forgot to update README.md file.

* - Small optimization related to CPU RSS calculation (rss-side)
	-> Thanks Ilwoo

* - Small fixes (thanks to YoungGyoun Moon)

* - Made it compatible with linux kernel versions >= 4.11.0

* - Updating travis configuration file slightly.

* - Updating travis configuration file slightly.
- Updating Id.

* - Small typo in travis file.

* - Small update to the tcp sent window logic

* - Slight updates to the README/README.md files.

* - Resolved issue #51

* onvm-mtcp cleaning

* Added a build with onvm config option

* Ifdefs for ONVM setup, ENABLE_ONVM flag

* Update README.md for ONVM module

* Aborting the old changes for a clean merge

* README.md updates

* README.md updates

* Update epserver.conf onvm args explanation

* Update epserver.conf

* Added routing table rule for onvm-module

* Update README

* Update README.md
master
Mykola Yurchenko 2017-10-24 06:24:55 -04:00 committed by Neel Shah
parent 5c8b4531ff
commit 3643bda209
90 changed files with 78191 additions and 554 deletions

View File

@ -9,6 +9,7 @@ notifications:
matrix:
include:
- env: COMPILER=gcc VERSION=6
- env: COMPILER=gcc VERSION=5
- env: COMPILER=gcc VERSION=4.8
@ -16,7 +17,9 @@ before_install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- |
if [ "$VERSION" = "5" ]; then
if [ "$VERSION" = "6" ]; then
sudo apt-get install -qq -y gcc-6
elif [ "$VERSION" = "5" ]; then
sudo apt-get install -qq -y gcc-5
elif [ "$VERSION" = "4.8" ]; then
sudo apt-get install -qq -y gcc-4.8
@ -24,7 +27,9 @@ before_install:
before_script:
- |
if [ "$VERSION" = "5" ]; then
if [ "$VERSION" = "6" ]; then
export CC=gcc-6
elif [ "$VERSION" = "5" ]; then
export CC=gcc-5
elif [ "$VERSION" = "4.8" ]; then
export CC=gcc-4.8

View File

@ -231,6 +231,8 @@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NETMAP = @NETMAP@
OBJEXT = @OBJEXT@
ONVM = @ONVM@
ONVMLIBPATH = @ONVMLIBPATH@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@

79
README
View File

@ -21,8 +21,11 @@ We require the following libraries to run mTCP.
* We have modified the dpdk-16.11 package to export net_device stat data
to the OS. To achieve this, the dpdk-16.11/lib/librte_eal/linuxapp/igb_uio/
directory was updated. We recommend using our package for DPDK installation.
(for Intel-based Ethernet adapters only) to the OS. To achieve this, the
dpdk-16.11/lib/librte_eal/linuxapp/igb_uio/ directory was updated. We also
modified mk/rte.app.mk and rte_cpuflags.mk files to ease the
compilation process of mTCP applications. We recommend using our package
for DPDK installation.
========================================================================
INCLUDED DIRECTORIES
@ -59,7 +62,7 @@ config - sample mTCP configuration files (may not be necessary)
========================================================================
INSTALL GUIDES
========================================================================
mTCP can be prepared in two ways.
mTCP can be prepared in three ways.
- PSIO VERSION -
----------------
@ -78,6 +81,11 @@ mTCP can be prepared in two ways.
# ./configure --with-psio-lib=<$path_to_ioengine>
## e.g. ./configure --with-psio-lib=`echo $PWD`/io_engine
# make
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 8-core system, by using the following command:
# ./configure --with-psio-lib=`echo $PWD`/io_engine CFLAGS="-DMAX_CPUS=8"
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-3 (configure again):
# autoreconf -ivf
@ -96,13 +104,13 @@ mTCP can be prepared in two ways.
- DPDK VERSION -
----------------
1. Set up Intel's DPDK driver. Please use our version of DPDK.
We have only changed the lib/igb_uio/ submodule. The best
method to compile DPDK package is to use DPDK's tools/setup.sh
script. Please compile your package based on your own hardware
configuration. We tested the mTCP stack on Intel Xeon E5-2690
(x86_64) machine with Intel 82599 Ethernet adapters (10G). We
used the following steps in the dpdk-setup.sh script for our
setup:
We have changed the lib/igb_uio/ submodule and a few makefiles
in DPDK's mk/ subdirectory. The best method to compile DPDK
package is to use DPDK's tools/setup.sh script. Please compile
your package based on your own hardware configuration. We
tested the mTCP stack on Intel Xeon E5-2690 (x86_64) machine
with Intel 82599 Ethernet adapters (10G). We used the following
steps in the dpdk-setup.sh script for our setup:
- Press [13] to compile the package
- Press [16] to install the driver
@ -118,6 +126,16 @@ mTCP can be prepared in two ways.
on this page: http://dpdk.org/doc/nics. Please make sure that your
NIC is compatible before moving on to the next step.
- recent Linux kernels tend to rename Ethernet interfaces based on
their PCI addresses. If you are using Intel based Ethernet adapters,
please rename the interface with a ``dpdk`` prefix. You can do so
using the following command:
# sudo ifconfig <iface> down
## where X is an integer value.
## e.g. sudo ip link set ens786f0 name dpdk0
# sudo ip link set <iface> name dpdkX
2. Next bring the dpdk-registered interfaces up. Please use the
setup_iface_single_process.sh script file present in dpdk-16.11/tools/
directory for this purpose. Please change lines 49-51 to change the IP
@ -137,6 +155,11 @@ mTCP can be prepared in two ways.
## And not dpdk-16.11!
## e.g. ./configure --with-dpdk-lib=`echo $PWD`/dpdk
# make
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 32-core system, by using the following command:
# ./configure --with-dpdk-lib=$<path_to_mtcp_release_v3>/dpdk CFLAGS="-DMAX_CPUS=32"
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-4 (configure again):
# autoreconf -ivf
@ -156,6 +179,41 @@ mTCP can be prepared in two ways.
6. Run the applications!
- ONVM VERSION -
----------------
Install openNetVM following these instructions
https://github.com/sdnfv/openNetVM/blob/master/docs/Install.md
1-3. ONVM uses DPDK so follow the dpdk installation up until step 4
4. Setup mtcp library
# ./configure --with-dpdk-lib=$<path_to_dpdk> --with-onvm-lib=$<path_to_onvm_lib>
# make
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 32-core system, by using the following command:
# ./configure --with-dpdk-lib=$<path_to_mtcp_release_v3>/dpdk --with-onvm-lib=$<path_to_onvm_lib> CFLAGS="-DMAX_CPUS=32"
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-4 (configure again):
# autoreconf -ivf
- checksum offloading in the NIC is now ENABLED (by default)!!!
- this only works for dpdk at the moment
- use
./configure --with-dpdk-lib=`echo $PWD`/dpdk --disable-hwcsum
to disable checksum offloading.
- check libmtcp.a in mtcp/lib
- check header files in mtcp/include
- check example binary files in apps/example
5. Check the configurations in apps/example
- epserver.conf for server-side configuration
- epwget.conf for client-side configuration
- you may write your own configuration file for your application
6. Run the applications!
========================================================================
TESTED ENVIRONMENTS
========================================================================
@ -203,6 +261,7 @@ We tested the DPDK version (polling driver) with Linux-3.13.0 kernel.
1. Intel-82598 ixgbe (Max-queue-limit: 16)
2. Intel-82599 ixgbe (Max-queue-limit: 16)
3. Intel-I350 igb (Max-queue-limit: 08)
4. Intel-X710 i40e (Max-queue-limit: ~)
========================================================================
FREQUENTLY ASKED QUESTIONS

113
README.md
View File

@ -1,17 +1,8 @@
[![Build Status](https://travis-ci.org/eunyoung14/mtcp.svg?branch=master)](https://travis-ci.org/eunyoung14/mtcp)
[![Build Status](https://scan.coverity.com/projects/11896/badge.svg)](https://scan.coverity.com/projects/eunyoung14-mtcp)
# README #
### This application was modified to work with [ONVM][onvm] ###
+ Currently only supports single core usage
+ Tested with the provided application epserver
#### INSTALL DIFFERENCES ####
+ Follow the installation steps for dpdk version
+ Make sure to set ONVM and RTE_SDK env path variable
mTCP is a highly scalable user-level TCP stack for multicore systems.
mTCP source code is distributed under the Modified BSD License. For
more detail, please refer to the LICENSE. The license term of io_engine
@ -24,12 +15,16 @@ We require the following libraries to run mTCP.
- ``libnuma``
- ``libpthread``
- ``librt``
Compling PSIO/DPDK driver requires kernel headers.
Compling PSIO/DPDK driver requires kernel headers.
- For Debian/Ubuntu, try ``apt-get install linux-headers-$(uname -r)``
We have modified the dpdk-16.11 package to export net_device stat data
to the OS. To achieve this, the dpdk-16.11/lib/librte_eal/linuxapp/igb_uio/
directory was updated. We recommend using our package for DPDK installation.
(for Intel-based Ethernet adapters only) to the OS. To achieve this, the
dpdk-16.11/lib/librte_eal/linuxapp/igb_uio/ directory was updated. We also modified
``mk/rte.app.mk`` and ``rte_cpuflags.mk`` files to ease the compilation
process of mTCP applications. We recommend using our package for DPDK
installation.
### INCLUDED DIRECTORIES ###
@ -64,7 +59,7 @@ config: sample mTCP configuration files (may not be necessary)
### INSTALL GUIDES ###
mTCP can be prepared in two ways.
mTCP can be prepared in three ways.
***PSIO VERSION***
@ -88,6 +83,14 @@ mTCP can be prepared in two ways.
## e.g. ./configure --with-psio-lib=`echo $PWD`/io_engine
# make
```
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 8-core system, by using the following command:
```bash
# ./configure --with-psio-lib=`echo $PWD`/io_engine CFLAGS="-DMAX_CPUS=8"
```
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-3 (configure again):
@ -107,13 +110,13 @@ mTCP can be prepared in two ways.
***DPDK VERSION***
1. Set up Intel's DPDK driver. Please use our version of DPDK.
We have only changed the lib/igb_uio/ submodule. The best
method to compile DPDK package is to use DPDK's tools/setup.sh
script. Please compile your package based on your own hardware
configuration. We tested the mTCP stack on Intel Xeon E5-2690
(x86_64) machine with Intel 82599 Ethernet adapters (10G). We
used the following steps in the dpdk-setup.sh script for our
setup:
We have changed the lib/igb_uio/ submodule and a few makefiles
in DPDK's ``mk/`` subdirectory. The best method to compile DPDK
package is to use DPDK's tools/setup.sh script. Please compile
your package based on your own hardware configuration. We tested
the mTCP stack on Intel Xeon E5-2690 (x86_64) machine with Intel
82599 Ethernet adapters (10G). We used the following steps in
the dpdk-setup.sh script for our setup:
- Press [13] to compile the package
- Press [16] to install the driver
@ -129,6 +132,18 @@ mTCP can be prepared in two ways.
on this page: http://dpdk.org/doc/nics. Please make sure that your
NIC is compatible before moving on to the next step.
- recent Linux kernels tend to rename Ethernet interfaces based on
their PCI addresses. If you are using Intel based Ethernet adapters,
please rename the interface with a ``dpdk`` prefix. You can do so
using the following command:
```bash
# sudo ifconfig <iface> down
## where X is an integer value.
## e.g. sudo ip link set ens786f0 name dpdk0
# sudo ip link set <iface> name dpdkX
```
2. Next bring the dpdk-registered interfaces up. Please use the
``setup_iface_single_process.sh`` script file present in ``dpdk-16.11/tools/``
directory for this purpose. Please change lines 49-51 to change the IP
@ -152,6 +167,15 @@ mTCP can be prepared in two ways.
## e.g. ./configure --with-dpdk-lib=`echo $PWD`/dpdk
# make
```
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 32-core system, by using the following command:
```bash
# ./configure --with-dpdk-lib=$<path_to_mtcp_release_v3>/dpdk CFLAGS="-DMAX_CPUS=32"
```
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-4 (configure again):
@ -170,6 +194,45 @@ mTCP can be prepared in two ways.
6. Run the applications!
***ONVM VERSION***
[Install openNetVM following these instructions](https://github.com/sdnfv/openNetVM/blob/master/docs/Install.md)
*ONVM uses DPDK so follow the dpdk installation up until step 4*
4. Setup mtcp library
```bash
# ./configure --with-dpdk-lib=$<path_to_dpdk> --with-onvm-lib=$<path_to_onvm_lib>
# make
```
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 32-core system, by using the following command:
```bash
# ./configure --with-dpdk-lib=$<path_to_mtcp_release_v3>/dpdk --with-onvm-lib=$<path_to_onvm_lib> CFLAGS="-DMAX_CPUS=32"
```
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-4 (configure again):
```# autoreconf -ivf```
- checksum offloading in the NIC is now ENABLED (by default)!!!
- this only works for dpdk at the moment
- use ```./configure --with-dpdk-lib=`echo $PWD`/dpdk --with-onvm-lib=$<path_to_onvm_lib> --disable-hwcsum``` to disable checksum offloading.
- check libmtcp.a in mtcp/lib
- check header files in mtcp/include
- check example binary files in apps/example
5. Check the configurations in apps/example
- epserver.conf for server-side configuration
- epwget.conf for client-side configuration
- you may write your own configuration file for your application
6. Run the applications!
***TESTED ENVIRONMENTS***
mTCP runs on Linux-based operating systems (2.6.x for PSIO) with generic
@ -211,8 +274,9 @@ We tested the DPDK version (polling driver) with Linux-3.13.0 kernel.
5. mTCP has been tested with the following Ethernet adapters:
1. Intel-82598 ixgbe (Max-queue-limit: 16)
2. Intel-82599 ixgbe (Max-queue-limit: 16)
3. Intel-I350 igb (Max-queue-limit: 08)
2. Intel-82599 ixgbe (Max-queue-limit: 16)
3. Intel-I350 igb (Max-queue-limit: 08)
4. Intel-X710 i40e (Max-queue-limit: ~)
***FREQUENTLY ASKED QUESTIONS***
@ -243,6 +307,3 @@ We tested the DPDK version (polling driver) with Linux-3.13.0 kernel.
April 2, 2015.
EunYoung Jeong <notav at ndsl.kaist.edu>
M. Asim Jamshed <ajamshed at ndsl.kaist.edu>
[onvm]: http://sdnfv.github.io/onvm/

View File

@ -59,6 +59,11 @@
2. Setup mtcp library:
# ./configure --enable-netmap
# make
- By default, mTCP assumes that there are 16 CPUs in your system.
You can set the CPU limit, e.g. on a 32-core system, by using the following command:
# ./configure --enable-netmap CFLAGS="-DMAX_CPUS=32"
Please note that your NIC should support RSS queues equal to the MAX_CPUS value
(since mTCP expects a one-to-one RSS queue to CPU binding).
- In case `./configure' script prints an error, run the
following command; and then re-do step-2 (configure again):
# autoreconf -ivf

View File

@ -2317,6 +2317,9 @@ static int open_postfile(const char *pfile)
int main(int argc, const char * const argv[])
{
#ifdef HAVE_MTCP
struct mtcp_conf mcfg;
#endif
int r, l;
char tmp[1024];
apr_status_t status;
@ -2386,6 +2389,11 @@ int main(int argc, const char * const argv[])
break;
case 'N':
_num_cpus = atoi(optarg);
#ifdef HAVE_MTCP
mtcp_getconf(&mcfg);
mcfg.num_cores = _num_cpus;
mtcp_setconf(&mcfg);
#endif
break;
case 'l':
num_ports = atoi(optarg);

View File

@ -1,17 +1,12 @@
# TODO: Make this Makefile.in pretty
TARGETS = epserver epwget
CC=@CC@ -g -O3 -Wall -Werror -fgnu89-inline
DPDK=@DPDK@
PS=@PSIO@
NETMAP=@NETMAP@
### Check onvm related env vars ###
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
ifeq ($(ONVM),)
$(error "Please define ONVM environment variable")
endif
ONVM=@ONVM@
CFLAGS=@CFLAGS@
# DPDK LIBRARY and HEADER
DPDK_INC=@DPDKLIBPATH@/include
@ -25,7 +20,7 @@ MTCP_TARGET = ${MTCP_LIB}/libmtcp.a
UTIL_FLD = ../../util
UTIL_INC = -I${UTIL_FLD}/include
UTIL_OBJ = ${UTIL_FLD}/http_parsing.o ${UTIL_FLD}/tdate_parse.o
UTIL_OBJ = ${UTIL_FLD}/http_parsing.o ${UTIL_FLD}/tdate_parse.o ${UTIL_FLD}/netlib.o
PS_DIR = ../../io_engine/
@ -48,6 +43,29 @@ DPDK_MACHINE_FLAGS = $(shell cat @DPDKLIBPATH@/include/cflags.txt)
INC += ${DPDK_MACHINE_FLAGS} -I${DPDK_INC} -include $(DPDK_INC)/rte_config.h
endif
ifeq ($(shell uname -m),x86_64)
LIBS += -m64
endif
ifeq ($(DPDK),1)
DPDK_LIB_FLAGS = $(shell cat @DPDKLIBPATH@/lib/ldflags.txt)
#LIBS += -m64 -g -O3 -pthread -lrt -march=native -Wl,-export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -Wl,-lnuma -Wl,-lmtcp -Wl,-lpthread -Wl,-lrt -Wl,-ldl -Wl,${DPDK_LIB_FLAGS}
LIBS += -g -O3 -pthread -lrt -march=native -export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -lnuma -lmtcp -lpthread -lrt -ldl ${DPDK_LIB_FLAGS}
else
#LIBS += -m64 -g -O3 -pthread -lrt -march=native -Wl,-export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -Wl,-lnuma -Wl,-lmtcp -Wl,-lpthread -Wl,-lrt -Wl,-ldl -Wl,${DPDK_LIB_FLAGS}
LIBS += -g -O3 -pthread -lrt -march=native -export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -lnuma -lmtcp -lpthread -lrt -ldl ${DPDK_LIB_FLAGS}
endif
ifeq ($(ONVM),1)
ifeq ($(RTE_TARGET),)
$(error "Please define RTE_TARGET environment variable")
endif
INC += -I@ONVMLIBPATH@/onvm_nflib
INC += -DENABLE_ONVM
LIBS += @ONVMLIBPATH@/onvm_nflib/onvm_nflib/$(RTE_TARGET)/libonvm.a
endif
ifeq ($V,) # no echo
export MSG=@echo
export HIDE=@
@ -56,25 +74,13 @@ else
export HIDE=
endif
ifeq ($(DPDK),1)
DPDK_LIB_FLAGS = $(shell cat @DPDKLIBPATH@/lib/ldflags.txt)
#LIBS += -m64 -g -O3 -pthread -lrt -march=native -Wl,-export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -Wl,-lnuma -Wl,-lmtcp -Wl,-lpthread -Wl,-lrt -Wl,-ldl -Wl,${DPDK_LIB_FLAGS}
LIBS += -m64 -g -O3 -pthread -lrt -march=native -export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -lnuma -lmtcp -lpthread -lrt -ldl ${DPDK_LIB_FLAGS}
else
#LIBS += -m64 -g -O3 -pthread -lrt -march=native -Wl,-export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -Wl,-lnuma -Wl,-lmtcp -Wl,-lpthread -Wl,-lrt -Wl,-ldl -Wl,${DPDK_LIB_FLAGS}
LIBS += -m64 -g -O3 -pthread -lrt -march=native -export-dynamic ${MTCP_FLD}/lib/libmtcp.a -L../../dpdk/lib -lnuma -lmtcp -lpthread -lrt -ldl ${DPDK_LIB_FLAGS}
endif
INC += -I$(ONVM)/onvm_nflib
LIBS += $(ONVM)/onvm_nflib/onvm_nflib/$(RTE_TARGET)/libonvm.a
all: epserver epwget
epserver.o: epserver.c
$(MSG) " CC $<"
$(HIDE) ${CC} -c $< ${CFLAGS} ${INC}
epserver: epserver.o
epserver: epserver.o ${MTCP_FLD}/lib/libmtcp.a
$(MSG) " LD $<"
$(HIDE) ${CC} $< ${LIBS} ${UTIL_OBJ} -o $@
@ -82,7 +88,7 @@ epwget.o: epwget.c
$(MSG) " CC $<"
$(HIDE) ${CC} -c $< ${CFLAGS} ${INC}
epwget: epwget.o
epwget: epwget.o ${MTCP_FLD}/lib/libmtcp.a
$(MSG) " LD $<"
$(HIDE) ${CC} $< ${LIBS} ${UTIL_OBJ} -o $@

View File

@ -1,13 +1,19 @@
This example application was modified to work with onvm
========================================================================
USAGE OF EXAMPLE APPLICATIONS
========================================================================
epserver: a simple mtcp-epoll-based web server
Single-Process, Multi-threaded Usage:
./epserver -p www_home -f epserver.conf [-N #cores] [-c core_list] -- [-s service_id]
ex) ./epserver -p /home/notav/www -f epserver.conf -N 1 -c 6 -- -r 1
./epserver -p www_home -f epserver.conf [-N #cores]
ex) ./epserver -p /home/notav/www -f epserver.conf -N 8
Multi-Process, Single-threaded Usage [DPDK-only]
(Master runs on core 0 by default, Slave processes on core 1~N)
ex) ./epserver -p /home/notav/www -f epserver-master.conf -c 0
for i in {1..7}
do
./epserver -p /home/notav/www -f epserver-slave.conf -c $i
done
options:
@ -16,15 +22,8 @@ options:
-N: number of CPU cores to use. default: all existing cores
-p: path to www/ files
-f: path to mtcp configuration file
-c: the core_list on which the process should run
[So far only single core is supported]
onvm args after --
-n: instanse id
-r: service id
-d: destination id
Epserver doesn't support large files
- Large files roughly > 10 Megabytes are currently causing an error in rte_eal_init for dpdk/onvm setup
-c: the core_id on which the process should run
[only works for multi-process mode]
========================================================================

View File

@ -14,12 +14,14 @@
#include <time.h>
#include <pthread.h>
#include <signal.h>
#include <limits.h>
#include <mtcp_api.h>
#include <mtcp_epoll.h>
#include "cpu.h"
#include "http_parsing.h"
#include "netlib.h"
#include "debug.h"
#define MAX_FLOW_NUM (10000)
@ -32,11 +34,10 @@
#define HTTP_HEADER_LEN 1024
#define URL_LEN 128
#define MAX_CPUS 16
#define MAX_FILES 30
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MIN(a, b) ((a)<(b)?(a):(b))
#define NAME_LIMIT 128
#define FULLNAME_LIMIT 256
#ifndef TRUE
#define TRUE (1)
@ -52,11 +53,14 @@
#define HT_SUPPORT FALSE
#ifndef MAX_CPUS
#define MAX_CPUS 16
#endif
/*----------------------------------------------------------------------------*/
struct file_cache
{
char name[128];
char fullname[256];
char name[NAME_LIMIT];
char fullname[FULLNAME_LIMIT];
uint64_t size;
char *file;
};
@ -72,7 +76,7 @@ struct server_vars
uint8_t keep_alive;
int fidx; // file cache index
char fname[128]; // file name
char fname[NAME_LIMIT]; // file name
long int fsize; // file size
};
/*----------------------------------------------------------------------------*/
@ -88,6 +92,7 @@ static int core_limit;
static pthread_t app_thread[MAX_CPUS];
static int done[MAX_CPUS];
static char *conf_file = NULL;
static int backlog = -1;
/*----------------------------------------------------------------------------*/
const char *www_main;
static struct file_cache fcache[MAX_FILES];
@ -332,12 +337,15 @@ InitializeServerThread(int core)
ctx->mctx = mtcp_create_context(core);
if (!ctx->mctx) {
TRACE_ERROR("Failed to create mtcp context!\n");
free(ctx);
return NULL;
}
/* create epoll descriptor */
ctx->ep = mtcp_epoll_create(ctx->mctx, MAX_EVENTS);
if (ctx->ep < 0) {
mtcp_destroy_context(ctx->mctx);
free(ctx);
TRACE_ERROR("Failed to create epoll descriptor!\n");
return NULL;
}
@ -346,6 +354,9 @@ InitializeServerThread(int core)
ctx->svars = (struct server_vars *)
calloc(MAX_FLOW_NUM, sizeof(struct server_vars));
if (!ctx->svars) {
mtcp_close(ctx->mctx, ctx->ep);
mtcp_destroy_context(ctx->mctx);
free(ctx);
TRACE_ERROR("Failed to create server_vars struct!\n");
return NULL;
}
@ -384,8 +395,8 @@ CreateListeningSocket(struct thread_context *ctx)
return -1;
}
/* listen (backlog: 4K) */
ret = mtcp_listen(ctx->mctx, listener, 4096);
/* listen (backlog: can be configured) */
ret = mtcp_listen(ctx->mctx, listener, backlog);
if (ret < 0) {
TRACE_ERROR("mtcp_listen() failed!\n");
return -1;
@ -537,15 +548,13 @@ static void
printHelp(const char *prog_name)
{
TRACE_CONFIG("%s -p <path_to_www/> -f <mtcp_conf_file> "
"[-N num_cores] [-c <core_list>] [-h] "
"-- [-n onvm_instance_id] [-r onvm_service_id] "
"[-d onvm_dest_id]\n",
"[-N num_cores] [-c <per-process core_id>] [-h]\n",
prog_name);
exit(EXIT_SUCCESS);
}
/*----------------------------------------------------------------------------*/
int
main(int argc, char *argv[])
main(int argc, char **argv)
{
DIR *dir;
struct dirent *ent;
@ -553,26 +562,21 @@ main(int argc, char *argv[])
int ret;
uint64_t total_read;
struct mtcp_conf mcfg;
int core_list[MAX_CPUS];
int cores[MAX_CPUS];
int process_cpu;
int o;
int i, val;
char *core_list_tokens;
int i, o;
num_cores = GetNumCPUs();
core_limit = num_cores;
process_cpu = -1;
dir = NULL;
i = 0;
if (argc < 2) {
TRACE_CONFIG("$%s directory_to_service\n", argv[0]);
return FALSE;
}
mtcp_getconf(&mcfg);
while (-1 != (o = getopt(argc, argv, "N:f:p:c:h"))) {
while (-1 != (o = getopt(argc, argv, "N:f:p:c:b:h"))) {
switch (o) {
case 'p':
/* open the directory to serve */
@ -585,59 +589,40 @@ main(int argc, char *argv[])
}
break;
case 'N':
core_limit = atoi(optarg);
core_limit = mystrtol(optarg, 10);
if (core_limit > num_cores) {
TRACE_CONFIG("CPU limit should be smaller than the "
"number of CPUs: %d\n", num_cores);
return FALSE;
}
if (core_limit != 1) {
TRACE_CONFIG("Multi core is currently NOT supported, "
"use -N 1\n");
return FALSE;
}
/**
* it is important that core limit is set
* before mtcp_init() is called. You can
* not set core_limit after mtcp_init()
*/
mtcp_getconf(&mcfg);
mcfg.num_cores = core_limit;
mtcp_setconf(&mcfg);
break;
case 'f':
conf_file = optarg;
break;
case 'c':
mcfg.core_list = optarg;
process_cpu = mystrtol(optarg, 10);
if (process_cpu > core_limit) {
TRACE_CONFIG("Starting CPU is way off limits!\n");
return FALSE;
}
break;
case 'b':
backlog = mystrtol(optarg, 10);
break;
case 'h':
printHelp(argv[0]);
break;
}
}
mtcp_setconf(&mcfg);
/* Modify argc/argv to correctly pass arguments to mtcp_parse_args */
argv += optind-1;
argc -= optind-1;
/* Check core_list was passed */
if (mcfg.core_list == NULL){
TRACE_CONFIG("You did not pass a valid core_list!\n");
exit(EXIT_FAILURE);
}
core_list_tokens = malloc(sizeof(char) * strlen(mcfg.core_list));
strcpy(core_list_tokens, mcfg.core_list);
if (core_list_tokens == NULL){
perror("core_list_tokens malloc");
}
}
while (core_list_tokens !=NULL){
val = atoi(core_list_tokens);
core_list[i++]=val;
core_list_tokens = strtok(NULL, ",");
}
if (dir == NULL) {
TRACE_CONFIG("You did not pass a valid www_path!\n");
exit(EXIT_FAILURE);
@ -650,8 +635,9 @@ main(int argc, char *argv[])
else if (strcmp(ent->d_name, "..") == 0)
continue;
strcpy(fcache[nfiles].name, ent->d_name);
sprintf(fcache[nfiles].fullname, "%s/%s", www_main, ent->d_name);
snprintf(fcache[nfiles].name, NAME_LIMIT, "%s", ent->d_name);
snprintf(fcache[nfiles].fullname, FULLNAME_LIMIT, "%s/%s",
www_main, ent->d_name);
fd = open(fcache[nfiles].fullname, O_RDONLY);
if (fd < 0) {
perror("open");
@ -701,22 +687,34 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
ret = mtcp_init(conf_file, argc, argv);
ret = mtcp_init(conf_file);
if (ret) {
TRACE_CONFIG("Failed to initialize mtcp\n");
exit(EXIT_FAILURE);
}
mtcp_getconf(&mcfg);
if (backlog > mcfg.max_concurrency) {
TRACE_CONFIG("backlog can not be set larger than CONFIG.max_concurrency\n");
return FALSE;
}
/* if backlog is not specified, set it to 4K */
if (backlog == -1) {
backlog = 4096;
}
/* register signal handler to mtcp */
mtcp_register_signal(SIGINT, SignalHandler);
TRACE_INFO("Application initialization finished.\n");
for (i = 0; i < core_limit; i++) {
done[core_list[i]] = FALSE;
for (i = ((process_cpu == -1) ? 0 : process_cpu); i < core_limit; i++) {
cores[i] = i;
done[i] = FALSE;
if (pthread_create(&app_thread[core_list[i]],
NULL, RunServerThread, (void *)&core_list[i])) {
if (pthread_create(&app_thread[i],
NULL, RunServerThread, (void *)&cores[i])) {
perror("pthread_create");
TRACE_CONFIG("Failed to create server thread.\n");
exit(EXIT_FAILURE);
@ -725,8 +723,8 @@ main(int argc, char *argv[])
break;
}
for (i = 0; i < core_limit; i++) {
pthread_join(app_thread[core_list[i]], NULL);
for (i = ((process_cpu == -1) ? 0 : process_cpu); i < core_limit; i++) {
pthread_join(app_thread[i], NULL);
if (process_cpu != -1)
break;

View File

@ -4,7 +4,8 @@
# enable only one out of the two.
#io = psio
#io = netmap
io = onvm
#io = onvm
io = dpdk
# No. of cores setting (enabling this option will override
# the `cpu' config for those applications that accept
@ -16,7 +17,17 @@ io = onvm
#num_cores = 8
# Number of memory channels per processor socket (dpdk-only)
num_mem_ch = 3
num_mem_ch = 4
# ONVM specific args
# Service id (required)
#onvm_serv = 1
#
# Instance id (optional)
#onvm_inst = 1
# Destination id (will forward to another NF)
# If not set will send packets out
#onvm_dest = 2
# Enable multi-process support (under development)
#multiprocess = 0 master
@ -27,11 +38,10 @@ num_mem_ch = 3
#port = xge0 xge1
#port = xge1
#------ DPDK ports -------#
#port = dpdk1
port = dpdk0
#port = dpdk0 dpdk1
#port = dpdk0:0
#port = dpdk0:1
port = dpdk0 dpdk1
# Maximum concurrency per core
max_concurrency = 10000
@ -41,7 +51,7 @@ max_concurrency = 10000
max_num_buffers = 10000
# Receive buffer size of sockets
rcvbuf = 8192
rcvbuf = 8192
# Send buffer size of sockets
sndbuf = 8192
@ -59,9 +69,9 @@ tcp_timewait = 0
#stat_print = xge0
#stat_print = xge1
#------ DPDK ports -------#
stat_print = dpdk0
#stat_print = dpdk0:0
#stat_print = dpdk0:1
#stat_print = dpdk1
stat_print = dpdk0 dpdk1
#######################################################

View File

@ -15,16 +15,16 @@
#include <arpa/inet.h>
#include <sys/queue.h>
#include <assert.h>
#include <limits.h>
#include <mtcp_api.h>
#include <mtcp_epoll.h>
#include "cpu.h"
#include "rss.h"
#include "http_parsing.h"
#include "netlib.h"
#include "debug.h"
#define MAX_CPUS 16
#define MAX_URL_LEN 128
#define MAX_FILE_LEN 128
#define HTTP_HEADER_LEN 1024
@ -40,9 +40,6 @@
#define TIMEVAL_TO_USEC(t) ((t.tv_sec * 1000000) + (t.tv_usec))
#define TS_GT(a,b) ((int64_t)((a)-(b)) > 0)
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MIN(a, b) ((a)<(b)?(a):(b))
#ifndef TRUE
#define TRUE (1)
#endif
@ -55,6 +52,9 @@
#define ERROR (-1)
#endif
#ifndef MAX_CPUS
#define MAX_CPUS 16
#endif
/*----------------------------------------------------------------------------*/
static pthread_t app_thread[MAX_CPUS];
static mctx_t g_mctx[MAX_CPUS];
@ -66,8 +66,8 @@ static int core_limit;
static int fio = FALSE;
static char outfile[MAX_FILE_LEN + 1];
/*----------------------------------------------------------------------------*/
static char host[MAX_IP_STR_LEN + 1];
static char url[MAX_URL_LEN + 1];
static char host[MAX_IP_STR_LEN + 1] = {'\0'};
static char url[MAX_URL_LEN + 1] = {'\0'};
static in_addr_t daddr;
static in_port_t dport;
static in_addr_t saddr;
@ -132,8 +132,8 @@ struct wget_vars
int fd;
};
/*----------------------------------------------------------------------------*/
static struct thread_context *g_ctx[MAX_CPUS];
static struct wget_stat *g_stat[MAX_CPUS];
static struct thread_context *g_ctx[MAX_CPUS] = {0};
static struct wget_stat *g_stat[MAX_CPUS] = {0};
/*----------------------------------------------------------------------------*/
thread_context_t
CreateContext(int core)
@ -151,6 +151,7 @@ CreateContext(int core)
ctx->mctx = mtcp_create_context(core);
if (!ctx->mctx) {
TRACE_ERROR("Failed to create mtcp context.\n");
free(ctx);
return NULL;
}
g_mctx[core] = ctx->mctx;
@ -161,6 +162,7 @@ CreateContext(int core)
void
DestroyContext(thread_context_t ctx)
{
g_stat[ctx->core] = NULL;
mtcp_destroy_context(ctx->mctx);
free(ctx);
}
@ -346,15 +348,23 @@ HandleReadEvent(thread_context_t ctx, int sockid, struct wget_vars *wv)
wv->response[wv->header_len] = '\0';
wv->file_len = http_header_long_val(wv->response,
CONTENT_LENGTH_HDR, sizeof(CONTENT_LENGTH_HDR) - 1);
if (wv->file_len < 0) {
/* failed to find the Content-Length field */
wv->recv += rd;
rd = 0;
CloseConnection(ctx, sockid);
return 0;
}
TRACE_APP("Socket %d Parsed response header. "
"Header length: %u, File length: %lu (%luMB)\n",
sockid, wv->header_len,
wv->file_len, wv->file_len / 1024 / 1024);
wv->headerset = TRUE;
wv->recv += (rd - (wv->resp_len - wv->header_len));
rd = (wv->resp_len - wv->header_len);
pbuf += (rd - (wv->resp_len - wv->header_len));
rd = (wv->resp_len - wv->header_len);
//printf("Successfully parse header.\n");
//fflush(stdout);
@ -476,6 +486,8 @@ PrintStats()
for (i = 0; i < core_limit; i++) {
st = g_stat[i];
if (st == NULL) continue;
avg_resp_time = st->completes? st->sum_resp_time / st->completes : 0;
#if 0
fprintf(stderr, "[CPU%2d] epoll_wait: %5lu, event: %7lu, "
@ -500,7 +512,7 @@ PrintStats()
total.errors += st->errors;
total.timedout += st->timedout;
memset(st, 0, sizeof(struct wget_stat));
memset(st, 0, sizeof(struct wget_stat));
}
fprintf(stderr, "[ ALL ] connect: %7lu, read: %4lu MB, write: %4lu MB, "
"completes: %7lu (resp_time avg: %4lu, max: %6lu us)\n",
@ -596,7 +608,7 @@ RunWgetMain(void *arg)
/* print statistics every second */
if (core == 0 && cur_tv.tv_sec > prev_tv.tv_sec) {
PrintStats();
PrintStats();
prev_tv = cur_tv;
}
@ -711,14 +723,14 @@ main(int argc, char **argv)
strncpy(url, strchr(argv[1], '/'), MAX_URL_LEN);
} else {
strncpy(host, argv[1], MAX_IP_STR_LEN);
strncpy(url, "/", 1);
strncpy(url, "/", 2);
}
daddr = inet_addr(host);
dport = htons(80);
saddr = INADDR_ANY;
total_flows = atoi(argv[2]);
total_flows = mystrtol(argv[2], 10);
if (total_flows <= 0) {
TRACE_CONFIG("Number of flows should be large than 0.\n");
return FALSE;
@ -729,11 +741,14 @@ main(int argc, char **argv)
concurrency = 100;
for (i = 3; i < argc - 1; i++) {
if (strcmp(argv[i], "-N") == 0) {
core_limit = atoi(argv[i + 1]);
core_limit = mystrtol(argv[i + 1], 10);
if (core_limit > num_cores) {
TRACE_CONFIG("CPU limit should be smaller than the "
"number of CPUS: %d\n", num_cores);
return FALSE;
} else if (core_limit < 1) {
TRACE_CONFIG("CPU limit should be greater than 0\n");
return FALSE;
}
/**
* it is important that core limit is set
@ -744,7 +759,7 @@ main(int argc, char **argv)
mcfg.num_cores = core_limit;
mtcp_setconf(&mcfg);
} else if (strcmp(argv[i], "-c") == 0) {
total_concurrency = atoi(argv[i + 1]);
total_concurrency = mystrtol(argv[i + 1], 10);
} else if (strcmp(argv[i], "-o") == 0) {
if (strlen(argv[i + 1]) > MAX_FILE_LEN) {

21
configure vendored
View File

@ -664,10 +664,12 @@ am__isrc
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
ONVMLIBPATH
PSLIBPATH
DPDKLIBPATH
HWCSUM
NETMAP
ONVM
PSIO
LRO
DPDK
@ -1369,6 +1371,7 @@ Optional Packages:
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-dpdk-lib path to the dpdk-16.11 install root
--with-psio-lib path to the ioengine install root
--with-onvm-lib path to the onvm install root
Some influential environment variables:
CC C compiler command
@ -4102,6 +4105,9 @@ LRO=0
# Reset PSIO to 0
PSIO=0
# Reset ONVM to 0
ONVM=0
# Reset NETMAP to 0
NETMAP=0
@ -4178,6 +4184,21 @@ if test "x$enable_netmap" = "xyes"; then :
fi
# Check onvm lib path
# Check whether --with-stuff was given.
if test "${with_stuff+set}" = set; then :
withval=$with_stuff;
fi
if test "$with_onvm_lib" != ""
then
ONVMLIBPATH=$with_onvm_lib
ONVM=1
fi
if test "$with_psio_lib" == "" && test "$with_dpdk_lib" == "" && test "x$enable_netmap" = "xno"
then
as_fn_error $? "Packet I/O library is missing. Please set either dpdk or psio or netmap as your I/O lib." "$LINENO" 5

View File

@ -47,6 +47,8 @@ AC_SUBST(DPDK, 0)
AC_SUBST(LRO, 0)
# Reset PSIO to 0
AC_SUBST(PSIO, 0)
# Reset ONVM to 0
AC_SUBST(ONVM, 0)
# Reset NETMAP to 0
AC_SUBST(NETMAP, 0)
# Reset HWCSUM to 1
@ -96,6 +98,14 @@ AS_IF([test "x$enable_netmap" = "xyes"], [
AC_SUBST(NETMAP, 1)
])
# Check onvm lib path
AC_ARG_WITH(stuff, [ --with-onvm-lib path to the onvm install root])
if test "$with_onvm_lib" != ""
then
AC_SUBST(ONVMLIBPATH, $with_onvm_lib)
AC_SUBST(ONVM, 1)
fi
if test "$with_psio_lib" == "" && test "$with_dpdk_lib" == "" && test "x$enable_netmap" = "xno"
then
AC_MSG_ERROR([Packet I/O library is missing. Please set either dpdk or psio or netmap as your I/O lib.])

View File

@ -37,17 +37,43 @@ include $(RTE_SDK)/mk/rte.vars.mk
MODULE = igb_uio
MODULE_PATH = drivers/net/igb_uio
include $(RTE_SDK)/lib/librte_eal/linuxapp/igb_uio/i40e/common.mk
#
# CFLAGS
#
MODULE_CFLAGS += -I$(SRCDIR) --param max-inline-insns-single=100
MODULE_CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/i40e
MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
MODULE_CFLAGS += -Winline -Wall -Werror
MODULE_CFLAGS += -Wall -Werror
MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
ifeq ($(shell lsb_release -si 2>/dev/null),Ubuntu)
MODULE_CFLAGS += -DUBUNTU_RELEASE_CODE=$(shell lsb_release -sr | tr -d .)
UBUNTU_KERNEL_CODE := $(shell echo `grep UTS_RELEASE $(RTE_KERNELDIR)/include/generated/utsrelease.h \
| cut -d '"' -f2 | cut -d- -f1,2 | tr .- ,`,1)
MODULE_CFLAGS += -D"UBUNTU_KERNEL_CODE=UBUNTU_KERNEL_VERSION($(UBUNTU_KERNEL_CODE))"
endif
#
# all source are stored in SRCS-y
#
SRCS-y := igb_uio.c
SRCS-y := igbuio.c
SRCS-y += i40e/i40e_main.c
SRCS-y += i40e/i40e_adminq.c
SRCS-y += i40e/i40e_dcb.c
SRCS-y += i40e/i40e_diag.c
SRCS-y += i40e/i40e_hmc.c
SRCS-y += i40e/i40e_nvm.c
SRCS-y += i40e/i40e_virtchnl_pf.c
SRCS-y += i40e/i40e_client.c
SRCS-y += i40e/i40e_dcb_nl.c
SRCS-y += i40e/i40e_ethtool.c
SRCS-y += i40e/i40e_lan_hmc.c
SRCS-y += i40e/i40e_ptp.c
SRCS-y += i40e/kcompat.c
SRCS-y += i40e/i40e_common.c
SRCS-y += i40e/i40e_debugfs.c
SRCS-y += i40e/i40e_fcoe.c
SRCS-y += i40e/i40e_txrx.c
include $(RTE_SDK)/mk/rte.module.mk

View File

@ -0,0 +1,165 @@
################################################################################
#
# Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
# Copyright(c) 2013 - 2017 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope 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.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
ifneq ($(KERNELRELEASE),)
# kbuild part of makefile
#
# Makefile for the Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
#
obj-$(CONFIG_I40E) += i40e.o
i40e-y := i40e_main.o \
i40e_ethtool.o \
i40e_adminq.o \
i40e_common.o \
i40e_hmc.o \
i40e_lan_hmc.o \
i40e_nvm.o \
i40e_debugfs.o \
i40e_diag.o \
i40e_txrx.o \
i40e_ptp.o \
i40e_client.o \
i40e_virtchnl_pf.o
i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o
i40e-y += kcompat.o
else # ifneq($(KERNELRELEASE),)
# normal makefile
DRIVER := i40e
ifeq (,$(wildcard common.mk))
$(error Cannot find common.mk build rules)
else
include common.mk
endif
# i40e does not support building on kernels older than 2.6.32
$(call minimum_kver_check,2,6,32)
###############
# Build rules #
###############
# Standard compilation, with regular output
default:
@+$(call kernelbuild,modules)
# Noisy output, for extra debugging
noisy:
@+$(call kernelbuild,modules,V=1)
# Silence any output generated
silent:
@+$(call kernelbuild,modules,>/dev/null)
# Enable higher warning level
checkwarnings: clean
@+$(call kernelbuild,modules,W=1)
# Run sparse static analyzer
sparse: clean
@+$(call kernelbuild,modules,C=2 CF="-D__CHECK_ENDIAN__ -Wbitwise -Wcontext")
# Run coccicheck static analyzer
ccc: clean
@+$(call kernelbuild,modules,coccicheck MODE=report)
# Build manfiles
manfile:
@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
# Clean the module subdirectories
clean:
@+$(call kernelbuild,clean)
@-rm -rf *.${MANSECTION}.gz *.ko
# Install the modules and manpage
install: default manfile
@echo "Copying manpages..."
@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
@echo "Installing modules..."
@+$(call kernelbuild,modules_install)
@echo "Running depmod..."
@$(call cmd_depmod)
ifeq (${cmd_initrd},)
@echo "Unable to update initrd. You may need to do this manually."
else
@echo "Updating initrd..."
-@$(call cmd_initrd)
endif
# Target used by rpmbuild spec file
rpm: default manfile
@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
@install -D -m 644 ${DRIVER}.ko ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko
uninstall:
rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko;
$(call cmd_depmod)
ifeq (${cmd_initrd},)
@echo "Unable to update initrd. You may need to do this manually."
else
@echo "Updating initrd..."
-@$(call cmd_initrd)
endif
if [ -e ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz ] ; then \
rm -f ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz ; \
fi;
########
# Help #
########
help:
@echo 'Cleaning targets:'
@echo ' clean - Clean files generated by kernel module build'
@echo 'Build targets:'
@echo ' default - Build module(s) with standard verbosity'
@echo ' noisy - Build module(s) with V=1 verbosity -- very noisy'
@echo ' silent - Build module(s), squelching all output'
@echo 'Static Analysis:'
@echo ' checkwarnings - Clean, then build module(s) with W=1 warnings enabled'
@echo ' sparse - Clean, then check module(s) using sparse'
@echo ' ccc - Clean, then check module(s) using coccicheck'
@echo 'Other targets:'
@echo ' manfile - Generate a gzipped manpage'
@echo ' install - Build then install the module(s) and manpage'
@echo ' uninstall - Uninstall the module(s) and manpage'
@echo ' help - Display this help message'
@echo 'Variables:'
@echo ' LINUX_VERSION - Debug tool to force kernel LINUX_VERSION_CODE. Use at your own risk.'
@echo ' W=N - Kernel variable for setting warning levels'
@echo ' V=N - Kernel variable for setting output verbosity'
@echo ' INSTALL_MOD_PATH - Add prefix for the module and manpage installation path'
@echo ' INSTALL_MOD_DIR - Use module directory other than updates/drivers/net/ethernet/intel/${DRIVER}'
@echo ' KSRC - Specifies the full path to the kernel tree to build against'
@echo ' Other variables may be available for tuning make process, see'
@echo ' Kernel Kbuild documentation for more information'
.PHONY: default noisy clean manfile silent sparse ccc install uninstall help
endif # ifneq($(KERNELRELEASE),)

View File

@ -0,0 +1 @@
i40e.ko external

View File

@ -0,0 +1,318 @@
################################################################################
#
# Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
# Copyright(c) 2013 - 2017 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope 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.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
# common Makefile rules useful for out-of-tree Linux driver builds
#
# Usage: include common.mk
#
# After including, you probably want to add a minimum_kver_check call
#
# Required Variables:
# DRIVER
# -- Set to the lowercase driver name
#####################
# Helpful functions #
#####################
readlink = $(shell readlink -f ${1})
# helper functions for converting kernel version to version codes
get_kver = $(or $(word ${2},$(subst ., ,${1})),0)
get_kvercode = $(shell [ "${1}" -ge 0 -a "${1}" -le 255 2>/dev/null ] && \
[ "${2}" -ge 0 -a "${2}" -le 255 2>/dev/null ] && \
[ "${3}" -ge 0 -a "${3}" -le 255 2>/dev/null ] && \
printf %d $$(( ( ${1} << 16 ) + ( ${2} << 8 ) + ( ${3} ) )) )
################
# depmod Macro #
################
cmd_depmod = /sbin/depmod $(if ${SYSTEM_MAP_FILE},-e -F ${SYSTEM_MAP_FILE}) \
$(if $(strip ${INSTALL_MOD_PATH}),-b ${INSTALL_MOD_PATH}) \
-a ${KVER}
################
# dracut Macro #
################
cmd_initrd := $(shell \
if which dracut > /dev/null 2>&1 ; then \
echo "dracut --force"; \
elif which update-initramfs > /dev/null 2>&1 ; then \
echo "update-initramfs -u"; \
fi )
#####################
# Environment tests #
#####################
DRIVER_UPPERCASE := $(shell echo ${DRIVER} | tr "[:lower:]" "[:upper:]")
ifeq (,${BUILD_KERNEL})
BUILD_KERNEL=$(shell uname -r)
endif
# Kernel Search Path
# All the places we look for kernel source
KSP := /lib/modules/${BUILD_KERNEL}/source \
/lib/modules/${BUILD_KERNEL}/build \
/usr/src/linux-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/-.*//') \
/usr/src/kernel-headers-${BUILD_KERNEL} \
/usr/src/kernel-source-${BUILD_KERNEL} \
/usr/src/linux-$(${BUILD_KERNEL} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \
/usr/src/linux \
/usr/src/kernels/${BUILD_KERNEL} \
/usr/src/kernels
# prune the list down to only values that exist and have an include/linux
# sub-directory. We can't use include/config because some older kernels don't
# have this.
test_dir = $(shell [ -e ${dir}/include/linux ] && echo ${dir})
KSP := $(foreach dir, ${KSP}, ${test_dir})
# we will use this first valid entry in the search path
ifeq (,${KSRC})
KSRC := $(firstword ${KSP})
endif
ifeq (,${KSRC})
$(warning *** Kernel header files not in any of the expected locations.)
$(warning *** Install the appropriate kernel development package, e.g.)
$(error kernel-devel, for building kernel modules and try again)
else
ifeq (/lib/modules/${BUILD_KERNEL}/source, ${KSRC})
KOBJ := /lib/modules/${BUILD_KERNEL}/build
else
KOBJ := ${KSRC}
endif
endif
# Version file Search Path
VSP := ${KOBJ}/include/generated/utsrelease.h \
${KOBJ}/include/linux/utsrelease.h \
${KOBJ}/include/linux/version.h \
${KOBJ}/include/generated/uapi/linux/version.h \
/boot/vmlinuz.version.h
# Config file Search Path
CSP := ${KOBJ}/include/generated/autoconf.h \
${KOBJ}/include/linux/autoconf.h \
/boot/vmlinuz.autoconf.h
# System.map Search Path (for depmod)
MSP := ${KSRC}/System.map \
/boot/System.map-${BUILD_KERNEL}
# prune the lists down to only files that exist
test_file = $(shell [ -f ${file} ] && echo ${file})
VSP := $(foreach file, ${VSP}, ${test_file})
CSP := $(foreach file, ${CSP}, ${test_file})
MSP := $(foreach file, ${MSP}, ${test_file})
# and use the first valid entry in the Search Paths
ifeq (,${VERSION_FILE})
VERSION_FILE := $(firstword ${VSP})
endif
ifeq (,${CONFIG_FILE})
CONFIG_FILE := $(firstword ${CSP})
endif
ifeq (,${SYSTEM_MAP_FILE})
SYSTEM_MAP_FILE := $(firstword ${MSP})
endif
ifeq (,$(wildcard ${VERSION_FILE}))
$(error Linux kernel source not configured - missing version header file)
endif
ifeq (,$(wildcard ${CONFIG_FILE}))
$(error Linux kernel source not configured - missing autoconf.h)
endif
ifeq (,$(wildcard ${SYSTEM_MAP_FILE}))
$(warning Missing System.map file - depmod will not check for missing symbols)
endif
#######################
# Linux Version Setup #
#######################
# The following command line parameter is intended for development of KCOMPAT
# against upstream kernels such as net-next which have broken or non-updated
# version codes in their Makefile. They are intended for debugging and
# development purpose only so that we can easily test new KCOMPAT early. If you
# don't know what this means, you do not need to set this flag. There is no
# arcane magic here.
# Convert LINUX_VERSION into LINUX_VERSION_CODE
ifneq (${LINUX_VERSION},)
LINUX_VERSION_CODE=$(call get_kvercode,$(call get_kver,${LINUX_VERSION},1),$(call get_kver,${LINUX_VERSION},2),$(call get_kver,${LINUX_VERSION},3))
endif
# Honor LINUX_VERSION_CODE
ifneq (${LINUX_VERSION_CODE},)
$(warning Forcing target kernel to build with LINUX_VERSION_CODE of ${LINUX_VERSION_CODE}$(if ${LINUX_VERSION}, from LINUX_VERSION=${LINUX_VERSION}). Do this at your own risk.)
KVER_CODE := ${LINUX_VERSION_CODE}
EXTRA_CFLAGS += -DLINUX_VERSION_CODE=${LINUX_VERSION_CODE}
endif
# Determine SLE_LOCALVERSION_CODE for SuSE SLE >= 11 (needed by kcompat)
# This assumes SuSE will continue setting CONFIG_LOCALVERSION to the string
# appended to the stable kernel version on which their kernel is based with
# additional versioning information (up to 3 numbers), a possible abbreviated
# git SHA1 commit id and a kernel type, e.g. CONFIG_LOCALVERSION=-1.2.3-default
# or CONFIG_LOCALVERSION=-999.gdeadbee-default
ifeq (1,$(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
grep -m 1 CONFIG_SUSE_KERNEL | awk '{ print $$3 }'))
ifneq (10,$(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
grep -m 1 CONFIG_SLE_VERSION | awk '{ print $$3 }'))
LOCALVERSION := $(shell ${CC} -E -dM ${CONFIG_FILE} 2> /dev/null |\
grep -m 1 CONFIG_LOCALVERSION | awk '{ print $$3 }' |\
cut -d'-' -f2 | sed 's/\.g[[:xdigit:]]\{7\}//')
LOCALVER_A := $(shell echo ${LOCALVERSION} | cut -d'.' -f1)
LOCALVER_B := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f2)
LOCALVER_C := $(shell echo ${LOCALVERSION} | cut -s -d'.' -f3)
SLE_LOCALVERSION_CODE := $(shell expr ${LOCALVER_A} \* 65536 + \
0${LOCALVER_B} \* 256 + 0${LOCALVER_C})
EXTRA_CFLAGS += -DSLE_LOCALVERSION_CODE=${SLE_LOCALVERSION_CODE}
endif
endif
EXTRA_CFLAGS += ${CFLAGS_EXTRA}
# get the kernel version - we use this to find the correct install path
KVER := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VERSION_FILE} | grep UTS_RELEASE | \
awk '{ print $$3 }' | sed 's/\"//g')
# assume source symlink is the same as build, otherwise adjust KOBJ
ifneq (,$(wildcard /lib/modules/${KVER}/build))
ifneq (${KSRC},$(call readlink,/lib/modules/${KVER}/build))
KOBJ=/lib/modules/${KVER}/build
endif
endif
ifeq (${KVER_CODE},)
KVER_CODE := $(shell ${CC} ${EXTRA_CFLAGS} -E -dM ${VSP} 2> /dev/null |\
grep -m 1 LINUX_VERSION_CODE | awk '{ print $$3 }' | sed 's/\"//g')
endif
# minimum_kver_check
#
# helper function to provide uniform output for different drivers to abort the
# build based on kernel version check. Usage: "$(call minimum_kver_check,2,6,XX)".
define _minimum_kver_check
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,${1},${2},${3}) ]; echo "$$?"))
$$(warning *** Aborting the build.)
$$(error This driver is not supported on kernel versions older than ${1}.${2}.${3})
endif
endef
minimum_kver_check = $(eval $(call _minimum_kver_check,${1},${2},${3}))
################
# Manual Pages #
################
MANSECTION = 7
ifeq (,${MANDIR})
# find the best place to install the man page
MANPATH := $(shell (manpath 2>/dev/null || echo $MANPATH) | sed 's/:/ /g')
ifneq (,${MANPATH})
# test based on inclusion in MANPATH
test_dir = $(findstring ${dir}, ${MANPATH})
else
# no MANPATH, test based on directory existence
test_dir = $(shell [ -e ${dir} ] && echo ${dir})
endif
# our preferred install path
# should /usr/local/man be in here ?
MANDIR := /usr/share/man /usr/man
MANDIR := $(foreach dir, ${MANDIR}, ${test_dir})
MANDIR := $(firstword ${MANDIR})
endif
ifeq (,${MANDIR})
# fallback to /usr/man
MANDIR := /usr/man
endif
####################
# CCFLAGS variable #
####################
# set correct CCFLAGS variable for kernels older than 2.6.24
ifeq (0,$(shell [ ${KVER_CODE} -lt $(call get_kvercode,2,6,24) ]; echo $$?))
CCFLAGS_VAR := EXTRA_CFLAGS
else
CCFLAGS_VAR := ccflags-y
endif
#################
# KBUILD_OUTPUT #
#################
# Only set KBUILD_OUTPUT if KOBJ differs from KSRC
ifneq (${KSRC},${KOBJ})
export KBUILD_OUTPUT ?= ${KOBJ}
endif
############################
# Module Install Directory #
############################
# Default to using updates/drivers/net/ethernet/intel/ path, since depmod since
# v3.1 defaults to checking updates folder first, and only checking kernels/
# and extra afterwards. We use updates instead of kernel/* due to desire to
# prevent over-writing built-in modules files.
export INSTALL_MOD_DIR ?= updates/drivers/net/ethernet/intel/${DRIVER}
######################
# Kernel Build Macro #
######################
# kernel build function
# ${1} is the kernel build target
# ${2} may contain any extra rules to pass directly to the sub-make process
#
# This function is expected to be executed by
# @+$(call kernelbuild,<target>,<extra parameters>)
# from within a Makefile recipe.
#
# The following variables are expected to be defined for its use:
# GCC_I_SYS -- if set it will enable use of gcc-i-sys.sh wrapper to use -isystem
# CCFLAGS_VAR -- the CCFLAGS variable to set extra CFLAGS
# EXTRA_CFLAGS -- a set of extra CFLAGS to pass into the ccflags-y variable
# KSRC -- the location of the kernel source tree to build against
# DRIVER_UPPERCASE -- the uppercase name of the kernel module, set from DRIVER
#
kernelbuild = ${MAKE} $(if ${GCC_I_SYS},CC="${GCC_I_SYS}") \
${CCFLAGS_VAR}="${EXTRA_CFLAGS}" \
-C "${KSRC}" \
CONFIG_${DRIVER_UPPERCASE}=m \
M="${CURDIR}" \
${2} ${1}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,156 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_ADMINQ_H_
#define _I40E_ADMINQ_H_
#include "i40e_osdep.h"
#include "i40e_status.h"
#include "i40e_adminq_cmd.h"
#define I40E_ADMINQ_DESC(R, i) \
(&(((struct i40e_aq_desc *)((R).desc_buf.va))[i]))
#define I40E_ADMINQ_DESC_ALIGNMENT 4096
struct i40e_adminq_ring {
struct i40e_virt_mem dma_head; /* space for dma structures */
struct i40e_dma_mem desc_buf; /* descriptor ring memory */
struct i40e_virt_mem cmd_buf; /* command buffer memory */
union {
struct i40e_dma_mem *asq_bi;
struct i40e_dma_mem *arq_bi;
} r;
u16 count; /* Number of descriptors */
u16 rx_buf_len; /* Admin Receive Queue buffer length */
/* used for interrupt processing */
u16 next_to_use;
u16 next_to_clean;
/* used for queue tracking */
u32 head;
u32 tail;
u32 len;
u32 bah;
u32 bal;
};
/* ASQ transaction details */
struct i40e_asq_cmd_details {
void *callback; /* cast from type I40E_ADMINQ_CALLBACK */
u64 cookie;
u16 flags_ena;
u16 flags_dis;
bool async;
bool postpone;
struct i40e_aq_desc *wb_desc;
};
#define I40E_ADMINQ_DETAILS(R, i) \
(&(((struct i40e_asq_cmd_details *)((R).cmd_buf.va))[i]))
/* ARQ event information */
struct i40e_arq_event_info {
struct i40e_aq_desc desc;
u16 msg_len;
u16 buf_len;
u8 *msg_buf;
};
/* Admin Queue information */
struct i40e_adminq_info {
struct i40e_adminq_ring arq; /* receive queue */
struct i40e_adminq_ring asq; /* send queue */
u32 asq_cmd_timeout; /* send queue cmd write back timeout*/
u16 num_arq_entries; /* receive queue depth */
u16 num_asq_entries; /* send queue depth */
u16 arq_buf_size; /* receive queue buffer size */
u16 asq_buf_size; /* send queue buffer size */
u16 fw_maj_ver; /* firmware major version */
u16 fw_min_ver; /* firmware minor version */
u32 fw_build; /* firmware build number */
u16 api_maj_ver; /* api major version */
u16 api_min_ver; /* api minor version */
struct i40e_spinlock asq_spinlock; /* Send queue spinlock */
struct i40e_spinlock arq_spinlock; /* Receive queue spinlock */
/* last status values on send and receive queues */
enum i40e_admin_queue_err asq_last_status;
enum i40e_admin_queue_err arq_last_status;
};
/**
* i40e_aq_rc_to_posix - convert errors to user-land codes
* aq_ret: AdminQ handler error code can override aq_rc
* aq_rc: AdminQ firmware error code to convert
**/
static INLINE int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
{
int aq_to_posix[] = {
0, /* I40E_AQ_RC_OK */
-EPERM, /* I40E_AQ_RC_EPERM */
-ENOENT, /* I40E_AQ_RC_ENOENT */
-ESRCH, /* I40E_AQ_RC_ESRCH */
-EINTR, /* I40E_AQ_RC_EINTR */
-EIO, /* I40E_AQ_RC_EIO */
-ENXIO, /* I40E_AQ_RC_ENXIO */
-E2BIG, /* I40E_AQ_RC_E2BIG */
-EAGAIN, /* I40E_AQ_RC_EAGAIN */
-ENOMEM, /* I40E_AQ_RC_ENOMEM */
-EACCES, /* I40E_AQ_RC_EACCES */
-EFAULT, /* I40E_AQ_RC_EFAULT */
-EBUSY, /* I40E_AQ_RC_EBUSY */
-EEXIST, /* I40E_AQ_RC_EEXIST */
-EINVAL, /* I40E_AQ_RC_EINVAL */
-ENOTTY, /* I40E_AQ_RC_ENOTTY */
-ENOSPC, /* I40E_AQ_RC_ENOSPC */
-ENOSYS, /* I40E_AQ_RC_ENOSYS */
-ERANGE, /* I40E_AQ_RC_ERANGE */
-EPIPE, /* I40E_AQ_RC_EFLUSHED */
-ESPIPE, /* I40E_AQ_RC_BAD_ADDR */
-EROFS, /* I40E_AQ_RC_EMODE */
-EFBIG, /* I40E_AQ_RC_EFBIG */
};
/* aq_rc is invalid if AQ timed out */
if (aq_ret == I40E_ERR_ADMIN_QUEUE_TIMEOUT)
return -EAGAIN;
if (!((u32)aq_rc < (sizeof(aq_to_posix) / sizeof((aq_to_posix)[0]))))
return -ERANGE;
return aq_to_posix[aq_rc];
}
/* general information */
#define I40E_AQ_LARGE_BUF 512
#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */
void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
u16 opcode);
#endif /* _I40E_ADMINQ_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_ALLOC_H_
#define _I40E_ALLOC_H_
struct i40e_hw;
/* Memory allocation types */
enum i40e_memory_type {
i40e_mem_arq_buf = 0, /* ARQ indirect command buffer */
i40e_mem_asq_buf = 1,
i40e_mem_atq_buf = 2, /* ATQ indirect command buffer */
i40e_mem_arq_ring = 3, /* ARQ descriptor ring */
i40e_mem_atq_ring = 4, /* ATQ descriptor ring */
i40e_mem_pd = 5, /* Page Descriptor */
i40e_mem_bp = 6, /* Backing Page - 4KB */
i40e_mem_bp_jumbo = 7, /* Backing Page - > 4KB */
i40e_mem_reserved
};
/* prototype for functions used for dynamic memory allocation */
i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw,
struct i40e_dma_mem *mem,
enum i40e_memory_type type,
u64 size, u32 alignment);
i40e_status i40e_free_dma_mem(struct i40e_hw *hw,
struct i40e_dma_mem *mem);
i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw,
struct i40e_virt_mem *mem,
u32 size);
i40e_status i40e_free_virt_mem(struct i40e_hw *hw,
struct i40e_virt_mem *mem);
#endif /* _I40E_ALLOC_H_ */

View File

@ -0,0 +1,814 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include <linux/list.h>
#include <linux/errno.h>
#include "i40e.h"
#include "i40e_prototype.h"
#include "i40e_client.h"
static const char i40e_client_interface_version_str[] = I40E_CLIENT_VERSION_STR;
static struct i40e_client *registered_client;
static LIST_HEAD(i40e_devices);
static DEFINE_MUTEX(i40e_device_mutex);
static int i40e_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client,
u32 vf_id, u8 *msg, u16 len);
static int i40e_client_setup_qvlist(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_qvlist_info *qvlist_info);
static void i40e_client_request_reset(struct i40e_info *ldev,
struct i40e_client *client,
u32 reset_level);
static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
struct i40e_client *client,
bool is_vf, u32 vf_id,
u32 flag, u32 valid_flag);
static struct i40e_ops i40e_lan_ops = {
.virtchnl_send = i40e_client_virtchnl_send,
.setup_qvlist = i40e_client_setup_qvlist,
.request_reset = i40e_client_request_reset,
.update_vsi_ctxt = i40e_client_update_vsi_ctxt,
};
/**
* i40e_client_get_params - Get the params that can change at runtime
* @vsi: the VSI with the message
* @param: clinet param struct
*
**/
static
int i40e_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
{
struct i40e_dcbx_config *dcb_cfg = &vsi->back->hw.local_dcbx_config;
int i = 0;
for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
u8 tc = dcb_cfg->etscfg.prioritytable[i];
u16 qs_handle;
/* If TC is not enabled for VSI use TC0 for UP */
if (!(vsi->tc_config.enabled_tc & BIT(tc)))
tc = 0;
qs_handle = le16_to_cpu(vsi->info.qs_handle[tc]);
params->qos.prio_qos[i].tc = tc;
params->qos.prio_qos[i].qs_handle = qs_handle;
if (qs_handle == I40E_AQ_VSI_QS_HANDLE_INVALID) {
dev_err(&vsi->back->pdev->dev, "Invalid queue set handle for TC = %d, vsi id = %d\n",
tc, vsi->id);
return -EINVAL;
}
}
params->mtu = vsi->netdev->mtu;
return 0;
}
/**
* i40e_notify_client_of_vf_msg - call the client vf message callback
* @vsi: the VSI with the message
* @vf_id: the absolute VF id that sent the message
* @msg: message buffer
* @len: length of the message
*
* If there is a client to this VSI, call the client
**/
void
i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len)
{
struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->virtchnl_receive) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance virtual channel receive routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort virtchnl_receive\n");
return;
}
cdev->client->ops->virtchnl_receive(&cdev->lan_info, cdev->client,
vf_id, msg, len);
}
/**
* i40e_notify_client_of_l2_param_changes - call the client notify callback
* @vsi: the VSI with l2 param changes
*
* If there is a client to this VSI, call the client
**/
void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
struct i40e_params params;
if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->l2_param_change) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance l2_param_change routine\n");
return;
}
memset(&params, 0, sizeof(params));
i40e_client_get_params(vsi, &params);
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
return;
}
memcpy(&cdev->lan_info.params, &params, sizeof(struct i40e_params));
cdev->client->ops->l2_param_change(&cdev->lan_info, cdev->client,
&params);
}
/**
* i40e_client_release_qvlist - release MSI-X vector mapping for client
* @ldev: pointer to L2 context.
*
**/
static void i40e_client_release_qvlist(struct i40e_info *ldev)
{
struct i40e_qvlist_info *qvlist_info = ldev->qvlist_info;
u32 i;
if (!ldev->qvlist_info)
return;
for (i = 0; i < qvlist_info->num_vectors; i++) {
struct i40e_pf *pf = ldev->pf;
struct i40e_qv_info *qv_info;
u32 reg_idx;
qv_info = &qvlist_info->qv_info[i];
if (!qv_info)
continue;
reg_idx = I40E_PFINT_LNKLSTN(qv_info->v_idx - 1);
wr32(&pf->hw, reg_idx, I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
}
kfree(ldev->qvlist_info);
ldev->qvlist_info = NULL;
}
/**
* i40e_notify_client_of_netdev_close - call the client close callback
* @vsi: the VSI with netdev closed
* @reset: true when close called due to a reset pending
*
* If there is a client to this netdev, call the client with close
**/
void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
{
struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->close) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance close routine\n");
return;
}
cdev->client->ops->close(&cdev->lan_info, cdev->client, reset);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
i40e_client_release_qvlist(&cdev->lan_info);
}
/**
* i40e_notify_client_of_vf_reset - call the client vf reset callback
* @pf: PF device pointer
* @vf_id: asolute id of VF being reset
*
* If there is a client attached to this PF, notify when a VF is reset
**/
void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id)
{
struct i40e_client_instance *cdev = pf->cinst;
if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->vf_reset) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF reset routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-reset\n");
return;
}
cdev->client->ops->vf_reset(&cdev->lan_info, cdev->client, vf_id);
}
/**
* i40e_notify_client_of_vf_enable - call the client vf notification callback
* @pf: PF device pointer
* @num_vfs: the number of VFs currently enabled, 0 for disable
*
* If there is a client attached to this PF, call its VF notification routine
**/
void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs)
{
struct i40e_client_instance *cdev = pf->cinst;
if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->vf_enable) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF enable routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-enable\n");
return;
}
cdev->client->ops->vf_enable(&cdev->lan_info, cdev->client, num_vfs);
}
/**
* i40e_vf_client_capable - ask the client if it likes the specified VF
* @pf: PF device pointer
* @vf_id: the VF in question
*
* If there is a client of the specified type attached to this PF, call
* its vf_capable routine
**/
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id)
{
struct i40e_client_instance *cdev = pf->cinst;
int capable = false;
if (!cdev || !cdev->client)
goto out;
if (!cdev->client->ops || !cdev->client->ops->vf_capable) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF capability routine\n");
goto out;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state))
goto out;
capable = cdev->client->ops->vf_capable(&cdev->lan_info,
cdev->client,
vf_id);
out:
return capable;
}
/**
* i40e_client_add_instance - add a client instance struct to the instance list
* @pf: pointer to the board struct
* @client: pointer to a client struct in the client list.
* @existing: if there was already an existing instance
*
**/
static void i40e_client_add_instance(struct i40e_pf *pf)
{
struct i40e_client_instance *cdev = NULL;
struct netdev_hw_addr *mac = NULL;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
if (!registered_client || pf->cinst)
return;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return;
cdev->lan_info.pf = (void *)pf;
cdev->lan_info.netdev = vsi->netdev;
cdev->lan_info.pcidev = pf->pdev;
cdev->lan_info.fid = pf->hw.pf_id;
cdev->lan_info.ftype = I40E_CLIENT_FTYPE_PF;
cdev->lan_info.hw_addr = pf->hw.hw_addr;
cdev->lan_info.ops = &i40e_lan_ops;
cdev->lan_info.version.major = I40E_CLIENT_VERSION_MAJOR;
cdev->lan_info.version.minor = I40E_CLIENT_VERSION_MINOR;
cdev->lan_info.version.build = I40E_CLIENT_VERSION_BUILD;
cdev->lan_info.fw_maj_ver = pf->hw.aq.fw_maj_ver;
cdev->lan_info.fw_min_ver = pf->hw.aq.fw_min_ver;
cdev->lan_info.fw_build = pf->hw.aq.fw_build;
set_bit(__I40E_CLIENT_INSTANCE_NONE, &cdev->state);
if (i40e_client_get_params(vsi, &cdev->lan_info.params)) {
kfree(cdev);
cdev = NULL;
return;
}
cdev->lan_info.msix_count = pf->num_iwarp_msix;
cdev->lan_info.msix_entries = &pf->msix_entries[pf->iwarp_base_vector];
mac = list_first_entry(&cdev->lan_info.netdev->dev_addrs.list,
struct netdev_hw_addr, list);
if (mac)
ether_addr_copy(cdev->lan_info.lanmac, mac->addr);
else
dev_err(&pf->pdev->dev, "MAC address list is empty!\n");
cdev->client = registered_client;
pf->cinst = cdev;
}
/**
* i40e_client_del_instance - removes a client instance from the list
* @pf: pointer to the board struct
*
**/
static
void i40e_client_del_instance(struct i40e_pf *pf)
{
kfree(pf->cinst);
pf->cinst = NULL;
}
/**
* i40e_client_subtask - client maintenance work
* @pf: board private structure
**/
void i40e_client_subtask(struct i40e_pf *pf)
{
struct i40e_client *client = registered_client;
struct i40e_client_instance *cdev;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
int ret = 0;
if (!(pf->flags & I40E_FLAG_SERVICE_CLIENT_REQUESTED))
return;
pf->flags &= ~I40E_FLAG_SERVICE_CLIENT_REQUESTED;
cdev = pf->cinst;
/* If we're down or resetting, just bail */
if (test_bit(__I40E_DOWN, &pf->state) ||
test_bit(__I40E_CONFIG_BUSY, &pf->state))
return;
if (!client || !cdev)
return;
/* Here we handle client opens. If the client is down, but
* the netdev is up, then open the client.
*/
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
if (!test_bit(__I40E_DOWN, &vsi->state) &&
client->ops && client->ops->open) {
set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
ret = client->ops->open(&cdev->lan_info, client);
if (ret) {
/* Remove failed client instance */
clear_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state);
i40e_client_del_instance(pf);
}
}
} else {
/* Likewise for client close. If the client is up, but the netdev
* is down, then close the client.
*/
if (test_bit(__I40E_DOWN, &vsi->state) &&
client->ops && client->ops->close) {
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
client->ops->close(&cdev->lan_info, client, false);
i40e_client_release_qvlist(&cdev->lan_info);
}
}
}
/**
* i40e_lan_add_device - add a lan device struct to the list of lan devices
* @pf: pointer to the board struct
*
* Returns 0 on success or none 0 on error
**/
int i40e_lan_add_device(struct i40e_pf *pf)
{
struct i40e_device *ldev;
int ret = 0;
mutex_lock(&i40e_device_mutex);
list_for_each_entry(ldev, &i40e_devices, list) {
if (ldev->pf == pf) {
ret = -EEXIST;
goto out;
}
}
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev) {
ret = -ENOMEM;
goto out;
}
ldev->pf = pf;
INIT_LIST_HEAD(&ldev->list);
list_add(&ldev->list, &i40e_devices);
dev_info(&pf->pdev->dev, "Added LAN device PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
pf->hw.pf_id, pf->hw.bus.bus_id,
pf->hw.bus.device, pf->hw.bus.func);
/* Since in some cases register may have happened before a device gets
* added, we can schedule a subtask to go initiate the clients if
* they can be launched at probe time.
*/
pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
i40e_service_event_schedule(pf);
out:
mutex_unlock(&i40e_device_mutex);
return ret;
}
/**
* i40e_lan_del_device - removes a lan device from the device list
* @pf: pointer to the board struct
*
* Returns 0 on success or non-0 on error
**/
int i40e_lan_del_device(struct i40e_pf *pf)
{
struct i40e_device *ldev, *tmp;
int ret = -ENODEV;
mutex_lock(&i40e_device_mutex);
list_for_each_entry_safe(ldev, tmp, &i40e_devices, list) {
if (ldev->pf == pf) {
dev_info(&pf->pdev->dev, "Deleted LAN device PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
pf->hw.pf_id, pf->hw.bus.bus_id,
pf->hw.bus.device, pf->hw.bus.func);
list_del(&ldev->list);
kfree(ldev);
ret = 0;
break;
}
}
mutex_unlock(&i40e_device_mutex);
return ret;
}
/**
* i40e_client_release - release client specific resources
* @client: pointer to the registered client
*
**/
static void i40e_client_release(struct i40e_client *client)
{
struct i40e_client_instance *cdev;
struct i40e_device *ldev;
struct i40e_pf *pf;
mutex_lock(&i40e_device_mutex);
list_for_each_entry(ldev, &i40e_devices, list) {
pf = ldev->pf;
cdev = pf->cinst;
if (!cdev)
continue;
while (test_and_set_bit(__I40E_SERVICE_SCHED,
&pf->state))
usleep_range(500, 1000);
if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
if (client->ops && client->ops->close)
client->ops->close(&cdev->lan_info, client,
false);
i40e_client_release_qvlist(&cdev->lan_info);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
dev_warn(&pf->pdev->dev,
"Client %s instance for PF id %d closed\n",
client->name, pf->hw.pf_id);
}
/* delete the client instance */
i40e_client_del_instance(pf);
dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n",
client->name);
clear_bit(__I40E_SERVICE_SCHED, &pf->state);
}
mutex_unlock(&i40e_device_mutex);
}
/**
* i40e_client_prepare - prepare client specific resources
* @client: pointer to the registered client
*
**/
static void i40e_client_prepare(struct i40e_client *client)
{
struct i40e_device *ldev;
struct i40e_pf *pf;
mutex_lock(&i40e_device_mutex);
list_for_each_entry(ldev, &i40e_devices, list) {
pf = ldev->pf;
i40e_client_add_instance(pf);
/* Start the client subtask */
pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
i40e_service_event_schedule(pf);
}
mutex_unlock(&i40e_device_mutex);
}
/**
* i40e_client_virtchnl_send - TBD
* @ldev: pointer to L2 context
* @client: Client pointer
* @vf_id: absolute VF identifier
* @msg: message buffer
* @len: length of message buffer
*
* Return 0 on success or < 0 on error
**/
static int i40e_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client,
u32 vf_id, u8 *msg, u16 len)
{
struct i40e_pf *pf = ldev->pf;
struct i40e_hw *hw = &pf->hw;
i40e_status err;
err = i40e_aq_send_msg_to_vf(hw, vf_id, I40E_VIRTCHNL_OP_IWARP,
I40E_SUCCESS, msg, len, NULL);
if (err)
dev_err(&pf->pdev->dev, "Unable to send iWarp message to VF, error %d, aq status %d\n",
err, hw->aq.asq_last_status);
return err;
}
/**
* i40e_client_setup_qvlist
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @qv_info: queue and vector list
*
* Return 0 on success or < 0 on error
**/
static int i40e_client_setup_qvlist(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_qvlist_info *qvlist_info)
{
struct i40e_pf *pf = ldev->pf;
struct i40e_hw *hw = &pf->hw;
struct i40e_qv_info *qv_info;
u32 v_idx, i, reg_idx, reg;
u32 size;
size = sizeof(struct i40e_qvlist_info) +
(sizeof(struct i40e_qv_info) * (qvlist_info->num_vectors - 1));
ldev->qvlist_info = kzalloc(size, GFP_KERNEL);
ldev->qvlist_info->num_vectors = qvlist_info->num_vectors;
for (i = 0; i < qvlist_info->num_vectors; i++) {
qv_info = &qvlist_info->qv_info[i];
if (!qv_info)
continue;
v_idx = qv_info->v_idx;
/* Validate vector id belongs to this client */
if ((v_idx >= (pf->iwarp_base_vector + pf->num_iwarp_msix)) ||
(v_idx < pf->iwarp_base_vector))
goto err;
ldev->qvlist_info->qv_info[i] = *qv_info;
reg_idx = I40E_PFINT_LNKLSTN(v_idx - 1);
if (qv_info->ceq_idx == I40E_QUEUE_INVALID_IDX) {
/* Special case - No CEQ mapped on this vector */
wr32(hw, reg_idx, I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK);
} else {
reg = (qv_info->ceq_idx &
I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) |
(I40E_QUEUE_TYPE_PE_CEQ <<
I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
wr32(hw, reg_idx, reg);
reg = (I40E_PFINT_CEQCTL_CAUSE_ENA_MASK |
(v_idx << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) |
(qv_info->itr_idx <<
I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) |
(I40E_QUEUE_END_OF_LIST <<
I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT));
wr32(hw, I40E_PFINT_CEQCTL(qv_info->ceq_idx), reg);
}
if (qv_info->aeq_idx != I40E_QUEUE_INVALID_IDX) {
reg = (I40E_PFINT_AEQCTL_CAUSE_ENA_MASK |
(v_idx << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) |
(qv_info->itr_idx <<
I40E_PFINT_AEQCTL_ITR_INDX_SHIFT));
wr32(hw, I40E_PFINT_AEQCTL, reg);
}
}
/* Mitigate sync problems with iwarp VF driver */
i40e_flush(hw);
return 0;
err:
kfree(ldev->qvlist_info);
ldev->qvlist_info = NULL;
return -EINVAL;
}
/**
* i40e_client_request_reset
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @level: reset level
**/
static void i40e_client_request_reset(struct i40e_info *ldev,
struct i40e_client *client,
u32 reset_level)
{
struct i40e_pf *pf = ldev->pf;
switch (reset_level) {
case I40E_CLIENT_RESET_LEVEL_PF:
set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
break;
case I40E_CLIENT_RESET_LEVEL_CORE:
set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
break;
default:
dev_warn(&pf->pdev->dev,
"Client for PF id %d requested an unsupported reset: %d.\n",
pf->hw.pf_id, reset_level);
break;
}
i40e_service_event_schedule(pf);
}
/**
* i40e_client_update_vsi_ctxt
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @is_vf: if this for the VF
* @vf_id: if is_vf true this carries the vf_id
* @flag: Any device level setting that needs to be done for PE
* @valid_flag: Bits in this match up and enable changing of flag bits
*
* Return 0 on success or < 0 on error
**/
static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
struct i40e_client *client,
bool is_vf, u32 vf_id,
u32 flag, u32 valid_flag)
{
struct i40e_pf *pf = ldev->pf;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
struct i40e_vsi_context ctxt;
bool update = true;
i40e_status err;
/* TODO: for now do not allow setting VF's VSI setting */
if (is_vf)
return -EINVAL;
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
err = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL);
ctxt.flags = I40E_AQ_VSI_TYPE_PF;
if (err) {
dev_info(&pf->pdev->dev,
"couldn't get PF vsi config, err %s aq_err %s\n",
i40e_stat_str(&pf->hw, err),
i40e_aq_str(&pf->hw,
pf->hw.aq.asq_last_status));
return -ENOENT;
}
if ((valid_flag & I40E_CLIENT_VSI_FLAG_TCP_PACKET_ENABLE) &&
(flag & I40E_CLIENT_VSI_FLAG_TCP_PACKET_ENABLE)) {
ctxt.info.valid_sections =
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA;
} else if ((valid_flag & I40E_CLIENT_VSI_FLAG_TCP_PACKET_ENABLE) &&
!(flag & I40E_CLIENT_VSI_FLAG_TCP_PACKET_ENABLE)) {
ctxt.info.valid_sections =
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags &= ~I40E_AQ_VSI_QUE_OPT_TCP_ENA;
} else {
update = false;
dev_warn(&pf->pdev->dev,
"Client for PF id %d request an unsupported Config: %x.\n",
pf->hw.pf_id, flag);
}
if (update) {
err = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
if (err) {
dev_info(&pf->pdev->dev,
"update VSI ctxt for PE failed, err %s aq_err %s\n",
i40e_stat_str(&pf->hw, err),
i40e_aq_str(&pf->hw,
pf->hw.aq.asq_last_status));
}
}
return err;
}
/**
* i40e_register_client - Register a i40e client driver with the L2 driver
* @client: pointer to the i40e_client struct
*
* Returns 0 on success or non-0 on error
**/
int i40e_register_client(struct i40e_client *client)
{
int ret = 0;
if (!client) {
ret = -EIO;
goto out;
}
if (strlen(client->name) == 0) {
pr_info("i40e: Failed to register client with no name\n");
ret = -EIO;
goto out;
}
if (registered_client) {
pr_info("i40e: Client %s has already been registered!\n",
client->name);
ret = -EEXIST;
goto out;
}
if ((client->version.major != I40E_CLIENT_VERSION_MAJOR) ||
(client->version.minor != I40E_CLIENT_VERSION_MINOR)) {
pr_info("i40e: Failed to register client %s due to mismatched client interface version\n",
client->name);
pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n",
client->version.major, client->version.minor,
client->version.build,
i40e_client_interface_version_str);
ret = -EIO;
goto out;
}
registered_client = client;
i40e_client_prepare(client);
pr_info("i40e: Registered client %s\n", client->name);
out:
return ret;
}
//EXPORT_SYMBOL(i40e_register_client);
/**
* i40e_unregister_client - Unregister a i40e client driver with the L2 driver
* @client: pointer to the i40e_client struct
*
* Returns 0 on success or non-0 on error
**/
int i40e_unregister_client(struct i40e_client *client)
{
int ret = 0;
if (registered_client != client) {
pr_info("i40e: Client %s has not been registered\n",
client->name);
ret = -ENODEV;
goto out;
}
registered_client = NULL;
/* When a unregister request comes through we would have to send
* a close for each of the client instances that were opened.
* client_release function is called to handle this.
*/
i40e_client_release(client);
pr_info("i40e: Unregistered client %s\n", client->name);
out:
return ret;
}
//EXPORT_SYMBOL(i40e_unregister_client);

View File

@ -0,0 +1,224 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_CLIENT_H_
#define _I40E_CLIENT_H_
#define I40E_CLIENT_STR_LENGTH 10
/* Client interface version should be updated anytime there is a change in the
* existing APIs or data structures.
*/
#define I40E_CLIENT_VERSION_MAJOR 0
#define I40E_CLIENT_VERSION_MINOR 01
#define I40E_CLIENT_VERSION_BUILD 00
#define I40E_CLIENT_VERSION_STR \
__stringify(I40E_CLIENT_VERSION_MAJOR) "." \
__stringify(I40E_CLIENT_VERSION_MINOR) "." \
__stringify(I40E_CLIENT_VERSION_BUILD)
struct i40e_client_version {
u8 major;
u8 minor;
u8 build;
u8 rsvd;
};
enum i40e_client_state {
__I40E_CLIENT_NULL,
__I40E_CLIENT_REGISTERED
};
enum i40e_client_instance_state {
__I40E_CLIENT_INSTANCE_NONE,
__I40E_CLIENT_INSTANCE_OPENED,
};
struct i40e_ops;
struct i40e_client;
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
* In order for us to keep the interface simple, SW will define a
* unique type value for AEQ.
*/
#define I40E_QUEUE_TYPE_PE_AEQ 0x80
#define I40E_QUEUE_INVALID_IDX 0xFFFF
struct i40e_qv_info {
u32 v_idx; /* msix_vector */
u16 ceq_idx;
u16 aeq_idx;
u8 itr_idx;
};
struct i40e_qvlist_info {
u32 num_vectors;
struct i40e_qv_info qv_info[1];
};
#define I40E_CLIENT_MSIX_ALL 0xFFFFFFFF
/* set of LAN parameters useful for clients managed by LAN */
/* Struct to hold per priority info */
struct i40e_prio_qos_params {
u16 qs_handle; /* qs handle for prio */
u8 tc; /* TC mapped to prio */
u8 reserved;
};
#define I40E_CLIENT_MAX_USER_PRIORITY 8
/* Struct to hold Client QoS */
struct i40e_qos_params {
struct i40e_prio_qos_params prio_qos[I40E_CLIENT_MAX_USER_PRIORITY];
};
struct i40e_params {
struct i40e_qos_params qos;
u16 mtu;
};
/* Structure to hold Lan device info for a client device */
struct i40e_info {
struct i40e_client_version version;
u8 lanmac[6];
struct net_device *netdev;
struct pci_dev *pcidev;
u8 __iomem *hw_addr;
u8 fid; /* function id, PF id or VF id */
#define I40E_CLIENT_FTYPE_PF 0
#define I40E_CLIENT_FTYPE_VF 1
u8 ftype; /* function type, PF or VF */
void *pf;
/* All L2 params that could change during the life span of the PF
* and needs to be communicated to the client when they change
*/
struct i40e_qvlist_info *qvlist_info;
struct i40e_params params;
struct i40e_ops *ops;
u16 msix_count; /* number of msix vectors*/
/* Array down below will be dynamically allocated based on msix_count */
struct msix_entry *msix_entries;
u16 itr_index; /* Which ITR index the PE driver is suppose to use */
u16 fw_maj_ver; /* firmware major version */
u16 fw_min_ver; /* firmware minor version */
u32 fw_build; /* firmware build number */
};
#define I40E_CLIENT_RESET_LEVEL_PF 1
#define I40E_CLIENT_RESET_LEVEL_CORE 2
#define I40E_CLIENT_VSI_FLAG_TCP_PACKET_ENABLE BIT(1)
struct i40e_ops {
/* setup_q_vector_list enables queues with a particular vector */
int (*setup_qvlist)(struct i40e_info *ldev, struct i40e_client *client,
struct i40e_qvlist_info *qv_info);
int (*virtchnl_send)(struct i40e_info *ldev, struct i40e_client *client,
u32 vf_id, u8 *msg, u16 len);
/* If the PE Engine is unresponsive, RDMA driver can request a reset.
* The level helps determine the level of reset being requested.
*/
void (*request_reset)(struct i40e_info *ldev,
struct i40e_client *client, u32 level);
/* API for the RDMA driver to set certain VSI flags that control
* PE Engine.
*/
int (*update_vsi_ctxt)(struct i40e_info *ldev,
struct i40e_client *client,
bool is_vf, u32 vf_id,
u32 flag, u32 valid_flag);
};
struct i40e_client_ops {
/* Should be called from register_client() or whenever PF is ready
* to create a specific client instance.
*/
int (*open)(struct i40e_info *ldev, struct i40e_client *client);
/* Should be called when netdev is unavailable or when unregister
* call comes in. If the close is happenening due to a reset being
* triggered set the reset bit to true.
*/
void (*close)(struct i40e_info *ldev, struct i40e_client *client,
bool reset);
/* called when some l2 managed parameters changes - mtu */
void (*l2_param_change)(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_params *params);
int (*virtchnl_receive)(struct i40e_info *ldev,
struct i40e_client *client, u32 vf_id,
u8 *msg, u16 len);
/* called when a VF is reset by the PF */
void (*vf_reset)(struct i40e_info *ldev,
struct i40e_client *client, u32 vf_id);
/* called when the number of VFs changes */
void (*vf_enable)(struct i40e_info *ldev,
struct i40e_client *client, u32 num_vfs);
/* returns true if VF is capable of specified offload */
int (*vf_capable)(struct i40e_info *ldev,
struct i40e_client *client, u32 vf_id);
};
/* Client device */
struct i40e_client_instance {
struct list_head list;
struct i40e_info lan_info;
struct i40e_client *client;
unsigned long state;
};
struct i40e_client {
struct list_head list; /* list of registered clients */
char name[I40E_CLIENT_STR_LENGTH];
struct i40e_client_version version;
unsigned long state; /* client state */
atomic_t ref_cnt; /* Count of all the client devices of this kind */
u32 flags;
#define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
#define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
u8 type;
#define I40E_CLIENT_IWARP 0
/* client ops provided by the client */
const struct i40e_client_ops *ops;
};
static inline bool i40e_client_is_registered(struct i40e_client *client)
{
return test_bit(__I40E_CLIENT_REGISTERED, &client->state);
}
/* used by clients */
int i40e_register_client(struct i40e_client *client);
int i40e_unregister_client(struct i40e_client *client);
#endif /* _I40E_CLIENT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,968 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include "i40e_adminq.h"
#include "i40e_prototype.h"
#include "i40e_dcb.h"
/**
* i40e_get_dcbx_status
* @hw: pointer to the hw struct
* @status: Embedded DCBX Engine Status
*
* Get the DCBX status from the Firmware
**/
i40e_status i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
{
u32 reg;
if (!status)
return I40E_ERR_PARAM;
reg = rd32(hw, I40E_PRTDCB_GENS);
*status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
return I40E_SUCCESS;
}
/**
* i40e_parse_ieee_etscfg_tlv
* @tlv: IEEE 802.1Qaz ETS CFG TLV
* @dcbcfg: Local store to update ETS CFG data
*
* Parses IEEE 802.1Qaz ETS CFG TLV
**/
static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
struct i40e_dcb_ets_config *etscfg;
u8 *buf = tlv->tlvinfo;
u16 offset = 0;
u8 priority;
int i;
/* First Octet post subtype
* --------------------------
* |will-|CBS | Re- | Max |
* |ing | |served| TCs |
* --------------------------
* |1bit | 1bit|3 bits|3bits|
*/
etscfg = &dcbcfg->etscfg;
etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
I40E_IEEE_ETS_WILLING_SHIFT);
etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
I40E_IEEE_ETS_CBS_SHIFT);
etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
I40E_IEEE_ETS_MAXTC_SHIFT);
/* Move offset to Priority Assignment Table */
offset++;
/* Priority Assignment Table (4 octets)
* Octets:| 1 | 2 | 3 | 4 |
* -----------------------------------------
* |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
* -----------------------------------------
* Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
I40E_IEEE_ETS_PRIO_1_SHIFT);
etscfg->prioritytable[i * 2] = priority;
priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
I40E_IEEE_ETS_PRIO_0_SHIFT);
etscfg->prioritytable[i * 2 + 1] = priority;
offset++;
}
/* TC Bandwidth Table (8 octets)
* Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* ---------------------------------
* |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
* ---------------------------------
*/
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
etscfg->tcbwtable[i] = buf[offset++];
/* TSA Assignment Table (8 octets)
* Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* ---------------------------------
* |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
* ---------------------------------
*/
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
etscfg->tsatable[i] = buf[offset++];
}
/**
* i40e_parse_ieee_etsrec_tlv
* @tlv: IEEE 802.1Qaz ETS REC TLV
* @dcbcfg: Local store to update ETS REC data
*
* Parses IEEE 802.1Qaz ETS REC TLV
**/
static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u8 *buf = tlv->tlvinfo;
u16 offset = 0;
u8 priority;
int i;
/* Move offset to priority table */
offset++;
/* Priority Assignment Table (4 octets)
* Octets:| 1 | 2 | 3 | 4 |
* -----------------------------------------
* |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
* -----------------------------------------
* Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
I40E_IEEE_ETS_PRIO_1_SHIFT);
dcbcfg->etsrec.prioritytable[i*2] = priority;
priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
I40E_IEEE_ETS_PRIO_0_SHIFT);
dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
offset++;
}
/* TC Bandwidth Table (8 octets)
* Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* ---------------------------------
* |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
* ---------------------------------
*/
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
/* TSA Assignment Table (8 octets)
* Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* ---------------------------------
* |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
* ---------------------------------
*/
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etsrec.tsatable[i] = buf[offset++];
}
/**
* i40e_parse_ieee_pfccfg_tlv
* @tlv: IEEE 802.1Qaz PFC CFG TLV
* @dcbcfg: Local store to update PFC CFG data
*
* Parses IEEE 802.1Qaz PFC CFG TLV
**/
static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u8 *buf = tlv->tlvinfo;
/* ----------------------------------------
* |will-|MBC | Re- | PFC | PFC Enable |
* |ing | |served| cap | |
* -----------------------------------------
* |1bit | 1bit|2 bits|4bits| 1 octet |
*/
dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
I40E_IEEE_PFC_WILLING_SHIFT);
dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
I40E_IEEE_PFC_MBC_SHIFT);
dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
I40E_IEEE_PFC_CAP_SHIFT);
dcbcfg->pfc.pfcenable = buf[1];
}
/**
* i40e_parse_ieee_app_tlv
* @tlv: IEEE 802.1Qaz APP TLV
* @dcbcfg: Local store to update APP PRIO data
*
* Parses IEEE 802.1Qaz APP PRIO TLV
**/
static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u16 typelength;
u16 offset = 0;
u16 length;
int i = 0;
u8 *buf;
typelength = ntohs(tlv->typelength);
length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
buf = tlv->tlvinfo;
/* The App priority table starts 5 octets after TLV header */
length -= (sizeof(tlv->ouisubtype) + 1);
/* Move offset to App Priority Table */
offset++;
/* Application Priority Table (3 octets)
* Octets:| 1 | 2 | 3 |
* -----------------------------------------
* |Priority|Rsrvd| Sel | Protocol ID |
* -----------------------------------------
* Bits:|23 21|20 19|18 16|15 0|
* -----------------------------------------
*/
while (offset < length) {
dcbcfg->app[i].priority = (u8)((buf[offset] &
I40E_IEEE_APP_PRIO_MASK) >>
I40E_IEEE_APP_PRIO_SHIFT);
dcbcfg->app[i].selector = (u8)((buf[offset] &
I40E_IEEE_APP_SEL_MASK) >>
I40E_IEEE_APP_SEL_SHIFT);
dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
buf[offset + 2];
/* Move to next app */
offset += 3;
i++;
if (i >= I40E_DCBX_MAX_APPS)
break;
}
dcbcfg->numapps = i;
}
/**
* i40e_parse_ieee_etsrec_tlv
* @tlv: IEEE 802.1Qaz TLV
* @dcbcfg: Local store to update ETS REC data
*
* Get the TLV subtype and send it to parsing function
* based on the subtype value
**/
static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u32 ouisubtype;
u8 subtype;
ouisubtype = ntohl(tlv->ouisubtype);
subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
I40E_LLDP_TLV_SUBTYPE_SHIFT);
switch (subtype) {
case I40E_IEEE_SUBTYPE_ETS_CFG:
i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
break;
case I40E_IEEE_SUBTYPE_ETS_REC:
i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
break;
case I40E_IEEE_SUBTYPE_PFC_CFG:
i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
break;
case I40E_IEEE_SUBTYPE_APP_PRI:
i40e_parse_ieee_app_tlv(tlv, dcbcfg);
break;
default:
break;
}
}
/**
* i40e_parse_cee_pgcfg_tlv
* @tlv: CEE DCBX PG CFG TLV
* @dcbcfg: Local store to update ETS CFG data
*
* Parses CEE DCBX PG CFG TLV
**/
static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
struct i40e_dcb_ets_config *etscfg;
u8 *buf = tlv->tlvinfo;
u16 offset = 0;
u8 priority;
int i;
etscfg = &dcbcfg->etscfg;
if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
etscfg->willing = 1;
etscfg->cbs = 0;
/* Priority Group Table (4 octets)
* Octets:| 1 | 2 | 3 | 4 |
* -----------------------------------------
* |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
* -----------------------------------------
* Bits:|7 4|3 0|7 4|3 0|7 4|3 0|7 4|3 0|
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
I40E_CEE_PGID_PRIO_1_SHIFT);
etscfg->prioritytable[i * 2] = priority;
priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
I40E_CEE_PGID_PRIO_0_SHIFT);
etscfg->prioritytable[i * 2 + 1] = priority;
offset++;
}
/* PG Percentage Table (8 octets)
* Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
* ---------------------------------
* |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
* ---------------------------------
*/
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
etscfg->tcbwtable[i] = buf[offset++];
/* Number of TCs supported (1 octet) */
etscfg->maxtcs = buf[offset];
}
/**
* i40e_parse_cee_pfccfg_tlv
* @tlv: CEE DCBX PFC CFG TLV
* @dcbcfg: Local store to update PFC CFG data
*
* Parses CEE DCBX PFC CFG TLV
**/
static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u8 *buf = tlv->tlvinfo;
if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
dcbcfg->pfc.willing = 1;
/* ------------------------
* | PFC Enable | PFC TCs |
* ------------------------
* | 1 octet | 1 octet |
*/
dcbcfg->pfc.pfcenable = buf[0];
dcbcfg->pfc.pfccap = buf[1];
}
/**
* i40e_parse_cee_app_tlv
* @tlv: CEE DCBX APP TLV
* @dcbcfg: Local store to update APP PRIO data
*
* Parses CEE DCBX APP PRIO TLV
**/
static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u16 length, typelength, offset = 0;
struct i40e_cee_app_prio *app;
u8 i;
typelength = ntohs(tlv->hdr.typelen);
length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
dcbcfg->numapps = length / sizeof(*app);
if (!dcbcfg->numapps)
return;
for (i = 0; i < dcbcfg->numapps; i++) {
u8 up, selector;
app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
if (app->prio_map & BIT(up))
break;
}
dcbcfg->app[i].priority = up;
/* Get Selector from lower 2 bits, and convert to IEEE */
selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
switch (selector) {
case I40E_CEE_APP_SEL_ETHTYPE:
dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
break;
case I40E_CEE_APP_SEL_TCPIP:
dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
break;
default:
/* Keep selector as it is for unknown types */
dcbcfg->app[i].selector = selector;
}
dcbcfg->app[i].protocolid = ntohs(app->protocol);
/* Move to next app */
offset += sizeof(*app);
}
}
/**
* i40e_parse_cee_tlv
* @tlv: CEE DCBX TLV
* @dcbcfg: Local store to update DCBX config data
*
* Get the TLV subtype and send it to parsing function
* based on the subtype value
**/
static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u16 len, tlvlen, sublen, typelength;
struct i40e_cee_feat_tlv *sub_tlv;
u8 subtype, feat_tlv_count = 0;
u32 ouisubtype;
ouisubtype = ntohl(tlv->ouisubtype);
subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
I40E_LLDP_TLV_SUBTYPE_SHIFT);
/* Return if not CEE DCBX */
if (subtype != I40E_CEE_DCBX_TYPE)
return;
typelength = ntohs(tlv->typelength);
tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
sizeof(struct i40e_cee_ctrl_tlv);
/* Return if no CEE DCBX Feature TLVs */
if (tlvlen <= len)
return;
sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
typelength = ntohs(sub_tlv->hdr.typelen);
sublen = (u16)((typelength &
I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
I40E_LLDP_TLV_TYPE_SHIFT);
switch (subtype) {
case I40E_CEE_SUBTYPE_PG_CFG:
i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
break;
case I40E_CEE_SUBTYPE_PFC_CFG:
i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
break;
case I40E_CEE_SUBTYPE_APP_PRI:
i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
break;
default:
return; /* Invalid Sub-type return */
}
feat_tlv_count++;
/* Move to next sub TLV */
sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
sizeof(sub_tlv->hdr.typelen) +
sublen);
}
}
/**
* i40e_parse_org_tlv
* @tlv: Organization specific TLV
* @dcbcfg: Local store to update ETS REC data
*
* Currently only IEEE 802.1Qaz TLV is supported, all others
* will be returned
**/
static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
u32 ouisubtype;
u32 oui;
ouisubtype = ntohl(tlv->ouisubtype);
oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
I40E_LLDP_TLV_OUI_SHIFT);
switch (oui) {
case I40E_IEEE_8021QAZ_OUI:
i40e_parse_ieee_tlv(tlv, dcbcfg);
break;
case I40E_CEE_DCBX_OUI:
i40e_parse_cee_tlv(tlv, dcbcfg);
break;
default:
break;
}
}
/**
* i40e_lldp_to_dcb_config
* @lldpmib: LLDPDU to be parsed
* @dcbcfg: store for LLDPDU data
*
* Parse DCB configuration from the LLDPDU
**/
i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
struct i40e_dcbx_config *dcbcfg)
{
i40e_status ret = I40E_SUCCESS;
struct i40e_lldp_org_tlv *tlv;
u16 type;
u16 length;
u16 typelength;
u16 offset = 0;
if (!lldpmib || !dcbcfg)
return I40E_ERR_PARAM;
/* set to the start of LLDPDU */
lldpmib += ETH_HLEN;
tlv = (struct i40e_lldp_org_tlv *)lldpmib;
while (1) {
typelength = ntohs(tlv->typelength);
type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
I40E_LLDP_TLV_TYPE_SHIFT);
length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
I40E_LLDP_TLV_LEN_SHIFT);
offset += sizeof(typelength) + length;
/* END TLV or beyond LLDPDU size */
if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
break;
switch (type) {
case I40E_TLV_TYPE_ORG:
i40e_parse_org_tlv(tlv, dcbcfg);
break;
default:
break;
}
/* Move to next TLV */
tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
sizeof(tlv->typelength) +
length);
}
return ret;
}
/**
* i40e_aq_get_dcb_config
* @hw: pointer to the hw struct
* @mib_type: mib type for the query
* @bridgetype: bridge type for the query (remote)
* @dcbcfg: store for LLDPDU data
*
* Query DCB configuration from the Firmware
**/
i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
u8 bridgetype,
struct i40e_dcbx_config *dcbcfg)
{
i40e_status ret = I40E_SUCCESS;
struct i40e_virt_mem mem;
u8 *lldpmib;
/* Allocate the LLDPDU */
ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
if (ret)
return ret;
lldpmib = (u8 *)mem.va;
ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
(void *)lldpmib, I40E_LLDPDU_SIZE,
NULL, NULL, NULL);
if (ret)
goto free_mem;
/* Parse LLDP MIB to get dcb configuration */
ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
free_mem:
i40e_free_virt_mem(hw, &mem);
return ret;
}
/**
* i40e_cee_to_dcb_v1_config
* @cee_cfg: pointer to CEE v1 response configuration struct
* @dcbcfg: DCB configuration struct
*
* Convert CEE v1 configuration from firmware to DCB configuration
**/
static void i40e_cee_to_dcb_v1_config(
struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
struct i40e_dcbx_config *dcbcfg)
{
u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
u8 i, tc, err;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
/* Note that the FW creates the oper_prio_tc nibbles reversed
* from those in the CEE Priority Group sub-TLV.
*/
for (i = 0; i < 4; i++) {
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_0_MASK) >>
I40E_CEE_PGID_PRIO_0_SHIFT);
dcbcfg->etscfg.prioritytable[i*2] = tc;
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_1_MASK) >>
I40E_CEE_PGID_PRIO_1_SHIFT);
dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
/* Map it to next empty TC */
dcbcfg->etscfg.prioritytable[i] =
cee_cfg->oper_num_tc - 1;
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
} else {
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
}
}
/* CEE PFC data to ETS config */
dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
I40E_AQC_CEE_APP_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
/* Add APPs if Error is False */
if (!err) {
/* CEE operating configuration supports FCoE/iSCSI/FIP only */
dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
/* FCoE APP */
dcbcfg->app[0].priority =
(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
I40E_AQC_CEE_APP_FCOE_SHIFT;
dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
/* iSCSI APP */
dcbcfg->app[1].priority =
(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
I40E_AQC_CEE_APP_ISCSI_SHIFT;
dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
/* FIP APP */
dcbcfg->app[2].priority =
(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
I40E_AQC_CEE_APP_FIP_SHIFT;
dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
}
}
/**
* i40e_cee_to_dcb_config
* @cee_cfg: pointer to CEE configuration struct
* @dcbcfg: DCB configuration struct
*
* Convert CEE configuration from firmware to DCB configuration
**/
static void i40e_cee_to_dcb_config(
struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
struct i40e_dcbx_config *dcbcfg)
{
u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
u8 i, tc, err, sync, oper;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
/* Note that the FW creates the oper_prio_tc nibbles reversed
* from those in the CEE Priority Group sub-TLV.
*/
for (i = 0; i < 4; i++) {
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_0_MASK) >>
I40E_CEE_PGID_PRIO_0_SHIFT);
dcbcfg->etscfg.prioritytable[i*2] = tc;
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_1_MASK) >>
I40E_CEE_PGID_PRIO_1_SHIFT);
dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
/* Map it to next empty TC */
dcbcfg->etscfg.prioritytable[i] =
cee_cfg->oper_num_tc - 1;
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
} else {
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
}
}
/* CEE PFC data to ETS config */
dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
i = 0;
status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
I40E_AQC_CEE_FCOE_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
/* Add FCoE APP if Error is False and Oper/Sync is True */
if (!err && sync && oper) {
/* FCoE APP */
dcbcfg->app[i].priority =
(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
I40E_AQC_CEE_APP_FCOE_SHIFT;
dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
i++;
}
status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
/* Add iSCSI APP if Error is False and Oper/Sync is True */
if (!err && sync && oper) {
/* iSCSI APP */
dcbcfg->app[i].priority =
(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
I40E_AQC_CEE_APP_ISCSI_SHIFT;
dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
i++;
}
status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
I40E_AQC_CEE_FIP_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
/* Add FIP APP if Error is False and Oper/Sync is True */
if (!err && sync && oper) {
/* FIP APP */
dcbcfg->app[i].priority =
(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
I40E_AQC_CEE_APP_FIP_SHIFT;
dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
i++;
}
dcbcfg->numapps = i;
}
/**
* i40e_get_ieee_dcb_config
* @hw: pointer to the hw struct
*
* Get IEEE mode DCB configuration from the Firmware
**/
static i40e_status i40e_get_ieee_dcb_config(struct i40e_hw *hw)
{
i40e_status ret = I40E_SUCCESS;
/* IEEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
/* Get Local DCB Config */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
&hw->local_dcbx_config);
if (ret)
goto out;
/* Get Remote DCB Config */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
&hw->remote_dcbx_config);
/* Don't treat ENOENT as an error for Remote MIBs */
if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
ret = I40E_SUCCESS;
out:
return ret;
}
/**
* i40e_get_dcb_config
* @hw: pointer to the hw struct
*
* Get DCB configuration from the Firmware
**/
i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
{
i40e_status ret = I40E_SUCCESS;
struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
/* If Firmware version < v4.33 on X710/XL710, IEEE only */
if ((hw->mac.type == I40E_MAC_XL710) &&
(((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
(hw->aq.fw_maj_ver < 4)))
return i40e_get_ieee_dcb_config(hw);
/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
if ((hw->mac.type == I40E_MAC_XL710) &&
((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
sizeof(cee_v1_cfg), NULL);
if (ret == I40E_SUCCESS) {
/* CEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
hw->local_dcbx_config.tlv_status =
LE16_TO_CPU(cee_v1_cfg.tlv_status);
i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
&hw->local_dcbx_config);
}
} else {
ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
sizeof(cee_cfg), NULL);
if (ret == I40E_SUCCESS) {
/* CEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
hw->local_dcbx_config.tlv_status =
LE32_TO_CPU(cee_cfg.tlv_status);
i40e_cee_to_dcb_config(&cee_cfg,
&hw->local_dcbx_config);
}
}
/* CEE mode not enabled try querying IEEE data */
if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
return i40e_get_ieee_dcb_config(hw);
if (ret != I40E_SUCCESS)
goto out;
/* Get CEE DCB Desired Config */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
&hw->desired_dcbx_config);
if (ret)
goto out;
/* Get Remote DCB Config */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
&hw->remote_dcbx_config);
/* Don't treat ENOENT as an error for Remote MIBs */
if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
ret = I40E_SUCCESS;
out:
return ret;
}
/**
* i40e_init_dcb
* @hw: pointer to the hw struct
*
* Update DCB configuration from the Firmware
**/
i40e_status i40e_init_dcb(struct i40e_hw *hw)
{
i40e_status ret = I40E_SUCCESS;
struct i40e_lldp_variables lldp_cfg;
u8 adminstatus = 0;
if (!hw->func_caps.dcb)
return ret;
/* Read LLDP NVM area */
ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
if (ret)
return ret;
/* Get the LLDP AdminStatus for the current port */
adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
adminstatus &= 0xF;
/* LLDP agent disabled */
if (!adminstatus) {
hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
return ret;
}
/* Get DCBX status */
ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
if (ret)
return ret;
/* Check the DCBX Status */
switch (hw->dcbx_status) {
case I40E_DCBX_STATUS_DONE:
case I40E_DCBX_STATUS_IN_PROGRESS:
/* Get current DCBX configuration */
ret = i40e_get_dcb_config(hw);
if (ret)
return ret;
break;
case I40E_DCBX_STATUS_DISABLED:
return ret;
case I40E_DCBX_STATUS_NOT_STARTED:
case I40E_DCBX_STATUS_MULTIPLE_PEERS:
default:
break;
}
/* Configure the LLDP MIB change event */
ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
if (ret)
return ret;
return ret;
}
/**
* i40e_read_lldp_cfg - read LLDP Configuration data from NVM
* @hw: pointer to the HW structure
* @lldp_cfg: pointer to hold lldp configuration variables
*
* Reads the LLDP configuration data from NVM
**/
i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
struct i40e_lldp_variables *lldp_cfg)
{
i40e_status ret = I40E_SUCCESS;
u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
if (!lldp_cfg)
return I40E_ERR_PARAM;
ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
if (ret != I40E_SUCCESS)
goto err_lldp_cfg;
ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
sizeof(struct i40e_lldp_variables),
(u8 *)lldp_cfg,
true, NULL);
i40e_release_nvm(hw);
err_lldp_cfg:
return ret;
}

View File

@ -0,0 +1,163 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_DCB_H_
#define _I40E_DCB_H_
#include "i40e_type.h"
#define I40E_DCBX_STATUS_NOT_STARTED 0
#define I40E_DCBX_STATUS_IN_PROGRESS 1
#define I40E_DCBX_STATUS_DONE 2
#define I40E_DCBX_STATUS_MULTIPLE_PEERS 3
#define I40E_DCBX_STATUS_DISABLED 7
#define I40E_TLV_TYPE_END 0
#define I40E_TLV_TYPE_ORG 127
#define I40E_IEEE_8021QAZ_OUI 0x0080C2
#define I40E_IEEE_SUBTYPE_ETS_CFG 9
#define I40E_IEEE_SUBTYPE_ETS_REC 10
#define I40E_IEEE_SUBTYPE_PFC_CFG 11
#define I40E_IEEE_SUBTYPE_APP_PRI 12
#define I40E_CEE_DCBX_OUI 0x001b21
#define I40E_CEE_DCBX_TYPE 2
#define I40E_CEE_SUBTYPE_CTRL 1
#define I40E_CEE_SUBTYPE_PG_CFG 2
#define I40E_CEE_SUBTYPE_PFC_CFG 3
#define I40E_CEE_SUBTYPE_APP_PRI 4
#define I40E_CEE_MAX_FEAT_TYPE 3
/* Defines for LLDP TLV header */
#define I40E_LLDP_TLV_LEN_SHIFT 0
#define I40E_LLDP_TLV_LEN_MASK (0x01FF << I40E_LLDP_TLV_LEN_SHIFT)
#define I40E_LLDP_TLV_TYPE_SHIFT 9
#define I40E_LLDP_TLV_TYPE_MASK (0x7F << I40E_LLDP_TLV_TYPE_SHIFT)
#define I40E_LLDP_TLV_SUBTYPE_SHIFT 0
#define I40E_LLDP_TLV_SUBTYPE_MASK (0xFF << I40E_LLDP_TLV_SUBTYPE_SHIFT)
#define I40E_LLDP_TLV_OUI_SHIFT 8
#define I40E_LLDP_TLV_OUI_MASK (0xFFFFFF << I40E_LLDP_TLV_OUI_SHIFT)
/* Defines for IEEE ETS TLV */
#define I40E_IEEE_ETS_MAXTC_SHIFT 0
#define I40E_IEEE_ETS_MAXTC_MASK (0x7 << I40E_IEEE_ETS_MAXTC_SHIFT)
#define I40E_IEEE_ETS_CBS_SHIFT 6
#define I40E_IEEE_ETS_CBS_MASK BIT(I40E_IEEE_ETS_CBS_SHIFT)
#define I40E_IEEE_ETS_WILLING_SHIFT 7
#define I40E_IEEE_ETS_WILLING_MASK BIT(I40E_IEEE_ETS_WILLING_SHIFT)
#define I40E_IEEE_ETS_PRIO_0_SHIFT 0
#define I40E_IEEE_ETS_PRIO_0_MASK (0x7 << I40E_IEEE_ETS_PRIO_0_SHIFT)
#define I40E_IEEE_ETS_PRIO_1_SHIFT 4
#define I40E_IEEE_ETS_PRIO_1_MASK (0x7 << I40E_IEEE_ETS_PRIO_1_SHIFT)
#define I40E_CEE_PGID_PRIO_0_SHIFT 0
#define I40E_CEE_PGID_PRIO_0_MASK (0xF << I40E_CEE_PGID_PRIO_0_SHIFT)
#define I40E_CEE_PGID_PRIO_1_SHIFT 4
#define I40E_CEE_PGID_PRIO_1_MASK (0xF << I40E_CEE_PGID_PRIO_1_SHIFT)
#define I40E_CEE_PGID_STRICT 15
/* Defines for IEEE TSA types */
#define I40E_IEEE_TSA_STRICT 0
#define I40E_IEEE_TSA_ETS 2
/* Defines for IEEE PFC TLV */
#define I40E_IEEE_PFC_CAP_SHIFT 0
#define I40E_IEEE_PFC_CAP_MASK (0xF << I40E_IEEE_PFC_CAP_SHIFT)
#define I40E_IEEE_PFC_MBC_SHIFT 6
#define I40E_IEEE_PFC_MBC_MASK BIT(I40E_IEEE_PFC_MBC_SHIFT)
#define I40E_IEEE_PFC_WILLING_SHIFT 7
#define I40E_IEEE_PFC_WILLING_MASK BIT(I40E_IEEE_PFC_WILLING_SHIFT)
/* Defines for IEEE APP TLV */
#define I40E_IEEE_APP_SEL_SHIFT 0
#define I40E_IEEE_APP_SEL_MASK (0x7 << I40E_IEEE_APP_SEL_SHIFT)
#define I40E_IEEE_APP_PRIO_SHIFT 5
#define I40E_IEEE_APP_PRIO_MASK (0x7 << I40E_IEEE_APP_PRIO_SHIFT)
/* TLV definitions for preparing MIB */
#define I40E_TLV_ID_CHASSIS_ID 0
#define I40E_TLV_ID_PORT_ID 1
#define I40E_TLV_ID_TIME_TO_LIVE 2
#define I40E_IEEE_TLV_ID_ETS_CFG 3
#define I40E_IEEE_TLV_ID_ETS_REC 4
#define I40E_IEEE_TLV_ID_PFC_CFG 5
#define I40E_IEEE_TLV_ID_APP_PRI 6
#define I40E_TLV_ID_END_OF_LLDPPDU 7
#define I40E_TLV_ID_START I40E_IEEE_TLV_ID_ETS_CFG
#define I40E_IEEE_ETS_TLV_LENGTH 25
#define I40E_IEEE_PFC_TLV_LENGTH 6
#define I40E_IEEE_APP_TLV_LENGTH 11
#pragma pack(1)
/* IEEE 802.1AB LLDP Organization specific TLV */
struct i40e_lldp_org_tlv {
__be16 typelength;
__be32 ouisubtype;
u8 tlvinfo[1];
};
struct i40e_cee_tlv_hdr {
__be16 typelen;
u8 operver;
u8 maxver;
};
struct i40e_cee_ctrl_tlv {
struct i40e_cee_tlv_hdr hdr;
__be32 seqno;
__be32 ackno;
};
struct i40e_cee_feat_tlv {
struct i40e_cee_tlv_hdr hdr;
u8 en_will_err; /* Bits: |En|Will|Err|Reserved(5)| */
#define I40E_CEE_FEAT_TLV_ENABLE_MASK 0x80
#define I40E_CEE_FEAT_TLV_WILLING_MASK 0x40
#define I40E_CEE_FEAT_TLV_ERR_MASK 0x20
u8 subtype;
u8 tlvinfo[1];
};
struct i40e_cee_app_prio {
__be16 protocol;
u8 upper_oui_sel; /* Bits: |Upper OUI(6)|Selector(2)| */
#define I40E_CEE_APP_SELECTOR_MASK 0x03
__be16 lower_oui;
u8 prio_map;
};
#pragma pack()
i40e_status i40e_get_dcbx_status(struct i40e_hw *hw,
u16 *status);
i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
struct i40e_dcbx_config *dcbcfg);
i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
u8 bridgetype,
struct i40e_dcbx_config *dcbcfg);
i40e_status i40e_get_dcb_config(struct i40e_hw *hw);
i40e_status i40e_init_dcb(struct i40e_hw *hw);
#endif /* _I40E_DCB_H_ */

View File

@ -0,0 +1,321 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifdef CONFIG_DCB
#include "i40e.h"
#include <net/dcbnl.h>
#ifdef HAVE_DCBNL_IEEE
/**
* i40e_get_pfc_delay - retrieve PFC Link Delay
* @hw: pointer to hardware struct
* @delay: holds the PFC Link delay value
*
* Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA
**/
static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
{
u32 val;
val = rd32(hw, I40E_PRTDCB_GENC);
*delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
I40E_PRTDCB_GENC_PFCLDA_SHIFT);
}
/**
* i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
* @netdev: the corresponding netdev
* @ets: structure to hold the ETS information
*
* Returns local IEEE ETS configuration
**/
static int i40e_dcbnl_ieee_getets(struct net_device *dev,
struct ieee_ets *ets)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
struct i40e_dcbx_config *dcbxcfg;
struct i40e_hw *hw = &pf->hw;
if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
dcbxcfg = &hw->local_dcbx_config;
ets->willing = dcbxcfg->etscfg.willing;
ets->ets_cap = dcbxcfg->etscfg.maxtcs;
ets->cbs = dcbxcfg->etscfg.cbs;
memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable,
sizeof(ets->tc_tx_bw));
memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable,
sizeof(ets->tc_rx_bw));
memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable,
sizeof(ets->tc_tsa));
memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable,
sizeof(ets->prio_tc));
memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable,
sizeof(ets->tc_reco_bw));
memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable,
sizeof(ets->tc_reco_tsa));
memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable,
sizeof(ets->reco_prio_tc));
return 0;
}
/**
* i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
* @netdev: the corresponding netdev
* @ets: structure to hold the PFC information
*
* Returns local IEEE PFC configuration
**/
static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
struct ieee_pfc *pfc)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
struct i40e_dcbx_config *dcbxcfg;
struct i40e_hw *hw = &pf->hw;
int i;
if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
dcbxcfg = &hw->local_dcbx_config;
pfc->pfc_cap = dcbxcfg->pfc.pfccap;
pfc->pfc_en = dcbxcfg->pfc.pfcenable;
pfc->mbc = dcbxcfg->pfc.mbc;
i40e_get_pfc_delay(hw, &pfc->delay);
/* Get Requests/Indicatiosn */
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
pfc->requests[i] = pf->stats.priority_xoff_tx[i];
pfc->indications[i] = pf->stats.priority_xoff_rx[i];
}
return 0;
}
/**
* i40e_dcbnl_getdcbx - retrieve current DCBx capability
* @netdev: the corresponding netdev
*
* Returns DCBx capability features
**/
static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
return pf->dcbx_cap;
}
/**
* i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx
* @netdev: the corresponding netdev
*
* Returns the SAN MAC address used for LLDP exchange
**/
static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,
u8 *perm_addr)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
int i, j;
memset(perm_addr, 0xff, MAX_ADDR_LEN);
for (i = 0; i < dev->addr_len; i++)
perm_addr[i] = pf->hw.mac.perm_addr[i];
for (j = 0; j < dev->addr_len; j++, i++)
perm_addr[i] = pf->hw.mac.san_addr[j];
}
static const struct dcbnl_rtnl_ops dcbnl_ops = {
.ieee_getets = i40e_dcbnl_ieee_getets,
.ieee_getpfc = i40e_dcbnl_ieee_getpfc,
.getdcbx = i40e_dcbnl_getdcbx,
.getpermhwaddr = i40e_dcbnl_get_perm_hw_addr,
};
/**
* i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config
* @vsi: the corresponding vsi
*
* Set up all the IEEE APPs in the DCBNL App Table and generate event for
* other settings
**/
void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
{
struct net_device *dev = vsi->netdev;
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
struct i40e_dcbx_config *dcbxcfg;
struct i40e_hw *hw = &pf->hw;
struct dcb_app sapp;
u8 prio, tc_map;
int i;
/* DCB not enabled */
if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
return;
/* MFP mode but not an iSCSI PF so return */
if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
return;
dcbxcfg = &hw->local_dcbx_config;
/* Set up all the App TLVs if DCBx is negotiated */
for (i = 0; i < dcbxcfg->numapps; i++) {
prio = dcbxcfg->app[i].priority;
tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]);
/* Add APP only if the TC is enabled for this VSI */
if (tc_map & vsi->tc_config.enabled_tc) {
sapp.selector = dcbxcfg->app[i].selector;
sapp.protocol = dcbxcfg->app[i].protocolid;
sapp.priority = prio;
dcb_ieee_setapp(dev, &sapp);
}
}
#ifdef HAVE_DCBNL_IEEE_DELAPP
/* Notify user-space of the changes */
dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0);
#endif
}
/**
* i40e_dcbnl_vsi_del_app - Delete APP for given VSI
* @vsi: the corresponding vsi
* @app: APP to delete
*
* Delete given APP from the DCBNL APP table for given
* VSI
**/
static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
struct i40e_dcb_app_priority_table *app)
{
struct net_device *dev = vsi->netdev;
struct dcb_app sapp;
if (!dev)
return -EINVAL;
sapp.selector = app->selector;
sapp.protocol = app->protocolid;
sapp.priority = app->priority;
return dcb_ieee_delapp(dev, &sapp);
}
/**
* i40e_dcbnl_del_app - Delete APP on all VSIs
* @pf: the corresponding PF
* @app: APP to delete
*
* Delete given APP from all the VSIs for given PF
**/
static void i40e_dcbnl_del_app(struct i40e_pf *pf,
struct i40e_dcb_app_priority_table *app)
{
int v, err;
for (v = 0; v < pf->num_alloc_vsi; v++) {
if (pf->vsi[v] && pf->vsi[v]->netdev) {
err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app);
dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n",
pf->vsi[v]->seid, err, app->selector,
app->protocolid, app->priority);
}
}
}
/**
* i40e_dcbnl_find_app - Search APP in given DCB config
* @cfg: DCBX configuration data
* @app: APP to search for
*
* Find given APP in the DCB configuration
**/
static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
struct i40e_dcb_app_priority_table *app)
{
int i;
for (i = 0; i < cfg->numapps; i++) {
if (app->selector == cfg->app[i].selector &&
app->protocolid == cfg->app[i].protocolid &&
app->priority == cfg->app[i].priority)
return true;
}
return false;
}
/**
* i40e_dcbnl_flush_apps - Delete all removed APPs
* @pf: the corresponding PF
* @old_cfg: old DCBX configuration data
* @new_cfg: new DCBX configuration data
*
* Find and delete all APPs that are not present in the passed
* DCB configuration
**/
void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
struct i40e_dcbx_config *old_cfg,
struct i40e_dcbx_config *new_cfg)
{
struct i40e_dcb_app_priority_table app;
int i;
/* MFP mode but not an iSCSI PF so return */
if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
return;
for (i = 0; i < old_cfg->numapps; i++) {
app = old_cfg->app[i];
/* The APP is not available anymore delete it */
if (!i40e_dcbnl_find_app(new_cfg, &app))
i40e_dcbnl_del_app(pf, &app);
}
}
/**
* i40e_dcbnl_setup - DCBNL setup
* @vsi: the corresponding vsi
*
* Set up DCBNL ops and initial APP TLVs
**/
void i40e_dcbnl_setup(struct i40e_vsi *vsi)
{
struct net_device *dev = vsi->netdev;
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
/* Not DCB capable */
if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
return;
dev->dcbnl_ops = &dcbnl_ops;
/* Set initial IEEE DCB settings */
i40e_dcbnl_set_all(vsi);
}
#endif /* HAVE_DCBNL_IEEE */
#endif /* CONFIG_DCB */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#define _I40E_DEVIDS_H_
/* Device IDs */
#define I40E_DEV_ID_SFP_XL710 0x1572
#define I40E_DEV_ID_QEMU 0x1574
#define I40E_DEV_ID_KX_B 0x1580
#define I40E_DEV_ID_KX_C 0x1581
#define I40E_DEV_ID_QSFP_A 0x1583
#define I40E_DEV_ID_QSFP_B 0x1584
#define I40E_DEV_ID_QSFP_C 0x1585
#define I40E_DEV_ID_10G_BASE_T 0x1586
#define I40E_DEV_ID_20G_KR2 0x1587
#define I40E_DEV_ID_20G_KR2_A 0x1588
#define I40E_DEV_ID_10G_BASE_T4 0x1589
#define I40E_DEV_ID_25G_B 0x158A
#define I40E_DEV_ID_25G_SFP28 0x158B
#define I40E_DEV_ID_X722_A0 0x374C
#define I40E_DEV_ID_KX_X722 0x37CE
#define I40E_DEV_ID_QSFP_X722 0x37CF
#define I40E_DEV_ID_SFP_X722 0x37D0
#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1
#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2
#define I40E_DEV_ID_SFP_I_X722 0x37D3
#define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \
(d) == I40E_DEV_ID_QSFP_B || \
(d) == I40E_DEV_ID_QSFP_C)

View File

@ -0,0 +1,145 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include "i40e_diag.h"
#include "i40e_prototype.h"
/**
* i40e_diag_reg_pattern_test
* @hw: pointer to the hw struct
* @reg: reg to be tested
* @mask: bits to be touched
**/
static i40e_status i40e_diag_reg_pattern_test(struct i40e_hw *hw,
u32 reg, u32 mask)
{
const u32 patterns[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
u32 pat, val, orig_val;
int i;
orig_val = rd32(hw, reg);
for (i = 0; i < ARRAY_SIZE(patterns); i++) {
pat = patterns[i];
wr32(hw, reg, (pat & mask));
val = rd32(hw, reg);
if ((val & mask) != (pat & mask)) {
#ifdef ETHTOOL_TEST
i40e_debug(hw, I40E_DEBUG_DIAG,
"%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n",
__func__, reg, pat, val);
#endif
return I40E_ERR_DIAG_TEST_FAILED;
}
}
wr32(hw, reg, orig_val);
val = rd32(hw, reg);
if (val != orig_val) {
#ifdef ETHTOOL_TEST
i40e_debug(hw, I40E_DEBUG_DIAG,
"%s: reg restore test failed - reg 0x%08x orig_val 0x%08x val 0x%08x\n",
__func__, reg, orig_val, val);
#endif
return I40E_ERR_DIAG_TEST_FAILED;
}
return I40E_SUCCESS;
}
struct i40e_diag_reg_test_info i40e_reg_list[] = {
/* offset mask elements stride */
{I40E_QTX_CTL(0), 0x0000FFBF, 1, I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
{I40E_PFINT_ITR0(0), 0x00000FFF, 3, I40E_PFINT_ITR0(1) - I40E_PFINT_ITR0(0)},
{I40E_PFINT_ITRN(0, 0), 0x00000FFF, 1, I40E_PFINT_ITRN(0, 1) - I40E_PFINT_ITRN(0, 0)},
{I40E_PFINT_ITRN(1, 0), 0x00000FFF, 1, I40E_PFINT_ITRN(1, 1) - I40E_PFINT_ITRN(1, 0)},
{I40E_PFINT_ITRN(2, 0), 0x00000FFF, 1, I40E_PFINT_ITRN(2, 1) - I40E_PFINT_ITRN(2, 0)},
{I40E_PFINT_STAT_CTL0, 0x0000000C, 1, 0},
{I40E_PFINT_LNKLST0, 0x00001FFF, 1, 0},
{I40E_PFINT_LNKLSTN(0), 0x000007FF, 1, I40E_PFINT_LNKLSTN(1) - I40E_PFINT_LNKLSTN(0)},
{I40E_QINT_TQCTL(0), 0x000000FF, 1, I40E_QINT_TQCTL(1) - I40E_QINT_TQCTL(0)},
{I40E_QINT_RQCTL(0), 0x000000FF, 1, I40E_QINT_RQCTL(1) - I40E_QINT_RQCTL(0)},
{I40E_PFINT_ICR0_ENA, 0xF7F20000, 1, 0},
{ 0 }
};
/**
* i40e_diag_reg_test
* @hw: pointer to the hw struct
*
* Perform registers diagnostic test
**/
i40e_status i40e_diag_reg_test(struct i40e_hw *hw)
{
i40e_status ret_code = I40E_SUCCESS;
u32 reg, mask;
u32 i, j;
for (i = 0; i40e_reg_list[i].offset != 0 &&
ret_code == I40E_SUCCESS; i++) {
/* set actual reg range for dynamically allocated resources */
if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) &&
hw->func_caps.num_tx_qp != 0)
i40e_reg_list[i].elements = hw->func_caps.num_tx_qp;
if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) ||
i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) ||
i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) ||
i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) ||
i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) &&
hw->func_caps.num_msix_vectors != 0)
i40e_reg_list[i].elements =
hw->func_caps.num_msix_vectors - 1;
/* test register access */
mask = i40e_reg_list[i].mask;
for (j = 0; j < i40e_reg_list[i].elements &&
ret_code == I40E_SUCCESS; j++) {
reg = i40e_reg_list[i].offset
+ (j * i40e_reg_list[i].stride);
ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
}
}
return ret_code;
}
/**
* i40e_diag_eeprom_test
* @hw: pointer to the hw struct
*
* Perform EEPROM diagnostic test
**/
i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw)
{
i40e_status ret_code;
u16 reg_val;
/* read NVM control word and if NVM valid, validate EEPROM checksum*/
ret_code = i40e_read_nvm_word(hw, I40E_SR_NVM_CONTROL_WORD, &reg_val);
if ((ret_code == I40E_SUCCESS) &&
((reg_val & I40E_SR_CONTROL_WORD_1_MASK) ==
BIT(I40E_SR_CONTROL_WORD_1_SHIFT)))
return i40e_validate_nvm_checksum(hw, NULL);
else
return I40E_ERR_DIAG_TEST_FAILED;
}

View File

@ -0,0 +1,48 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_DIAG_H_
#define _I40E_DIAG_H_
#include "i40e_type.h"
enum i40e_lb_mode {
I40E_LB_MODE_NONE = 0x0,
I40E_LB_MODE_PHY_LOCAL = I40E_AQ_LB_PHY_LOCAL,
I40E_LB_MODE_PHY_REMOTE = I40E_AQ_LB_PHY_REMOTE,
I40E_LB_MODE_MAC_LOCAL = I40E_AQ_LB_MAC_LOCAL,
};
struct i40e_diag_reg_test_info {
u32 offset; /* the base register */
u32 mask; /* bits that can be tested */
u32 elements; /* number of elements if array */
u32 stride; /* bytes between each element */
};
extern struct i40e_diag_reg_test_info i40e_reg_list[];
i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
#endif /* _I40E_DIAG_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_FCOE_H_
#define _I40E_FCOE_H_
/* FCoE HW context helper macros */
#define I40E_DDP_CONTEXT_DESC(R, i) \
(&(((struct i40e_fcoe_ddp_context_desc *)((R)->desc))[i]))
#define I40E_QUEUE_CONTEXT_DESC(R, i) \
(&(((struct i40e_fcoe_queue_context_desc *)((R)->desc))[i]))
#define I40E_FILTER_CONTEXT_DESC(R, i) \
(&(((struct i40e_fcoe_filter_context_desc *)((R)->desc))[i]))
/* receive queue descriptor filter status for FCoE */
#define I40E_RX_DESC_FLTSTAT_FCMASK 0x3
#define I40E_RX_DESC_FLTSTAT_NOMTCH 0x0 /* no ddp context match */
#define I40E_RX_DESC_FLTSTAT_NODDP 0x1 /* no ddp due to error */
#define I40E_RX_DESC_FLTSTAT_DDP 0x2 /* DDPed payload, post header */
#define I40E_RX_DESC_FLTSTAT_FCPRSP 0x3 /* FCP_RSP */
/* receive queue descriptor error codes for FCoE */
#define I40E_RX_DESC_FCOE_ERROR_MASK \
(I40E_RX_DESC_ERROR_L3L4E_PROT | \
I40E_RX_DESC_ERROR_L3L4E_FC | \
I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR | \
I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN)
/* receive queue descriptor programming error */
#define I40E_RX_PROG_FCOE_ERROR_TBL_FULL(e) \
(((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) & 0x1)
#define I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) \
(((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) & 0x1)
#define I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT \
BIT(I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT)
#define I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT \
BIT(I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT)
#define I40E_RX_PROG_FCOE_ERROR_INVLFAIL(e) \
I40E_RX_PROG_FCOE_ERROR_CONFLICT(e)
#define I40E_RX_PROG_FCOE_ERROR_INVLFAIL_BIT \
I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT
/* FCoE DDP related definitions */
#define I40E_FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */
#define I40E_FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */
#define I40E_FCOE_DDP_BUFFCNT_MAX 512 /* 9 bits bufcnt */
#define I40E_FCOE_DDP_PTR_ALIGN 16
#define I40E_FCOE_DDP_PTR_MAX (I40E_FCOE_DDP_BUFFCNT_MAX * sizeof(dma_addr_t))
#define I40E_FCOE_DDP_BUF_MIN 4096
#define I40E_FCOE_DDP_MAX 2048
#define I40E_FCOE_FILTER_CTX_QW1_PCTYPE_SHIFT 8
/* supported netdev features for FCoE */
#define I40E_FCOE_NETIF_FEATURES (NETIF_F_ALL_FCOE | \
NETIF_F_HW_VLAN_CTAG_TX | \
NETIF_F_HW_VLAN_CTAG_RX | \
NETIF_F_HW_VLAN_CTAG_FILTER)
/* DDP context flags */
enum i40e_fcoe_ddp_flags {
__I40E_FCOE_DDP_NONE = 1,
__I40E_FCOE_DDP_TARGET,
__I40E_FCOE_DDP_INITALIZED,
__I40E_FCOE_DDP_PROGRAMMED,
__I40E_FCOE_DDP_DONE,
__I40E_FCOE_DDP_ABORTED,
__I40E_FCOE_DDP_UNMAPPED,
};
/* DDP SW context struct */
struct i40e_fcoe_ddp {
int len;
u16 xid;
u16 firstoff;
u16 lastsize;
u16 list_len;
u8 fcerr;
u8 prerr;
unsigned long flags;
unsigned int sgc;
struct scatterlist *sgl;
dma_addr_t udp;
u64 *udl;
struct dma_pool *pool;
};
struct i40e_fcoe_ddp_pool {
struct dma_pool *pool;
};
struct i40e_fcoe {
unsigned long mode;
atomic_t refcnt;
struct i40e_fcoe_ddp_pool __percpu *ddp_pool;
struct i40e_fcoe_ddp ddp[I40E_FCOE_DDP_MAX];
};
#endif /* _I40E_FCOE_H_ */

View File

@ -0,0 +1,143 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_HELPER_H_
#define _I40E_HELPER_H_
#include "i40e_alloc.h"
/**
* i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
* @size: size of memory requested
* @alignment: what to align the allocation to
**/
inline int i40e_allocate_dma_mem_d(struct i40e_hw *hw,
struct i40e_dma_mem *mem,
__always_unused enum i40e_memory_type mtype,
u64 size, u32 alignment)
{
struct i40e_pf *nf = (struct i40e_pf *)hw->back;
mem->size = ALIGN(size, alignment);
mem->va = dma_zalloc_coherent(&nf->pdev->dev, mem->size,
&mem->pa, GFP_KERNEL);
if (!mem->va)
return -ENOMEM;
return 0;
}
/**
* i40e_free_dma_mem_d - OS specific memory free for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
inline int i40e_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem)
{
struct i40e_pf *nf = (struct i40e_pf *)hw->back;
dma_free_coherent(&nf->pdev->dev, mem->size, mem->va, mem->pa);
mem->va = NULL;
mem->pa = 0;
mem->size = 0;
return 0;
}
/**
* i40e_allocate_virt_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
* @size: size of memory requested
**/
inline int i40e_allocate_virt_mem_d(struct i40e_hw *hw,
struct i40e_virt_mem *mem,
u32 size)
{
mem->size = size;
mem->va = kzalloc(size, GFP_KERNEL);
if (!mem->va)
return -ENOMEM;
return 0;
}
/**
* i40e_free_virt_mem_d - OS specific memory free for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to free
**/
inline int i40e_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem)
{
/* it's ok to kfree a NULL pointer */
kfree(mem->va);
mem->va = NULL;
mem->size = 0;
return 0;
}
/* prototype */
inline void i40e_destroy_spinlock_d(struct i40e_spinlock *sp);
inline void i40e_acquire_spinlock_d(struct i40e_spinlock *sp);
inline void i40e_release_spinlock_d(struct i40e_spinlock *sp);
/**
* i40e_init_spinlock_d - OS specific spinlock init for shared code
* @sp: pointer to a spinlock declared in driver space
**/
static inline void i40e_init_spinlock_d(struct i40e_spinlock *sp)
{
mutex_init((struct mutex *)sp);
}
/**
* i40e_acquire_spinlock_d - OS specific spinlock acquire for shared code
* @sp: pointer to a spinlock declared in driver space
**/
inline void i40e_acquire_spinlock_d(struct i40e_spinlock *sp)
{
mutex_lock((struct mutex *)sp);
}
/**
* i40e_release_spinlock_d - OS specific spinlock release for shared code
* @sp: pointer to a spinlock declared in driver space
**/
inline void i40e_release_spinlock_d(struct i40e_spinlock *sp)
{
mutex_unlock((struct mutex *)sp);
}
/**
* i40e_destroy_spinlock_d - OS specific spinlock destroy for shared code
* @sp: pointer to a spinlock declared in driver space
**/
inline void i40e_destroy_spinlock_d(struct i40e_spinlock *sp)
{
mutex_destroy((struct mutex *)sp);
}
#endif /* _I40E_HELPER_H_ */

View File

@ -0,0 +1,362 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#include "i40e_osdep.h"
#include "i40e_register.h"
#include "i40e_status.h"
#include "i40e_alloc.h"
#include "i40e_hmc.h"
#ifndef I40E_NO_TYPE_HEADER
#include "i40e_type.h"
#endif
/**
* i40e_add_sd_table_entry - Adds a segment descriptor to the table
* @hw: pointer to our hw struct
* @hmc_info: pointer to the HMC configuration information struct
* @sd_index: segment descriptor index to manipulate
* @type: what type of segment descriptor we're manipulating
* @direct_mode_sz: size to alloc in direct mode
**/
i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 sd_index,
enum i40e_sd_entry_type type,
u64 direct_mode_sz)
{
i40e_status ret_code = I40E_SUCCESS;
struct i40e_hmc_sd_entry *sd_entry;
enum i40e_memory_type mem_type;
bool dma_mem_alloc_done = false;
struct i40e_dma_mem mem;
u64 alloc_len;
if (NULL == hmc_info->sd_table.sd_entry) {
ret_code = I40E_ERR_BAD_PTR;
hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n");
goto exit;
}
if (sd_index >= hmc_info->sd_table.sd_cnt) {
ret_code = I40E_ERR_INVALID_SD_INDEX;
hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n");
goto exit;
}
sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
if (!sd_entry->valid) {
if (I40E_SD_TYPE_PAGED == type) {
mem_type = i40e_mem_pd;
alloc_len = I40E_HMC_PAGED_BP_SIZE;
} else {
mem_type = i40e_mem_bp_jumbo;
alloc_len = direct_mode_sz;
}
/* allocate a 4K pd page or 2M backing page */
ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len,
I40E_HMC_PD_BP_BUF_ALIGNMENT);
if (ret_code)
goto exit;
dma_mem_alloc_done = true;
if (I40E_SD_TYPE_PAGED == type) {
ret_code = i40e_allocate_virt_mem(hw,
&sd_entry->u.pd_table.pd_entry_virt_mem,
sizeof(struct i40e_hmc_pd_entry) * 512);
if (ret_code)
goto exit;
sd_entry->u.pd_table.pd_entry =
(struct i40e_hmc_pd_entry *)
sd_entry->u.pd_table.pd_entry_virt_mem.va;
i40e_memcpy(&sd_entry->u.pd_table.pd_page_addr,
&mem, sizeof(struct i40e_dma_mem),
I40E_NONDMA_TO_NONDMA);
} else {
i40e_memcpy(&sd_entry->u.bp.addr,
&mem, sizeof(struct i40e_dma_mem),
I40E_NONDMA_TO_NONDMA);
sd_entry->u.bp.sd_pd_index = sd_index;
}
/* initialize the sd entry */
hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
/* increment the ref count */
I40E_INC_SD_REFCNT(&hmc_info->sd_table);
}
/* Increment backing page reference count */
if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type)
I40E_INC_BP_REFCNT(&sd_entry->u.bp);
exit:
if (I40E_SUCCESS != ret_code)
if (dma_mem_alloc_done)
i40e_free_dma_mem(hw, &mem);
return ret_code;
}
/**
* i40e_add_pd_table_entry - Adds page descriptor to the specified table
* @hw: pointer to our HW structure
* @hmc_info: pointer to the HMC configuration information structure
* @pd_index: which page descriptor index to manipulate
* @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
*
* This function:
* 1. Initializes the pd entry
* 2. Adds pd_entry in the pd_table
* 3. Mark the entry valid in i40e_hmc_pd_entry structure
* 4. Initializes the pd_entry's ref count to 1
* assumptions:
* 1. The memory for pd should be pinned down, physically contiguous and
* aligned on 4K boundary and zeroed memory.
* 2. It should be 4K in size.
**/
i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 pd_index,
struct i40e_dma_mem *rsrc_pg)
{
i40e_status ret_code = I40E_SUCCESS;
struct i40e_hmc_pd_table *pd_table;
struct i40e_hmc_pd_entry *pd_entry;
struct i40e_dma_mem mem;
struct i40e_dma_mem *page = &mem;
u32 sd_idx, rel_pd_idx;
u64 *pd_addr;
u64 page_desc;
if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n");
goto exit;
}
/* find corresponding sd */
sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD);
if (I40E_SD_TYPE_PAGED !=
hmc_info->sd_table.sd_entry[sd_idx].entry_type)
goto exit;
rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD);
pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
pd_entry = &pd_table->pd_entry[rel_pd_idx];
if (!pd_entry->valid) {
if (rsrc_pg) {
pd_entry->rsrc_pg = true;
page = rsrc_pg;
} else {
/* allocate a 4K backing page */
ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp,
I40E_HMC_PAGED_BP_SIZE,
I40E_HMC_PD_BP_BUF_ALIGNMENT);
if (ret_code)
goto exit;
pd_entry->rsrc_pg = false;
}
i40e_memcpy(&pd_entry->bp.addr, page,
sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA);
pd_entry->bp.sd_pd_index = pd_index;
pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
/* Set page address and valid bit */
page_desc = page->pa | 0x1;
pd_addr = (u64 *)pd_table->pd_page_addr.va;
pd_addr += rel_pd_idx;
/* Add the backing page physical address in the pd entry */
i40e_memcpy(pd_addr, &page_desc, sizeof(u64),
I40E_NONDMA_TO_DMA);
pd_entry->sd_index = sd_idx;
pd_entry->valid = true;
I40E_INC_PD_REFCNT(pd_table);
}
I40E_INC_BP_REFCNT(&pd_entry->bp);
exit:
return ret_code;
}
/**
* i40e_remove_pd_bp - remove a backing page from a page descriptor
* @hw: pointer to our HW structure
* @hmc_info: pointer to the HMC configuration information structure
* @idx: the page index
* @is_pf: distinguishes a VF from a PF
*
* This function:
* 1. Marks the entry in pd tabe (for paged address mode) or in sd table
* (for direct address mode) invalid.
* 2. Write to register PMPDINV to invalidate the backing page in FV cache
* 3. Decrement the ref count for the pd _entry
* assumptions:
* 1. Caller can deallocate the memory used by backing storage after this
* function returns.
**/
i40e_status i40e_remove_pd_bp(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx)
{
i40e_status ret_code = I40E_SUCCESS;
struct i40e_hmc_pd_entry *pd_entry;
struct i40e_hmc_pd_table *pd_table;
struct i40e_hmc_sd_entry *sd_entry;
u32 sd_idx, rel_pd_idx;
u64 *pd_addr;
/* calculate index */
sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
if (sd_idx >= hmc_info->sd_table.sd_cnt) {
ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n");
goto exit;
}
sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
ret_code = I40E_ERR_INVALID_SD_TYPE;
hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n");
goto exit;
}
/* get the entry and decrease its ref counter */
pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
pd_entry = &pd_table->pd_entry[rel_pd_idx];
I40E_DEC_BP_REFCNT(&pd_entry->bp);
if (pd_entry->bp.ref_cnt)
goto exit;
/* mark the entry invalid */
pd_entry->valid = false;
I40E_DEC_PD_REFCNT(pd_table);
pd_addr = (u64 *)pd_table->pd_page_addr.va;
pd_addr += rel_pd_idx;
i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM);
I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
/* free memory here */
if (!pd_entry->rsrc_pg)
ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
if (I40E_SUCCESS != ret_code)
goto exit;
if (!pd_table->ref_cnt)
i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
exit:
return ret_code;
}
/**
* i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
* @hmc_info: pointer to the HMC configuration information structure
* @idx: the page index
**/
i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
u32 idx)
{
i40e_status ret_code = I40E_SUCCESS;
struct i40e_hmc_sd_entry *sd_entry;
/* get the entry and decrease its ref counter */
sd_entry = &hmc_info->sd_table.sd_entry[idx];
I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
if (sd_entry->u.bp.ref_cnt) {
ret_code = I40E_ERR_NOT_READY;
goto exit;
}
I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
/* mark the entry invalid */
sd_entry->valid = false;
exit:
return ret_code;
}
/**
* i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor
* @hw: pointer to our hw struct
* @hmc_info: pointer to the HMC configuration information structure
* @idx: the page index
* @is_pf: used to distinguish between VF and PF
**/
i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx, bool is_pf)
{
struct i40e_hmc_sd_entry *sd_entry;
if (!is_pf)
return I40E_NOT_SUPPORTED;
/* get the entry and decrease its ref counter */
sd_entry = &hmc_info->sd_table.sd_entry[idx];
I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
return i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
}
/**
* i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
* @hmc_info: pointer to the HMC configuration information structure
* @idx: segment descriptor index to find the relevant page descriptor
**/
i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
u32 idx)
{
i40e_status ret_code = I40E_SUCCESS;
struct i40e_hmc_sd_entry *sd_entry;
sd_entry = &hmc_info->sd_table.sd_entry[idx];
if (sd_entry->u.pd_table.ref_cnt) {
ret_code = I40E_ERR_NOT_READY;
goto exit;
}
/* mark the entry invalid */
sd_entry->valid = false;
I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
exit:
return ret_code;
}
/**
* i40e_remove_pd_page_new - Removes a PD page from sd entry.
* @hw: pointer to our hw struct
* @hmc_info: pointer to the HMC configuration information structure
* @idx: segment descriptor index to find the relevant page descriptor
* @is_pf: used to distinguish between VF and PF
**/
i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx, bool is_pf)
{
struct i40e_hmc_sd_entry *sd_entry;
if (!is_pf)
return I40E_NOT_SUPPORTED;
sd_entry = &hmc_info->sd_table.sd_entry[idx];
I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
return i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr));
}

View File

@ -0,0 +1,235 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_HMC_H_
#define _I40E_HMC_H_
#define I40E_HMC_MAX_BP_COUNT 512
/* forward-declare the HW struct for the compiler */
struct i40e_hw;
#define I40E_HMC_INFO_SIGNATURE 0x484D5347 /* HMSG */
#define I40E_HMC_PD_CNT_IN_SD 512
#define I40E_HMC_DIRECT_BP_SIZE 0x200000 /* 2M */
#define I40E_HMC_PAGED_BP_SIZE 4096
#define I40E_HMC_PD_BP_BUF_ALIGNMENT 4096
#define I40E_FIRST_VF_FPM_ID 16
struct i40e_hmc_obj_info {
u64 base; /* base addr in FPM */
u32 max_cnt; /* max count available for this hmc func */
u32 cnt; /* count of objects driver actually wants to create */
u64 size; /* size in bytes of one object */
};
enum i40e_sd_entry_type {
I40E_SD_TYPE_INVALID = 0,
I40E_SD_TYPE_PAGED = 1,
I40E_SD_TYPE_DIRECT = 2
};
struct i40e_hmc_bp {
enum i40e_sd_entry_type entry_type;
struct i40e_dma_mem addr; /* populate to be used by hw */
u32 sd_pd_index;
u32 ref_cnt;
};
struct i40e_hmc_pd_entry {
struct i40e_hmc_bp bp;
u32 sd_index;
bool rsrc_pg;
bool valid;
};
struct i40e_hmc_pd_table {
struct i40e_dma_mem pd_page_addr; /* populate to be used by hw */
struct i40e_hmc_pd_entry *pd_entry; /* [512] for sw book keeping */
struct i40e_virt_mem pd_entry_virt_mem; /* virt mem for pd_entry */
u32 ref_cnt;
u32 sd_index;
};
struct i40e_hmc_sd_entry {
enum i40e_sd_entry_type entry_type;
bool valid;
union {
struct i40e_hmc_pd_table pd_table;
struct i40e_hmc_bp bp;
} u;
};
struct i40e_hmc_sd_table {
struct i40e_virt_mem addr; /* used to track sd_entry allocations */
u32 sd_cnt;
u32 ref_cnt;
struct i40e_hmc_sd_entry *sd_entry; /* (sd_cnt*512) entries max */
};
struct i40e_hmc_info {
u32 signature;
/* equals to pci func num for PF and dynamically allocated for VFs */
u8 hmc_fn_id;
u16 first_sd_index; /* index of the first available SD */
/* hmc objects */
struct i40e_hmc_obj_info *hmc_obj;
struct i40e_virt_mem hmc_obj_virt_mem;
struct i40e_hmc_sd_table sd_table;
};
#define I40E_INC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt++)
#define I40E_INC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt++)
#define I40E_INC_BP_REFCNT(bp) ((bp)->ref_cnt++)
#define I40E_DEC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt--)
#define I40E_DEC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt--)
#define I40E_DEC_BP_REFCNT(bp) ((bp)->ref_cnt--)
/**
* I40E_SET_PF_SD_ENTRY - marks the sd entry as valid in the hardware
* @hw: pointer to our hw struct
* @pa: pointer to physical address
* @sd_index: segment descriptor index
* @type: if sd entry is direct or paged
**/
#define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type) \
{ \
u32 val1, val2, val3; \
val1 = (u32)(upper_32_bits(pa)); \
val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT << \
I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \
((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \
I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \
BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \
val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \
wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \
wr32((hw), I40E_PFHMC_SDDATALOW, val2); \
wr32((hw), I40E_PFHMC_SDCMD, val3); \
}
/**
* I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware
* @hw: pointer to our hw struct
* @sd_index: segment descriptor index
* @type: if sd entry is direct or paged
**/
#define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type) \
{ \
u32 val2, val3; \
val2 = (I40E_HMC_MAX_BP_COUNT << \
I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \
((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \
I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \
val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \
wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \
wr32((hw), I40E_PFHMC_SDDATALOW, val2); \
wr32((hw), I40E_PFHMC_SDCMD, val3); \
}
/**
* I40E_INVALIDATE_PF_HMC_PD - Invalidates the pd cache in the hardware
* @hw: pointer to our hw struct
* @sd_idx: segment descriptor index
* @pd_idx: page descriptor index
**/
#define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx) \
wr32((hw), I40E_PFHMC_PDINV, \
(((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) | \
((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
/**
* I40E_FIND_SD_INDEX_LIMIT - finds segment descriptor index limit
* @hmc_info: pointer to the HMC configuration information structure
* @type: type of HMC resources we're searching
* @index: starting index for the object
* @cnt: number of objects we're trying to create
* @sd_idx: pointer to return index of the segment descriptor in question
* @sd_limit: pointer to return the maximum number of segment descriptors
*
* This function calculates the segment descriptor index and index limit
* for the resource defined by i40e_hmc_rsrc_type.
**/
#define I40E_FIND_SD_INDEX_LIMIT(hmc_info, type, index, cnt, sd_idx, sd_limit)\
{ \
u64 fpm_addr, fpm_limit; \
fpm_addr = (hmc_info)->hmc_obj[(type)].base + \
(hmc_info)->hmc_obj[(type)].size * (index); \
fpm_limit = fpm_addr + (hmc_info)->hmc_obj[(type)].size * (cnt);\
*(sd_idx) = (u32)(fpm_addr / I40E_HMC_DIRECT_BP_SIZE); \
*(sd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_DIRECT_BP_SIZE); \
/* add one more to the limit to correct our range */ \
*(sd_limit) += 1; \
}
/**
* I40E_FIND_PD_INDEX_LIMIT - finds page descriptor index limit
* @hmc_info: pointer to the HMC configuration information struct
* @type: HMC resource type we're examining
* @idx: starting index for the object
* @cnt: number of objects we're trying to create
* @pd_index: pointer to return page descriptor index
* @pd_limit: pointer to return page descriptor index limit
*
* Calculates the page descriptor index and index limit for the resource
* defined by i40e_hmc_rsrc_type.
**/
#define I40E_FIND_PD_INDEX_LIMIT(hmc_info, type, idx, cnt, pd_index, pd_limit)\
{ \
u64 fpm_adr, fpm_limit; \
fpm_adr = (hmc_info)->hmc_obj[(type)].base + \
(hmc_info)->hmc_obj[(type)].size * (idx); \
fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt); \
*(pd_index) = (u32)(fpm_adr / I40E_HMC_PAGED_BP_SIZE); \
*(pd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_PAGED_BP_SIZE); \
/* add one more to the limit to correct our range */ \
*(pd_limit) += 1; \
}
i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 sd_index,
enum i40e_sd_entry_type type,
u64 direct_mode_sz);
i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 pd_index,
struct i40e_dma_mem *rsrc_pg);
i40e_status i40e_remove_pd_bp(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx);
i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
u32 idx);
i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx, bool is_pf);
i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
u32 idx);
i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw,
struct i40e_hmc_info *hmc_info,
u32 idx, bool is_pf);
#endif /* _I40E_HMC_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_LAN_HMC_H_
#define _I40E_LAN_HMC_H_
/* forward-declare the HW struct for the compiler */
struct i40e_hw;
/* HMC element context information */
/* Rx queue context data
*
* The sizes of the variables may be larger than needed due to crossing byte
* boundaries. If we do not have the width of the variable set to the correct
* size then we could end up shifting bits off the top of the variable when the
* variable is at the top of a byte and crosses over into the next byte.
*/
struct i40e_hmc_obj_rxq {
u16 head;
u16 cpuid; /* bigger than needed, see above for reason */
u64 base;
u16 qlen;
#define I40E_RXQ_CTX_DBUFF_SHIFT 7
u16 dbuff; /* bigger than needed, see above for reason */
#define I40E_RXQ_CTX_HBUFF_SHIFT 6
u16 hbuff; /* bigger than needed, see above for reason */
u8 dtype;
u8 dsize;
u8 crcstrip;
u8 fc_ena;
u8 l2tsel;
u8 hsplit_0;
u8 hsplit_1;
u8 showiv;
u32 rxmax; /* bigger than needed, see above for reason */
u8 tphrdesc_ena;
u8 tphwdesc_ena;
u8 tphdata_ena;
u8 tphhead_ena;
u16 lrxqthresh; /* bigger than needed, see above for reason */
u8 prefena; /* NOTE: normally must be set to 1 at init */
};
/* Tx queue context data
*
* The sizes of the variables may be larger than needed due to crossing byte
* boundaries. If we do not have the width of the variable set to the correct
* size then we could end up shifting bits off the top of the variable when the
* variable is at the top of a byte and crosses over into the next byte.
*/
struct i40e_hmc_obj_txq {
u16 head;
u8 new_context;
u64 base;
u8 fc_ena;
u8 timesync_ena;
u8 fd_ena;
u8 alt_vlan_ena;
u16 thead_wb;
u8 cpuid;
u8 head_wb_ena;
u16 qlen;
u8 tphrdesc_ena;
u8 tphrpacket_ena;
u8 tphwdesc_ena;
u64 head_wb_addr;
u32 crc;
u16 rdylist;
u8 rdylist_act;
};
/* for hsplit_0 field of Rx HMC context */
enum i40e_hmc_obj_rx_hsplit_0 {
I40E_HMC_OBJ_RX_HSPLIT_0_NO_SPLIT = 0,
I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 = 1,
I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP = 2,
I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP = 4,
I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP = 8,
};
/* fcoe_cntx and fcoe_filt are for debugging purpose only */
struct i40e_hmc_obj_fcoe_cntx {
u32 rsv[32];
};
struct i40e_hmc_obj_fcoe_filt {
u32 rsv[8];
};
/* Context sizes for LAN objects */
enum i40e_hmc_lan_object_size {
I40E_HMC_LAN_OBJ_SZ_8 = 0x3,
I40E_HMC_LAN_OBJ_SZ_16 = 0x4,
I40E_HMC_LAN_OBJ_SZ_32 = 0x5,
I40E_HMC_LAN_OBJ_SZ_64 = 0x6,
I40E_HMC_LAN_OBJ_SZ_128 = 0x7,
I40E_HMC_LAN_OBJ_SZ_256 = 0x8,
I40E_HMC_LAN_OBJ_SZ_512 = 0x9,
};
#define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512
#define I40E_HMC_OBJ_SIZE_TXQ 128
#define I40E_HMC_OBJ_SIZE_RXQ 32
#define I40E_HMC_OBJ_SIZE_FCOE_CNTX 64
#define I40E_HMC_OBJ_SIZE_FCOE_FILT 64
enum i40e_hmc_lan_rsrc_type {
I40E_HMC_LAN_FULL = 0,
I40E_HMC_LAN_TX = 1,
I40E_HMC_LAN_RX = 2,
I40E_HMC_FCOE_CTX = 3,
I40E_HMC_FCOE_FILT = 4,
I40E_HMC_LAN_MAX = 5
};
enum i40e_hmc_model {
I40E_HMC_MODEL_DIRECT_PREFERRED = 0,
I40E_HMC_MODEL_DIRECT_ONLY = 1,
I40E_HMC_MODEL_PAGED_ONLY = 2,
I40E_HMC_MODEL_UNKNOWN,
};
struct i40e_hmc_lan_create_obj_info {
struct i40e_hmc_info *hmc_info;
u32 rsrc_type;
u32 start_idx;
u32 count;
enum i40e_sd_entry_type entry_type;
u64 direct_mode_sz;
};
struct i40e_hmc_lan_delete_obj_info {
struct i40e_hmc_info *hmc_info;
u32 rsrc_type;
u32 start_idx;
u32 count;
};
i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
u32 rxq_num, u32 fcoe_cntx_num,
u32 fcoe_filt_num);
i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw,
enum i40e_hmc_model model);
i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw);
i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw,
u16 queue);
i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw,
u16 queue,
struct i40e_hmc_obj_txq *s);
i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw,
u16 queue);
i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw,
u16 queue,
struct i40e_hmc_obj_rxq *s);
#endif /* _I40E_LAN_HMC_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_OSDEP_H_
#define _I40E_OSDEP_H_
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/tcp.h>
#include <linux/pci.h>
#include <linux/highuid.h>
#include <linux/io.h>
#include <asm-generic/int-ll64.h>
#ifndef readq
static inline __u64 readq(const volatile void __iomem *addr)
{
const volatile u32 __iomem *p = addr;
u32 low, high;
low = readl(p);
high = readl(p + 1);
return low + ((u64)high << 32);
}
#endif
#ifndef writeq
static inline void writeq(__u64 val, volatile void __iomem *addr)
{
writel(val, addr);
writel(val >> 32, addr + 4);
}
#endif
#include "kcompat.h"
/* File to be the magic between shared code and
* actual OS primitives
*/
#ifndef hw_dbg
#define hw_dbg(h, s, ...) do { \
pr_debug("i40e %02x:%02x.%x " s, \
(h)->bus.bus_id, (h)->bus.device, \
(h)->bus.func, ##__VA_ARGS__); \
} while (0)
#endif
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define rd32(a, reg) readl((a)->hw_addr + (reg))
#define wr64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
#define rd64(a, reg) readq((a)->hw_addr + (reg))
#define i40e_flush(a) readl((a)->hw_addr + I40E_GLGEN_STAT)
/* memory allocation tracking */
struct i40e_dma_mem {
void *va;
dma_addr_t pa;
u32 size;
} __packed;
#define i40e_allocate_dma_mem(h, m, unused, s, a) \
i40e_allocate_dma_mem_d(h, m, unused, s, a)
#define i40e_free_dma_mem(h, m) i40e_free_dma_mem_d(h, m)
struct i40e_virt_mem {
void *va;
u32 size;
} __packed;
#define i40e_allocate_virt_mem(h, m, s) i40e_allocate_virt_mem_d(h, m, s)
#define i40e_free_virt_mem(h, m) i40e_free_virt_mem_d(h, m)
#define i40e_debug(h, m, s, ...) \
do { \
if (((m) & (h)->debug_mask)) \
pr_info("i40e %02x:%02x.%x " s, \
(h)->bus.bus_id, (h)->bus.device, \
(h)->bus.func, ##__VA_ARGS__); \
} while (0)
/* these things are all directly replaced with sed during the kernel build */
#define INLINE inline
#define CPU_TO_LE16(o) cpu_to_le16(o)
#define CPU_TO_LE32(s) cpu_to_le32(s)
#define CPU_TO_LE64(h) cpu_to_le64(h)
#define LE16_TO_CPU(a) le16_to_cpu(a)
#define LE32_TO_CPU(c) le32_to_cpu(c)
#define LE64_TO_CPU(k) le64_to_cpu(k)
/* SW spinlock */
struct i40e_spinlock {
struct mutex spinlock;
};
static inline void i40e_no_action(struct i40e_spinlock *sp)
{
/* nothing */
}
/* the locks are initialized in _probe and destroyed in _remove
* so make sure NOT to implement init/destroy here, as to
* avoid the i40e_init_adminq code trying to reinitialize
* the persistent lock memory
*/
#define i40e_init_spinlock(_sp) i40e_no_action(_sp)
#define i40e_acquire_spinlock(_sp) i40e_acquire_spinlock_d(_sp)
#define i40e_release_spinlock(_sp) i40e_release_spinlock_d(_sp)
#define i40e_destroy_spinlock(_sp) i40e_no_action(_sp)
#define I40E_HTONL(a) htonl(a)
#define i40e_memset(a, b, c, d) memset((a), (b), (c))
#define i40e_memcpy(a, b, c, d) memcpy((a), (b), (c))
typedef enum i40e_status_code i40e_status;
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
#ifdef WITH_FCOE
#define I40E_FCOE
#endif
#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */
#endif /* _I40E_OSDEP_H_ */

View File

@ -0,0 +1,435 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_PROTOTYPE_H_
#define _I40E_PROTOTYPE_H_
#include "i40e_type.h"
#include "i40e_alloc.h"
#include "i40e_virtchnl.h"
/* Prototypes for shared code functions that are not in
* the standard function pointer structures. These are
* mostly because they are needed even before the init
* has happened and will assist in the early SW and FW
* setup.
*/
/* adminq functions */
i40e_status i40e_init_adminq(struct i40e_hw *hw);
i40e_status i40e_shutdown_adminq(struct i40e_hw *hw);
void i40e_adminq_init_ring_data(struct i40e_hw *hw);
i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
struct i40e_arq_event_info *e,
u16 *events_pending);
i40e_status i40e_asq_send_command(struct i40e_hw *hw,
struct i40e_aq_desc *desc,
void *buff, /* can be NULL */
u16 buff_size,
struct i40e_asq_cmd_details *cmd_details);
/* debug function for adminq */
void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
void *desc, void *buffer, u16 buf_len);
void i40e_idle_aq(struct i40e_hw *hw);
bool i40e_check_asq_alive(struct i40e_hw *hw);
i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, bool unloading);
i40e_status i40e_aq_get_rss_lut(struct i40e_hw *hw, u16 seid,
bool pf_lut, u8 *lut, u16 lut_size);
i40e_status i40e_aq_set_rss_lut(struct i40e_hw *hw, u16 seid,
bool pf_lut, u8 *lut, u16 lut_size);
i40e_status i40e_aq_get_rss_key(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_get_set_rss_key_data *key);
i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_get_set_rss_key_data *key);
const char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err);
const char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err);
u32 i40e_led_get(struct i40e_hw *hw);
void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink);
i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
u16 led_addr, u32 mode);
i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
u16 *val);
i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
u32 time, u32 interval);
/* admin send queue commands */
i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw,
u16 *fw_major_version, u16 *fw_minor_version,
u32 *fw_build,
u16 *api_major_version, u16 *api_minor_version,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw,
u32 reg_addr, u64 reg_val,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw,
u32 reg_addr, u64 *reg_val,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_clear_default_vsi(struct i40e_hw *hw, u16 vsi_id,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
bool qualified_modules, bool report_init,
struct i40e_aq_get_phy_abilities_resp *abilities,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_phy_config(struct i40e_hw *hw,
struct i40e_aq_set_phy_config *config,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures,
bool atomic_reset);
i40e_status i40e_aq_set_phy_int_mask(struct i40e_hw *hw, u16 mask,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
bool enable_link, struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
bool enable_lse, struct i40e_link_status *link,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_local_advt_reg(struct i40e_hw *hw,
u64 advt_reg,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
struct i40e_driver_version *dv,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_vsi(struct i40e_hw *hw,
struct i40e_vsi_context *vsi_ctx,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
u16 vsi_id, bool set_filter,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details,
bool rx_only_promisc);
i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_full_promiscuous(struct i40e_hw *hw,
u16 seid, bool set,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_mc_promisc_on_vlan(struct i40e_hw *hw,
u16 seid, bool enable, u16 vid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_uc_promisc_on_vlan(struct i40e_hw *hw,
u16 seid, bool enable, u16 vid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_bc_promisc_on_vlan(struct i40e_hw *hw,
u16 seid, bool enable, u16 vid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw,
u16 seid, bool enable,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
struct i40e_vsi_context *vsi_ctx,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_update_vsi_params(struct i40e_hw *hw,
struct i40e_vsi_context *vsi_ctx,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
u16 downlink_seid, u8 enabled_tc,
bool default_port, u16 *pveb_seid,
bool enable_stats,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw,
u16 veb_seid, u16 *switch_id, bool *floating,
u16 *statistic_index, u16 *vebs_used,
u16 *vebs_free,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 vsi_id,
struct i40e_aqc_add_macvlan_element_data *mv_list,
u16 count, struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 vsi_id,
struct i40e_aqc_remove_macvlan_element_data *mv_list,
u16 count, struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
struct i40e_asq_cmd_details *cmd_details,
u16 *rule_id, u16 *rules_used, u16 *rules_free);
i40e_status i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
u16 rule_type, u16 rule_id, u16 count, __le16 *mr_list,
struct i40e_asq_cmd_details *cmd_details,
u16 *rules_used, u16 *rules_free);
i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
struct i40e_aqc_get_switch_config_resp *buf,
u16 buf_size, u16 *start_seid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_switch_config(struct i40e_hw *hw,
u16 flags, u16 valid_flags,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_request_resource(struct i40e_hw *hw,
enum i40e_aq_resources_ids resource,
enum i40e_aq_resource_access_type access,
u8 sdp_number, u64 *timeout,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_release_resource(struct i40e_hw *hw,
enum i40e_aq_resources_ids resource,
u8 sdp_number,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer,
u32 offset, u16 length, void *data,
bool last_command,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer,
u32 offset, u16 length, bool last_command,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_read_nvm_config(struct i40e_hw *hw,
u8 cmd_flags, u32 field_id, void *data,
u16 buf_size, u16 *element_count,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_write_nvm_config(struct i40e_hw *hw,
u8 cmd_flags, void *data, u16 buf_size,
u16 element_count,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_oem_post_update(struct i40e_hw *hw,
void *buff, u16 buff_size,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw,
void *buff, u16 buff_size, u16 *data_size,
enum i40e_admin_queue_opc list_type_opc,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer,
u32 offset, u16 length, void *data,
bool last_command,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
u8 mib_type, void *buff, u16 buff_size,
u16 *local_len, u16 *remote_len,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_lldp_mib(struct i40e_hw *hw,
u8 mib_type, void *buff, u16 buff_size,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_cfg_lldp_mib_change_event(struct i40e_hw *hw,
bool enable_update,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_cee_dcb_config(struct i40e_hw *hw,
void *buff, u16 buff_size,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_start_stop_dcbx(struct i40e_hw *hw,
bool start_agent,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
u16 udp_port, u8 protocol_index,
u8 *filter_index,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_switch_resource_alloc(struct i40e_hw *hw,
u8 *num_entries,
struct i40e_aqc_switch_resource_alloc_element_resp *buf,
u16 count,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw,
u16 flags, u8 *mac_addr,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw,
u16 seid, u16 credit, u8 max_credit,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_dcb_updated(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_config_switch_comp_bw_limit(struct i40e_hw *hw,
u16 seid, u16 credit, u8 max_bw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_config_vsi_tc_bw(struct i40e_hw *hw, u16 seid,
struct i40e_aqc_configure_vsi_tc_bw_data *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_config_switch_comp_ets(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_configure_switching_comp_ets_data *ets_data,
enum i40e_admin_queue_opc opcode,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_config_switch_comp_bw_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_configure_switching_comp_bw_config_data *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_query_vsi_bw_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_vsi_bw_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_query_vsi_ets_sla_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_vsi_ets_sla_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_query_switch_comp_ets_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_switching_comp_ets_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_query_port_ets_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_port_ets_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_switching_comp_bw_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
struct i40e_lldp_variables *lldp_cfg);
i40e_status i40e_aq_add_cloud_filters(struct i40e_hw *hw,
u16 vsi,
struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
u8 filter_count);
i40e_status i40e_aq_remove_cloud_filters(struct i40e_hw *hw,
u16 vsi,
struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
u8 filter_count);
i40e_status i40e_aq_alternate_read(struct i40e_hw *hw,
u32 reg_addr0, u32 *reg_val0,
u32 reg_addr1, u32 *reg_val1);
/* i40e_common */
i40e_status i40e_init_shared_code(struct i40e_hw *hw);
i40e_status i40e_pf_reset(struct i40e_hw *hw);
void i40e_clear_hw(struct i40e_hw *hw);
void i40e_clear_pxe_mode(struct i40e_hw *hw);
i40e_status i40e_get_link_status(struct i40e_hw *hw, bool *link_up);
i40e_status i40e_update_link_info(struct i40e_hw *hw);
i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
i40e_status i40e_read_bw_from_alt_ram(struct i40e_hw *hw,
u32 *max_bw, u32 *min_bw, bool *min_valid, bool *max_valid);
i40e_status i40e_aq_configure_partition_bw(struct i40e_hw *hw,
struct i40e_aqc_configure_partition_bw_data *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num,
u32 pba_num_size);
void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable);
#ifdef I40E_FCOE
i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
#endif
/* prototype for functions used for NVM access */
i40e_status i40e_init_nvm(struct i40e_hw *hw);
i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
enum i40e_aq_resource_access_type access);
void i40e_release_nvm(struct i40e_hw *hw);
i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
u16 *data);
i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
u16 *words, u16 *data);
i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module,
u32 offset, u16 words, void *data,
bool last_command);
i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw);
i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
u16 *checksum);
i40e_status i40e_nvmupd_command(struct i40e_hw *hw,
struct i40e_nvm_access *cmd,
u8 *bytes, int *);
void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode);
void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status);
extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[];
static INLINE struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
{
return i40e_ptype_lookup[ptype];
}
/* prototype for functions used for SW spinlocks */
void i40e_init_spinlock(struct i40e_spinlock *sp);
void i40e_acquire_spinlock(struct i40e_spinlock *sp);
void i40e_release_spinlock(struct i40e_spinlock *sp);
void i40e_destroy_spinlock(struct i40e_spinlock *sp);
/* i40e_common for VF drivers*/
void i40e_vf_parse_hw_config(struct i40e_hw *hw,
struct i40e_virtchnl_vf_resource *msg);
i40e_status i40e_vf_reset(struct i40e_hw *hw);
i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
enum i40e_virtchnl_ops v_opcode,
i40e_status v_retval,
u8 *msg, u16 msglen,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_set_filter_control(struct i40e_hw *hw,
struct i40e_filter_control_settings *settings);
i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
u8 *mac_addr, u16 ethtype, u16 flags,
u16 vsi_seid, u16 queue, bool is_add,
struct i40e_control_filter_stats *stats,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_debug_dump(struct i40e_hw *hw, u8 cluster_id,
u8 table_id, u32 start_index, u16 buff_size,
void *buff, u16 *ret_buff_size,
u8 *ret_next_table, u32 *ret_next_index,
struct i40e_asq_cmd_details *cmd_details);
void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
u16 vsi_seid);
i40e_status i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
u32 reg_addr, u32 *reg_val,
struct i40e_asq_cmd_details *cmd_details);
u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
u32 reg_addr, u32 reg_val,
struct i40e_asq_cmd_details *cmd_details);
void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
i40e_status i40e_aq_set_arp_proxy_config(struct i40e_hw *hw,
struct i40e_aqc_arp_proxy_data *proxy_config,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_ns_proxy_table_entry(struct i40e_hw *hw,
struct i40e_aqc_ns_proxy_data *ns_proxy_table_entry,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_clear_wol_filter(struct i40e_hw *hw,
u8 filter_index,
struct i40e_aqc_set_wol_filter_data *filter,
bool set_filter, bool no_wol_tco,
bool filter_valid, bool no_wol_tco_valid,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_wake_event_reason(struct i40e_hw *hw,
u16 *wake_reason,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_clear_all_wol_filters(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw,
u16 reg, u8 phy_addr, u16 *value);
i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw,
u16 reg, u8 phy_addr, u16 value);
i40e_status i40e_read_phy_register_clause45(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 *value);
i40e_status i40e_write_phy_register_clause45(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 value);
i40e_status i40e_read_phy_register(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 *value);
i40e_status i40e_write_phy_register(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 value);
u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
u32 time, u32 interval);
#endif /* _I40E_PROTOTYPE_H_ */

View File

@ -0,0 +1,813 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
/* this lets the macros that return timespec64 or structs compile cleanly with
* W=2
*/
#pragma GCC diagnostic ignored "-Waggregate-return"
#include "i40e.h"
#ifdef HAVE_PTP_1588_CLOCK
#include <linux/ptp_classify.h>
/* The XL710 timesync is very much like Intel's 82599 design when it comes to
* the fundamental clock design. However, the clock operations are much simpler
* in the XL710 because the device supports a full 64 bits of nanoseconds.
* Because the field is so wide, we can forgo the cycle counter and just
* operate with the nanosecond field directly without fear of overflow.
*
* Much like the 82599, the update period is dependent upon the link speed:
* At 40Gb link or no link, the period is 1.6ns.
* At 10Gb link, the period is multiplied by 2. (3.2ns)
* At 1Gb link, the period is multiplied by 20. (32ns)
* 1588 functionality is not supported at 100Mbps.
*/
#define I40E_PTP_40GB_INCVAL 0x0199999999ULL
#define I40E_PTP_10GB_INCVAL 0x0333333333ULL
#define I40E_PTP_1GB_INCVAL 0x2000000000ULL
#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (2 << \
I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
/**
* i40e_ptp_read - Read the PHC time from the device
* @pf: Board private structure
* @ts: timespec structure to hold the current time value
*
* This function reads the PRTTSYN_TIME registers and stores them in a
* timespec. However, since the registers are 64 bits of nanoseconds, we must
* convert the result to a timespec before we can return.
**/
static void i40e_ptp_read(struct i40e_pf *pf, struct timespec64 *ts)
{
struct i40e_hw *hw = &pf->hw;
u32 hi, lo;
u64 ns;
/* The timer latches on the lowest register read. */
lo = rd32(hw, I40E_PRTTSYN_TIME_L);
hi = rd32(hw, I40E_PRTTSYN_TIME_H);
ns = (((u64)hi) << 32) | lo;
*ts = ns_to_timespec64(ns);
}
/**
* i40e_ptp_write - Write the PHC time to the device
* @pf: Board private structure
* @ts: timespec structure that holds the new time value
*
* This function writes the PRTTSYN_TIME registers with the user value. Since
* we receive a timespec from the stack, we must convert that timespec into
* nanoseconds before programming the registers.
**/
static void i40e_ptp_write(struct i40e_pf *pf, const struct timespec64 *ts)
{
struct i40e_hw *hw = &pf->hw;
u64 ns = timespec64_to_ns(ts);
/* The timer will not update until the high register is written, so
* write the low register first.
*/
wr32(hw, I40E_PRTTSYN_TIME_L, (u32)ns);
wr32(hw, I40E_PRTTSYN_TIME_H, (u32)(ns >> 32));
}
/**
* i40e_ptp_convert_to_hwtstamp - Convert device clock to system time
* @hwtstamps: Timestamp structure to update
* @timestamp: Timestamp from the hardware
*
* We need to convert the NIC clock value into a hwtstamp which can be used by
* the upper level timestamping functions. Since the timestamp is simply a 64-
* bit nanosecond value, we can call ns_to_ktime directly to handle this.
**/
static void i40e_ptp_convert_to_hwtstamp(struct skb_shared_hwtstamps *hwtstamps,
u64 timestamp)
{
memset(hwtstamps, 0, sizeof(*hwtstamps));
hwtstamps->hwtstamp = ns_to_ktime(timestamp);
}
/**
* i40e_ptp_adjfreq - Adjust the PHC frequency
* @ptp: The PTP clock structure
* @ppb: Parts per billion adjustment from the base
*
* Adjust the frequency of the PHC by the indicated parts per billion from the
* base frequency.
**/
static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
{
struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
struct i40e_hw *hw = &pf->hw;
u64 adj, freq, diff;
int neg_adj = 0;
if (ppb < 0) {
neg_adj = 1;
ppb = -ppb;
}
smp_mb(); /* Force any pending update before accessing. */
adj = ACCESS_ONCE(pf->ptp_base_adj);
freq = adj;
freq *= ppb;
diff = div_u64(freq, 1000000000ULL);
if (neg_adj)
adj -= diff;
else
adj += diff;
wr32(hw, I40E_PRTTSYN_INC_L, (u32)adj);
wr32(hw, I40E_PRTTSYN_INC_H, (u32)(adj >> 32));
return 0;
}
/**
* i40e_ptp_adjtime - Adjust the PHC time
* @ptp: The PTP clock structure
* @delta: Offset in nanoseconds to adjust the PHC time by
*
* Adjust the frequency of the PHC by the indicated parts per billion from the
* base frequency.
**/
static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
struct timespec64 now;
mutex_lock(&pf->tmreg_lock);
i40e_ptp_read(pf, &now);
timespec64_add_ns(&now, delta);
i40e_ptp_write(pf, (const struct timespec64 *)&now);
mutex_unlock(&pf->tmreg_lock);
return 0;
}
/**
* i40e_ptp_gettime64 - Get the time of the PHC
* @ptp: The PTP clock structure
* @ts: timespec64 structure to hold the current time value
*
* Read the device clock and return the correct value on ns, after converting it
* into a timespec struct.
**/
static int i40e_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
mutex_lock(&pf->tmreg_lock);
i40e_ptp_read(pf, ts);
mutex_unlock(&pf->tmreg_lock);
return 0;
}
/**
* i40e_ptp_settime64 - Set the time of the PHC
* @ptp: The PTP clock structure
* @ts: timespec64 structure that holds the new time value
*
* Set the device clock to the user input value. The conversion from timespec
* to ns happens in the write function.
**/
static int i40e_ptp_settime64(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
mutex_lock(&pf->tmreg_lock);
i40e_ptp_write(pf, ts);
mutex_unlock(&pf->tmreg_lock);
return 0;
}
#ifndef HAVE_PTP_CLOCK_INFO_GETTIME64
/**
* i40e_ptp_gettime - Get the time of the PHC
* @ptp: The PTP clock structure
* @ts: timespec structure to hold the current time value
*
* Read the device clock and return the correct value on ns, after converting it
* into a timespec struct.
**/
static int i40e_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
{
struct timespec64 ts64;
int err;
err = i40e_ptp_gettime64(ptp, &ts64);
if (err)
return err;
*ts = timespec64_to_timespec(ts64);
return 0;
}
/**
* i40e_ptp_settime - Set the time of the PHC
* @ptp: The PTP clock structure
* @ts: timespec structure that holds the new time value
*
* Set the device clock to the user input value. The conversion from timespec
* to ns happens in the write function.
**/
static int i40e_ptp_settime(struct ptp_clock_info *ptp,
const struct timespec *ts)
{
struct timespec64 ts64 = timespec_to_timespec64(*ts);
return i40e_ptp_settime64(ptp, &ts64);
}
#endif
/**
* i40e_ptp_feature_enable - Enable/disable ancillary features of the PHC subsystem
* @ptp: The PTP clock structure
* @rq: The requested feature to change
* @on: Enable/disable flag
*
* The XL710 does not support any of the ancillary features of the PHC
* subsystem, so this function may just return.
**/
static int i40e_ptp_feature_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
/**
* i40e_ptp_update_latch_events - Read I40E_PRTTSYN_STAT_1 and latch events
* @pf: the PF data structure
*
* This function reads I40E_PRTTSYN_STAT_1 and updates the corresponding timers
* for noticed latch events. This allows the driver to keep track of the first
* time a latch event was noticed which will be used to help clear out Rx
* timestamps for packets that got dropped or lost.
*
* This function will return the current value of I40E_PRTTSYN_STAT_1 and is
* expected to be called only while under the ptp_rx_lock.
**/
static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
u32 prttsyn_stat, new_latch_events;
int i;
prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
new_latch_events = prttsyn_stat & ~pf->latch_event_flags;
/* Update the jiffies time for any newly latched timestamp. This
* ensures that we store the time that we first discovered a timestamp
* was latched by the hardware. The service task will later determine
* if we should free the latch and drop that timestamp should too much
* time pass. This flow ensures that we only update jiffies for new
* events latched since the last time we checked, and not all events
* currently latched, so that the service task accounting remains
* accurate.
*/
for (i = 0; i < 4; i++) {
if (new_latch_events & BIT(i))
pf->latch_events[i] = jiffies;
}
/* Finally, we store the current status of the Rx timestamp latches */
pf->latch_event_flags = prttsyn_stat;
return prttsyn_stat;
}
/**
* i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung
* @vsi: The VSI with the rings relevant to 1588
*
* This watchdog task is scheduled to detect error case where hardware has
* dropped an Rx packet that was timestamped when the ring is full. The
* particular error is rare but leaves the device in a state unable to timestamp
* any future packets.
**/
void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
struct i40e_hw *hw = &pf->hw;
unsigned int i, cleared = 0;
/* Since we cannot turn off the Rx timestamp logic if the device is
* configured for Tx timestamping, we check if Rx timestamping is
* configured. We don't want to spuriously warn about Rx timestamp
* hangs if we don't care about the timestamps.
*/
if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
return;
spin_lock_bh(&pf->ptp_rx_lock);
/* Update current latch times for Rx events */
i40e_ptp_get_rx_events(pf);
/* Check all the currently latched Rx events and see whether they have
* been latched for over a second. It is assumed that any timestamp
* should have been cleared within this time, or else it was captured
* for a dropped frame that the driver never received. Thus, we will
* clear any timestamp that has been latched for over 1 second.
*/
for (i = 0; i < 4; i++) {
if ((pf->latch_event_flags & BIT(i)) &&
time_is_before_jiffies(pf->latch_events[i] + HZ)) {
rd32(hw, I40E_PRTTSYN_RXTIME_H(i));
pf->latch_event_flags &= ~BIT(i);
cleared++;
}
}
spin_unlock_bh(&pf->ptp_rx_lock);
/* Log a warning if more than 2 timestamps got dropped in the same
* check. We don't want to warn about all drops because it can occur
* in normal scenarios such as PTP frames on multicast addresses we
* aren't listening to. However, administrator should know if this is
* the reason packets aren't receiving timestamps.
*/
if (cleared > 2)
dev_dbg(&pf->pdev->dev,
"Dropped %d missed RXTIME timestamp events\n",
cleared);
/* Finally, update the rx_hwtstamp_cleared counter */
pf->rx_hwtstamp_cleared += cleared;
}
/**
* i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp
* @pf: Board private structure
*
* Read the value of the Tx timestamp from the registers, convert it into a
* value consumable by the stack, and store that result into the shhwtstamps
* struct before returning it up the stack.
**/
void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
{
struct skb_shared_hwtstamps shhwtstamps;
struct i40e_hw *hw = &pf->hw;
u32 hi, lo;
u64 ns;
if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
return;
/* don't attempt to timestamp if we don't have an skb */
if (!pf->ptp_tx_skb)
return;
lo = rd32(hw, I40E_PRTTSYN_TXTIME_L);
hi = rd32(hw, I40E_PRTTSYN_TXTIME_H);
ns = (((u64)hi) << 32) | lo;
i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns);
skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps);
dev_kfree_skb_any(pf->ptp_tx_skb);
pf->ptp_tx_skb = NULL;
clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, &pf->state);
}
/**
* i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp
* @pf: Board private structure
* @skb: Particular skb to send timestamp with
* @index: Index into the receive timestamp registers for the timestamp
*
* The XL710 receives a notification in the receive descriptor with an offset
* into the set of RXTIME registers where the timestamp is for that skb. This
* function goes and fetches the receive timestamp from that offset, if a valid
* one exists. The RXTIME registers are in ns, so we must convert the result
* first.
**/
void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index)
{
u32 prttsyn_stat, hi, lo;
struct i40e_hw *hw;
u64 ns;
/* Since we cannot turn off the Rx timestamp logic if the device is
* doing Tx timestamping, check if Rx timestamping is configured.
*/
if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
return;
hw = &pf->hw;
spin_lock_bh(&pf->ptp_rx_lock);
/* Get current Rx events and update latch times */
prttsyn_stat = i40e_ptp_get_rx_events(pf);
/* TODO: Should we warn about missing Rx timestamp event? */
if (!(prttsyn_stat & BIT(index))) {
spin_unlock_bh(&pf->ptp_rx_lock);
return;
}
/* Clear the latched event since we're about to read its register */
pf->latch_event_flags &= ~BIT(index);
lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index));
hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index));
spin_unlock_bh(&pf->ptp_rx_lock);
ns = (((u64)hi) << 32) | lo;
i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns);
}
/**
* i40e_ptp_set_increment - Utility function to update clock increment rate
* @pf: Board private structure
*
* During a link change, the DMA frequency that drives the 1588 logic will
* change. In order to keep the PRTTSYN_TIME registers in units of nanoseconds,
* we must update the increment value per clock tick.
**/
void i40e_ptp_set_increment(struct i40e_pf *pf)
{
struct i40e_link_status *hw_link_info;
struct i40e_hw *hw = &pf->hw;
u64 incval;
hw_link_info = &hw->phy.link_info;
i40e_aq_get_link_info(&pf->hw, true, NULL, NULL);
switch (hw_link_info->link_speed) {
case I40E_LINK_SPEED_10GB:
incval = I40E_PTP_10GB_INCVAL;
break;
case I40E_LINK_SPEED_1GB:
incval = I40E_PTP_1GB_INCVAL;
break;
case I40E_LINK_SPEED_100MB:
dev_warn(&pf->pdev->dev,
"1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n");
incval = 0;
break;
case I40E_LINK_SPEED_40GB:
default:
incval = I40E_PTP_40GB_INCVAL;
break;
}
/* Write the new increment value into the increment register. The
* hardware will not update the clock until both registers have been
* written.
*/
wr32(hw, I40E_PRTTSYN_INC_L, (u32)incval);
wr32(hw, I40E_PRTTSYN_INC_H, (u32)(incval >> 32));
/* Update the base adjustement value. */
ACCESS_ONCE(pf->ptp_base_adj) = incval;
smp_mb(); /* Force the above update. */
}
/**
* i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping
* @pf: Board private structure
* @ifreq: ioctl data
*
* Obtain the current hardware timestamping settigs as requested. To do this,
* keep a shadow copy of the timestamp settings rather than attempting to
* deconstruct it from the registers.
**/
int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
{
struct hwtstamp_config *config = &pf->tstamp_config;
if (!(pf->flags & I40E_FLAG_PTP))
return -EOPNOTSUPP;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
}
/**
* i40e_ptp_set_timestamp_mode - setup hardware for requested timestamp mode
* @pf: Board private structure
* @config: hwtstamp settings requested or saved
*
* Control hardware registers to enter the specific mode requested by the
* user. Also used during reset path to ensure that timestamp settings are
* maintained.
*
* Note: modifies config in place, and may update the requested mode to be
* more broad if the specific filter is not directly supported.
**/
static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
struct hwtstamp_config *config)
{
struct i40e_hw *hw = &pf->hw;
u32 tsyntype, regval;
/* Reserved for future extensions. */
if (config->flags)
return -EINVAL;
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
pf->ptp_tx = false;
break;
case HWTSTAMP_TX_ON:
pf->ptp_tx = true;
break;
default:
return -ERANGE;
}
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
pf->ptp_rx = false;
/* We set the type to V1, but do not enable UDP packet
* recognition. In this way, we should be as close to
* disabling PTP Rx timestamps as possible since V1 packets
* are always UDP, since L2 packets are a V2 feature.
*/
tsyntype = I40E_PRTTSYN_CTL1_TSYNTYPE_V1;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
if (!(pf->flags & I40E_FLAG_PTP_L4_CAPABLE))
return -ERANGE;
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK |
I40E_PRTTSYN_CTL1_TSYNTYPE_V1 |
I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
if (!(pf->flags & I40E_FLAG_PTP_L4_CAPABLE))
return -ERANGE;
/* fall through */
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK |
I40E_PRTTSYN_CTL1_TSYNTYPE_V2;
if (pf->flags & I40E_FLAG_PTP_L4_CAPABLE) {
tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
} else {
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
}
break;
case HWTSTAMP_FILTER_ALL:
default:
return -ERANGE;
}
/* Clear out all 1588-related registers to clear and unlatch them. */
spin_lock_bh(&pf->ptp_rx_lock);
rd32(hw, I40E_PRTTSYN_STAT_0);
rd32(hw, I40E_PRTTSYN_TXTIME_H);
rd32(hw, I40E_PRTTSYN_RXTIME_H(0));
rd32(hw, I40E_PRTTSYN_RXTIME_H(1));
rd32(hw, I40E_PRTTSYN_RXTIME_H(2));
rd32(hw, I40E_PRTTSYN_RXTIME_H(3));
pf->latch_event_flags = 0;
spin_unlock_bh(&pf->ptp_rx_lock);
/* Enable/disable the Tx timestamp interrupt based on user input. */
regval = rd32(hw, I40E_PRTTSYN_CTL0);
if (pf->ptp_tx)
regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK;
else
regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK;
wr32(hw, I40E_PRTTSYN_CTL0, regval);
regval = rd32(hw, I40E_PFINT_ICR0_ENA);
if (pf->ptp_tx)
regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
else
regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
wr32(hw, I40E_PFINT_ICR0_ENA, regval);
/* Although there is no simple on/off switch for Rx, we "disable" Rx
* timestamps by setting to V1 only mode and clear the UDP
* recognition. This ought to disable all PTP Rx timestamps as V1
* packets are always over UDP. Note that software is configured to
* ignore Rx timestamps via the pf->ptp_rx flag.
*/
regval = rd32(hw, I40E_PRTTSYN_CTL1);
/* clear everything but the enable bit */
regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
/* now enable bits for desired Rx timestamps */
regval |= tsyntype;
wr32(hw, I40E_PRTTSYN_CTL1, regval);
return 0;
}
/**
* i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping
* @pf: Board private structure
* @ifreq: ioctl data
*
* Respond to the user filter requests and make the appropriate hardware
* changes here. The XL710 cannot support splitting of the Tx/Rx timestamping
* logic, so keep track in software of whether to indicate these timestamps
* or not.
*
* It is permissible to "upgrade" the user request to a broader filter, as long
* as the user receives the timestamps they care about and the user is notified
* the filter has been broadened.
**/
int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
{
struct hwtstamp_config config;
int err;
if (!(pf->flags & I40E_FLAG_PTP))
return -EOPNOTSUPP;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
err = i40e_ptp_set_timestamp_mode(pf, &config);
if (err)
return err;
/* save these settings for future reference */
pf->tstamp_config = config;
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
/**
* i40e_ptp_create_clock - Create PTP clock device for userspace
* @pf: Board private structure
*
* This function creates a new PTP clock device. It only creates one if we
* don't already have one, so it is safe to call. Will return error if it
* can't create one, but success if we already have a device. Should be used
* by i40e_ptp_init to create clock initially, and prevent global resets from
* creating new clock devices.
**/
static long i40e_ptp_create_clock(struct i40e_pf *pf)
{
/* no need to create a clock device if we already have one */
if (!IS_ERR_OR_NULL(pf->ptp_clock))
return 0;
strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name));
pf->ptp_caps.owner = THIS_MODULE;
pf->ptp_caps.max_adj = 999999999;
pf->ptp_caps.n_ext_ts = 0;
pf->ptp_caps.pps = 0;
pf->ptp_caps.adjfreq = i40e_ptp_adjfreq;
pf->ptp_caps.adjtime = i40e_ptp_adjtime;
#ifdef HAVE_PTP_CLOCK_INFO_GETTIME64
pf->ptp_caps.gettime64 = i40e_ptp_gettime64;
pf->ptp_caps.settime64 = i40e_ptp_settime64;
#else
pf->ptp_caps.gettime = i40e_ptp_gettime;
pf->ptp_caps.settime = i40e_ptp_settime;
#endif
pf->ptp_caps.enable = i40e_ptp_feature_enable;
/* Attempt to register the clock before enabling the hardware. */
pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev);
if (IS_ERR(pf->ptp_clock))
return PTR_ERR(pf->ptp_clock);
/* clear the hwtstamp settings here during clock create, instead of
* during regular init, so that we can maintain settings across a
* reset or suspend.
*/
pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
return 0;
}
/**
* i40e_ptp_init - Initialize the 1588 support after device probe or reset
* @pf: Board private structure
*
* This function sets device up for 1588 support. The first time it is run, it
* will create a PHC clock device. It does not create a clock device if one
* already exists. It also reconfigures the device after a reset.
**/
void i40e_ptp_init(struct i40e_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
u32 pf_id;
long err;
/* Only one PF is assigned to control 1588 logic per port. Do not
* enable any support for PFs not assigned via PRTTSYN_CTL0.PF_ID
*/
pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >>
I40E_PRTTSYN_CTL0_PF_ID_SHIFT;
if (hw->pf_id != pf_id) {
pf->flags &= ~I40E_FLAG_PTP;
dev_info(&pf->pdev->dev, "PTP not supported on this device\n");
return;
}
mutex_init(&pf->tmreg_lock);
spin_lock_init(&pf->ptp_rx_lock);
/* ensure we have a clock device */
err = i40e_ptp_create_clock(pf);
if (err) {
pf->ptp_clock = NULL;
dev_err(&pf->pdev->dev,
"PTP clock register failed: %ld\n", err);
} else {
struct timespec64 ts;
u32 regval;
if (pf->hw.debug_mask & I40E_DEBUG_LAN)
dev_info(&pf->pdev->dev, "PHC enabled\n");
pf->flags |= I40E_FLAG_PTP;
/* Ensure the clocks are running. */
regval = rd32(hw, I40E_PRTTSYN_CTL0);
regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK;
wr32(hw, I40E_PRTTSYN_CTL0, regval);
regval = rd32(hw, I40E_PRTTSYN_CTL1);
regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
wr32(hw, I40E_PRTTSYN_CTL1, regval);
/* Set the increment value per clock tick. */
i40e_ptp_set_increment(pf);
/* reset timestamping mode */
i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config);
/* Set the clock value. */
ts = ktime_to_timespec64(ktime_get_real());
i40e_ptp_settime64(&pf->ptp_caps, &ts);
}
}
/**
* i40e_ptp_stop - Disable the driver/hardware support and unregister the PHC
* @pf: Board private structure
*
* This function handles the cleanup work required from the initialization by
* clearing out the important information and unregistering the PHC.
**/
void i40e_ptp_stop(struct i40e_pf *pf)
{
pf->flags &= ~I40E_FLAG_PTP;
pf->ptp_tx = false;
pf->ptp_rx = false;
if (pf->ptp_tx_skb) {
dev_kfree_skb_any(pf->ptp_tx_skb);
pf->ptp_tx_skb = NULL;
clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, &pf->state);
}
if (pf->ptp_clock) {
ptp_clock_unregister(pf->ptp_clock);
pf->ptp_clock = NULL;
dev_info(&pf->pdev->dev, "removed PHC from %s\n",
pf->vsi[pf->lan_vsi]->netdev->name);
}
}
#endif /* HAVE_PTP_1588_CLOCK */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_STATUS_H_
#define _I40E_STATUS_H_
/* Error Codes */
enum i40e_status_code {
I40E_SUCCESS = 0,
I40E_ERR_NVM = -1,
I40E_ERR_NVM_CHECKSUM = -2,
I40E_ERR_PHY = -3,
I40E_ERR_CONFIG = -4,
I40E_ERR_PARAM = -5,
I40E_ERR_MAC_TYPE = -6,
I40E_ERR_UNKNOWN_PHY = -7,
I40E_ERR_LINK_SETUP = -8,
I40E_ERR_ADAPTER_STOPPED = -9,
I40E_ERR_INVALID_MAC_ADDR = -10,
I40E_ERR_DEVICE_NOT_SUPPORTED = -11,
I40E_ERR_MASTER_REQUESTS_PENDING = -12,
I40E_ERR_INVALID_LINK_SETTINGS = -13,
I40E_ERR_AUTONEG_NOT_COMPLETE = -14,
I40E_ERR_RESET_FAILED = -15,
I40E_ERR_SWFW_SYNC = -16,
I40E_ERR_NO_AVAILABLE_VSI = -17,
I40E_ERR_NO_MEMORY = -18,
I40E_ERR_BAD_PTR = -19,
I40E_ERR_RING_FULL = -20,
I40E_ERR_INVALID_PD_ID = -21,
I40E_ERR_INVALID_QP_ID = -22,
I40E_ERR_INVALID_CQ_ID = -23,
I40E_ERR_INVALID_CEQ_ID = -24,
I40E_ERR_INVALID_AEQ_ID = -25,
I40E_ERR_INVALID_SIZE = -26,
I40E_ERR_INVALID_ARP_INDEX = -27,
I40E_ERR_INVALID_FPM_FUNC_ID = -28,
I40E_ERR_QP_INVALID_MSG_SIZE = -29,
I40E_ERR_QP_TOOMANY_WRS_POSTED = -30,
I40E_ERR_INVALID_FRAG_COUNT = -31,
I40E_ERR_QUEUE_EMPTY = -32,
I40E_ERR_INVALID_ALIGNMENT = -33,
I40E_ERR_FLUSHED_QUEUE = -34,
I40E_ERR_INVALID_PUSH_PAGE_INDEX = -35,
I40E_ERR_INVALID_IMM_DATA_SIZE = -36,
I40E_ERR_TIMEOUT = -37,
I40E_ERR_OPCODE_MISMATCH = -38,
I40E_ERR_CQP_COMPL_ERROR = -39,
I40E_ERR_INVALID_VF_ID = -40,
I40E_ERR_INVALID_HMCFN_ID = -41,
I40E_ERR_BACKING_PAGE_ERROR = -42,
I40E_ERR_NO_PBLCHUNKS_AVAILABLE = -43,
I40E_ERR_INVALID_PBLE_INDEX = -44,
I40E_ERR_INVALID_SD_INDEX = -45,
I40E_ERR_INVALID_PAGE_DESC_INDEX = -46,
I40E_ERR_INVALID_SD_TYPE = -47,
I40E_ERR_MEMCPY_FAILED = -48,
I40E_ERR_INVALID_HMC_OBJ_INDEX = -49,
I40E_ERR_INVALID_HMC_OBJ_COUNT = -50,
I40E_ERR_INVALID_SRQ_ARM_LIMIT = -51,
I40E_ERR_SRQ_ENABLED = -52,
I40E_ERR_ADMIN_QUEUE_ERROR = -53,
I40E_ERR_ADMIN_QUEUE_TIMEOUT = -54,
I40E_ERR_BUF_TOO_SHORT = -55,
I40E_ERR_ADMIN_QUEUE_FULL = -56,
I40E_ERR_ADMIN_QUEUE_NO_WORK = -57,
I40E_ERR_BAD_IWARP_CQE = -58,
I40E_ERR_NVM_BLANK_MODE = -59,
I40E_ERR_NOT_IMPLEMENTED = -60,
I40E_ERR_PE_DOORBELL_NOT_ENABLED = -61,
I40E_ERR_DIAG_TEST_FAILED = -62,
I40E_ERR_NOT_READY = -63,
I40E_NOT_SUPPORTED = -64,
I40E_ERR_FIRMWARE_API_VERSION = -65,
};
#endif /* _I40E_STATUS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,508 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_TXRX_H_
#define _I40E_TXRX_H_
/* Interrupt Throttling and Rate Limiting Goodies */
#define I40E_MAX_ITR 0x0FF0 /* reg uses 2 usec resolution */
#define I40E_MIN_ITR 0x0001 /* reg uses 2 usec resolution */
#define I40E_ITR_100K 0x0005
#define I40E_ITR_50K 0x000A
#define I40E_ITR_20K 0x0019
#define I40E_ITR_18K 0x001B
#define I40E_ITR_8K 0x003E
#define I40E_ITR_4K 0x007A
#define I40E_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
#define I40E_ITR_RX_DEF I40E_ITR_20K
#define I40E_ITR_TX_DEF I40E_ITR_20K
#define I40E_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
#define I40E_MIN_INT_RATE 250 /* ~= 1000000 / (I40E_MAX_ITR * 2) */
#define I40E_MAX_INT_RATE 500000 /* == 1000000 / (I40E_MIN_ITR * 2) */
#define I40E_DEFAULT_IRQ_WORK 256
#define ITR_TO_REG(setting) ((setting & ~I40E_ITR_DYNAMIC) >> 1)
#define ITR_IS_DYNAMIC(setting) (!!(setting & I40E_ITR_DYNAMIC))
#define ITR_REG_TO_USEC(itr_reg) (itr_reg << 1)
/* 0x40 is the enable bit for interrupt rate limiting, and must be set if
* the value of the rate limit is non-zero
*/
#define INTRL_ENA BIT(6)
#define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2)
/**
* i40e_intrl_usec_to_reg - convert interrupt rate limit to register
* @intrl: interrupt rate limit to convert
*
* This function converts a decimal interrupt rate limit to the appropriate
* register format expected by the firmware when setting interrupt rate limit.
*/
static inline u16 i40e_intrl_usec_to_reg(int intrl)
{
if (intrl >> 2)
return ((intrl >> 2) | INTRL_ENA);
else
return 0;
}
#define I40E_INTRL_8K 125 /* 8000 ints/sec */
#define I40E_INTRL_62K 16 /* 62500 ints/sec */
#define I40E_INTRL_83K 12 /* 83333 ints/sec */
#define I40E_QUEUE_END_OF_LIST 0x7FF
/* this enum matches hardware bits and is meant to be used by DYN_CTLN
* registers and QINT registers or more generally anywhere in the manual
* mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any
* register but instead is a special value meaning "don't update" ITR0/1/2.
*/
enum i40e_dyn_idx_t {
I40E_IDX_ITR0 = 0,
I40E_IDX_ITR1 = 1,
I40E_IDX_ITR2 = 2,
I40E_ITR_NONE = 3 /* ITR_NONE must not be used as an index */
};
/* these are indexes into ITRN registers */
#define I40E_RX_ITR I40E_IDX_ITR0
#define I40E_TX_ITR I40E_IDX_ITR1
#define I40E_PE_ITR I40E_IDX_ITR2
/* Supported RSS offloads */
#define I40E_DEFAULT_RSS_HENA ( \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \
BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD))
#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
#define i40e_pf_get_default_rss_hena(pf) \
(((pf)->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \
I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA)
/* Supported Rx Buffer Sizes (a multiple of 128) */
#define I40E_RXBUFFER_256 256
#define I40E_RXBUFFER_2048 2048
#define I40E_RXBUFFER_3072 3072 /* For FCoE MTU of 2158 */
#define I40E_RXBUFFER_4096 4096
#define I40E_RXBUFFER_8192 8192
#define I40E_MAX_RXBUFFER 9728 /* largest size for single descriptor */
/* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we
* reserve 2 more, and skb_shared_info adds an additional 384 bytes more,
* this adds up to 512 bytes of extra data meaning the smallest allocation
* we could have is 1K.
* i.e. RXBUFFER_256 --> 960 byte skb (size-1024 slab)
* i.e. RXBUFFER_512 --> 1216 byte skb (size-2048 slab)
*/
#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
#define i40e_rx_desc i40e_32byte_rx_desc
/**
* i40e_test_staterr - tests bits in Rx descriptor status and error fields
* @rx_desc: pointer to receive descriptor (in le64 format)
* @stat_err_bits: value to mask
*
* This function does some fast chicanery in order to return the
* value of the mask which is really only used for boolean tests.
* The status_error_len doesn't need to be shifted because it begins
* at offset zero.
*/
static inline bool i40e_test_staterr(union i40e_rx_desc *rx_desc,
const u64 stat_err_bits)
{
return !!(rx_desc->wb.qword1.status_error_len &
cpu_to_le64(stat_err_bits));
}
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define I40E_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define I40E_RX_INCREMENT(r, i) \
do { \
(i)++; \
if ((i) == (r)->count) \
i = 0; \
r->next_to_clean = i; \
} while (0)
#define I40E_RX_NEXT_DESC(r, i, n) \
do { \
(i)++; \
if ((i) == (r)->count) \
i = 0; \
(n) = I40E_RX_DESC((r), (i)); \
} while (0)
#define I40E_RX_NEXT_DESC_PREFETCH(r, i, n) \
do { \
I40E_RX_NEXT_DESC((r), (i), (n)); \
prefetch((n)); \
} while (0)
#define I40E_MAX_BUFFER_TXD 8
#define I40E_MIN_TX_LEN 17
/* The size limit for a transmit buffer in a descriptor is (16K - 1).
* In order to align with the read requests we will align the value to
* the nearest 4K which represents our maximum read request size.
*/
#define I40E_MAX_READ_REQ_SIZE 4096
#define I40E_MAX_DATA_PER_TXD (16 * 1024 - 1)
#define I40E_MAX_DATA_PER_TXD_ALIGNED \
(I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1))
/**
* i40e_txd_use_count - estimate the number of descriptors needed for Tx
* @size: transmit request size in bytes
*
* Due to hardware alignment restrictions (4K alignment), we need to
* assume that we can have no more than 12K of data per descriptor, even
* though each descriptor can take up to 16K - 1 bytes of aligned memory.
* Thus, we need to divide by 12K. But division is slow! Instead,
* we decompose the operation into shifts and one relatively cheap
* multiply operation.
*
* To divide by 12K, we first divide by 4K, then divide by 3:
* To divide by 4K, shift right by 12 bits
* To divide by 3, multiply by 85, then divide by 256
* (Divide by 256 is done by shifting right by 8 bits)
* Finally, we add one to round up. Because 256 isn't an exact multiple of
* 3, we'll underestimate near each multiple of 12K. This is actually more
* accurate as we have 4K - 1 of wiggle room that we can fit into the last
* segment. For our purposes this is accurate out to 1M which is orders of
* magnitude greater than our largest possible GSO size.
*
* This would then be implemented as:
* return (((size >> 12) * 85) >> 8) + 1;
*
* Since multiplication and division are commutative, we can reorder
* operations into:
* return ((size * 85) >> 20) + 1;
*/
static inline unsigned int i40e_txd_use_count(unsigned int size)
{
return ((size * 85) >> 20) + 1;
}
/* Tx Descriptors needed, worst case */
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
#define I40E_MIN_DESC_PENDING 4
#define I40E_TX_FLAGS_HW_VLAN BIT(1)
#define I40E_TX_FLAGS_SW_VLAN BIT(2)
#define I40E_TX_FLAGS_TSO BIT(3)
#define I40E_TX_FLAGS_IPV4 BIT(4)
#define I40E_TX_FLAGS_IPV6 BIT(5)
#define I40E_TX_FLAGS_FCCRC BIT(6)
#define I40E_TX_FLAGS_FSO BIT(7)
#ifdef HAVE_PTP_1588_CLOCK
#define I40E_TX_FLAGS_TSYN BIT(8)
#endif /* HAVE_PTP_1588_CLOCK */
#define I40E_TX_FLAGS_FD_SB BIT(9)
#define I40E_TX_FLAGS_TUNNEL BIT(10)
#define I40E_TX_FLAGS_VLAN_MASK 0xffff0000
#define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define I40E_TX_FLAGS_VLAN_SHIFT 16
struct i40e_tx_buffer {
struct i40e_tx_desc *next_to_watch;
union {
struct sk_buff *skb;
void *raw_buf;
};
unsigned int bytecount;
unsigned short gso_segs;
DEFINE_DMA_UNMAP_ADDR(dma);
DEFINE_DMA_UNMAP_LEN(len);
u32 tx_flags;
};
struct i40e_rx_buffer {
dma_addr_t dma;
struct page *page;
unsigned int page_offset;
};
struct i40e_queue_stats {
u64 packets;
u64 bytes;
};
struct i40e_tx_queue_stats {
u64 restart_queue;
u64 tx_busy;
u64 tx_done_old;
u64 tx_linearize;
u64 tx_force_wb;
u64 tx_lost_interrupt;
};
struct i40e_rx_queue_stats {
u64 non_eop_descs;
u64 alloc_page_failed;
u64 alloc_buff_failed;
u64 page_reuse_count;
u64 realloc_count;
};
enum i40e_ring_state_t {
__I40E_TX_FDIR_INIT_DONE,
__I40E_TX_XPS_INIT_DONE,
};
/* some useful defines for virtchannel interface, which
* is the only remaining user of header split
*/
#define I40E_RX_DTYPE_NO_SPLIT 0
#define I40E_RX_DTYPE_HEADER_SPLIT 1
#define I40E_RX_DTYPE_SPLIT_ALWAYS 2
#define I40E_RX_SPLIT_L2 0x1
#define I40E_RX_SPLIT_IP 0x2
#define I40E_RX_SPLIT_TCP_UDP 0x4
#define I40E_RX_SPLIT_SCTP 0x8
/* struct that defines a descriptor ring, associated with a VSI */
struct i40e_ring {
struct i40e_ring *next; /* pointer to next ring in q_vector */
void *desc; /* Descriptor ring memory */
struct device *dev; /* Used for DMA mapping */
struct net_device *netdev; /* netdev ring maps to */
union {
struct i40e_tx_buffer *tx_bi;
struct i40e_rx_buffer *rx_bi;
};
unsigned long state;
u16 queue_index; /* Queue number of ring */
u8 dcb_tc; /* Traffic class of ring */
u8 __iomem *tail;
/* high bit set means dynamic, use accessor routines to read/write.
* hardware only supports 2us resolution for the ITR registers.
* these values always store the USER setting, and must be converted
* before programming to a register.
*/
u16 rx_itr_setting;
u16 tx_itr_setting;
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
u16 rx_buf_len;
/* used in interrupt processing */
u16 next_to_use;
u16 next_to_clean;
u8 atr_sample_rate;
u8 atr_count;
bool ring_active; /* is ring online or not */
bool arm_wb; /* do something to arm write back */
u8 packet_stride;
u16 flags;
#define I40E_TXR_FLAGS_WB_ON_ITR BIT(0)
/* stats structs */
struct i40e_queue_stats stats;
#ifdef HAVE_NDO_GET_STATS64
struct u64_stats_sync syncp;
#endif
union {
struct i40e_tx_queue_stats tx_stats;
struct i40e_rx_queue_stats rx_stats;
};
unsigned int size; /* length of descriptor ring in bytes */
dma_addr_t dma; /* physical address of ring */
struct i40e_vsi *vsi; /* Backreference to associated VSI */
struct i40e_q_vector *q_vector; /* Backreference to associated vector */
struct rcu_head rcu; /* to avoid race on free */
u16 next_to_alloc;
struct sk_buff *skb; /* When i40e_clean_rx_ring_irq() must
* return before it sees the EOP for
* the current packet, we save that skb
* here and resume receiving this
* packet the next time
* i40e_clean_rx_ring_irq() is called
* for this ring.
*/
} ____cacheline_internodealigned_in_smp;
enum i40e_latency_range {
I40E_LOWEST_LATENCY = 0,
I40E_LOW_LATENCY = 1,
I40E_BULK_LATENCY = 2,
I40E_ULTRA_LATENCY = 3,
};
struct i40e_ring_container {
/* array of pointers to rings */
struct i40e_ring *ring;
unsigned int total_bytes; /* total bytes processed this int */
unsigned int total_packets; /* total packets processed this int */
u16 count;
enum i40e_latency_range latency_range;
u16 itr;
};
/* iterator for handling rings in ring container */
#define i40e_for_each_ring(pos, head) \
for (pos = (head).ring; pos != NULL; pos = pos->next)
bool i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
#if !defined(HAVE_NET_DEVICE_OPS) && defined(HAVE_NETDEV_SELECT_QUEUE)
extern u16 i40e_lan_select_queue(struct net_device *netdev,
struct sk_buff *skb);
#endif
void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);
int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring);
void i40e_free_tx_resources(struct i40e_ring *tx_ring);
void i40e_free_rx_resources(struct i40e_ring *rx_ring);
int i40e_napi_poll(struct napi_struct *napi, int budget);
#ifdef I40E_FCOE
void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
struct i40e_tx_buffer *first, u32 tx_flags,
const u8 hdr_len, u32 td_cmd, u32 td_offset);
int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
struct i40e_ring *tx_ring, u32 *flags);
#endif
void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
bool __i40e_chk_linearize(struct sk_buff *skb);
/**
* i40e_get_head - Retrieve head from head writeback
* @tx_ring: tx ring to fetch head of
*
* Returns value of Tx ring head based on value stored
* in head write-back location
**/
static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
{
void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
return le32_to_cpu(*(volatile __le32 *)head);
}
/**
* i40e_rx_is_fcoe - returns true if the rx packet type is FCoE
* @ptype: the packet type field from rx descriptor write-back
**/
static inline bool i40e_rx_is_fcoe(u16 ptype)
{
return (ptype >= I40E_RX_PTYPE_L2_FCOE_PAY3) &&
(ptype <= I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER);
}
/**
* i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
* @skb: send buffer
* @tx_ring: ring to send buffer on
*
* Returns number of data descriptors needed for this skb. Returns 0 to indicate
* there is not enough descriptors available in this ring since we need at least
* one descriptor.
**/
static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
{
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
int count = 0, size = skb_headlen(skb);
for (;;) {
count += i40e_txd_use_count(size);
if (!nr_frags--)
break;
size = skb_frag_size(frag++);
}
return count;
}
/**
* i40e_maybe_stop_tx - 1st level check for Tx stop conditions
* @tx_ring: the ring to be checked
* @size: the size buffer we want to assure is available
*
* Returns 0 if stop is not needed
**/
static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
{
if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
return 0;
return __i40e_maybe_stop_tx(tx_ring, size);
}
/**
* i40e_chk_linearize - Check if there are more than 8 fragments per packet
* @skb: send buffer
* @count: number of buffers used
*
* Note: Our HW can't scatter-gather more than 8 fragments to build
* a packet on the wire and so we need to figure out the cases where we
* need to linearize the skb.
**/
static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
{
/* Both TSO and single send will work if count is less than 8 */
if (likely(count < I40E_MAX_BUFFER_TXD))
return false;
if (skb_is_gso(skb))
return __i40e_chk_linearize(skb);
/* we can support up to 8 data buffers for a single send */
return count != I40E_MAX_BUFFER_TXD;
}
/**
* txring_txq - Find the netdev Tx ring based on the i40e Tx ring
* @ring: Tx ring to find the netdev equivalent of
**/
static inline struct netdev_queue *txring_txq(const struct i40e_ring *ring)
{
return netdev_get_tx_queue(ring->netdev, ring->queue_index);
}
#endif /* _I40E_TXRX_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,445 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_VIRTCHNL_H_
#define _I40E_VIRTCHNL_H_
#include "i40e_type.h"
/* Description:
* This header file describes the VF-PF communication protocol used
* by the various i40e drivers.
*
* Admin queue buffer usage:
* desc->opcode is always i40e_aqc_opc_send_msg_to_pf
* flags, retval, datalen, and data addr are all used normally.
* Firmware copies the cookie fields when sending messages between the PF and
* VF, but uses all other fields internally. Due to this limitation, we
* must send all messages as "indirect", i.e. using an external buffer.
*
* All the vsi indexes are relative to the VF. Each VF can have maximum of
* three VSIs. All the queue indexes are relative to the VSI. Each VF can
* have a maximum of sixteen queues for all of its VSIs.
*
* The PF is required to return a status code in v_retval for all messages
* except RESET_VF, which does not require any response. The return value is of
* i40e_status_code type, defined in the i40e_type.h.
*
* In general, VF driver initialization should roughly follow the order of these
* opcodes. The VF driver must first validate the API version of the PF driver,
* then request a reset, then get resources, then configure queues and
* interrupts. After these operations are complete, the VF driver may start
* its queues, optionally add MAC and VLAN filters, and process traffic.
*/
/* Opcodes for VF-PF communication. These are placed in the v_opcode field
* of the virtchnl_msg structure.
*/
enum i40e_virtchnl_ops {
/* The PF sends status change events to VFs using
* the I40E_VIRTCHNL_OP_EVENT opcode.
* VFs send requests to the PF using the other ops.
*/
I40E_VIRTCHNL_OP_UNKNOWN = 0,
I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */
I40E_VIRTCHNL_OP_RESET_VF = 2,
I40E_VIRTCHNL_OP_GET_VF_RESOURCES = 3,
I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE = 4,
I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE = 5,
I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES = 6,
I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP = 7,
I40E_VIRTCHNL_OP_ENABLE_QUEUES = 8,
I40E_VIRTCHNL_OP_DISABLE_QUEUES = 9,
I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS = 10,
I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS = 11,
I40E_VIRTCHNL_OP_ADD_VLAN = 12,
I40E_VIRTCHNL_OP_DEL_VLAN = 13,
I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14,
I40E_VIRTCHNL_OP_GET_STATS = 15,
I40E_VIRTCHNL_OP_FCOE = 16,
I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */
I40E_VIRTCHNL_OP_IWARP = 20,
I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21,
I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22,
I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23,
I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24,
I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25,
I40E_VIRTCHNL_OP_SET_RSS_HENA = 26,
};
/* Virtual channel message descriptor. This overlays the admin queue
* descriptor. All other data is passed in external buffers.
*/
struct i40e_virtchnl_msg {
u8 pad[8]; /* AQ flags/opcode/len/retval fields */
enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */
i40e_status v_retval; /* ditto for desc->retval */
u32 vfid; /* used by PF when sending to VF */
};
/* Message descriptions and data structures.*/
/* I40E_VIRTCHNL_OP_VERSION
* VF posts its version number to the PF. PF responds with its version number
* in the same format, along with a return code.
* Reply from PF has its major/minor versions also in param0 and param1.
* If there is a major version mismatch, then the VF cannot operate.
* If there is a minor version mismatch, then the VF can operate but should
* add a warning to the system log.
*
* This enum element MUST always be specified as == 1, regardless of other
* changes in the API. The PF must always respond to this message without
* error regardless of version mismatch.
*/
#define I40E_VIRTCHNL_VERSION_MAJOR 1
#define I40E_VIRTCHNL_VERSION_MINOR 1
#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0
struct i40e_virtchnl_version_info {
u32 major;
u32 minor;
};
/* I40E_VIRTCHNL_OP_RESET_VF
* VF sends this request to PF with no parameters
* PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register
* until reset completion is indicated. The admin queue must be reinitialized
* after this operation.
*
* When reset is complete, PF must ensure that all queues in all VSIs associated
* with the VF are stopped, all queue configurations in the HMC are set to 0,
* and all MAC and VLAN filters (except the default MAC address) on all VSIs
* are cleared.
*/
/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES
* Version 1.0 VF sends this request to PF with no parameters
* Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities
* PF responds with an indirect message containing
* i40e_virtchnl_vf_resource and one or more
* i40e_virtchnl_vsi_resource structures.
*/
struct i40e_virtchnl_vsi_resource {
u16 vsi_id;
u16 num_queue_pairs;
enum i40e_vsi_type vsi_type;
u16 qset_handle;
u8 default_mac_addr[ETH_ALEN];
};
/* VF offload flags */
#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001
#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002
#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004
#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008
#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010
#define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020
#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000
#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000
#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 0x00040000
#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF 0X00080000
#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM 0X00100000
#define I40E_VF_BASE_MODE_OFFLOADS (I40E_VIRTCHNL_VF_OFFLOAD_L2 | \
I40E_VIRTCHNL_VF_OFFLOAD_VLAN | \
I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF)
struct i40e_virtchnl_vf_resource {
u16 num_vsis;
u16 num_queue_pairs;
u16 max_vectors;
u16 max_mtu;
u32 vf_offload_flags;
u32 rss_key_size;
u32 rss_lut_size;
struct i40e_virtchnl_vsi_resource vsi_res[1];
};
/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE
* VF sends this message to set up parameters for one TX queue.
* External data buffer contains one instance of i40e_virtchnl_txq_info.
* PF configures requested queue and returns a status code.
*/
/* Tx queue config info */
struct i40e_virtchnl_txq_info {
u16 vsi_id;
u16 queue_id;
u16 ring_len; /* number of descriptors, multiple of 8 */
u16 headwb_enabled;
u64 dma_ring_addr;
u64 dma_headwb_addr;
};
/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE
* VF sends this message to set up parameters for one RX queue.
* External data buffer contains one instance of i40e_virtchnl_rxq_info.
* PF configures requested queue and returns a status code.
*/
/* Rx queue config info */
struct i40e_virtchnl_rxq_info {
u16 vsi_id;
u16 queue_id;
u32 ring_len; /* number of descriptors, multiple of 32 */
u16 hdr_size;
u16 splithdr_enabled;
u32 databuffer_size;
u32 max_pkt_size;
u64 dma_ring_addr;
enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos;
};
/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES
* VF sends this message to set parameters for all active TX and RX queues
* associated with the specified VSI.
* PF configures queues and returns status.
* If the number of queues specified is greater than the number of queues
* associated with the VSI, an error is returned and no queues are configured.
*/
struct i40e_virtchnl_queue_pair_info {
/* NOTE: vsi_id and queue_id should be identical for both queues. */
struct i40e_virtchnl_txq_info txq;
struct i40e_virtchnl_rxq_info rxq;
};
struct i40e_virtchnl_vsi_queue_config_info {
u16 vsi_id;
u16 num_queue_pairs;
struct i40e_virtchnl_queue_pair_info qpair[1];
};
/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP
* VF uses this message to map vectors to queues.
* The rxq_map and txq_map fields are bitmaps used to indicate which queues
* are to be associated with the specified vector.
* The "other" causes are always mapped to vector 0.
* PF configures interrupt mapping and returns status.
*/
struct i40e_virtchnl_vector_map {
u16 vsi_id;
u16 vector_id;
u16 rxq_map;
u16 txq_map;
u16 rxitr_idx;
u16 txitr_idx;
};
struct i40e_virtchnl_irq_map_info {
u16 num_vectors;
struct i40e_virtchnl_vector_map vecmap[1];
};
/* I40E_VIRTCHNL_OP_ENABLE_QUEUES
* I40E_VIRTCHNL_OP_DISABLE_QUEUES
* VF sends these message to enable or disable TX/RX queue pairs.
* The queues fields are bitmaps indicating which queues to act upon.
* (Currently, we only support 16 queues per VF, but we make the field
* u32 to allow for expansion.)
* PF performs requested action and returns status.
*/
struct i40e_virtchnl_queue_select {
u16 vsi_id;
u16 pad;
u32 rx_queues;
u32 tx_queues;
};
/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS
* VF sends this message in order to add one or more unicast or multicast
* address filters for the specified VSI.
* PF adds the filters and returns status.
*/
/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS
* VF sends this message in order to remove one or more unicast or multicast
* filters for the specified VSI.
* PF removes the filters and returns status.
*/
struct i40e_virtchnl_ether_addr {
u8 addr[ETH_ALEN];
u8 pad[2];
};
struct i40e_virtchnl_ether_addr_list {
u16 vsi_id;
u16 num_elements;
struct i40e_virtchnl_ether_addr list[1];
};
/* I40E_VIRTCHNL_OP_ADD_VLAN
* VF sends this message to add one or more VLAN tag filters for receives.
* PF adds the filters and returns status.
* If a port VLAN is configured by the PF, this operation will return an
* error to the VF.
*/
/* I40E_VIRTCHNL_OP_DEL_VLAN
* VF sends this message to remove one or more VLAN tag filters for receives.
* PF removes the filters and returns status.
* If a port VLAN is configured by the PF, this operation will return an
* error to the VF.
*/
struct i40e_virtchnl_vlan_filter_list {
u16 vsi_id;
u16 num_elements;
u16 vlan_id[1];
};
/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
* VF sends VSI id and flags.
* PF returns status code in retval.
* Note: we assume that broadcast accept mode is always enabled.
*/
struct i40e_virtchnl_promisc_info {
u16 vsi_id;
u16 flags;
};
#define I40E_FLAG_VF_UNICAST_PROMISC 0x00000001
#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002
/* I40E_VIRTCHNL_OP_GET_STATS
* VF sends this message to request stats for the selected VSI. VF uses
* the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id
* field is ignored by the PF.
*
* PF replies with struct i40e_eth_stats in an external buffer.
*/
/* I40E_VIRTCHNL_OP_CONFIG_RSS_KEY
* I40E_VIRTCHNL_OP_CONFIG_RSS_LUT
* VF sends these messages to configure RSS. Only supported if both PF
* and VF drivers set the I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF bit during
* configuration negotiation. If this is the case, then the rss fields in
* the vf resource struct are valid.
* Both the key and LUT are initialized to 0 by the PF, meaning that
* RSS is effectively disabled until set up by the VF.
*/
struct i40e_virtchnl_rss_key {
u16 vsi_id;
u16 key_len;
u8 key[1]; /* RSS hash key, packed bytes */
};
struct i40e_virtchnl_rss_lut {
u16 vsi_id;
u16 lut_entries;
u8 lut[1]; /* RSS lookup table*/
};
/* I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS
* I40E_VIRTCHNL_OP_SET_RSS_HENA
* VF sends these messages to get and set the hash filter enable bits for RSS.
* By default, the PF sets these to all possible traffic types that the
* hardware supports. The VF can query this value if it wants to change the
* traffic types that are hashed by the hardware.
* Traffic types are defined in the i40e_filter_pctype enum in i40e_type.h
*/
struct i40e_virtchnl_rss_hena {
u64 hena;
};
/* I40E_VIRTCHNL_OP_EVENT
* PF sends this message to inform the VF driver of events that may affect it.
* No direct response is expected from the VF, though it may generate other
* messages in response to this one.
*/
enum i40e_virtchnl_event_codes {
I40E_VIRTCHNL_EVENT_UNKNOWN = 0,
I40E_VIRTCHNL_EVENT_LINK_CHANGE,
I40E_VIRTCHNL_EVENT_RESET_IMPENDING,
I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE,
};
#define I40E_PF_EVENT_SEVERITY_INFO 0
#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM 255
struct i40e_virtchnl_pf_event {
enum i40e_virtchnl_event_codes event;
union {
struct {
enum i40e_aq_link_speed link_speed;
bool link_status;
} link_event;
} event_data;
int severity;
};
/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP
* VF uses this message to request PF to map IWARP vectors to IWARP queues.
* The request for this originates from the VF IWARP driver through
* a client interface between VF LAN and VF IWARP driver.
* A vector could have an AEQ and CEQ attached to it although
* there is a single AEQ per VF IWARP instance in which case
* most vectors will have an INVALID_IDX for aeq and valid idx for ceq.
* There will never be a case where there will be multiple CEQs attached
* to a single vector.
* PF configures interrupt mapping and returns status.
*/
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
* In order for us to keep the interface simple, SW will define a
* unique type value for AEQ.
*/
#define I40E_QUEUE_TYPE_PE_AEQ 0x80
#define I40E_QUEUE_INVALID_IDX 0xFFFF
struct i40e_virtchnl_iwarp_qv_info {
u32 v_idx; /* msix_vector */
u16 ceq_idx;
u16 aeq_idx;
u8 itr_idx;
};
struct i40e_virtchnl_iwarp_qvlist_info {
u32 num_vectors;
struct i40e_virtchnl_iwarp_qv_info qv_info[1];
};
/* VF reset states - these are written into the RSTAT register:
* I40E_VFGEN_RSTAT1 on the PF
* I40E_VFGEN_RSTAT on the VF
* When the PF initiates a reset, it writes 0
* When the reset is complete, it writes 1
* When the PF detects that the VF has recovered, it writes 2
* VF checks this register periodically to determine if a reset has occurred,
* then polls it to know when the reset is complete.
* If either the PF or VF reads the register while the hardware
* is in a reset state, it will return DEADBEEF, which, when masked
* will result in 3.
*/
enum i40e_vfr_states {
I40E_VFR_INPROGRESS = 0,
I40E_VFR_COMPLETED,
I40E_VFR_VFACTIVE,
I40E_VFR_UNKNOWN,
};
#endif /* _I40E_VIRTCHNL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,171 @@
/*******************************************************************************
*
* Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
* Copyright(c) 2013 - 2017 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
******************************************************************************/
#ifndef _I40E_VIRTCHNL_PF_H_
#define _I40E_VIRTCHNL_PF_H_
#include "i40e.h"
#define I40E_MAX_VLANID 4095
#define I40E_VIRTCHNL_SUPPORTED_QTYPES 2
#define I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED 3
#define I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED 10
#define I40E_VLAN_PRIORITY_SHIFT 12
#define I40E_VLAN_MASK 0xFFF
#define I40E_PRIORITY_MASK 0x7000
#define VF_IS_V10(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 0))
#define VF_IS_V11(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 1))
/* Various queue ctrls */
enum i40e_queue_ctrl {
I40E_QUEUE_CTRL_UNKNOWN = 0,
I40E_QUEUE_CTRL_ENABLE,
I40E_QUEUE_CTRL_ENABLECHECK,
I40E_QUEUE_CTRL_DISABLE,
I40E_QUEUE_CTRL_DISABLECHECK,
I40E_QUEUE_CTRL_FASTDISABLE,
I40E_QUEUE_CTRL_FASTDISABLECHECK,
};
/* VF states */
enum i40e_vf_states {
I40E_VF_STAT_INIT = 0,
I40E_VF_STAT_ACTIVE,
I40E_VF_STAT_IWARPENA,
I40E_VF_STAT_FCOEENA,
I40E_VF_STAT_DISABLED,
I40E_VF_STAT_MC_PROMISC,
I40E_VF_STAT_UC_PROMISC,
};
/* VF capabilities */
enum i40e_vf_capabilities {
I40E_VIRTCHNL_VF_CAP_PRIVILEGE = 0,
I40E_VIRTCHNL_VF_CAP_L2,
I40E_VIRTCHNL_VF_CAP_IWARP,
#ifdef I40E_FCOE
I40E_VIRTCHNL_VF_CAP_FCOE,
#endif
};
/* VF information structure */
struct i40e_vf {
struct i40e_pf *pf;
/* VF id in the PF space */
s16 vf_id;
/* all VF vsis connect to the same parent */
enum i40e_switch_element_types parent_type;
struct i40e_virtchnl_version_info vf_ver;
u32 driver_caps; /* reported by VF driver */
/* VF Port Extender (PE) stag if used */
u16 stag;
struct i40e_virtchnl_ether_addr default_lan_addr;
struct i40e_virtchnl_ether_addr default_fcoe_addr;
u16 port_vlan_id;
bool pf_set_mac; /* The VMM admin set the VF MAC address */
bool trusted;
/* VSI indices - actual VSI pointers are maintained in the PF structure
* When assigned, these will be non-zero, because VSI 0 is always
* the main LAN VSI for the PF.
*/
u16 lan_vsi_idx; /* index into PF struct */
u16 lan_vsi_id; /* ID as used by firmware */
#ifdef I40E_FCOE
u8 fcoe_vsi_index;
u8 fcoe_vsi_id;
#endif
u8 num_queue_pairs; /* num of qps assigned to VF vsis */
u64 num_mdd_events; /* num of mdd events detected */
/* num of continuous malformed or invalid msgs detected */
u64 num_invalid_msgs;
u64 num_valid_msgs; /* num of valid msgs detected */
unsigned long vf_caps; /* vf's adv. capabilities */
unsigned long vf_states; /* vf's runtime states */
unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
#ifdef HAVE_NDO_SET_VF_LINK_STATE
bool link_forced;
bool link_up; /* only valid if VF link is forced */
#endif
bool spoofchk;
u16 num_mac;
u16 num_vlan;
/* RDMA Client */
struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info;
};
void i40e_free_vfs(struct i40e_pf *pf);
#if defined(HAVE_SRIOV_CONFIGURE) || defined(HAVE_RHEL6_SRIOV_CONFIGURE)
int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
#endif
int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs);
int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen);
int i40e_vc_process_vflr_event(struct i40e_pf *pf);
void i40e_reset_vf(struct i40e_vf *vf, bool flr);
void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
/* VF configuration related iplink handlers */
int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
#ifdef IFLA_VF_VLAN_INFO_MAX
int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
u16 vlan_id, u8 qos, __be16 vlan_proto);
#else
int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
int vf_id, u16 vlan_id, u8 qos);
#endif
#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
int max_tx_rate);
#else
int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate);
#endif
#ifdef HAVE_NDO_SET_VF_TRUST
int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting);
#endif
int i40e_ndo_enable_vf(struct net_device *netdev, int vf_id, bool enable);
#ifdef IFLA_VF_MAX
int i40e_ndo_get_vf_config(struct net_device *netdev,
int vf_id, struct ifla_vf_info *ivi);
#ifdef HAVE_NDO_SET_VF_LINK_STATE
int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
#endif
#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);
#endif
#endif
void i40e_vc_notify_link_state(struct i40e_pf *pf);
void i40e_vc_notify_reset(struct i40e_pf *pf);
#endif /* _I40E_VIRTCHNL_PF_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,8 +32,13 @@
#include <linux/rtnetlink.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "../kni/ethtool/ixgbe/ixgbe_type.h"
#include "../kni/ethtool/igb/e1000_hw.h"
#include <linux/hashtable.h>
#include "i40e/i40e_type.h"
#include "i40e/i40e_prototype.h"
#include "i40e/i40e.h"
#ifdef CONFIG_XEN_DOM0
#include <xen/xen.h>
#endif
@ -44,10 +49,35 @@
* struct to hold adapter-specific parameters
* it currently supports Intel 1/10 Gbps adapters
*/
enum dev_type {IXGBE, IGB};
enum dev_type {IXGBE, IGB, I40E};
/*----------------------------------------------------------------------------*/
/* list of 1 Gbps cards */
/* list of 1 Gbps controllers */
static struct pci_device_id e1000_pci_tbl[] = {
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82540EM)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82545EM_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82545EM_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82546EB_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82546EB_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82546EB_QUAD_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82574LA)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES)},
@ -56,20 +86,17 @@ static struct pci_device_id e1000_pci_tbl[] = {
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_DA4)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_82583V)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_OEM1)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_IT)},
@ -79,18 +106,28 @@ static struct pci_device_id e1000_pci_tbl[] = {
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_FLASHLESS)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES_FLASHLESS)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_DA4)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM2)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V2)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM3)},
{PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V3)},
/* required last entry */
{0,}
};
/*----------------------------------------------------------------------------*/
static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
/* list of 10 Gbps controllers */
static struct pci_device_id ixgbe_pci_tbl[] = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT)},
@ -109,9 +146,11 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE)},
{PCI_VDEVICE(INTEL, IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4)},
{PCI_VDEVICE(INTEL, IXGBE_SUBDEV_ID_82599_RNDC)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP)},
{PCI_VDEVICE(INTEL, IXGBE_SUBDEV_ID_82599_SFP)},
{PCI_VDEVICE(INTEL, IXGBE_SUBDEV_ID_82599_560FLR)},
{PCI_VDEVICE(INTEL, IXGBE_SUBDEV_ID_82599_ECNA_DP)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_BACKPLANE_FCOE)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_FCOE)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM)},
@ -122,9 +161,48 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_1G_T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550T1)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_KR_L)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SGMII_L)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_10G_T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_QSFP)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_QSFP_N)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_1G_T_L)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KX4)},
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR)},
/* required last entry */
{0, }
};
/* list of 40 Gbps controllers */
static struct pci_device_id i40e_pci_tbl[] = {
{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_B)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_C)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QEMU)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_B)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C)},
{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_XL710)},
/* required last entry */
{0, }
};
#define I40E_MAX_CSR_SPACE (4 * 1024 * 1024 - 64 * 1024)
/*----------------------------------------------------------------------------*/
/**
* net adapter private struct
@ -136,6 +214,7 @@ struct net_adapter {
union {
struct ixgbe_hw _ixgbe_hw;
struct e1000_hw _e1000_hw;
struct i40e_hw _i40e_hw;
} hw;
u16 bd_number;
bool netdev_registered;
@ -154,8 +233,8 @@ struct stats_struct {
uint8_t dev;
};
/* max qid */
#define MAX_QID 16
#define MAX_DEVICES 16
#define MAX_QID 128
#define MAX_DEVICES 128
/* ioctl# */
#define SEND_STATS 0
/* major number */
@ -406,6 +485,7 @@ retrieve_dev_addr(struct net_device *netdev, struct net_adapter *adapter)
{
struct ixgbe_hw *hw_i;
struct e1000_hw *hw_e;
struct i40e_hw *hw_i4;
u32 rar_high;
u32 rar_low;
u16 i;
@ -433,6 +513,22 @@ retrieve_dev_addr(struct net_device *netdev, struct net_adapter *adapter)
for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
netdev->dev_addr[i+4] = (u8)(rar_high >> (i*8));
break;
case I40E:
hw_i4 = &adapter->hw._i40e_hw;
(void) hw_i4;
#if 0
rar_high = E1000_READ_REG(hw_e, E1000_RAH(0));
rar_low = E1000_READ_REG(hw_e, E1000_RAL(0));
for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
netdev->dev_addr[i] = (u8)(rar_low >> (i*8));
for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
netdev->dev_addr[i+4] = (u8)(rar_high >> (i*8));
#else
memcpy(netdev->dev_addr, hw_i4->mac.addr, ETH_ALEN);
#endif
break;
}
}
/*----------------------------------------------------------------------------*/
@ -465,6 +561,15 @@ retrieve_dev_specs(const struct pci_device_id *id)
}
no_of_elements = sizeof(i40e_pci_tbl)/sizeof(struct pci_device_id);
for (i = 0; i < no_of_elements; i++) {
if (i40e_pci_tbl[i].vendor == id->vendor &&
i40e_pci_tbl[i].device == id->device) {
return I40E;
}
}
return res;
}
/*----------------------------------------------------------------------------*/

View File

@ -341,6 +341,7 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
struct net_adapter *adapter = NULL;
struct ixgbe_hw *hw_i = NULL;
struct e1000_hw *hw_e = NULL;
struct i40e_hw *hw_i4 = NULL;
udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);
if (!udev)
@ -461,6 +462,15 @@ igbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto fail_ioremap;
}
break;
case I40E:
hw_i4 = &adapter->hw._i40e_hw;
hw_i4->back = adapter;
if (i40e_get_local_mac_addr(dev, id, hw_i4->mac.addr)) {
err = -EIO;
goto fail_ioremap;
}
break;
}
netdev_assign_netdev_ops(netdev);
@ -534,6 +544,9 @@ igbuio_pci_remove(struct pci_dev *dev)
case IGB:
iounmap(udev->adapter->hw._e1000_hw.hw_addr);
break;
case I40E:
/* do nothing */
break;
}
free_netdev(netdev);
@ -570,7 +583,7 @@ igbuio_config_intr_mode(char *intr_str)
}
static int
update_stats(struct stats_struct __user *stats)
update_stats(struct stats_struct *stats)
{
uint8_t qid = stats->qid;
uint8_t device = stats->dev;
@ -617,10 +630,17 @@ igb_net_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct stats_struct ss;
ret = copy_from_user(&ss,
(struct stats_struct __user *)arg,
sizeof(struct stats_struct));
if (ret)
return -EFAULT;
switch (cmd) {
case SEND_STATS:
ret = update_stats((struct stats_struct __user *) arg);
ret = update_stats(&ss);
break;
default:
ret = -ENOTTY;
@ -657,7 +677,7 @@ igbuio_pci_init_module(void)
printk(KERN_ERR "register_chrdev failed\n");
return ret;
}
return pci_register_driver(&igbuio_pci_driver);
}

View File

@ -34,6 +34,102 @@
struct e1000_hw;
#define E1000_DEV_ID_82542 0x1000
#define E1000_DEV_ID_82543GC_FIBER 0x1001
#define E1000_DEV_ID_82543GC_COPPER 0x1004
#define E1000_DEV_ID_82544EI_COPPER 0x1008
#define E1000_DEV_ID_82544EI_FIBER 0x1009
#define E1000_DEV_ID_82544GC_COPPER 0x100C
#define E1000_DEV_ID_82544GC_LOM 0x100D
#define E1000_DEV_ID_82540EM 0x100E
#define E1000_DEV_ID_82540EM_LOM 0x1015
#define E1000_DEV_ID_82540EP_LOM 0x1016
#define E1000_DEV_ID_82540EP 0x1017
#define E1000_DEV_ID_82540EP_LP 0x101E
#define E1000_DEV_ID_82545EM_COPPER 0x100F
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82545GM_COPPER 0x1026
#define E1000_DEV_ID_82545GM_FIBER 0x1027
#define E1000_DEV_ID_82545GM_SERDES 0x1028
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82546GB_COPPER 0x1079
#define E1000_DEV_ID_82546GB_FIBER 0x107A
#define E1000_DEV_ID_82546GB_SERDES 0x107B
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EI_MOBILE 0x1018
#define E1000_DEV_ID_82541ER_LOM 0x1014
#define E1000_DEV_ID_82541ER 0x1078
#define E1000_DEV_ID_82541GI 0x1076
#define E1000_DEV_ID_82541GI_LF 0x107C
#define E1000_DEV_ID_82541GI_MOBILE 0x1077
#define E1000_DEV_ID_82547EI 0x1019
#define E1000_DEV_ID_82547EI_MOBILE 0x101A
#define E1000_DEV_ID_82547GI 0x1075
#define E1000_DEV_ID_82571EB_COPPER 0x105E
#define E1000_DEV_ID_82571EB_FIBER 0x105F
#define E1000_DEV_ID_82571EB_SERDES 0x1060
#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC
#define E1000_DEV_ID_82572EI_COPPER 0x107D
#define E1000_DEV_ID_82572EI_FIBER 0x107E
#define E1000_DEV_ID_82572EI_SERDES 0x107F
#define E1000_DEV_ID_82572EI 0x10B9
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
#define E1000_DEV_ID_82573L 0x109A
#define E1000_DEV_ID_82574L 0x10D3
#define E1000_DEV_ID_82574LA 0x10F6
#define E1000_DEV_ID_82583V 0x150C
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
#define E1000_DEV_ID_ICH8_82567V_3 0x1501
#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
#define E1000_DEV_ID_ICH8_IGP_C 0x104B
#define E1000_DEV_ID_ICH8_IFE 0x104C
#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
#define E1000_DEV_ID_ICH8_IGP_M 0x104D
#define E1000_DEV_ID_ICH9_IGP_M 0x10BF
#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
#define E1000_DEV_ID_ICH9_BM 0x10E5
#define E1000_DEV_ID_ICH9_IGP_C 0x294C
#define E1000_DEV_ID_ICH9_IFE 0x10C0
#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE
#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF
#define E1000_DEV_ID_ICH10_D_BM_V 0x1525
#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA
#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB
#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF
#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0
#define E1000_DEV_ID_PCH2_LV_LM 0x1502
#define E1000_DEV_ID_PCH2_LV_V 0x1503
#define E1000_DEV_ID_PCH_LPT_I217_LM 0x153A
#define E1000_DEV_ID_PCH_LPT_I217_V 0x153B
#define E1000_DEV_ID_PCH_LPTLP_I218_LM 0x155A
#define E1000_DEV_ID_PCH_LPTLP_I218_V 0x1559
#define E1000_DEV_ID_PCH_I218_LM2 0x15A0
#define E1000_DEV_ID_PCH_I218_V2 0x15A1
#define E1000_DEV_ID_PCH_I218_LM3 0x15A2 /* Wildcat Point PCH */
#define E1000_DEV_ID_PCH_I218_V3 0x15A3 /* Wildcat Point PCH */
#define E1000_DEV_ID_82576 0x10C9
#define E1000_DEV_ID_82576_FIBER 0x10E6
#define E1000_DEV_ID_82576_SERDES 0x10E7
@ -42,6 +138,10 @@ struct e1000_hw;
#define E1000_DEV_ID_82576_NS 0x150A
#define E1000_DEV_ID_82576_NS_SERDES 0x1518
#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
#define E1000_DEV_ID_82576_VF 0x10CA
#define E1000_DEV_ID_82576_VF_HV 0x152D
#define E1000_DEV_ID_I350_VF 0x1520
#define E1000_DEV_ID_I350_VF_HV 0x152F
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6

View File

@ -55,6 +55,80 @@
#define IXGBE_DEV_ID_82599_CX4 0x10F9
#define IXGBE_DEV_ID_82599_SFP 0x10FB
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_SUBDEV_ID_82599_SFP_WOL0 0x1071
#define IXGBE_SUBDEV_ID_82599_RNDC 0x1F72
#define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0
#define IXGBE_SUBDEV_ID_82599_ECNA_DP 0x0470
#define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B
#define IXGBE_SUBDEV_ID_82599_LOM_SNAP6 0x2159
#define IXGBE_SUBDEV_ID_82599_SFP_1OCP 0x000D
#define IXGBE_SUBDEV_ID_82599_SFP_2OCP 0x0008
#define IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM1 0x8976
#define IXGBE_SUBDEV_ID_82599_SFP_LOM_OEM2 0x06EE
#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152A
#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D
#define IXGBE_DEV_ID_82599_SFP_SF_QP 0x154A
#define IXGBE_DEV_ID_82599_QSFP_SF_QP 0x1558
#define IXGBE_DEV_ID_82599EN_SFP 0x1557
#define IXGBE_SUBDEV_ID_82599EN_SFP_OCP1 0x0001
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_T3_LOM 0x151C
#define IXGBE_DEV_ID_82599_VF 0x10ED
#define IXGBE_DEV_ID_82599_VF_HV 0x152E
#define IXGBE_DEV_ID_82599_LS 0x154F
#define IXGBE_DEV_ID_X540T 0x1528
#define IXGBE_DEV_ID_X540_VF 0x1515
#define IXGBE_DEV_ID_X540_VF_HV 0x1530
#define IXGBE_DEV_ID_X540T1 0x1560
#define IXGBE_DEV_ID_X550T 0x1563
#define IXGBE_DEV_ID_X550T1 0x15D1
/* Placeholder value, pending official value. */
#define IXGBE_DEV_ID_X550EM_A_KR 0x15C2
#define IXGBE_DEV_ID_X550EM_A_KR_L 0x15C3
#define IXGBE_DEV_ID_X550EM_A_SFP_N 0x15C4
#define IXGBE_DEV_ID_X550EM_A_SGMII 0x15C6
#define IXGBE_DEV_ID_X550EM_A_SGMII_L 0x15C7
#define IXGBE_DEV_ID_X550EM_A_10G_T 0x15C8
#define IXGBE_DEV_ID_X550EM_A_QSFP 0x15CA
#define IXGBE_DEV_ID_X550EM_A_QSFP_N 0x15CC
#define IXGBE_DEV_ID_X550EM_A_SFP 0x15CE
#define IXGBE_DEV_ID_X550EM_A_1G_T 0x15E4
#define IXGBE_DEV_ID_X550EM_A_1G_T_L 0x15E5
#define IXGBE_DEV_ID_X550EM_X_KX4 0x15AA
#define IXGBE_DEV_ID_X550EM_X_KR 0x15AB
#define IXGBE_DEV_ID_X550EM_X_SFP 0x15AC
#define IXGBE_DEV_ID_X550EM_X_10G_T 0x15AD
#define IXGBE_DEV_ID_X550EM_X_1G_T 0x15AE
#define IXGBE_DEV_ID_X550_VF_HV 0x1564
#define IXGBE_DEV_ID_X550_VF 0x1565
#define IXGBE_DEV_ID_X550EM_A_VF 0x15C5
#define IXGBE_DEV_ID_X550EM_A_VF_HV 0x15B4
#define IXGBE_DEV_ID_X550EM_X_VF 0x15A8
#define IXGBE_DEV_ID_X550EM_X_VF_HV 0x15A9
#if 0
#define IXGBE_DEV_ID_82598 0x10B6
#define IXGBE_DEV_ID_82598_BX 0x1508
#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6
#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
#define IXGBE_DEV_ID_82598AT 0x10C8
#define IXGBE_DEV_ID_82598AT2 0x150B
#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB
#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1
#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1
#define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4
#define IXGBE_DEV_ID_82599_KX4 0x10F7
#define IXGBE_DEV_ID_82599_KX4_MEZZ 0x1514
#define IXGBE_DEV_ID_82599_KR 0x1517
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C
#define IXGBE_DEV_ID_82599_CX4 0x10F9
#define IXGBE_DEV_ID_82599_SFP 0x10FB
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0
#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152A
#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
@ -66,6 +140,7 @@
#define IXGBE_DEV_ID_82599_T3_LOM 0x151C
#define IXGBE_DEV_ID_82599_LS 0x154F
#define IXGBE_DEV_ID_X540T 0x1528
#endif
/* General Registers */
#define IXGBE_CTRL 0x00000

View File

@ -35,6 +35,9 @@
#include <linux/skbuff.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h>
#endif
#include <exec-env/rte_kni_common.h>
#include <kni_fifo.h>

View File

@ -63,6 +63,7 @@ struct ____cacheline_aligned ps_context {
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#if defined(__i386__) || defined(__x86_64__)
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum;
@ -92,6 +93,60 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
: "memory");
return (__sum16)sum;
}
#else
#define __force
typedef unsigned int u32;
static inline __sum16 csum_fold(__wsum csum)
{
u32 sum = (__force u32)csum;;
sum += (sum << 16);
csum = (sum < csum);
sum >>= 16;
sum += csum;
return (__force __sum16)~sum;
}
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
*
* By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
* Arnt Gulbrandsen.
*/
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
const unsigned int *word = iph;
const unsigned int *stop = word + ihl;
unsigned int csum;
int carry;
csum = word[0];
csum += word[1];
carry = (csum < word[1]);
csum += carry;
csum += word[2];
carry = (csum < word[2]);
csum += carry;
csum += word[3];
carry = (csum < word[3]);
csum += carry;
word += 4;
do {
csum += *word;
carry = (csum < *word);
csum += carry;
word++;
} while (word != stop);
return csum_fold(csum);
}
#endif
#endif /* __KERNEL__ */

View File

@ -1,3 +1,4 @@
# TODO: Make this Makefile.in pretty
.PHONY: clean
@ -5,6 +6,7 @@
PS=@PSIO@
DPDK=@DPDK@
NETMAP=@NETMAP@
ONVM=@ONVM@
LRO=@LRO@
HWCSUM=@HWCSUM@
MTCP_LIB_DIR=../lib
@ -12,30 +14,27 @@ MTCP_LIB=libmtcp.a
MTCP_HDR_DIR=../include
MTCP_HDR = mtcp_api.h mtcp_epoll.h
### Check onvm related env vars ###
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
ifeq ($(ONVM),)
$(error "Please define ONVM environment variable")
endif
### GCC ###
GCC=@CC@
### FLAGS ###
GCC_OPT = -m64 -Wall -fPIC -fgnu89-inline -Werror
ifeq ($(shell uname -m),x86_64)
GCC_OPT = -m64
else
GCC_OPT =
endif
GCC_OPT += -Wall -fPIC -fgnu89-inline -Werror
#DBG_OPT = -DDBGMSG -DDBGFUNC -DSTREAM -DSTATE -DTSTAT -DAPP -DEPOLL
#DBG_OPT = -DDBGMSG -DDBGFUNC -DSTREAM -DSTATE
#DBG_OPT += -DPKTDUMP
#DBG_OPT += -DDUMP_STREAM
#GCC_OPT += -g -DNETSTAT -DINFO -DDBGERR -DDBGCERR
GCC_OPT += -DNDEBUG -O3 -DNETSTAT -DINFO -DDBGERR -DDBGCERR
GCC_OPT += -DNDEBUG -g -O3 -DNETSTAT -DINFO -DDBGERR -DDBGCERR
#GCC_OPT += -DNDEBUG -g -DNETSTAT -DINFO -DDBGERR -DDBGCERR
GCC_OPT += $(DBG_OPT)
CFLAGS=@CFLAGS@
ifeq ($(LRO),1)
GCC_OPT += -DENABLELRO
endif
@ -48,9 +47,6 @@ endif
INC_DIR=./include
INC= -I$(INC_DIR)
INC += -I$(ONVM)/onvm_nflib
LDFLAGS += $(ONVM)/onvm_nflib/onvm_nflib/$(RTE_TARGET)/libonvm.a
ifeq ($(PS),1)
LIBS = -lps
else
@ -63,6 +59,16 @@ else
INC += -DDISABLE_NETMAP
endif
ifeq ($(ONVM),1)
ifeq ($(RTE_TARGET),)
$(error "Please define RTE_SDK environment variable")
endif
INC += -I@ONVMLIBPATH@/onvm_nflib
INC += -DENABLE_ONVM
LDFLAGS += @ONVMLIBPATH@/onvm_nflib/onvm_nflib/$(RTE_TARGET)/libonvm.a
endif
# PacketShader LIBRARY and HEADER
PS_DIR=../../io_engine
INC += -I$(PS_DIR)/include
@ -83,14 +89,6 @@ else
GCC_OPT += -DHUGEPAGE
endif
ifeq ($V,) # no echo
export MSG=@echo
export HIDE=@
else
export MSG=@\#
export HIDE=
endif
### SOURCE CODE ###
SRCS = core.c tcp_stream.c config.c api.c eventpoll.c socket.c pipe.c \
tcp_util.c eth_in.c ip_in.c tcp_in.c eth_out.c ip_out.c tcp_out.c \
@ -101,6 +99,13 @@ SRCS = core.c tcp_stream.c config.c api.c eventpoll.c socket.c pipe.c \
OBJS = $(patsubst %.c,%.o,$(SRCS))
DEPS = $(patsubst %.c,.%.d,$(SRCS))
ifeq ($V,) # no echo
export MSG=@echo
export HIDE=@
else
export MSG=@\#
export HIDE=
endif
### GOALS ###
all: default
@ -111,7 +116,7 @@ default: $(OBJS) $(MTCP_HDR)
$(OBJS): %.o: %.c Makefile
$(MSG) " CC $<"
$(HIDE) $(GCC) $(GCC_OPT) $(INC) -c $< -o $@
$(HIDE) $(GCC) $(CFLAGS) $(GCC_OPT) $(INC) -c $< -o $@
$(DEPS): .%.d: %.c Makefile
$(HIDE) $(GCC) $(GCC_OPT) $(INC) -MM $(CFLAGS) $< > $@

View File

@ -112,8 +112,12 @@ CreateAddressPoolPerCore(int core, int num_queues,
uint32_t saddr_h, daddr_h;
uint16_t sport_h, dport_h;
int rss_core;
#if 0
uint8_t endian_check = (current_iomodule_func == &dpdk_module_func) ?
0 : 1;
#else
uint8_t endian_check = FetchEndianType();
#endif
ap = (addr_pool_t)calloc(1, sizeof(struct addr_pool));
if (!ap)
@ -216,8 +220,12 @@ FetchAddress(addr_pool_t ap, int core, int num_queues,
struct addr_entry *walk, *next;
int rss_core;
int ret = -1;
#if 0
uint8_t endian_check = (current_iomodule_func == &dpdk_module_func) ?
0 : 1;
#else
uint8_t endian_check = FetchEndianType();
#endif
if (!ap || !daddr || !saddr)
return -1;
@ -265,6 +273,34 @@ FetchAddress(addr_pool_t ap, int core, int num_queues,
}
/*----------------------------------------------------------------------------*/
int
FetchAddressPerCore(addr_pool_t ap, int core, int num_queues,
const struct sockaddr_in *daddr, struct sockaddr_in *saddr)
{
struct addr_entry *walk;
int ret = -1;
if (!ap || !daddr || !saddr)
return -1;
pthread_mutex_lock(&ap->lock);
/* we don't need to calculate RSSCPUCore if mtcp_init_rss is called */
walk = TAILQ_FIRST(&ap->free_list);
if (walk) {
*saddr = walk->addr;
TAILQ_REMOVE(&ap->free_list, walk, addr_link);
TAILQ_INSERT_TAIL(&ap->used_list, walk, addr_link);
ap->num_free--;
ap->num_used++;
ret = 0;
}
pthread_mutex_unlock(&ap->lock);
return ret;
}
/*----------------------------------------------------------------------------*/
int
FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr)
{
struct addr_entry *walk, *next;
@ -280,7 +316,7 @@ FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr)
uint16_t port_h = ntohs(addr->sin_port);
int index = addr_h - ap->addr_base;
if (index >= 0 || index < ap->num_addr) {
if (index >= 0 && index < ap->num_addr) {
walk = ap->mapper[addr_h - ap->addr_base].addrmap[port_h];
} else {
walk = NULL;

View File

@ -46,7 +46,7 @@ GetMTCPManager(mctx_t mctx)
return NULL;
}
if (mctx->cpu < 0) {
if (mctx->cpu < 0 || mctx->cpu >= num_cpus) {
errno = EINVAL;
return NULL;
}
@ -395,7 +395,7 @@ mtcp_socket(mctx_t mctx, int domain, int type, int protocol)
}
if (type == SOCK_STREAM) {
type = MTCP_SOCK_STREAM;
type = (int)MTCP_SOCK_STREAM;
} else {
errno = EINVAL;
return -1;
@ -525,16 +525,21 @@ mtcp_listen(mctx_t mctx, int sockid, int backlog)
listener->socket = &mtcp->smap[sockid];
if (pthread_cond_init(&listener->accept_cond, NULL)) {
/* errno set internally */
perror("pthread_cond_init of ctx->accept_cond\n");
free(listener);
return -1;
}
if (pthread_mutex_init(&listener->accept_lock, NULL)) {
/* errno set internally */
perror("pthread_mutex_init of ctx->accept_lock\n");
free(listener);
return -1;
}
listener->acceptq = CreateStreamQueue(backlog);
if (!listener->acceptq) {
free(listener);
errno = ENOMEM;
return -1;
}
@ -644,16 +649,23 @@ mtcp_init_rss(mctx_t mctx, in_addr_t saddr_base, int num_addr,
mtcp = GetMTCPManager(mctx);
if (!mtcp) {
errno = EACCES;
return -1;
}
if (saddr_base == INADDR_ANY) {
int nif_out;
int nif_out, eidx;
/* for the INADDR_ANY, find the output interface for the destination
and set the saddr_base as the ip address of the output interface */
nif_out = GetOutputInterface(daddr);
saddr_base = CONFIG.eths[nif_out].ip_addr;
if (nif_out < 0) {
errno = EINVAL;
TRACE_DBG("Could not determine nif idx!\n");
return -1;
}
eidx = CONFIG.nif_to_eidx[nif_out];
saddr_base = CONFIG.eths[eidx].ip_addr;
}
ap = CreateAddressPoolPerCore(mctx->cpu, num_cpus,
@ -679,7 +691,7 @@ mtcp_connect(mctx_t mctx, int sockid,
in_addr_t dip;
in_port_t dport;
int is_dyn_bound = FALSE;
int ret;
int ret, nif;
mtcp = GetMTCPManager(mctx);
if (!mtcp) {
@ -737,8 +749,12 @@ mtcp_connect(mctx_t mctx, int sockid,
socket->saddr.sin_port != INPORT_ANY &&
socket->saddr.sin_addr.s_addr != INADDR_ANY) {
int rss_core;
#if 0
uint8_t endian_check = (current_iomodule_func == &dpdk_module_func) ?
0 : 1;
#else
uint8_t endian_check = FetchEndianType();
#endif
rss_core = GetRSSCPUCore(socket->saddr.sin_addr.s_addr, dip,
socket->saddr.sin_port, dport, num_queues, endian_check);
@ -749,10 +765,15 @@ mtcp_connect(mctx_t mctx, int sockid,
}
} else {
if (mtcp->ap) {
ret = FetchAddress(mtcp->ap,
mctx->cpu, num_queues, addr_in, &socket->saddr);
ret = FetchAddressPerCore(mtcp->ap,
mctx->cpu, num_queues, addr_in, &socket->saddr);
} else {
ret = FetchAddress(ap[GetOutputInterface(dip)],
nif = GetOutputInterface(dip);
if (nif < 0) {
errno = EINVAL;
return -1;
}
ret = FetchAddress(ap[nif],
mctx->cpu, num_queues, addr_in, &socket->saddr);
}
if (ret < 0) {

View File

@ -140,10 +140,11 @@ ARPOutput(struct mtcp_manager *mtcp, int nif, int opcode,
arph->ar_op = htons(opcode);
/* Fill arp body */
arph->ar_sip = CONFIG.eths[nif].ip_addr;
int edix = CONFIG.nif_to_eidx[nif];
arph->ar_sip = CONFIG.eths[edix].ip_addr;
arph->ar_tip = dst_ip;
memcpy(arph->ar_sha, CONFIG.eths[nif].haddr, arph->ar_hln);
memcpy(arph->ar_sha, CONFIG.eths[edix].haddr, arph->ar_hln);
if (target_haddr) {
memcpy(arph->ar_tha, target_haddr, arph->ar_hln);
} else {
@ -255,7 +256,7 @@ ProcessARPPacket(mtcp_manager_t mtcp, uint32_t cur_ts,
const int ifidx, unsigned char *pkt_data, int len)
{
struct arphdr *arph = (struct arphdr *)(pkt_data + sizeof(struct ethhdr));
int i;
int i, nif;
int to_me = FALSE;
/* process the arp messages destined to me */
@ -274,7 +275,8 @@ ProcessARPPacket(mtcp_manager_t mtcp, uint32_t cur_ts,
switch (ntohs(arph->ar_op)) {
case arp_op_request:
ProcessARPRequest(mtcp, arph, ifidx, cur_ts);
nif = CONFIG.eths[ifidx].ifindex; // use the port index as argument
ProcessARPRequest(mtcp, arph, nif, cur_ts);
break;
case arp_op_reply:
@ -294,11 +296,11 @@ ProcessARPPacket(mtcp_manager_t mtcp, uint32_t cur_ts,
void
ARPTimer(mtcp_manager_t mtcp, uint32_t cur_ts)
{
struct arp_queue_entry *ent;
struct arp_queue_entry *ent, *ent_tmp;
/* if the arp requet is timed out, retransmit */
pthread_mutex_lock(&g_arpm.lock);
TAILQ_FOREACH(ent, &g_arpm.list, arp_link) {
TAILQ_FOREACH_SAFE(ent, &g_arpm.list, arp_link, ent_tmp) {
if (TCP_SEQ_GT(cur_ts, ent->ts_out + SEC_TO_TS(ARP_TIMEOUT_SEC))) {
TRACE_INFO("[CPU%2d] ARP request timed out.\n",
mtcp->ctx->cpu);

View File

@ -9,6 +9,7 @@
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <limits.h>
#include "mtcp.h"
#include "config.h"
@ -29,6 +30,29 @@ struct mtcp_manager *g_mtcp[MAX_CPUS] = {NULL};
struct mtcp_config CONFIG = {0};
addr_pool_t ap[ETH_NUM] = {NULL};
/*----------------------------------------------------------------------------*/
static inline int
mystrtol(const char *nptr, int base)
{
int rval;
char *endptr;
errno = 0;
rval = strtol(nptr, &endptr, 10);
/* check for strtol errors */
if ((errno == ERANGE && (rval == LONG_MAX ||
rval == LONG_MIN))
|| (errno != 0 && rval == 0)) {
perror("strtol");
exit(EXIT_FAILURE);
}
if (endptr == nptr) {
TRACE_CONFIG("Parsing strtol error!\n");
exit(EXIT_FAILURE);
}
return rval;
}
/*----------------------------------------------------------------------------*/
static int
GetIntValue(char* value)
{
@ -66,6 +90,7 @@ EnrollRouteTableEntry(char *optstr)
int i;
char * saveptr;
saveptr = NULL;
daddr_s = strtok_r(optstr, "/", &saveptr);
prefix = strtok_r(NULL, " ", &saveptr);
dev = strtok_r(NULL, "\n", &saveptr);
@ -88,7 +113,8 @@ EnrollRouteTableEntry(char *optstr)
TRACE_CONFIG("Interface %s does not exist!\n", dev);
exit(4);
}
} else if (current_iomodule_func == &dpdk_module_func) {
} else if (current_iomodule_func == &dpdk_module_func ||
current_iomodule_func == &onvm_module_func) {
for (i = 0; i < num_devices; i++) {
if (strcmp(CONFIG.eths[i].dev_name, dev))
continue;
@ -99,7 +125,7 @@ EnrollRouteTableEntry(char *optstr)
ridx = CONFIG.routes++;
CONFIG.rtable[ridx].daddr = inet_addr(daddr_s);
CONFIG.rtable[ridx].prefix = atoi(prefix);
CONFIG.rtable[ridx].prefix = mystrtol(prefix, 10);
if (CONFIG.rtable[ridx].prefix > 32 || CONFIG.rtable[ridx].prefix < 0) {
TRACE_CONFIG("Prefix length should be between 0 - 32.\n");
exit(4);
@ -200,6 +226,7 @@ ParseMACAddress(unsigned char *haddr, char *haddr_str)
unsigned int temp;
char *saveptr = NULL;
saveptr = NULL;
str = strtok_r(haddr_str, ":", &saveptr);
i = 0;
while (str != NULL) {
@ -207,7 +234,10 @@ ParseMACAddress(unsigned char *haddr, char *haddr_str)
TRACE_CONFIG("MAC address length exceeds %d!\n", ETH_ALEN);
exit(4);
}
sscanf(str, "%x", &temp);
if (sscanf(str, "%x", &temp) < 1) {
TRACE_CONFIG("sscanf failed!\n");
exit(4);
}
haddr[i++] = temp;
str = strtok_r(NULL, ":", &saveptr);
}
@ -315,7 +345,8 @@ EnrollARPTableEntry(char *optstr)
int idx;
char *saveptr;
saveptr = NULL;
dip_s = strtok_r(optstr, "/", &saveptr);
prefix_s = strtok_r(NULL, " ", &saveptr);
daddr_s = strtok_r(NULL, "\n", &saveptr);
@ -327,7 +358,7 @@ EnrollARPTableEntry(char *optstr)
if (prefix_s == NULL)
prefix = 32;
else
prefix = atoi(prefix_s);
prefix = mystrtol(prefix_s, 10);
if (prefix > 32 || prefix < 0) {
TRACE_CONFIG("Prefix length should be between 0 - 32.\n");
@ -438,12 +469,13 @@ SetMultiProcessSupport(char *multiprocess_details)
TRACE_CONFIG("Loading multi-process configuration\n");
saveptr = NULL;
sample = strtok_r(multiprocess_details, token, &saveptr);
if (sample == NULL) {
TRACE_CONFIG("No option for multi-process support given!\n");
return -1;
}
CONFIG.multi_process_curr_core = atoi(sample);
CONFIG.multi_process_curr_core = mystrtol(sample, 10);
sample = strtok_r(NULL, token, &saveptr);
if (sample != NULL && !strcmp(sample, "master"))
@ -461,6 +493,7 @@ ParseConfiguration(char *line)
char *saveptr;
strncpy(optstr, line, MAX_OPTLINE_LEN - 1);
saveptr = NULL;
p = strtok_r(optstr, " \t=", &saveptr);
if (p == NULL) {
@ -475,7 +508,7 @@ ParseConfiguration(char *line)
}
if (strcmp(p, "num_cores") == 0) {
CONFIG.num_cores = atoi(q);
CONFIG.num_cores = mystrtol(q, 10);
if (CONFIG.num_cores <= 0) {
TRACE_CONFIG("Number of cores should be larger than 0.\n");
return -1;
@ -487,36 +520,36 @@ ParseConfiguration(char *line)
}
num_cpus = CONFIG.num_cores;
} else if (strcmp(p, "max_concurrency") == 0) {
CONFIG.max_concurrency = atoi(q);
CONFIG.max_concurrency = mystrtol(q, 10);
if (CONFIG.max_concurrency < 0) {
TRACE_CONFIG("The maximum concurrency should be larger than 0.\n");
return -1;
}
} else if (strcmp(p, "max_num_buffers") == 0) {
CONFIG.max_num_buffers = atoi(q);
CONFIG.max_num_buffers = mystrtol(q, 10);
if (CONFIG.max_num_buffers < 0) {
TRACE_CONFIG("The maximum # buffers should be larger than 0.\n");
return -1;
}
} else if (strcmp(p, "rcvbuf") == 0) {
CONFIG.rcvbuf_size = atoi(q);
CONFIG.rcvbuf_size = mystrtol(q, 10);
if (CONFIG.rcvbuf_size < 64) {
TRACE_CONFIG("Receive buffer size should be larger than 64.\n");
return -1;
}
} else if (strcmp(p, "sndbuf") == 0) {
CONFIG.sndbuf_size = atoi(q);
CONFIG.sndbuf_size = mystrtol(q, 10);
if (CONFIG.sndbuf_size < 64) {
TRACE_CONFIG("Send buffer size should be larger than 64.\n");
return -1;
}
} else if (strcmp(p, "tcp_timeout") == 0) {
CONFIG.tcp_timeout = atoi(q);
CONFIG.tcp_timeout = mystrtol(q, 10);
if (CONFIG.tcp_timeout > 0) {
CONFIG.tcp_timeout = SEC_TO_USEC(CONFIG.tcp_timeout) / TIME_TICK;
}
} else if (strcmp(p, "tcp_timewait") == 0) {
CONFIG.tcp_timewait = atoi(q);
CONFIG.tcp_timewait = mystrtol(q, 10);
if (CONFIG.tcp_timewait > 0) {
CONFIG.tcp_timewait = SEC_TO_USEC(CONFIG.tcp_timewait) / TIME_TICK;
}
@ -537,7 +570,15 @@ ParseConfiguration(char *line)
} else if (strcmp(p, "io") == 0) {
AssignIOModule(q);
} else if (strcmp(p, "num_mem_ch") == 0) {
CONFIG.num_mem_ch = atoi(q);
CONFIG.num_mem_ch = mystrtol(q, 10);
#ifdef ENABLE_ONVM
} else if (strcmp(p, "onvm_inst") == 0) {
CONFIG.onvm_inst = mystrtol(q, 10);
} else if (strcmp(p, "onvm_serv") == 0) {
CONFIG.onvm_serv = mystrtol(q, 10);
} else if (strcmp(p, "onvm_dest") == 0) {
CONFIG.onvm_dest = mystrtol(q, 10);
#endif
} else if (strcmp(p, "multiprocess") == 0) {
CONFIG.multi_process = 1;
SetMultiProcessSupport(line + strlen(p) + 1);
@ -575,7 +616,11 @@ LoadConfiguration(const char *fname)
CONFIG.tcp_timeout = TCP_TIMEOUT;
CONFIG.tcp_timewait = TCP_TIMEWAIT;
CONFIG.num_mem_ch = 0;
#ifdef ENABLE_ONVM
CONFIG.onvm_inst = (uint16_t) -1;
CONFIG.onvm_dest = (uint16_t) -1;
CONFIG.onvm_serv = (uint16_t) -1;
#endif
while (1) {
char *p;
char *temp;
@ -597,8 +642,10 @@ LoadConfiguration(const char *fname)
if (*p == 0) /* nothing more to process? */
continue;
if (ParseConfiguration(p) < 0)
if (ParseConfiguration(p) < 0) {
fclose(fp);
return -1;
}
}
fclose(fp);
@ -637,9 +684,6 @@ PrintConfiguration()
}
TRACE_CONFIG("TCP timewait seconds: %d\n",
USEC_TO_SEC(CONFIG.tcp_timewait * TIME_TICK));
TRACE_CONFIG("Instance ID: %d\n", CONFIG.instance_id);
TRACE_CONFIG("Service ID: %d\n", CONFIG.service_id);
TRACE_CONFIG("Destination ID: %d\n", CONFIG.dest_id);
TRACE_CONFIG("NICs to print statistics:");
for (i = 0; i < CONFIG.eths_num; i++) {
if (CONFIG.eths[i].stat_print) {

View File

@ -35,6 +35,10 @@
#include <rte_lcore.h>
#endif
#ifdef ENABLE_ONVM
#include "onvm_nflib.h"
#endif
#define PS_CHUNK_SIZE 64
#define RX_THRESH (PS_CHUNK_SIZE * 0.8)
@ -70,6 +74,8 @@ static int sigint_cnt[MAX_CPUS] = {0};
static struct timespec sigint_ts[MAX_CPUS];
/*----------------------------------------------------------------------------*/
static int mtcp_master = -1;
void
mtcp_free_context(mctx_t mctx);
/*----------------------------------------------------------------------------*/
void
HandleSignal(int signal)
@ -80,7 +86,9 @@ HandleSignal(int signal)
int core;
struct timespec cur_ts;
#ifdef ENABLE_ONVM
onvm_nflib_stop();
#endif
core = sched_getcpu();
clock_gettime(CLOCK_REALTIME, &cur_ts);
@ -265,7 +273,7 @@ PrintNetworkStats(mtcp_manager_t mtcp, uint32_t cur_ts)
mtcp->p_nstat_ts = cur_ts;
gflow_cnt = 0;
memset(&g_nstat, 0, sizeof(struct net_stat));
for (i = 0; i < MAX_CPUS; i++) {
for (i = 0; i < CONFIG.num_cores; i++) {
if (running[i]) {
PrintThreadNetworkStats(g_mtcp[i], &ns);
#if NETSTAT_TOTAL
@ -892,7 +900,7 @@ InitializeMTCPManager(struct mtcp_thread_context* ctx)
mtcp = (mtcp_manager_t)calloc(1, sizeof(struct mtcp_manager));
if (!mtcp) {
perror("malloc");
CTRACE_ERROR("Failed to allocate mtcp_manager.\n");
fprintf(stderr, "Failed to allocate mtcp_manager.\n");
return NULL;
}
g_mtcp[ctx->cpu] = mtcp;
@ -1121,6 +1129,9 @@ MTCPRunThread(void *arg)
/* start the main loop */
RunMainLoop(ctx);
struct mtcp_context m;
m.cpu = cpu;
mtcp_free_context(&m);
/* destroy hash tables */
DestroyHashtable(g_mtcp[cpu]->tcp_flow_table);
DestroyHashtable(g_mtcp[cpu]->listeners);
@ -1130,27 +1141,26 @@ MTCPRunThread(void *arg)
return 0;
}
/*----------------------------------------------------------------------------*/
#ifndef DISABLE_DPDK
static int MTCPDPDKRunThread(void *arg)
{
MTCPRunThread(arg);
return 0;
}
#endif
/*----------------------------------------------------------------------------*/
mctx_t
mtcp_create_context(int cpu)
{
mctx_t mctx;
int ret;
/* check if mtcp_create_context() was already initialized */
if (g_logctx[cpu] != NULL) {
TRACE_ERROR("%s was already initialized before!\n",
__FUNCTION__);
if (cpu >= CONFIG.num_cores) {
TRACE_ERROR("Failed initialize new mtcp context. "
"Requested cpu id %d exceed the number of cores %d configured to use.\n",
cpu, CONFIG.num_cores);
return NULL;
}
/* check if mtcp_create_context() was already initialized */
if (g_logctx[cpu] != NULL) {
TRACE_ERROR("%s was already initialized before!\n",
__FUNCTION__);
return NULL;
}
ret = sem_init(&g_init_sem[cpu], 0, 0);
if (ret) {
TRACE_ERROR("Failed initialize init_sem.\n");
@ -1168,8 +1178,9 @@ mtcp_create_context(int cpu)
g_logctx[cpu] = (struct log_thread_context *)
calloc(1, sizeof(struct log_thread_context));
if (!g_logctx[cpu]) {
perror("malloc");
perror("calloc");
TRACE_ERROR("Failed to allocate memory for log thread context.\n");
free(mctx);
return NULL;
}
InitLogThreadContext(g_logctx[cpu], cpu);
@ -1177,31 +1188,15 @@ mtcp_create_context(int cpu)
NULL, ThreadLogMain, (void *)g_logctx[cpu])) {
perror("pthread_create");
TRACE_ERROR("Failed to create log thread\n");
free(g_logctx[cpu]);
free(mctx);
return NULL;
}
/* Wake up mTCP threads (wake up I/O threads) */
if (current_iomodule_func == &dpdk_module_func) {
#ifndef DISABLE_DPDK
int master;
master = rte_get_master_lcore();
if (master == cpu) {
lcore_config[master].ret = 0;
lcore_config[master].state = FINISHED;
if (pthread_create(&g_thread[cpu],
NULL, MTCPRunThread, (void *)mctx) != 0) {
TRACE_ERROR("pthread_create of mtcp thread failed!\n");
return NULL;
}
} else
rte_eal_remote_launch(MTCPDPDKRunThread, mctx, cpu);
#endif /* !DISABLE_DPDK */
} else {
if (pthread_create(&g_thread[cpu],
NULL, MTCPRunThread, (void *)mctx) != 0) {
TRACE_ERROR("pthread_create of mtcp thread failed!\n");
return NULL;
}
if (pthread_create(&g_thread[cpu],
NULL, MTCPRunThread, (void *)mctx) != 0) {
TRACE_ERROR("pthread_create of mtcp thread failed!\n");
return NULL;
}
sem_wait(&g_init_sem[cpu]);
@ -1217,14 +1212,25 @@ mtcp_create_context(int cpu)
return mctx;
}
/*----------------------------------------------------------------------------*/
void
void
mtcp_destroy_context(mctx_t mctx)
{
struct mtcp_thread_context *ctx = g_pctx[mctx->cpu];
if (ctx != NULL)
ctx->done = 1;
free(mctx);
}
/*----------------------------------------------------------------------------*/
void
mtcp_free_context(mctx_t mctx)
{
struct mtcp_thread_context *ctx = g_pctx[mctx->cpu];
struct mtcp_manager *mtcp = ctx->mtcp_manager;
struct log_thread_context *log_ctx = mtcp->logger;
int ret, i;
if (g_pctx[mctx->cpu] == NULL) return;
TRACE_DBG("CPU %d: mtcp_destroy_context()\n", mctx->cpu);
/* close all stream sockets that are still open */
@ -1244,6 +1250,7 @@ mtcp_destroy_context(mctx_t mctx)
ctx->done = 1;
//pthread_kill(g_thread[mctx->cpu], SIGINT);
#if 0
/* XXX - dpdk logic changes */
if (current_iomodule_func == &dpdk_module_func) {
#ifndef DISABLE_DPDK
@ -1254,7 +1261,10 @@ mtcp_destroy_context(mctx_t mctx)
rte_eal_wait_lcore(mctx->cpu);
#endif /* !DISABLE_DPDK */
} else
pthread_join(g_thread[mctx->cpu], NULL);
#endif
{
pthread_join(g_thread[mctx->cpu], NULL);
}
TRACE_INFO("MTCP thread %d joined.\n", mctx->cpu);
running[mctx->cpu] = FALSE;
@ -1320,6 +1330,7 @@ mtcp_destroy_context(mctx_t mctx)
if (mtcp->ap) {
DestroyAddressPool(mtcp->ap);
mtcp->ap = NULL;
}
SQ_LOCK_DESTROY(&ctx->connect_lock);
@ -1332,7 +1343,11 @@ mtcp_destroy_context(mctx_t mctx)
//TRACE_INFO("MTCP thread %d destroyed.\n", mctx->cpu);
mtcp->iom->destroy_handle(ctx);
free(ctx);
free(mctx);
if (g_logctx[mctx->cpu]) {
free(g_logctx[mctx->cpu]);
g_logctx[mctx->cpu] = NULL;
}
g_pctx[mctx->cpu] = NULL;
}
/*----------------------------------------------------------------------------*/
mtcp_sighandler_t
@ -1369,8 +1384,6 @@ mtcp_getconf(struct mtcp_conf *conf)
conf->tcp_timewait = CONFIG.tcp_timewait;
conf->tcp_timeout = CONFIG.tcp_timeout;
conf->core_list = CONFIG.core_list;
return 0;
}
/*----------------------------------------------------------------------------*/
@ -1395,8 +1408,6 @@ mtcp_setconf(const struct mtcp_conf *conf)
CONFIG.tcp_timewait = conf->tcp_timewait;
if (conf->tcp_timeout > 0)
CONFIG.tcp_timeout = conf->tcp_timeout;
if (conf->core_list)
CONFIG.core_list = conf->core_list;
TRACE_CONFIG("Configuration updated by mtcp_setconf().\n");
//PrintConfiguration();
@ -1405,40 +1416,7 @@ mtcp_setconf(const struct mtcp_conf *conf)
}
/*----------------------------------------------------------------------------*/
int
mtcp_parse_args(int argc, char *argv[])
{
int c;
/* Set default values */
CONFIG.instance_id = NF_NO_ID;
CONFIG.dest_id = (uint16_t) - 1;
CONFIG.service_id = (int16_t) -1;
opterr = 0;
optind = 1;
while ((c = getopt (argc, argv, "n:r:d:")) != -1){
switch (c) {
case 'n':
CONFIG.instance_id = (uint16_t) strtoul(optarg, NULL, 10);
break;
case 'r':
CONFIG.service_id = (uint16_t) strtoul(optarg, NULL, 10);
break;
case 'd':
CONFIG.dest_id = (uint16_t) strtoul(optarg, NULL, 10);
break;
}
}
if (CONFIG.service_id == (uint16_t)-1) {
/* Service ID is required */
fprintf(stderr, "You must provide a nonzero service ID with -r\n");
return -1;
}
return optind;
}
/*----------------------------------------------------------------------------*/
int
mtcp_init(const char *config_file, int argc, char *argv[])
mtcp_init(const char *config_file)
{
int i;
int ret;
@ -1451,30 +1429,23 @@ mtcp_init(const char *config_file, int argc, char *argv[])
/* getting cpu and NIC */
/* set to max cpus only if user has not arbitrarily set it to lower # */
num_cpus = (CONFIG.num_cores == 0) ? GetNumCPUs() : CONFIG.num_cores;
assert(num_cpus >= 1);
if (num_cpus > MAX_CPUS) {
TRACE_ERROR("You cannot run mTCP with more than %d cores due "
"to NIC hardware queues restriction. Please disable "
"the last %d cores in your system\n",
"to your static mTCP configuration. Please disable "
"the last %d cores in your system.\n",
MAX_CPUS, num_cpus - MAX_CPUS);
exit(EXIT_FAILURE);
}
for (i = 0; i < MAX_CPUS; i++) {
for (i = 0; i < num_cpus; i++) {
g_mtcp[i] = NULL;
running[i] = FALSE;
sigint_cnt[i] = 0;
}
/* Set specific onvm args */
ret = mtcp_parse_args(argc, argv);
if (ret < 0){
TRACE_CONFIG("Error while parsing command line arguments.\n");
return -1;
}
ret = LoadConfiguration(config_file);
if (ret) {
TRACE_CONFIG("Error occured while loading configuration.\n");

View File

@ -66,7 +66,13 @@ mtcp_core_affinitize(int cpu)
errno = EFAULT;
return -1;
}
unused = fscanf(fp, "%d", &phy_id);
ret = fscanf(fp, "%d", &phy_id);
if (ret != 1) {
fclose(fp);
perror("Fail to read core id");
errno = EFAULT;
return -1;
}
numa_bitmask_setbit(bmask, phy_id);
numa_set_membind(bmask);

View File

@ -27,16 +27,22 @@
#endif /* !ENABLE_STATS_IOCTL */
/* for ip pseudo-chksum */
#include <rte_ip.h>
//#define IP_DEFRAG 1
#ifdef IP_DEFRAG
/* for ip defragging */
#include <rte_ip_frag.h>
#endif
/*----------------------------------------------------------------------------*/
/* Essential macros */
#define MAX_RX_QUEUE_PER_LCORE MAX_CPUS
#define MAX_TX_QUEUE_PER_PORT MAX_CPUS
#ifdef ENABLELRO
#define MBUF_SIZE (16384 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
#define BUF_SIZE 16384
#else
#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
#define BUF_SIZE 2048
#endif /* !ENABLELRO */
#define MBUF_SIZE (BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
#define NB_MBUF 8192
#define MEMPOOL_CACHE_SIZE 256
//#define RX_IDLE_ENABLE 1
@ -70,8 +76,16 @@
#define RTE_TEST_RX_DESC_DEFAULT 128
#define RTE_TEST_TX_DESC_DEFAULT 128
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/*
* Ethernet frame overhead
*/
#define ETHER_IFG 12
#define ETHER_PREAMBLE 8
#define ETHER_OVR (ETHER_CRC_LEN + ETHER_PREAMBLE + ETHER_IFG)
static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
/*----------------------------------------------------------------------------*/
/* packet memory pools for storing packet bufs */
static struct rte_mempool *pktmbuf_pool[MAX_CPUS] = {NULL};
@ -101,7 +115,8 @@ static struct rte_eth_conf port_conf = {
.rx_adv_conf = {
.rss_conf = {
.rss_key = NULL,
.rss_hf = ETH_RSS_TCP
.rss_hf = ETH_RSS_TCP | ETH_RSS_UDP |
ETH_RSS_IP | ETH_RSS_L2_PAYLOAD
},
},
.txmode = {
@ -146,6 +161,10 @@ struct dpdk_private_context {
#ifdef RX_IDLE_ENABLE
uint8_t rx_idle;
#endif
#ifdef IP_DEFRAG
struct rte_ip_frag_tbl *frag_tbl;
struct rte_ip_frag_death_row death_row;
#endif
#ifdef ENABLELRO
struct rte_mbuf *cur_rx_m;
#endif
@ -155,6 +174,7 @@ struct dpdk_private_context {
} __rte_cache_aligned;
#ifdef ENABLE_STATS_IOCTL
#define DEV_NAME "/dev/dpdk-iface"
/**
* stats struct passed on from user space to the driver
*/
@ -167,13 +187,20 @@ struct stats_struct {
uint8_t dev;
};
#endif /* !ENABLE_STATS_IOCTL */
#ifdef IP_DEFRAG
/* Should be power of two. */
#define IP_FRAG_TBL_BUCKET_ENTRIES 16
#define RTE_LOGTYPE_IP_RSMBL RTE_LOGTYPE_USER1
#define MAX_FRAG_NUM RTE_LIBRTE_IP_FRAG_MAX_FRAG
#endif /* !IP_DEFRAG */
/*----------------------------------------------------------------------------*/
void
dpdk_init_handle(struct mtcp_thread_context *ctxt)
{
struct dpdk_private_context *dpc;
int i, j;
char mempool_name[20];
char mempool_name[RTE_MEMPOOL_NAMESIZE];
/* create and initialize private I/O module context */
ctxt->io_private_context = calloc(1, sizeof(struct dpdk_private_context));
@ -182,7 +209,7 @@ dpdk_init_handle(struct mtcp_thread_context *ctxt)
"Can't allocate memory\n");
exit(EXIT_FAILURE);
}
sprintf(mempool_name, "mbuf_pool-%d", ctxt->cpu);
dpc = (struct dpdk_private_context *)ctxt->io_private_context;
dpc->pktmbuf_pool = pktmbuf_pool[ctxt->cpu];
@ -202,10 +229,32 @@ dpdk_init_handle(struct mtcp_thread_context *ctxt)
dpc->wmbufs[j].len = 0;
}
#ifdef IP_DEFRAG
int max_flows;
int socket;
uint64_t frag_cycles;
max_flows = CONFIG.max_concurrency / CONFIG.num_cores;
frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1)
/ MS_PER_S * max_flows;
socket = rte_lcore_to_socket_id(ctxt->cpu);
if ((dpc->frag_tbl = rte_ip_frag_table_create(max_flows,
IP_FRAG_TBL_BUCKET_ENTRIES,
max_flows,
frag_cycles,
socket)) == NULL) {
RTE_LOG(ERR, IP_RSMBL, "ip_frag_tbl_create(%u) on "
"lcore: %u for queue: %u failed\n",
max_flows, ctxt->cpu, ctxt->cpu);
exit(EXIT_FAILURE);
}
#endif /* !IP_DEFRAG */
#ifdef ENABLE_STATS_IOCTL
dpc->fd = open("/dev/dpdk-iface", O_RDWR);
dpc->fd = open(DEV_NAME, O_RDWR);
if (dpc->fd == -1) {
TRACE_ERROR("Can't open /dev/dpdk-iface for context->cpu: %d! "
TRACE_ERROR("Can't open " DEV_NAME " for context->cpu: %d! "
"Are you using mlx4/mlx5 driver?\n",
ctxt->cpu);
}
@ -216,55 +265,55 @@ int
dpdk_link_devices(struct mtcp_thread_context *ctxt)
{
/* linking takes place during mtcp_init() */
return 0;
}
/*----------------------------------------------------------------------------*/
void
dpdk_release_pkt(struct mtcp_thread_context *ctxt, int ifidx, unsigned char *pkt_data, int len)
{
/*
/*
* do nothing over here - memory reclamation
* will take place in dpdk_recv_pkts
* will take place in dpdk_recv_pkts
*/
}
/*----------------------------------------------------------------------------*/
int
dpdk_send_pkts(struct mtcp_thread_context *ctxt, int nif)
dpdk_send_pkts(struct mtcp_thread_context *ctxt, int ifidx)
{
struct dpdk_private_context *dpc;
mtcp_manager_t mtcp;
int ret, i;
int ret, i, portid = CONFIG.eths[ifidx].ifindex;
dpc = (struct dpdk_private_context *)ctxt->io_private_context;
mtcp = ctxt->mtcp_manager;
ret = 0;
/* if there are packets in the queue... flush them out to the wire */
if (dpc->wmbufs[nif].len >/*= MAX_PKT_BURST*/ 0) {
if (dpc->wmbufs[ifidx].len >/*= MAX_PKT_BURST*/ 0) {
struct rte_mbuf **pkts;
#ifdef ENABLE_STATS_IOCTL
struct stats_struct ss;
#endif /* !ENABLE_STATS_IOCTL */
int cnt = dpc->wmbufs[nif].len;
pkts = dpc->wmbufs[nif].m_table;
int cnt = dpc->wmbufs[ifidx].len;
pkts = dpc->wmbufs[ifidx].m_table;
#ifdef NETSTAT
mtcp->nstat.tx_packets[nif] += cnt;
mtcp->nstat.tx_packets[ifidx] += cnt;
#ifdef ENABLE_STATS_IOCTL
if (likely(dpc->fd >= 0)) {
ss.tx_pkts = mtcp->nstat.tx_packets[nif];
ss.tx_bytes = mtcp->nstat.tx_bytes[nif];
ss.rx_pkts = mtcp->nstat.rx_packets[nif];
ss.rx_bytes = mtcp->nstat.rx_bytes[nif];
ss.tx_pkts = mtcp->nstat.tx_packets[ifidx];
ss.tx_bytes = mtcp->nstat.tx_bytes[ifidx];
ss.rx_pkts = mtcp->nstat.rx_packets[ifidx];
ss.rx_bytes = mtcp->nstat.rx_bytes[ifidx];
ss.qid = ctxt->cpu;
ss.dev = nif;
ss.dev = portid;
ioctl(dpc->fd, 0, &ss);
}
#endif /* !ENABLE_STATS_IOCTL */
#endif
do {
/* tx cnt # of packets */
ret = rte_eth_tx_burst(nif, ctxt->cpu,
ret = rte_eth_tx_burst(portid, ctxt->cpu,
pkts, cnt);
pkts += ret;
cnt -= ret;
@ -272,24 +321,24 @@ dpdk_send_pkts(struct mtcp_thread_context *ctxt, int nif)
} while (cnt > 0);
/* time to allocate fresh mbufs for the queue */
for (i = 0; i < dpc->wmbufs[nif].len; i++) {
dpc->wmbufs[nif].m_table[i] = rte_pktmbuf_alloc(pktmbuf_pool[ctxt->cpu]);
for (i = 0; i < dpc->wmbufs[ifidx].len; i++) {
dpc->wmbufs[ifidx].m_table[i] = rte_pktmbuf_alloc(pktmbuf_pool[ctxt->cpu]);
/* error checking */
if (unlikely(dpc->wmbufs[nif].m_table[i] == NULL)) {
if (unlikely(dpc->wmbufs[ifidx].m_table[i] == NULL)) {
TRACE_ERROR("Failed to allocate %d:wmbuf[%d] on device %d!\n",
ctxt->cpu, i, nif);
ctxt->cpu, i, ifidx);
exit(EXIT_FAILURE);
}
}
/* reset the len of mbufs var after flushing of packets */
dpc->wmbufs[nif].len = 0;
dpc->wmbufs[ifidx].len = 0;
}
return ret;
}
/*----------------------------------------------------------------------------*/
uint8_t *
dpdk_get_wptr(struct mtcp_thread_context *ctxt, int nif, uint16_t pktsize)
dpdk_get_wptr(struct mtcp_thread_context *ctxt, int ifidx, uint16_t pktsize)
{
struct dpdk_private_context *dpc;
mtcp_manager_t mtcp;
@ -299,14 +348,14 @@ dpdk_get_wptr(struct mtcp_thread_context *ctxt, int nif, uint16_t pktsize)
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
mtcp = ctxt->mtcp_manager;
/* sanity check */
if (unlikely(dpc->wmbufs[nif].len == MAX_PKT_BURST))
if (unlikely(dpc->wmbufs[ifidx].len == MAX_PKT_BURST))
return NULL;
len_of_mbuf = dpc->wmbufs[nif].len;
m = dpc->wmbufs[nif].m_table[len_of_mbuf];
len_of_mbuf = dpc->wmbufs[ifidx].len;
m = dpc->wmbufs[ifidx].m_table[len_of_mbuf];
/* retrieve the right write offset */
ptr = (void *)rte_pktmbuf_mtod(m, struct ether_hdr *);
m->pkt_len = m->data_len = pktsize;
@ -314,12 +363,12 @@ dpdk_get_wptr(struct mtcp_thread_context *ctxt, int nif, uint16_t pktsize)
m->next = NULL;
#ifdef NETSTAT
mtcp->nstat.tx_bytes[nif] += pktsize + 24;
mtcp->nstat.tx_bytes[ifidx] += pktsize + ETHER_OVR;
#endif
/* increment the len_of_mbuf var */
dpc->wmbufs[nif].len = len_of_mbuf + 1;
dpc->wmbufs[ifidx].len = len_of_mbuf + 1;
return (uint8_t *)ptr;
}
/*----------------------------------------------------------------------------*/
@ -348,9 +397,10 @@ dpdk_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx)
dpc->rmbufs[ifidx].len = 0;
}
ret = rte_eth_rx_burst((uint8_t)ifidx, ctxt->cpu,
int portid = CONFIG.eths[ifidx].ifindex;
ret = rte_eth_rx_burst((uint8_t)portid, ctxt->cpu,
dpc->pkts_burst, MAX_PKT_BURST);
#ifdef RX_IDLE_ENABLE
#ifdef RX_IDLE_ENABLE
dpc->rx_idle = (likely(ret != 0)) ? 0 : dpc->rx_idle + 1;
#endif
dpc->rmbufs[ifidx].len = ret;
@ -358,6 +408,49 @@ dpdk_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx)
return ret;
}
/*----------------------------------------------------------------------------*/
#ifdef IP_DEFRAG
struct rte_mbuf *
ip_reassemble(struct dpdk_private_context *dpc, struct rte_mbuf *m)
{
struct ether_hdr *eth_hdr;
struct rte_ip_frag_tbl *tbl;
struct rte_ip_frag_death_row *dr;
/* if packet is IPv4 */
if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) {
struct ipv4_hdr *ip_hdr;
eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
ip_hdr = (struct ipv4_hdr *)(eth_hdr + 1);
/* if it is a fragmented packet, then try to reassemble. */
if (rte_ipv4_frag_pkt_is_fragmented(ip_hdr)) {
struct rte_mbuf *mo;
tbl = dpc->frag_tbl;
dr = &dpc->death_row;
/* prepare mbuf: setup l2_len/l3_len. */
m->l2_len = sizeof(*eth_hdr);
m->l3_len = sizeof(*ip_hdr);
/* process this fragment. */
mo = rte_ipv4_frag_reassemble_packet(tbl, dr, m, rte_rdtsc(), ip_hdr);
if (mo == NULL)
/* no packet to send out. */
return NULL;
/* we have our packet reassembled. */
if (mo != m)
m = mo;
}
}
/* if packet isn't IPv4, just accept it! */
return m;
}
#endif
/*----------------------------------------------------------------------------*/
uint8_t *
dpdk_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len)
{
@ -365,10 +458,12 @@ dpdk_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *
struct rte_mbuf *m;
uint8_t *pktbuf;
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
m = dpc->pkts_burst[index];
//rte_prefetch0(rte_pktmbuf_mtod(m, void *));
#ifdef IP_DEFRAG
m = ip_reassemble(dpc, m);
#endif
*len = m->pkt_len;
pktbuf = rte_pktmbuf_mtod(m, uint8_t *);
@ -394,7 +489,7 @@ dpdk_select(struct mtcp_thread_context *ctxt)
{
#ifdef RX_IDLE_ENABLE
struct dpdk_private_context *dpc;
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
if (dpc->rx_idle > RX_IDLE_THRESH) {
dpc->rx_idle = 0;
@ -410,7 +505,7 @@ dpdk_destroy_handle(struct mtcp_thread_context *ctxt)
struct dpdk_private_context *dpc;
int i;
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
dpc = (struct dpdk_private_context *) ctxt->io_private_context;
/* free wmbufs */
for (i = 0; i < num_devices_attached; i++)
@ -489,10 +584,12 @@ dpdk_load_module(void)
struct rte_eth_fc_conf fc_conf;
/* setting the rss key */
static const uint8_t key[] = {
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 10 */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 20 */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 30 */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 40 */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 50 */
0x05, 0x05 /* 60 - 8 */
};
port_conf.rx_adv_conf.rss_conf.rss_key = (uint8_t *)&key;
@ -500,23 +597,47 @@ dpdk_load_module(void)
if (!CONFIG.multi_process || (CONFIG.multi_process && CONFIG.multi_process_is_master)) {
for (rxlcore_id = 0; rxlcore_id < CONFIG.num_cores; rxlcore_id++) {
char name[20];
char name[RTE_MEMPOOL_NAMESIZE];
uint32_t nb_mbuf;
sprintf(name, "mbuf_pool-%d", rxlcore_id);
nb_mbuf = NB_MBUF;
#ifdef IP_DEFRAG
int max_flows;
max_flows = CONFIG.max_concurrency / CONFIG.num_cores;
/*
* At any given moment up to <max_flows * (MAX_FRAG_NUM)>
* mbufs could be stored int the fragment table.
* Plus, each TX queue can hold up to <max_flows> packets.
*/
nb_mbuf = RTE_MAX(max_flows, 2UL * MAX_PKT_BURST) * MAX_FRAG_NUM;
nb_mbuf *= (port_conf.rxmode.max_rx_pkt_len + BUF_SIZE - 1) / BUF_SIZE;
nb_mbuf += RTE_TEST_RX_DESC_DEFAULT + RTE_TEST_TX_DESC_DEFAULT;
nb_mbuf = RTE_MAX(nb_mbuf, (uint32_t)NB_MBUF);
#endif
/* create the mbuf pools */
pktmbuf_pool[rxlcore_id] =
rte_mempool_create(name, NB_MBUF,
MBUF_SIZE, MEMPOOL_CACHE_SIZE,
sizeof(struct rte_pktmbuf_pool_private),
rte_pktmbuf_pool_init, NULL,
rte_pktmbuf_init, NULL,
rte_socket_id(), 0);
rte_mempool_create(name, nb_mbuf,
MBUF_SIZE, MEMPOOL_CACHE_SIZE,
sizeof(struct rte_pktmbuf_pool_private),
rte_pktmbuf_pool_init, NULL,
rte_pktmbuf_init, NULL,
rte_socket_id(), MEMPOOL_F_SP_PUT |
MEMPOOL_F_SC_GET);
if (pktmbuf_pool[rxlcore_id] == NULL)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool, errno: %d\n",
rte_errno);
rte_errno);
}
/* Initialise each port */
for (portid = 0; portid < num_devices_attached; portid++) {
int i;
for (i = 0; i < num_devices_attached; ++i) {
/* get portid form the index of attached devices */
portid = devices_attached[i];
/* init port */
printf("Initializing port %u... ", (unsigned) portid);
fflush(stdout);
@ -524,7 +645,7 @@ dpdk_load_module(void)
if (ret < 0)
rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
ret, (unsigned) portid);
/* init one RX queue per CPU */
fflush(stdout);
#ifdef DEBUG
@ -538,44 +659,44 @@ dpdk_load_module(void)
rte_eth_dev_socket_id(portid), &rx_conf,
pktmbuf_pool[rxlcore_id]);
if (ret < 0)
rte_exit(EXIT_FAILURE,
rte_exit(EXIT_FAILURE,
"rte_eth_rx_queue_setup:err=%d, port=%u, queueid: %d\n",
ret, (unsigned) portid, rxlcore_id);
}
/* init one TX queue on each port per CPU (this is redundant for this app) */
fflush(stdout);
for (rxlcore_id = 0; rxlcore_id < CONFIG.num_cores; rxlcore_id++) {
ret = rte_eth_tx_queue_setup(portid, rxlcore_id, nb_txd,
rte_eth_dev_socket_id(portid), &tx_conf);
if (ret < 0)
rte_exit(EXIT_FAILURE,
rte_exit(EXIT_FAILURE,
"rte_eth_tx_queue_setup:err=%d, port=%u, queueid: %d\n",
ret, (unsigned) portid, rxlcore_id);
}
/* Start device */
ret = rte_eth_dev_start(portid);
if (ret < 0)
rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
ret, (unsigned) portid);
printf("done: \n");
rte_eth_promiscuous_enable(portid);
/* retrieve current flow control settings per port */
memset(&fc_conf, 0, sizeof(fc_conf));
ret = rte_eth_dev_flow_ctrl_get(portid, &fc_conf);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Failed to get flow control info!\n");
/* and just disable the rx/tx flow control */
fc_conf.mode = RTE_FC_NONE;
ret = rte_eth_dev_flow_ctrl_set(portid, &fc_conf);
if (ret != 0)
if (ret != 0)
rte_exit(EXIT_FAILURE, "Failed to set flow control info!: errno: %d\n",
ret);
#ifdef DEBUG
printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
(unsigned) portid,
@ -587,6 +708,8 @@ dpdk_load_module(void)
ports_eth_addr[portid].addr_bytes[5]);
#endif
}
/* only check for link status if the thread is master */
check_all_ports_link_status(num_devices_attached, 0xFFFFFFFF);
} else { /* CONFIG.multi_process && !CONFIG.multi_process_is_master */
for (rxlcore_id = 0; rxlcore_id < CONFIG.num_cores; rxlcore_id++) {
char name[20];
@ -598,8 +721,6 @@ dpdk_load_module(void)
rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
}
}
check_all_ports_link_status(num_devices_attached, 0xFFFFFFFF);
}
/*----------------------------------------------------------------------------*/
int32_t
@ -610,19 +731,28 @@ dpdk_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
int len_of_mbuf;
struct iphdr *iph;
struct tcphdr *tcph;
void **argpptr = (void **)argp;
#ifdef ENABLELRO
uint8_t *payload, *to;
int seg_off;
#endif
if (cmd == DRV_NAME) {
*argpptr = (void *)dev_info[nif].driver_name;
return 0;
}
int eidx = CONFIG.nif_to_eidx[nif];
iph = (struct iphdr *)argp;
dpc = (struct dpdk_private_context *)ctx->io_private_context;
len_of_mbuf = dpc->wmbufs[nif].len;
len_of_mbuf = dpc->wmbufs[eidx].len;
switch (cmd) {
case PKT_TX_IP_CSUM:
if ((dev_info[nif].tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) == 0)
goto dev_ioctl_err;
m = dpc->wmbufs[nif].m_table[len_of_mbuf - 1];
m = dpc->wmbufs[eidx].m_table[len_of_mbuf - 1];
m->ol_flags = PKT_TX_IP_CKSUM | PKT_TX_IPV4;
m->l2_len = sizeof(struct ether_hdr);
m->l3_len = (iph->ihl<<2);
@ -630,7 +760,7 @@ dpdk_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
case PKT_TX_TCP_CSUM:
if ((dev_info[nif].tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) == 0)
goto dev_ioctl_err;
m = dpc->wmbufs[nif].m_table[len_of_mbuf - 1];
m = dpc->wmbufs[eidx].m_table[len_of_mbuf - 1];
tcph = (struct tcphdr *)((unsigned char *)iph + (iph->ihl<<2));
m->ol_flags |= PKT_TX_TCP_CKSUM;
tcph->check = rte_ipv4_phdr_cksum((struct ipv4_hdr *)iph, m->ol_flags);
@ -667,7 +797,7 @@ dpdk_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
goto dev_ioctl_err;
if ((dev_info[nif].tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) == 0)
goto dev_ioctl_err;
m = dpc->wmbufs[nif].m_table[len_of_mbuf - 1];
m = dpc->wmbufs[eidx].m_table[len_of_mbuf - 1];
iph = rte_pktmbuf_mtod_offset(m, struct iphdr *, sizeof(struct ether_hdr));
tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2));
m->l2_len = sizeof(struct ether_hdr);
@ -678,7 +808,7 @@ dpdk_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
break;
case PKT_RX_IP_CSUM:
if ((dev_info[nif].rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM) == 0)
goto dev_ioctl_err;
goto dev_ioctl_err;
break;
case PKT_RX_TCP_CSUM:
if ((dev_info[nif].rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM) == 0)
@ -688,7 +818,7 @@ dpdk_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
if ((dev_info[nif].tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) == 0)
goto dev_ioctl_err;
if ((dev_info[nif].tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) == 0)
goto dev_ioctl_err;
goto dev_ioctl_err;
break;
default:
goto dev_ioctl_err;

View File

@ -38,7 +38,7 @@ EthernetOutput(struct mtcp_manager *mtcp, uint16_t h_proto,
{
uint8_t *buf;
struct ethhdr *ethh;
int i;
int i, eidx;
/*
* -sanity check-
@ -49,7 +49,13 @@ EthernetOutput(struct mtcp_manager *mtcp, uint16_t h_proto,
return NULL;
}
buf = mtcp->iom->get_wptr(mtcp->ctx, nif, iplen + ETHERNET_HEADER_LEN);
eidx = CONFIG.nif_to_eidx[nif];
if (eidx < 0) {
TRACE_INFO("No interface selected!\n");
return NULL;
}
buf = mtcp->iom->get_wptr(mtcp->ctx, eidx, iplen + ETHERNET_HEADER_LEN);
if (!buf) {
//TRACE_DBG("Failed to get available write buffer\n");
return NULL;
@ -65,7 +71,7 @@ EthernetOutput(struct mtcp_manager *mtcp, uint16_t h_proto,
ethh = (struct ethhdr *)buf;
for (i = 0; i < ETH_ALEN; i++) {
ethh->h_source[i] = CONFIG.eths[nif].haddr[i];
ethh->h_source[i] = CONFIG.eths[eidx].haddr[i];
ethh->h_dest[i] = dst_haddr[i];
}
ethh->h_proto = htons(h_proto);

View File

@ -111,19 +111,26 @@ mtcp_epoll_create(mctx_t mctx, int size)
/* create event queues */
ep->usr_queue = CreateEventQueue(size);
if (!ep->usr_queue)
if (!ep->usr_queue) {
FreeSocket(mctx, epsocket->id, FALSE);
free(ep);
return -1;
}
ep->usr_shadow_queue = CreateEventQueue(size);
if (!ep->usr_shadow_queue) {
DestroyEventQueue(ep->usr_queue);
FreeSocket(mctx, epsocket->id, FALSE);
free(ep);
return -1;
}
ep->mtcp_queue = CreateEventQueue(size);
if (!ep->mtcp_queue) {
DestroyEventQueue(ep->usr_queue);
DestroyEventQueue(ep->usr_shadow_queue);
DestroyEventQueue(ep->usr_queue);
FreeSocket(mctx, epsocket->id, FALSE);
free(ep);
return -1;
}
@ -133,9 +140,19 @@ mtcp_epoll_create(mctx_t mctx, int size)
epsocket->ep = ep;
if (pthread_mutex_init(&ep->epoll_lock, NULL)) {
DestroyEventQueue(ep->mtcp_queue);
DestroyEventQueue(ep->usr_shadow_queue);
DestroyEventQueue(ep->usr_queue);
FreeSocket(mctx, epsocket->id, FALSE);
free(ep);
return -1;
}
if (pthread_cond_init(&ep->epoll_cond, NULL)) {
DestroyEventQueue(ep->mtcp_queue);
DestroyEventQueue(ep->usr_shadow_queue);
DestroyEventQueue(ep->usr_queue);
FreeSocket(mctx, epsocket->id, FALSE);
free(ep);
return -1;
}
@ -162,7 +179,6 @@ CloseEpollSocket(mctx_t mctx, int epid)
DestroyEventQueue(ep->usr_queue);
DestroyEventQueue(ep->usr_shadow_queue);
DestroyEventQueue(ep->mtcp_queue);
free(ep);
pthread_mutex_lock(&ep->epoll_lock);
mtcp->ep = NULL;
@ -172,6 +188,7 @@ CloseEpollSocket(mctx_t mctx, int epid)
pthread_cond_destroy(&ep->epoll_cond);
pthread_mutex_destroy(&ep->epoll_lock);
free(ep);
return 0;
}

View File

@ -33,6 +33,10 @@ FetchAddress(addr_pool_t ap, int core, int num_queues,
const struct sockaddr_in *daddr, struct sockaddr_in *saddr);
/*----------------------------------------------------------------------------*/
int
FetchAddressPerCore(addr_pool_t ap, int core, int num_queues,
const struct sockaddr_in *daddr, struct sockaddr_in *saddr);
/*----------------------------------------------------------------------------*/
int
FreeAddress(addr_pool_t ap, const struct sockaddr_in *addr);
/*----------------------------------------------------------------------------*/

View File

@ -5,9 +5,6 @@
#include <stdint.h>
/* for ps lib funcs */
#include "ps.h"
/* for onvm */
#include "onvm_nflib.h"
#include "onvm_pkt_helper.h"
/*----------------------------------------------------------------------------*/
/**
* Declaration to soothe down the warnings
@ -15,27 +12,27 @@
struct mtcp_thread_context;
/**
* io_module_funcs - contains template for the various 10Gbps pkt I/O
* - libraries that can be adopted.
* - libraries that can be adopted.
*
* load_module() : Used to set system-wide I/O module
* initialization.
*
* init_handle() : Used to initialize the driver library
* : Also use the context to create/initialize
* : a private packet I/O data structures.
* init_handle() : Used to initialize the driver library
* : Also use the context to create/initialize
* : a private packet I/O data structures.
*
* link_devices() : Used to add link(s) to the mtcp stack.
* link_devices() : Used to add link(s) to the mtcp stack.
* Returns 0 on success; -1 on failure.
*
* release_pkt() : release the packet if mTCP does not need
* to process it (e.g. non-IPv4, non-TCP pkts).
*
* get_wptr() : retrieve the next empty pkt buffer for the
* application for packet writing. Returns
* application for packet writing. Returns
* ptr to pkt buffer.
*
* send_pkts() : transmit batch of packets via interface
* idx (=nif).
* idx (=nif).
* Returns 0 on success; -1 on failure
*
* get_rptr() : retrieve next pkt for application for
@ -50,17 +47,17 @@ struct mtcp_thread_context;
* select() : for blocking I/O
*
* destroy_handle() : free up resources allocated during
* init_handle(). Normally called during
* init_handle(). Normally called during
* process termination.
*
* dev_ioctl() : contains submodules for select drivers
* dev_ioctl() : contains submodules for select drivers
*
*/
typedef struct io_module_func {
void (*load_module)(void);
void (*init_handle)(struct mtcp_thread_context *ctx);
void (*init_handle)(struct mtcp_thread_context *ctx);
int32_t (*link_devices)(struct mtcp_thread_context *ctx);
void (*release_pkt)(struct mtcp_thread_context *ctx, int ifidx, unsigned char *pkt_data, int len);
void (*release_pkt)(struct mtcp_thread_context *ctx, int ifidx, unsigned char *pkt_data, int len);
uint8_t * (*get_wptr)(struct mtcp_thread_context *ctx, int ifidx, uint16_t len);
int32_t (*send_pkts)(struct mtcp_thread_context *ctx, int nif);
uint8_t * (*get_rptr)(struct mtcp_thread_context *ctx, int ifidx, int index, uint16_t *len);
@ -72,22 +69,26 @@ typedef struct io_module_func {
/*----------------------------------------------------------------------------*/
/* set I/O module context */
int SetInterfaceInfo(char *);
/* retrive device-specific endian type */
int FetchEndianType();
/*----------------------------------------------------------------------------*/
/* ptr to the `running' I/O module context */
extern io_module_func *current_iomodule_func;
/* dev_ioctl related macros */
#define PKT_TX_IP_CSUM 0x01
#define PKT_TX_TCP_CSUM 0x02
#define PKT_TX_IP_CSUM 0x01
#define PKT_TX_TCP_CSUM 0x02
#define PKT_RX_TCP_LROSEG 0x03
#define PKT_TX_TCPIP_CSUM 0x04
#define PKT_RX_IP_CSUM 0x05
#define PKT_RX_TCP_CSUM 0x06
#define PKT_TX_TCPIP_CSUM_PEEK 0x07
#define DRV_NAME 0x08
/* registered psio context */
#ifdef DISABLE_PSIO
#define ps_list_devices(x) 0
#define ps_list_devices(x) 0
#endif
extern io_module_func ps_module_func;
struct ps_device devices[MAX_DEVICES];
@ -109,8 +110,8 @@ extern io_module_func onvm_module_func;
current_iomodule_func = &dpdk_module_func; \
else if (!strcmp(m, "netmap")) \
current_iomodule_func = &netmap_module_func; \
else if (!strcmp(m, "onvm")) \
current_iomodule_func = &onvm_module_func; \
else if (!strcmp(m, "onvm")) \
current_iomodule_func = &onvm_module_func; \
else \
assert(0); \
}

View File

@ -32,8 +32,6 @@
#define ERROR (-1)
#endif
#define MAX_CPUS 16
#define ETHERNET_HEADER_LEN 14 // sizeof(struct ethhdr)
#define IP_HEADER_LEN 20 // sizeof(struct iphdr)
#define TCP_HEADER_LEN 20 // sizeof(struct tcphdr)
@ -55,6 +53,9 @@
/* blocking api became obsolete */
#define BLOCKING_SUPPORT FALSE
#ifndef MAX_CPUS
#define MAX_CPUS 16
#endif
/*----------------------------------------------------------------------------*/
/* Statistics */
#ifdef NETSTAT
@ -83,6 +84,14 @@
#define SBUF_LOCK(lock) pthread_mutex_lock(lock)
#define SBUF_UNLOCK(lock) pthread_mutex_unlock(lock)
#endif /* USE_SPIN_LOCK */
/* add macro if it is not defined in /usr/include/sys/queue.h */
#ifndef TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
/*----------------------------------------------------------------------------*/
struct eth_table
{
@ -126,6 +135,7 @@ struct mtcp_config
/* network interface config */
struct eth_table *eths;
int *nif_to_eidx; // mapping physic port indexes to that of the configured port-list
int eths_num;
/* route config */
@ -139,14 +149,6 @@ struct mtcp_config
int num_mem_ch;
int max_concurrency;
/* dpdk args */
char * core_list;
/* onvm args */
uint16_t service_id;
uint16_t instance_id;
uint16_t dest_id;
int max_num_buffers;
int rcvbuf_size;
int sndbuf_size;
@ -158,6 +160,13 @@ struct mtcp_config
uint8_t multi_process;
uint8_t multi_process_is_master;
uint8_t multi_process_curr_core;
#ifdef ENABLE_ONVM
/* onvm specific args */
uint16_t onvm_serv;
uint16_t onvm_inst;
uint16_t onvm_dest;
#endif
};
/*----------------------------------------------------------------------------*/
struct mtcp_context

View File

@ -36,8 +36,6 @@ struct mtcp_conf
int rcvbuf_size;
int sndbuf_size;
char * core_list;
int tcp_timewait;
int tcp_timeout;
};
@ -45,7 +43,7 @@ struct mtcp_conf
typedef struct mtcp_context *mctx_t;
int
mtcp_init(const char *config_file, int argc, char *argv[]);
mtcp_init(const char *config_file);
void
mtcp_destroy();
@ -56,9 +54,6 @@ mtcp_getconf(struct mtcp_conf *conf);
int
mtcp_setconf(const struct mtcp_conf *conf);
int
mtcp_parse_args(int argc, char *argv[]);
int
mtcp_core_affinitize(int cpu);

View File

@ -27,6 +27,11 @@
/* for getifaddrs */
#include <sys/types.h>
#include <ifaddrs.h>
#ifdef ENABLE_ONVM
/* for onvm */
#include "onvm_nflib.h"
#include "onvm_pkt_helper.h"
#endif
/*----------------------------------------------------------------------------*/
io_module_func *current_iomodule_func = &dpdk_module_func;
#define ALL_STRING "all"
@ -38,13 +43,13 @@ io_module_func *current_iomodule_func = &dpdk_module_func;
/* onvm struct for port info lookup */
extern struct port_info *ports;
static int
static int
GetNumQueues()
{
FILE *fp;
char buf[MAX_PROCLINE_LEN];
int queue_cnt;
fp = fopen("/proc/interrupts", "r");
if (!fp) {
TRACE_CONFIG("Failed to read data from /proc/interrupts!\n");
@ -68,7 +73,7 @@ GetNumQueues()
}
/*----------------------------------------------------------------------------*/
int
SetInterfaceInfo(char* dev_name_list)
SetInterfaceInfo(char* dev_name_list)
{
struct ifreq ifr;
int eidx = 0;
@ -77,11 +82,13 @@ SetInterfaceInfo(char* dev_name_list)
int set_all_inf = (strncmp(dev_name_list, ALL_STRING, sizeof(ALL_STRING))==0);
TRACE_CONFIG("Loading interface setting\n");
CONFIG.eths = (struct eth_table *)
calloc(MAX_DEVICES, sizeof(struct eth_table));
if (!CONFIG.eths)
if (!CONFIG.eths) {
TRACE_ERROR("Can't allocate space for CONFIG.eths\n");
exit(EXIT_FAILURE);
}
if (current_iomodule_func == &ps_module_func) {
/* calculate num_devices now! */
@ -89,47 +96,48 @@ SetInterfaceInfo(char* dev_name_list)
if (num_devices == -1) {
perror("ps_list_devices");
exit(EXIT_FAILURE);
}
}
/* Create socket */
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
perror("socket");
TRACE_ERROR("socket");
exit(EXIT_FAILURE);
}
/* To Do: Parse dev_name_list rather than use strstr */
for (i = 0; i < num_devices; i++) {
strcpy(ifr.ifr_name, devices[i].name);
/* getting interface information */
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (!set_all_inf && strstr(dev_name_list, ifr.ifr_name) == NULL)
continue;
/* Setting informations */
eidx = CONFIG.eths_num++;
strcpy(CONFIG.eths[eidx].dev_name, ifr.ifr_name);
CONFIG.eths[eidx].ifindex = devices[i].ifindex;
/* getting address */
if (ioctl(sock, SIOCGIFADDR, &ifr) == 0 ) {
struct in_addr sin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
CONFIG.eths[eidx].ip_addr = *(uint32_t *)&sin;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0 ) {
for (j = 0; j < ETH_ALEN; j ++) {
CONFIG.eths[eidx].haddr[j] = ifr.ifr_addr.sa_data[j];
}
}
/* Net MASK */
if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0) {
struct in_addr sin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
CONFIG.eths[eidx].netmask = *(uint32_t *)&sin;
}
/* add to attached devices */
for (j = 0; j < num_devices_attached; j++) {
if (devices_attached[j] == devices[i].ifindex) {
@ -138,20 +146,23 @@ SetInterfaceInfo(char* dev_name_list)
}
devices_attached[num_devices_attached] = devices[i].ifindex;
num_devices_attached++;
} else {
} else {
perror("SIOCGIFFLAGS");
}
}
num_queues = GetNumQueues();
if (num_queues <= 0) {
TRACE_CONFIG("Failed to find NIC queues!\n");
close(sock);
return -1;
}
if (num_queues > num_cpus) {
TRACE_CONFIG("Too many NIC queues available.\n");
close(sock);
return -1;
}
close(sock);
} else if (current_iomodule_func == &dpdk_module_func) {
#ifndef DISABLE_DPDK
int cpu = CONFIG.num_cores;
@ -160,7 +171,7 @@ SetInterfaceInfo(char* dev_name_list)
char mem_channels[5];
int ret;
static struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
/* get the cpu mask */
for (ret = 0; ret < cpu; ret++)
cpumask = (cpumask | (1 << ret));
@ -175,17 +186,17 @@ SetInterfaceInfo(char* dev_name_list)
sprintf(mem_channels, "%d", CONFIG.num_mem_ch);
/* initialize the rte env first, what a waste of implementation effort! */
char *argv[] = {"",
"-c",
cpumaskbuf,
"-n",
char *argv[] = {"",
"-c",
cpumaskbuf,
"-n",
mem_channels,
"--proc-type=auto",
""
};
const int argc = 6;
/*
/*
* re-set getopt extern variable optind.
* this issue was a bitch to debug
* rte_eal_init() internally uses getopt() syscall
@ -205,11 +216,11 @@ SetInterfaceInfo(char* dev_name_list)
if (num_devices == 0) {
rte_exit(EXIT_FAILURE, "No Ethernet port!\n");
}
/* get mac addr entries of 'detected' dpdk ports */
for (ret = 0; ret < num_devices; ret++)
rte_eth_macaddr_get(ret, &ports_eth_addr[ret]);
num_queues = MIN(CONFIG.num_cores, MAX_CPUS);
struct ifaddrs *ifap;
@ -220,16 +231,16 @@ SetInterfaceInfo(char* dev_name_list)
perror("getifaddrs: ");
exit(EXIT_FAILURE);
}
iter_if = ifap;
do {
if (iter_if->ifa_addr->sa_family == AF_INET &&
!set_all_inf &&
!set_all_inf &&
(seek=strstr(dev_name_list, iter_if->ifa_name)) != NULL &&
/* check if the interface was not aliased */
*(seek + strlen(iter_if->ifa_name)) != ':') {
struct ifreq ifr;
/* Setting informations */
eidx = CONFIG.eths_num++;
strcpy(CONFIG.eths[eidx].dev_name, iter_if->ifa_name);
@ -239,8 +250,9 @@ SetInterfaceInfo(char* dev_name_list)
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
perror("socket");
}
exit(EXIT_FAILURE);
}
/* getting address */
if (ioctl(sock, SIOCGIFADDR, &ifr) == 0 ) {
struct in_addr sin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
@ -259,29 +271,29 @@ SetInterfaceInfo(char* dev_name_list)
CONFIG.eths[eidx].netmask = *(uint32_t *)&sin;
}
close(sock);
for (j = 0; j < num_devices; j++) {
if (!memcmp(&CONFIG.eths[eidx].haddr[0], &ports_eth_addr[j],
ETH_ALEN))
CONFIG.eths[eidx].ifindex = j;
}
/* add to attached devices */
for (j = 0; j < num_devices_attached; j++) {
if (devices_attached[j] == CONFIG.eths[eidx].ifindex) {
break;
}
}
}
devices_attached[num_devices_attached] = CONFIG.eths[eidx].ifindex;
num_devices_attached++;
fprintf(stderr, "Total number of attached devices: %d\n",
num_devices_attached);
fprintf(stderr, "Interface name: %s\n",
fprintf(stderr, "Interface name: %s\n",
iter_if->ifa_name);
}
iter_if = iter_if->ifa_next;
} while (iter_if != NULL);
freeifaddrs(ifap);
#endif /* !DISABLE_DPDK */
} else if (current_iomodule_func == &netmap_module_func) {
@ -296,39 +308,40 @@ SetInterfaceInfo(char* dev_name_list)
perror("getifaddrs: ");
exit(EXIT_FAILURE);
}
iter_if = ifap;
do {
if (iter_if->ifa_addr->sa_family == AF_INET &&
!set_all_inf &&
!set_all_inf &&
(seek=strstr(dev_name_list, iter_if->ifa_name)) != NULL &&
/* check if the interface was not aliased */
*(seek + strlen(iter_if->ifa_name)) != ':') {
struct ifreq ifr;
/* Setting informations */
eidx = CONFIG.eths_num++;
strcpy(CONFIG.eths[eidx].dev_name, iter_if->ifa_name);
strcpy(ifr.ifr_name, iter_if->ifa_name);
/* Create socket */
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
perror("socket");
}
exit(EXIT_FAILURE);
}
/* getting address */
if (ioctl(sock, SIOCGIFADDR, &ifr) == 0 ) {
struct in_addr sin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
CONFIG.eths[eidx].ip_addr = *(uint32_t *)&sin;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0 ) {
for (j = 0; j < ETH_ALEN; j ++) {
CONFIG.eths[eidx].haddr[j] = ifr.ifr_addr.sa_data[j];
}
}
/* Net MASK */
if (ioctl(sock, SIOCGIFNETMASK, &ifr) == 0) {
struct in_addr sin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
@ -342,32 +355,32 @@ SetInterfaceInfo(char* dev_name_list)
CONFIG.eths[eidx].ifindex = ifr.ifr_ifindex;
#endif
CONFIG.eths[eidx].ifindex = eidx;//if_nametoindex(ifr.ifr_name);
TRACE_INFO("Ifindex of interface %s is: %d\n",
TRACE_INFO("Ifindex of interface %s is: %d\n",
ifr.ifr_name, CONFIG.eths[eidx].ifindex);
#if 0
}
#endif
/* add to attached devices */
for (j = 0; j < num_devices_attached; j++) {
if (devices_attached[j] == CONFIG.eths[eidx].ifindex) {
break;
}
}
}
devices_attached[num_devices_attached] = if_nametoindex(ifr.ifr_name);//CONFIG.eths[eidx].ifindex;
num_devices_attached++;
fprintf(stderr, "Total number of attached devices: %d\n",
num_devices_attached);
fprintf(stderr, "Interface name: %s\n",
fprintf(stderr, "Interface name: %s\n",
iter_if->ifa_name);
}
iter_if = iter_if->ifa_next;
} while (iter_if != NULL);
freeifaddrs(ifap);
#endif /* !DISABLE_NETMAP */
} else if (current_iomodule_func == &onvm_module_func) {
#ifndef DISABLE_DPDK
#ifdef ENABLE_ONVM
int cpu = CONFIG.num_cores;
uint32_t cpumask = 0;
char cpumaskbuf[10];
@ -388,13 +401,13 @@ SetInterfaceInfo(char* dev_name_list)
exit(EXIT_FAILURE);
}
sprintf(mem_channels, "%d", CONFIG.num_mem_ch);
sprintf(service, "%d", CONFIG.service_id);
sprintf(instance, "%d", CONFIG.instance_id);
sprintf(service, "%d", CONFIG.onvm_serv);
sprintf(instance, "%d", CONFIG.onvm_inst);
/* initialize the rte env first, what a waste of implementation effort! */
char *argv[] = {"",
"-l",
CONFIG.core_list,
"-c",
cpumaskbuf,
"-n",
mem_channels,
"--proc-type=secondary",
@ -486,7 +499,48 @@ SetInterfaceInfo(char* dev_name_list)
} while (iter_if != NULL);
freeifaddrs(ifap);
#endif /* !DISABLE_DPDK */
}return 0;
#endif /* ENABLE_ONVM */
}
CONFIG.nif_to_eidx = (int*)calloc(MAX_DEVICES, sizeof(int));
if (!CONFIG.nif_to_eidx) {
exit(EXIT_FAILURE);
}
for (i = 0; i < MAX_DEVICES; ++i) {
CONFIG.nif_to_eidx[i] = -1;
}
for (i = 0; i < CONFIG.eths_num; ++i) {
j = CONFIG.eths[i].ifindex;
if (j >= MAX_DEVICES) {
TRACE_ERROR("ifindex of eths_%d exceed the limit: %d\n", i, j);
exit(EXIT_FAILURE);
}
/* the physic port index of the i-th port listed in the config file is j*/
CONFIG.nif_to_eidx[j] = i;
}
return 0;
}
/*----------------------------------------------------------------------------*/
int
FetchEndianType()
{
#ifndef DISABLE_DPDK
char *argv;
char **argp = &argv;
/* dpdk_module_func logic down below */
dpdk_module_func.dev_ioctl(NULL, CONFIG.eths[0].ifindex, DRV_NAME, (void *)argp);
if (!strcmp(*argp, "net_i40e"))
return 1;
return 0;
#else
return 1;
#endif
}
/*----------------------------------------------------------------------------*/

View File

@ -9,7 +9,6 @@ inline int
GetOutputInterface(uint32_t daddr)
{
int nif = -1;
int nif_index = -1;
int i;
int prefix = 0;
@ -30,22 +29,7 @@ GetOutputInterface(uint32_t daddr)
assert(0);
}
/* match nif to eth nif_index */
for (i = 0; i < CONFIG.eths_num; i++) {
if (CONFIG.eths[i].ifindex == nif) {
nif_index = i;
break;
}
}
if (nif_index < 0) {
uint8_t *da = (uint8_t *)&daddr;
TRACE_ERROR("[WARNING] No eth id for route to %u.%u.%u.%u\n",
da[0], da[1], da[2], da[3]);
assert(0);
}
return nif_index;
return nif;
}
/*----------------------------------------------------------------------------*/
uint8_t *
@ -92,8 +76,16 @@ IPOutputStandalone(struct mtcp_manager *mtcp, uint8_t protocol,
iph->check = 0;
#ifndef DISABLE_HWCSUM
if (mtcp->iom->dev_ioctl != NULL)
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_TCPIP_CSUM_PEEK, iph);
if (mtcp->iom->dev_ioctl != NULL) {
switch(iph->protocol) {
case IPPROTO_TCP:
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_TCPIP_CSUM_PEEK, iph);
break;
case IPPROTO_ICMP:
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
break;
}
}
/* otherwise calculate IP checksum in S/W */
if (rc == -1)
iph->check = ip_fast_csum(iph, iph->ihl);
@ -154,8 +146,16 @@ IPOutput(struct mtcp_manager *mtcp, tcp_stream *stream, uint16_t tcplen)
#ifndef DISABLE_HWCSUM
/* offload IP checkum if possible */
if (mtcp->iom->dev_ioctl != NULL)
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_TCPIP_CSUM_PEEK, iph);
if (mtcp->iom->dev_ioctl != NULL) {
switch (iph->protocol) {
case IPPROTO_TCP:
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_TCPIP_CSUM_PEEK, iph);
break;
case IPPROTO_ICMP:
rc = mtcp->iom->dev_ioctl(mtcp->ctx, nif, PKT_TX_IP_CSUM, iph);
break;
}
}
/* otherwise calculate IP checksum in S/W */
if (rc == -1)
iph->check = ip_fast_csum(iph, iph->ihl);

View File

@ -67,7 +67,7 @@ MPCreate(int chunk_size, size_t total_size, int is_hugepage)
if (!mp->mp_startptr) {
TRACE_ERROR("posix_memalign failed, size=%ld\n", total_size);
assert(0);
if (mp) free(mp);
free(mp);
return (NULL);
}
} else {
@ -76,7 +76,7 @@ MPCreate(int chunk_size, size_t total_size, int is_hugepage)
if (res != 0) {
TRACE_ERROR("posix_memalign failed, size=%ld\n", total_size);
assert(0);
if (mp) free(mp);
free(mp);
return (NULL);
}
#ifdef HUGETABLE

View File

@ -1,6 +1,6 @@
/* for io_module_func def'ns */
#include "io_module.h"
#ifndef DISABLE_DPDK
#ifdef ENABLE_ONVM
/* for mtcp related def'ns */
#include "mtcp.h"
/* for errno */
@ -216,13 +216,13 @@ onvm_send_pkts(struct mtcp_thread_context *ctxt, int nif)
for(i=0;i<cnt;i++){
meta = onvm_get_pkt_meta(pkts[i]);
if (CONFIG.dest_id == (uint16_t) -1){
if (CONFIG.onvm_dest == (uint16_t) -1){
meta->action = ONVM_NF_ACTION_OUT;
meta->destination = CONFIG.eths[nif].ifindex;
}
else {
meta->action = ONVM_NF_ACTION_TONF;
meta->destination = CONFIG.dest_id;
meta->destination = CONFIG.onvm_dest;
}
}
ret = rte_ring_enqueue_bulk(tx_ring, (void * const*)pkts ,cnt);
@ -529,4 +529,4 @@ io_module_func onvm_module_func = {
.dev_ioctl = NULL
};
/*----------------------------------------------------------------------------*/
#endif /* !DISABLE_DPDK */
#endif /* ENABLE_ONVM */

View File

@ -88,8 +88,8 @@ mtcp_pipe(mctx_t mctx, int pipeid[2])
FreeSocket(mctx, socket[0]->id, FALSE);
FreeSocket(mctx, socket[1]->id, FALSE);
free(pp->buf);
free(pp);
pthread_mutex_destroy(&pp->pipe_lock);
free(pp);
return -1;
}

View File

@ -1243,8 +1243,14 @@ ProcessTCPPacket(mtcp_manager_t mtcp,
/* SYN retransmit implies our SYN/ACK was lost. Resend */
if (tcph->syn && seq == cur_stream->rcvvar->irs)
Handle_TCP_ST_LISTEN(mtcp, cur_ts, cur_stream, tcph);
else
else {
Handle_TCP_ST_SYN_RCVD(mtcp, cur_ts, cur_stream, tcph, ack_seq);
if (payloadlen > 0 && cur_stream->state == TCP_ST_ESTABLISHED) {
Handle_TCP_ST_ESTABLISHED(mtcp, cur_ts, cur_stream, tcph,
seq, ack_seq, payload,
payloadlen, window);
}
}
break;
case TCP_ST_ESTABLISHED:

View File

@ -365,6 +365,7 @@ FlushTCPSendingBuffer(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_
int16_t sndlen;
uint32_t window;
int packets = 0;
uint8_t wack_sent = 0;
if (!sndvar->sndbuf) {
TRACE_ERROR("Stream %d: No send buffer available.\n", cur_stream->id);
@ -410,6 +411,9 @@ FlushTCPSendingBuffer(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_
len = buffered_len;
}
if (len > window)
len = window;
if (len <= 0)
break;
@ -426,9 +430,11 @@ FlushTCPSendingBuffer(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_
"peer_wnd: %u, (snd_nxt-snd_una): %u\n",
sndvar->peer_wnd, seq - sndvar->snd_una);
#endif
if (TS_TO_MSEC(cur_ts - sndvar->ts_lastack_sent) > 500) {
if (!wack_sent && TS_TO_MSEC(cur_ts - sndvar->ts_lastack_sent) > 500) {
EnqueueACK(mtcp, cur_stream, cur_ts, ACK_OPT_WACK);
}
else
wack_sent = 1;
}
packets = -3;
goto out;
@ -441,6 +447,8 @@ FlushTCPSendingBuffer(mtcp_manager_t mtcp, tcp_stream *cur_stream, uint32_t cur_
goto out;
}
packets++;
window -= len;
}
out:
@ -790,14 +798,15 @@ GetSender(mtcp_manager_t mtcp, tcp_stream *cur_stream)
{
if (cur_stream->sndvar->nif_out < 0) {
return mtcp->g_sender;
}
} else if (cur_stream->sndvar->nif_out >= CONFIG.eths_num) {
int eidx = CONFIG.nif_to_eidx[cur_stream->sndvar->nif_out];
if (eidx < 0 || eidx >= CONFIG.eths_num) {
TRACE_ERROR("(NEVER HAPPEN) Failed to find appropriate sender.\n");
return NULL;
} else {
return mtcp->n_sender[cur_stream->sndvar->nif_out];
}
return mtcp->n_sender[eidx];
}
/*----------------------------------------------------------------------------*/
inline void

View File

@ -197,6 +197,7 @@ RBInit(rb_manager_t rbm, uint32_t init_seq)
buff->data = MPAllocateChunk(rbm->mp);
if(!buff->data){
perror("rb_init MPAllocateChunk");
free(buff);
return NULL;
}

View File

@ -46,6 +46,8 @@ SBManagerCreate(size_t chunk_size, uint32_t cnum)
sbm->freeq = CreateSBQueue(cnum);
if (!sbm->freeq) {
TRACE_ERROR("Failed to create free buffer queue.\n");
MPDestroy(sbm->mp);
free(sbm);
return NULL;
}
@ -62,12 +64,13 @@ SBInit(sb_manager_t sbm, uint32_t init_seq)
if (!buf) {
buf = (struct tcp_send_buffer *)malloc(sizeof(struct tcp_send_buffer));
if (!buf) {
perror("calloc() for buf");
perror("malloc() for buf");
return NULL;
}
buf->data = MPAllocateChunk(sbm->mp);
if (!buf->data) {
TRACE_ERROR("Failed to fetch memory chunk for data.\n");
free(buf);
return NULL;
}
sbm->cur_num++;

View File

@ -500,9 +500,14 @@ DestroyTCPStream(mtcp_manager_t mtcp, tcp_stream *stream)
if (mtcp->ap) {
ret = FreeAddress(mtcp->ap, &addr);
} else {
int nif;
nif = GetOutputInterface(addr.sin_addr.s_addr);
ret = FreeAddress(ap[nif], &addr);
int nif = GetOutputInterface(addr.sin_addr.s_addr);
if (nif < 0) {
TRACE_ERROR("nif is negative!\n");
ret = -1;
} else {
int eidx = CONFIG.nif_to_eidx[nif];
ret = FreeAddress(ap[eidx], &addr);
}
}
if (ret < 0) {
TRACE_ERROR("(NEVER HAPPEN) Failed to free address.\n");

View File

@ -1,6 +1,12 @@
### GCC ###
GCC=@CC@
GCC_OPT = -m64 -Wall -fPIC -c
ifeq ($(shell uname -m),x86_64)
GCC_OPT = -m64
else
GCC_OPT =
endif
GCC_OPT += -Wall -fPIC -c
GCC_OPT += -DNDEBUG -O3 -DNETSTAT -DINFO -DDBGERR -DDBGCERR
@ -8,7 +14,7 @@ GCC_OPT += -DNDEBUG -O3 -DNETSTAT -DINFO -DDBGERR -DDBGCERR
CFLAGS = -I./include/
### SOURCE CODE ###
SRCS = tdate_parse.c http_parsing.c
SRCS = tdate_parse.c http_parsing.c netlib.c
OBJS = $(patsubst %.c,%.o,$(SRCS))

View File

@ -106,12 +106,10 @@ http_header_str_val(const char* buf, const char *key, const int keylen,
}
/* copy value data */
if (temp) {
while (*temp && !CR_OR_NEWLINE(*temp) && i < value_len-1)
value[i++] = *temp++;
value[i] = 0;
}
while (*temp && !CR_OR_NEWLINE(*temp) && i < value_len-1)
value[i++] = *temp++;
value[i] = 0;
if (i == 0) {
*value = 0;
return NULL;

View File

@ -31,6 +31,7 @@ int GetNumCPUCores(void);
int AffinitizeThreadToCore(int core);
int CreateServerSocket(int port, int isNonBlocking);
int CreateConnectionSocket(in_addr_t addr, int port, int isNonBlocking);
int mystrtol(const char *nptr, int base);
/* processing options */
struct Options {

View File

@ -12,6 +12,7 @@
#include <stdio.h>
#include <netdb.h>
#include <ctype.h>
#include <limits.h>
#include "netlib.h"
@ -233,3 +234,27 @@ GetHeaderLong(const char* buf, const char* header, int hdrsize, long int *val)
}
return (FALSE);
}
/*----------------------------------------------------------------------------*/
int
mystrtol(const char *nptr, int base)
{
int rval;
char *endptr;
errno = 0;
rval = strtol(nptr, &endptr, 10);
/* check for strtol errors */
if ((errno == ERANGE && (rval == LONG_MAX ||
rval == LONG_MIN))
|| (errno != 0 && rval == 0)) {
perror("strtol");
exit(EXIT_FAILURE);
}
if (endptr == nptr) {
fprintf(stderr, "Parsing strtol error!\n");
exit(EXIT_FAILURE);
}
return rval;
}
/*----------------------------------------------------------------------------*/