- add netmap-libpcap

- add netmap (FreeBSD header files need to be updated with this)
- move prototype perl scripts to prototype/ folder
- create basic structure for sipcap app (no code yet)
This commit is contained in:
farrokhi
2014-07-10 17:04:13 +04:30
parent 19fc3fb80f
commit ccdba9490b
334 changed files with 121141 additions and 0 deletions

169
netmap/LINUX/Makefile Normal file
View File

@ -0,0 +1,169 @@
# To build external modules, you must have a prebuilt kernel available
# that contains the configuration and header files used in the build.
# go in the kernel directory and do a
# make oldconfig; make scripts; make prepare
# or make defconfig; make scripts; make prepare
#
# list of objects for this module
#
# objects whose source file is in ../sys/dev/netmap
remoteobjs := netmap.o netmap_mem2.o \
netmap_generic.o netmap_mbq.o netmap_vale.o \
netmap_offloadings.o netmap_pipe.o
# all objects
netmap_lin-objs := $(remoteobjs) netmap_linux.o
obj-$(CONFIG_NETMAP) = netmap_lin.o
ifndef NODRIVERS
# list of modules to be built (actually also forcedeth and r8169)
MOD_LIST:= CONFIG_E1000=m CONFIG_E1000E=m \
CONFIG_IXGBE=m CONFIG_IGB=m \
CONFIG_BNX2X=m CONFIG_MLX4=m \
CONFIG_VIRTIO_NET=m
obj-m += $(O_DRIVERS)
GET_DRIVERS := get-drivers
else
MOD_LIST:=
endif
# DRIVER_SRCS names of the driver sources is only used to
# clean files that we copied.
DRIVER_SRCS = r8169.c forcedeth.c e1000/ e1000e/ ixgbe/ igb/
DRIVER_SRCS += bnx2x/ mellanox/ mlx4/ virtio_net.c
# _DRV_SUBDIRS contains the subdirs with driver sources.
# In old linuxes everything is under drivers/net, newer versions
# have them in source/drivers/net/ethernet/$(manufacturer)
_DRV_SUBDIRS= nvidia realtek intel broadcom . ..
# The following commands are needed to build the modules as out-of-tree,
# in fact the kernel sources path must be specified.
PWD ?= $(CURDIR)
M:=$(PWD)
# Additional compile flags (e.g. header location)
EXTRA_CFLAGS := -I$(M) -I$(M)/../sys -I$(M)/../sys/dev -DCONFIG_NETMAP
EXTRA_CFLAGS += -Wno-unused-but-set-variable
# We use KSRC for the kernel configuration and sources.
# If the sources are elsewhere, then use SRC to point to them.
KSRC ?= /lib/modules/$(shell uname -r)/build
SRC ?= $(KSRC)
# extract version number.
# version.h can be in two different places.
# NOTE- A.B.C translates to aXXYY where XXYY are hex
LIN_VER = $(shell V=linux/version.h; G=. ; \
[ -f $(KSRC)/include/$${V} ] || G=generated/uapi ;\
grep LINUX_VERSION_CODE $(KSRC)/include/$${G}/linux/version.h | \
awk '{printf "%03x%02x", $$3/256, $$3%256} ')
# produce a list of applicable patches for this version
PATCHES := $(shell \
cd $(PWD)/patches; ls diff--* | awk -v v=$(LIN_VER) -F -- \
'{ if ((!$$3 || $$3 <= v) && (!$$4 || v < $$4)) print $$0; }')
# source drivers to copy. Names derived from the patches
S_DRIVERS := $(shell \
cd $(PWD)/patches; ls diff--* | awk -v v=$(LIN_VER) -F -- \
'{ if ((!$$3 || $$3 <= v) && (!$$4 || v < $$4)) print $$2 }' )
# actual drivers after copy and patch
DRIVERS = $(shell [ "$(PATCHES)" != "" ] && ls -dAp \
`echo $(PATCHES:diff--%=%) | sed -r 's/--[0-9a-f-]+//g'` 2> /dev/null)
# Compile v1000 (vhost porting to e1000) only if
# the LIN_VER >= 3.8.0, because we don't want to deal
# with backporting problems for v1000.
ifeq ($(word 1, $(sort 30800 $(LIN_VER))), 30800)
CONFIG_V1000:=m
else
CONFIG_V1000:=n
endif
CONFIG_V1000:=n # force disable by now
obj-$(CONFIG_V1000) += vhost-port/
all: build
build: $(GET_DRIVERS)
$(MAKE) -C $(KSRC) M=$(PWD) CONFIG_NETMAP=m $(MOD_LIST) \
EXTRA_CFLAGS='$(EXTRA_CFLAGS)' \
O_DRIVERS="$(DRIVERS:%.c=%.o)" modules
@ls -l `find . -name \*.ko`
test:
@echo "version $(LIN_VER)"
@echo "patches $(PATCHES)"
@echo "drivers $(DRIVERS)"
clean:
-@ $(MAKE) -C $(KSRC) M=$(PWD) clean 2> /dev/null
-@ (rm -rf $(DRIVER_SRCS) *.orig *.rej *.ko *.o .*.d \
.tmp_versions *.mod.c modules.order \
Module.symvers .*.cmd get-drivers )
# the source is not here so we need to specify a dependency
define remote_template
$$(obj)/$(1): $$(M)/../sys/dev/netmap/$(1:.o=.c)
$$(call cmd,cc_o_c)
$$(call cmd,modversions)
endef
$(foreach o,$(remoteobjs),$(eval $(call remote_template,$(o))))
#-- copy and patch initial files
# The location changes depending on the OS version, so ...
get-drivers:
-@( \
if [ -d "$(DRIVER_SRC)" ] ; then \
cd "$(DRIVER_SRC)"; s=.; what="`ls -dp *`" ; \
else \
cd $(SRC); [ -d source ] && cd source ; \
cd drivers/net; s=. ; \
[ -d ethernet ] && cd ethernet && s="$(_DRV_SUBDIRS)" ; \
what="$(S_DRIVERS)" ; \
fi ; \
echo "LIN_VER $(LIN_VER)" ; \
[ "$${what}" = "" ] && echo "-- NO DRIVERS --" && return; \
echo "---- Building from `pwd`"; \
echo "---- copying $${what} ---" ; \
what="$${what} cnic_if.h"; \
for i in $$s; do (cd $$i ; \
echo " From `pwd` :"; \
ls -ldp $${what} 2> /dev/null | sed 's/^/ /' ; \
cp -Rp $${what} $(PWD) 2>/dev/null ); \
done ; \
cd $(PWD) ; \
for i in $(PATCHES) ; \
do echo "** patch with $$i"; \
patch --posix --quiet --force -p1 < patches/$$i; \
done ; \
echo "Building the following drivers: $(S_DRIVERS)" )
@touch get-drivers
test3:
@echo "from $(PATCHES) -- to $(MYDRIVERS)"
@echo "Drivers is $(DRIVERS)"
@echo "Actually have `ls -d $(DRIVERS) 2> /dev/null`"
# compute the diffs for the original files
diffs:
@for i in `find . -name \*.orig`; do \
diff -urp $$i $${i%.orig} ; \
done
apps:
(cd ../examples; $(MAKE))
+%:
@echo $($*)

154
netmap/LINUX/README Normal file
View File

@ -0,0 +1,154 @@
# $Id: README 10863 2012-04-11 17:10:39Z luigi $
NETMAP FOR LINUX
----------------
This directory contains a version of the "netmap" and "VALE" code for Linux.
Netmap is a BSD-licensed framework that supports line-rate direct packet
I/O even on 10GBit/s interfaces (14.88Mpps) with limited system load,
and includes a libpcap emulation library to port applications.
See
http://info.iet.unipi.it/~luigi/netmap/
for more details. There you can also find the latest versions
of the code and documentation as well as pre-built TinyCore
images based on linux 3.0.3 and containing the netmap modules
and some test applications.
This version supports r8169, ixgbe, igb, e1000, e1000e and forcedeth.
Netmap relies on a kernel module (netmap_lin.ko) and slightly modified
device drivers. Userspace programs can use the native API (documented
in netmap.4) or a libpcap emulation library.
The FreeBSD and Linux versions share the same codebase, which
is located in ../sys . For Linux we use some additional glue code,
(bsd_glue.h).
Device drivers are taken directly from the Linux distributions,
and patched using the files in the patches/ directory.
Common driver modifications are in the .h files in this directory.
HOW TO BUILD THE CODE
---------------------
1. make sure you have kernel sources/headers matching your installed system
2. do the following
make clean; make KSRC=/usr/src/linux-kernel-source-or-headers
this produces ./netmap_lin.ko and other kernel modules.
3. to build sample applications, run
(cd ../examples; make )
(you will need the pthreads and libpcap-dev packages to build them)
If you want support for additional drivers please have a look at
ixgbe_netmap_linux.h and the patches in patches/
The patch file are named as diff--DRIVER--LOW--HIGH--otherstuff
where DRIVER is the driver name to patch, LOW and HIGH are the
versions to which the patch applies (LOW included, HIGH excluded, so
diff--r8169.c--20638--30300--ok applies from 2.6.38 to 3.3.0 (excluded)
HOW TO USE THE CODE
-------------------
REMEMBER
THIS IS EXPERIMENTAL CODE WHICH MAY CRASH YOUR SYSTEM.
USE IT AT YOUR OWN RISk.
Whether you built your own modules, or are using the prebuilt
TinyCore image, the following steps can be used for initial testing:
1. unload any modules for the network cards you want to use, e.g.
sudo rmmod ixgbe
sudo rmmod e1000
...
2. load netmap and device driver module
sudo insmod ./netmap_lin.ko
sudo insmod ./ixgbe/ixgbe.ko
sudo insmod ./e1000/e1000.ko
...
3. turn the interface(s) up
sudo ifconfig eth0 up # and same for others
4. Run test applications -- as an example, pkt-gen is a raw packet
sender/receiver which can do line rate on a 10G interface
# send about 500 million packets of 60 bytes each.
# wait 5s before starting, so the link can go up
sudo pkt-gen -i eth0 -f tx -n 500111222 -l 60 -w 5
# you should see about 14.88 Mpps
sudo pkt-gen -i eth0 -f rx # act as a receiver
COMMON PROBLEMS
----------------
* switching in/out of netmap mode causes the link to go down and up.
If your card is connected to a switch with spanning tree enabled,
the switch will likely MUTE THE LINK FOR 10 SECONDS while it is
detecting the new topology. Either disable the spanning tree on
the switch or use long pauses before sending data;
* Not all cards can do line rate no matter how fast is your software or
CPU. Several have hardware limitations that prevent reaching the peak
speed, especially for small packet sizes. Examples:
- ixgbe cannot receive at line rate with packet sizes that are
not multiple of 64 (after CRC stripping).
This is especially evident with minimum-sized frames (-l 60 )
- some of the low-end 'e1000' cards can send 1.2 - 1.3Mpps instead
of the theoretical maximum (1.488Mpps)
- the 'realtek' cards seem unable to send more than 450-500Kpps
even though they can receive at least 1.1Mpps
* if the link is not up when the packet generator starts, you will
see frequent messages about a link reset. While we work on a fix,
use the '-w' argument on the generator to specify a longer timeout
* the ixgbe driver (and perhaps others) is severely slowed down if the
remote party is senting flow control frames to slow down traffic.
If that happens try to use the ethtool command to disable flow control.
REVISION HISTORY
-----------------
20120813 - updated distribution using common code for FreeBSD and Linux,
and inclusion of drivers from the linux source tree
20120322 - fixed the 'igb' driver, now it can send and receive correctly
(the problem was in netmap_rx_irq() so it might have affected
other multiqueue cards).
Also tested the 'r8169' in transmit mode.
Added comments on switches and spanning tree.
20120217 - initial version. Only ixgbe, e1000 and e1000e are working.
Other drivers (igb, r8169, forcedeth) are supplied only as a
proof of concept.
DETAILS
--------
+ igb: on linux 3.2 and above the igb driver moved to split buffers,
and netmap was not updated until end of june 2013.
Symptoms were inability to receive short packets.
+ there are reports of ixgbe and igb unable to read packets.
We are unable to reproduce the problem.
- Ubuntu 12.04 LTS 3.5.0-25-generic. igb read problems ?
- 3.2.0-32-generic with 82598 not working
+ if_e1000_e uses regular descriptor up 3.1 at least
3.2.32 is reported to use extended descriptors
(in my repo updated at -r 11975)

View File

@ -0,0 +1,74 @@
# See http://wiki.archlinux.org/index.php/VCS_PKGBUILD_Guidelines
# for more information on packaging from GIT sources.
# Maintainer: Vincenzo Maffione <v.maffione@gmail.com>
pkgname=netmap
pkgver=2.0
pkgrel=1
pkgdesc="Netmap is a framework for high speed network packet I/O."
arch=('any')
url="http://info.iet.unipi.it/~luigi/netmap"
license=('BSD')
groups=()
depends=('linux' 'glibc')
makedepends=('git' 'sed' 'gzip' 'linux-headers')
provides=()
conflicts=()
replaces=()
backup=()
options=()
install="netmap.install"
source=()
noextract=()
md5sums=() #generate with 'makepkg -g'
_gitroot="https://v.maffione@code.google.com/p/netmap/"
_gitname="netmap"
build() {
cd "$srcdir"
msg "Connecting to GIT server...."
if [[ -d "$_gitname" ]]; then
cd "$_gitname" && git pull origin
msg "The local files are updated."
else
git clone "$_gitroot" "$_gitname"
fi
msg "GIT checkout done or server timeout"
msg "Starting build..."
rm -rf "$srcdir/$_gitname-build"
git clone "$srcdir/$_gitname" "$srcdir/$_gitname-build"
cd "$srcdir/$_gitname-build"
# Build the netmap kernel module
cd "$srcdir/$_gitname-build/LINUX"
make || return 1
# Build pkt-gen and vale-ctl
cd "$srcdir/$_gitname-build/examples"
make pkt-gen vale-ctl || return 1
}
package() {
# Compute the version numbers of the running kernel
KVER1=$(uname -r)
KVER2=$(uname -r | sed 's/\.[0-9]\+-[0-9]\+//')
# Install the netmap module into the extramodules-VERSION directory
mkdir -p "$pkgdir/lib/modules/extramodules-${KVER2}"
cp "$srcdir/$_gitname-build/LINUX/netmap_lin.ko" "$pkgdir/lib/modules/extramodules-${KVER2}"
# Install pkt-gen and valectl into /usr/bin
mkdir -p "$pkgdir/usr/bin"
cp "$srcdir/$_gitname-build/examples/pkt-gen" "$pkgdir/usr/bin"
cp "$srcdir/$_gitname-build/examples/vale-ctl" "$pkgdir/usr/bin"
# Install the netmap man page
mkdir -p "$pkgdir/usr/share/man/man4"
cp "$srcdir/$_gitname-build/share/man/man4/netmap.4" "$pkgdir/usr/share/man/man4"
gzip "$pkgdir/usr/share/man/man4/netmap.4"
}
# vim:set ts=2 sw=2 et:

View File

@ -0,0 +1,20 @@
post_common() {
depmod -a
}
## arg 1: the new package version
post_install() {
post_common
}
## arg 1: the new package version
## arg 2: the old package version
post_upgrade() {
post_common
}
## arg 1: the old package version
post_remove() {
post_common
}

424
netmap/LINUX/bsd_glue.h Normal file
View File

@ -0,0 +1,424 @@
/*
* Copyright (C) 2012-2014 Luigi Rizzo - Universita` di Pisa
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* glue code to build the netmap bsd code under linux.
* Some of these tweaks are generic, some are specific for
* character device drivers and network code/device drivers.
*/
#ifndef _BSD_GLUE_H
#define _BSD_GLUE_H
/* a set of headers used in netmap */
#include <linux/version.h>
#include <linux/compiler.h> // ACCESS_ONCE()
#include <linux/if.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/miscdevice.h>
#include <linux/etherdevice.h> // eth_type_trans
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/virtio.h> // virt_to_phys
#include <net/sock.h>
#include <linux/delay.h> // msleep
#include <linux/skbuff.h> // skb_copy_to_linear_data_offset
#include <linux/io.h> // virt_to_phys
#include <linux/hrtimer.h>
#define printf(fmt, arg...) printk(KERN_ERR fmt, ##arg)
#define KASSERT(a, b) BUG_ON(!(a))
/*----- support for compiling on older versions of linux -----*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
#define HRTIMER_MODE_REL HRTIMER_REL
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
#define skb_copy_from_linear_data_offset(skb, offset, to, copy) \
memcpy(to, (skb)->data + offset, copy)
#define skb_copy_to_linear_data_offset(skb, offset, from, copy) \
memcpy((skb)->data + offset, from, copy)
#define skb_copy_to_linear_data(skb, from, copy) \
memcpy((skb)->data, from, copy)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
#define ACCESS_ONCE(x) (x)
#define uintptr_t unsigned long
#define skb_get_queue_mapping(m) (0)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
/* Forward a hrtimer so it expires after the hrtimer's current now */
static inline u64 hrtimer_forward_now(struct hrtimer *timer,
ktime_t interval)
{
return hrtimer_forward(timer, timer->base->get_time(), interval);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
typedef unsigned long phys_addr_t;
extern struct net init_net;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) // XXX
#define netdev_ops hard_start_xmit
struct net_device_ops {
int (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) // XXX 31
#define netdev_tx_t int
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
#define usleep_range(a, b) msleep((a)+(b)+999)
#endif /* up to 2.6.35 */
/*----------- end of LINUX_VERSION_CODE dependencies ----------*/
/* Type redefinitions. XXX check them */
typedef void * bus_dma_tag_t;
typedef void * bus_dmamap_t;
typedef int bus_size_t;
typedef int bus_dma_segment_t;
typedef void * bus_addr_t;
#define vm_paddr_t phys_addr_t
/* XXX the 'off_t' on Linux corresponds to a 'long' */
#define vm_offset_t uint32_t
#define vm_ooffset_t unsigned long
struct thread;
/* endianness macros/functions */
#define le16toh le16_to_cpu
#define le32toh le32_to_cpu
#define le64toh le64_to_cpu
#define be16toh be16_to_cpu
#define be32toh be32_to_cpu
#define be64toh be64_to_cpu
#define htole32 cpu_to_le32
#define htole64 cpu_to_le64
#define htobe16 cpu_to_be16
#define htobe32 cpu_to_be32
#include <linux/jiffies.h>
#define time_second (jiffies_to_msecs(jiffies) / 1000U )
#define bzero(a, len) memset(a, 0, len)
/* Atomic variables. */
#define NM_ATOMIC_TEST_AND_SET(p) test_and_set_bit(0, (p))
#define NM_ATOMIC_CLEAR(p) clear_bit(0, (p))
#define NM_ATOMIC_SET(p, v) atomic_set(p, v)
#define NM_ATOMIC_INC(p) atomic_inc(p)
#define NM_ATOMIC_READ_AND_CLEAR(p) atomic_xchg(p, 0)
#define NM_ATOMIC_READ(p) atomic_read(p)
// XXX maybe implement it as a proper function somewhere
// it is important to set s->len before the copy.
#define m_devget(_buf, _len, _ofs, _dev, _fn) ( { \
struct sk_buff *s = netdev_alloc_skb(_dev, _len); \
if (s) { \
skb_put(s, _len); \
skb_copy_to_linear_data_offset(s, _ofs, _buf, _len); \
s->protocol = eth_type_trans(s, _dev); \
} \
s; } )
#define mbuf sk_buff
#define m_nextpkt next // chain of mbufs
#define m_freem(m) dev_kfree_skb_any(m) // free a sk_buff
#define GET_MBUF_REFCNT(m) NM_ATOMIC_READ(&((m)->users))
#define netmap_get_mbuf(size) alloc_skb(size, GFP_ATOMIC)
/*
* on tx we force skb->queue_mapping = ring_nr,
* but on rx it is the driver that sets the value,
* and it is 0 for no setting, ring_nr+1 otherwise.
*/
#define MBUF_TXQ(m) skb_get_queue_mapping(m)
#define MBUF_RXQ(m) (skb_rx_queue_recorded(m) ? skb_get_rx_queue(m) : 0)
#define SET_MBUF_DESTRUCTOR(m, f) m->destructor = (void *)&f
/* Magic number for sk_buff.priority field, used to take decisions in
* generic_ndo_start_xmit() and in linux_generic_rx_handler().
*/
#define NM_MAGIC_PRIORITY_TX 0xad86d310U
#define NM_MAGIC_PRIORITY_RX 0xad86d311U
/*
* m_copydata() copies from mbuf to buffer following the mbuf chain.
* skb_copy_bits() copies the skb headlen and all the fragments.
*/
#define m_copydata(m, o, l, b) skb_copy_bits(m, o, b, l)
#define copyin(_from, _to, _len) copy_from_user(_to, _from, _len)
/*
* struct ifnet is remapped into struct net_device on linux.
* ifnet has an if_softc field pointing to the device-specific struct
* (adapter).
* On linux the ifnet/net_device is at the beginning of the device-specific
* structure, so a pointer to the first field of the ifnet works.
* We don't use this in netmap, though.
*
* if_xname name device name
* if_capenable priv_flags
* we would use "features" but it is all taken.
* XXX check for conflict in flags use.
*
* In netmap we use if_pspare[0] to point to the netmap_adapter,
* in linux we have no spares so we overload ax25_ptr, and the detection
* for netmap-capable is some magic in the area pointed by that.
*/
#define WNA(_ifp) (_ifp)->ax25_ptr
#define ifnet net_device /* remap */
#define if_xname name /* field ifnet-> net_device */
#define if_capenable priv_flags /* IFCAP_NETMAP */
/* some other FreeBSD APIs */
struct net_device* ifunit_ref(const char *name);
void if_rele(struct net_device *ifp);
/* hook to send from user space */
netdev_tx_t linux_netmap_start_xmit(struct sk_buff *, struct net_device *);
/* prevent ring params change while in netmap mode */
int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *);
#ifdef ETHTOOL_SCHANNELS
int linux_netmap_set_channels(struct net_device *, struct ethtool_channels *);
#endif
#define CURVNET_SET(x)
#define CURVNET_RESTORE(x)
#define refcount_acquire(_a) atomic_add(1, (atomic_t *)_a)
#define refcount_release(_a) atomic_dec_and_test((atomic_t *)_a)
/*
* We use spin_lock_irqsave() because we use the lock in the
* (hard) interrupt context.
*/
typedef struct {
spinlock_t sl;
ulong flags;
} safe_spinlock_t;
static inline void mtx_lock(safe_spinlock_t *m)
{
spin_lock_irqsave(&(m->sl), m->flags);
}
static inline void mtx_unlock(safe_spinlock_t *m)
{
ulong flags = ACCESS_ONCE(m->flags);
spin_unlock_irqrestore(&(m->sl), flags);
}
#define mtx_init(a, b, c, d) spin_lock_init(&((a)->sl))
#define mtx_destroy(a) // XXX spin_lock_destroy(a)
/*
* XXX these must be changed, as we cannot sleep within the RCU.
* Must change to proper rwlock, and then can move the definitions
* into the main netmap.c file.
*/
#define BDG_RWLOCK_T struct rw_semaphore
#define BDG_RWINIT(b) init_rwsem(&(b)->bdg_lock)
#define BDG_WLOCK(b) down_write(&(b)->bdg_lock)
#define BDG_WUNLOCK(b) up_write(&(b)->bdg_lock)
#define BDG_RLOCK(b) down_read(&(b)->bdg_lock)
#define BDG_RUNLOCK(b) up_read(&(b)->bdg_lock)
#define BDG_RTRYLOCK(b) down_read_trylock(&(b)->bdg_lock)
#define BDG_SET_VAR(lval, p) ((lval) = (p))
#define BDG_GET_VAR(lval) (lval)
#define BDG_FREE(p) kfree(p)
/* use volatile to fix a probable compiler error on 2.6.25 */
#define malloc(_size, type, flags) \
({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); })
#define free(a, t) kfree(a)
// XXX do we need GPF_ZERO ?
// XXX do we need GFP_DMA for slots ?
// http://www.mjmwired.net/kernel/Documentation/DMA-API.txt
#ifndef ilog2 /* not in 2.6.18 */
static inline int ilog2(uint64_t n)
{
uint64_t k = 1ULL<<63;
int i;
for (i = 63; i >= 0 && !(n &k); i--, k >>=1)
;
return i;
}
#endif /* ilog2 */
#define contigmalloc(sz, ty, flags, a, b, pgsz, c) \
(char *) __get_free_pages(GFP_ATOMIC | __GFP_ZERO, \
ilog2(roundup_pow_of_two((sz)/PAGE_SIZE)))
#define contigfree(va, sz, ty) free_pages((unsigned long)va, \
ilog2(roundup_pow_of_two(sz)/PAGE_SIZE))
#define vtophys virt_to_phys
/*--- selrecord and friends ---*/
/* wake_up() or wake_up_interruptible() ? */
#define OS_selwakeup(sw, pri) wake_up(sw)
#define selrecord(x, y) poll_wait((struct file *)x, y, pwait)
// #define knlist_destroy(x) // XXX todo
#define tsleep(a, b, c, t) msleep(10)
// #define wakeup(sw) // XXX double check
#define microtime do_gettimeofday // debugging
/*
* The following trick is to map a struct cdev into a struct miscdevice
* On FreeBSD cdev and cdevsw are two different objects.
*/
#define cdev miscdevice
#define cdevsw miscdevice
/*
* XXX to complete - the dmamap interface
*/
#define BUS_DMA_NOWAIT 0
#define bus_dmamap_load(_1, _2, _3, _4, _5, _6, _7)
#define bus_dmamap_unload(_1, _2)
typedef int (d_mmap_t)(struct file *f, struct vm_area_struct *vma);
typedef unsigned int (d_poll_t)(struct file * file, struct poll_table_struct *pwait);
/*
* make_dev will set an error and return the first argument.
* This relies on the availability of the 'error' local variable.
* For old linux systems that do not have devfs, generate a
* message in syslog so the sysadmin knows which command to run
* in order to create the /dev/netmap entry
*/
#define make_dev(_cdev, _zero, _uid, _gid, _perm, _name) \
({error = misc_register(_cdev); \
D("run mknod /dev/%s c %d %d # error %d", \
(_cdev)->name, MISC_MAJOR, (_cdev)->minor, error); \
_cdev; } )
#define destroy_dev(_cdev) misc_deregister(_cdev)
/*--- sysctl API ----*/
/*
* linux: sysctl are mapped into /sys/module/ipfw_mod parameters
* windows: they are emulated via get/setsockopt
*/
#define CTLFLAG_RD 1
#define CTLFLAG_RW 2
struct sysctl_oid;
struct sysctl_req;
#define SYSCTL_DECL(_1)
#define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8)
#define SYSCTL_NODE(_1, _2, _3, _4, _5, _6)
#define _SYSCTL_BASE(_name, _var, _ty, _perm) \
module_param_named(_name, *(_var), _ty, \
( (_perm) == CTLFLAG_RD) ? 0444: 0644 )
/* XXX should implement this */
extern struct kernel_param_ops generic_sysctl_ops;
#define SYSCTL_PROC(_base, _oid, _name, _mode, _var, _val, _fn, _ty, _desc) \
module_param_cb(_name, &generic_sysctl_ops, _fn, \
( (_mode) & CTLFLAG_WR) ? 0644: 0444 )
/* for a string, _var is a preallocated buffer of size _varlen */
#define SYSCTL_STRING(_base, _oid, _name, _mode, _var, _varlen, _desc) \
module_param_string(_name, _var, _varlen, \
((_mode) == CTLFLAG_RD) ? 0444: 0644 )
#define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, int, _mode)
#define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, long, _mode)
#define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, ulong, _mode)
#define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, uint, _mode)
// #define TUNABLE_INT(_name, _ptr)
#define SYSCTL_VNET_PROC SYSCTL_PROC
#define SYSCTL_VNET_INT SYSCTL_INT
#define SYSCTL_HANDLER_ARGS \
struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
int sysctl_handle_int(SYSCTL_HANDLER_ARGS);
int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
#define MALLOC_DECLARE(a)
#define MALLOC_DEFINE(a, b, c)
#define devfs_get_cdevpriv(pp) \
({ *(struct netmap_priv_d **)pp = ((struct file *)td)->private_data; \
(*pp ? 0 : ENOENT); })
/* devfs_set_cdevpriv cannot fail on linux */
#define devfs_set_cdevpriv(p, fn) \
({ ((struct file *)td)->private_data = p; (p ? 0 : EINVAL); })
#define devfs_clear_cdevpriv() do { \
netmap_dtor(priv); ((struct file *)td)->private_data = 0; \
} while (0)
#endif /* _BSD_GLUE_H */

View File

@ -0,0 +1,104 @@
diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
index bcd192c..5de7009 100644
--- a/e1000/e1000_main.c
+++ b/e1000/e1000_main.c
@@ -213,6 +213,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000_netmap.h>
+#endif
+
/**
* e1000_init_module - Driver Registration Routine
*
@@ -375,6 +379,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
/* call E1000_DESC_UNUSED which always leaves
* at least 1 descriptor unused to make sure
* next_to_use != next_to_clean */
@@ -402,6 +410,10 @@ int e1000_up(struct e1000_adapter *adapter)
netif_wake_queue(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* fire a link change interrupt to start the watchdog */
ew32(ICS, E1000_ICS_LSC);
return 0;
@@ -485,6 +497,10 @@ void e1000_down(struct e1000_adapter *adapter)
ew32(RCTL, rctl & ~E1000_RCTL_EN);
/* flush and sleep below */
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
netif_tx_disable(netdev);
/* disable transmits in the hardware */
@@ -1035,6 +1051,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
adapter->wol = adapter->eeprom_wol;
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
/* print bus type/speed/width info */
DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ",
((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
@@ -1113,6 +1133,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
iounmap(hw->hw_addr);
if (hw->flash_address)
@@ -1291,6 +1315,10 @@ static int e1000_open(struct net_device *netdev)
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif
+
/* fire a link status change interrupt to start the watchdog */
ew32(ICS, E1000_ICS_LSC);
@@ -3429,6 +3457,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
unsigned int count = 0;
unsigned int total_tx_bytes=0, total_tx_packets=0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -3795,6 +3827,11 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
bool cleaned = false;
unsigned int total_rx_bytes=0, total_rx_packets=0;
+#ifdef DEV_NETMAP
+ ND("calling netmap_rx_irq");
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];

View File

@ -0,0 +1,91 @@
diff --git a/e1000e/netdev.c b/e1000e/netdev.c
index fad8f9e..50f74e2 100644
--- a/e1000e/netdev.c
+++ b/e1000e/netdev.c
@@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000e_netmap.h>
+#endif
+
/**
* e1000_receive_skb - helper function to handle Rx indications
* @adapter: board private structure
@@ -446,6 +450,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
bool cleaned = 0;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
@@ -624,6 +632,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
unsigned int count = 0;
unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -2632,6 +2644,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000e_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
}
@@ -2892,6 +2908,10 @@ void e1000e_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* disable transmits in the hardware */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_EN;
@@ -3174,6 +3194,10 @@ static int e1000_open(struct net_device *netdev)
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
/* fire a link status change interrupt to start the watchdog */
ew32(ICS, E1000_ICS_LSC);
@@ -5227,6 +5251,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_register;
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -5300,6 +5327,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);

View File

@ -0,0 +1,91 @@
diff --git a/e1000e/netdev.c b/e1000e/netdev.c
index 57a7e41..d8bc988 100644
--- a/e1000e/netdev.c
+++ b/e1000e/netdev.c
@@ -435,6 +435,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000e_netmap.h>
+#endif
+
/**
* e1000_receive_skb - helper function to handle Rx indications
* @adapter: board private structure
@@ -763,6 +767,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
bool cleaned = 0;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
@@ -977,6 +985,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
unsigned int count = 0;
unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -3001,6 +3013,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000e_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
}
@@ -3240,6 +3256,10 @@ void e1000e_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* disable transmits in the hardware */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_EN;
@@ -3532,6 +3552,10 @@ static int e1000_open(struct net_device *netdev)
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
adapter->idle_check = true;
pm_runtime_put(&pdev->dev);
@@ -5716,6 +5740,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_register;
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -5813,6 +5840,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);

View File

@ -0,0 +1,91 @@
diff --git a/e1000e/netdev.c b/e1000e/netdev.c
index 2198e61..caf2767 100644
--- a/e1000e/netdev.c
+++ b/e1000e/netdev.c
@@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000e_netmap.h>
+#endif
+
/**
* e1000_receive_skb - helper function to handle Rx indications
* @adapter: board private structure
@@ -849,6 +853,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
bool cleaned = 0;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
@@ -1066,6 +1074,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
unsigned int count = 0;
unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -3177,6 +3189,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000e_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring),
GFP_KERNEL);
}
@@ -3468,6 +3484,10 @@ void e1000e_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* disable transmits in the hardware */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_EN;
@@ -3755,6 +3775,10 @@ static int e1000_open(struct net_device *netdev)
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
adapter->idle_check = true;
pm_runtime_put(&pdev->dev);
@@ -6147,6 +6171,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_register;
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -6234,6 +6261,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);

View File

@ -0,0 +1,91 @@
diff --git a/e1000e/netdev.c b/e1000e/netdev.c
index 9520a6a..f6f2df6 100644
--- a/e1000e/netdev.c
+++ b/e1000e/netdev.c
@@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000e_netmap.h>
+#endif
+
/**
* e1000_receive_skb - helper function to handle Rx indications
* @adapter: board private structure
@@ -875,6 +879,10 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
bool cleaned = false;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -1129,6 +1137,10 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
unsigned int total_tx_bytes = 0, total_tx_packets = 0;
unsigned int bytes_compl = 0, pkts_compl = 0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -3358,6 +3370,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000e_setup_rss_hash(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000e_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
}
@@ -3657,6 +3673,10 @@ void e1000e_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* disable transmits in the hardware */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_EN;
@@ -3946,6 +3966,10 @@ static int e1000_open(struct net_device *netdev)
adapter->tx_hang_recheck = false;
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
adapter->idle_check = true;
pm_runtime_put(&pdev->dev);
@@ -6417,6 +6441,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_register;
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -6504,6 +6531,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);

View File

@ -0,0 +1,91 @@
diff --git a/e1000e/netdev.c b/e1000e/netdev.c
index 7e615e2..f9d8a88 100644
--- a/e1000e/netdev.c
+++ b/e1000e/netdev.c
@@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_e1000e_netmap.h>
+#endif
+
/**
* e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
* @adapter: board private structure
@@ -914,6 +918,10 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
bool cleaned = false;
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, 0, work_done))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -1203,6 +1211,10 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
unsigned int total_tx_bytes = 0, total_tx_packets = 0;
unsigned int bytes_compl = 0, pkts_compl = 0;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, 0))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -3685,6 +3697,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000e_setup_rss_hash(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
+#ifdef DEV_NETMAP
+ if (e1000e_netmap_init_buffers(adapter))
+ return;
+#endif /* DEV_NETMAP */
adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
}
@@ -3988,6 +4004,10 @@ void e1000e_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* disable transmits in the hardware */
tctl = er32(TCTL);
tctl &= ~E1000_TCTL_EN;
@@ -4307,6 +4327,10 @@ static int e1000_open(struct net_device *netdev)
adapter->tx_hang_recheck = false;
netif_start_queue(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
adapter->idle_check = true;
hw->mac.get_link_status = true;
pm_runtime_put(&pdev->dev);
@@ -6768,6 +6792,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_register;
+#ifdef DEV_NETMAP
+ e1000_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
@@ -6866,6 +6893,10 @@ static void e1000_remove(struct pci_dev *pdev)
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(adapter->hw.hw_addr);
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);

View File

@ -0,0 +1,76 @@
diff --git a/forcedeth.c b/forcedeth.c
index 9c0b1ba..b081d6b 100644
--- a/forcedeth.c
+++ b/forcedeth.c
@@ -1865,12 +1865,25 @@ static void nv_init_tx(struct net_device *dev)
}
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/* we need a few forward declarations */
+static void nv_drain_rxtx(struct net_device *dev);
+static int nv_init_ring(struct net_device *dev);
+#include <forcedeth_netmap.h>
+#endif
+
static int nv_init_ring(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
nv_init_tx(dev);
nv_init_rx(dev);
+#ifdef DEV_NETMAP
+ forcedeth_netmap_tx_init(np);
+ if (forcedeth_netmap_rx_init(np))
+ return 0; /* success */
+#endif /* DEV_NETMAP */
+
if (!nv_optimized(np))
return nv_alloc_rx(dev);
@@ -3386,6 +3399,11 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
int i;
unsigned long flags;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(dev, 0))
+ return IRQ_HANDLED;
+#endif /* DEV_NETMAP */
+
for (i = 0;; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
@@ -3497,6 +3515,11 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
int i;
unsigned long flags;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(dev, 0, &i))
+ return IRQ_HANDLED;
+#endif /* DEV_NETMAP */
+
for (i = 0;; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
@@ -5645,6 +5668,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_error;
}
+#ifdef DEV_NETMAP
+ forcedeth_netmap_attach(np);
+#endif /* DEV_NETMAP */
+
netif_carrier_off(dev);
dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
@@ -5728,6 +5755,10 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
unregister_netdev(dev);
+#ifdef DEV_NETMAP
+ netmap_detach(dev);
+#endif /* DEV_NETMAP */
+
nv_restore_mac_addr(pci_dev);
/* restore any phy related changes */

View File

@ -0,0 +1,37 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index c881347..77b3fda 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -1144,6 +1144,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1167,6 +1171,10 @@ void igb_down(struct igb_adapter *adapter)
wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
/* flush and sleep below */
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
netif_tx_stop_all_queues(netdev);
/* disable transmits in the hardware */
@@ -2018,6 +2026,10 @@ static int igb_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);

View File

@ -0,0 +1,115 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index cea37e0..70777e4 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -201,6 +201,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_igb_netmap.h>
+#endif
+
struct igb_reg_info {
u32 ofs;
char *name;
@@ -1478,6 +1482,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1501,6 +1509,10 @@ void igb_down(struct igb_adapter *adapter)
wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
/* flush and sleep below */
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
netif_tx_stop_all_queues(netdev);
/* disable transmits in the hardware */
@@ -1963,6 +1975,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+#ifdef DEV_NETMAP
+ igb_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_IGB_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -2072,6 +2088,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
dev_info(&pdev->dev, "IOV Disabled\n");
}
#endif
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(hw->hw_addr);
if (hw->flash_address)
@@ -2366,6 +2386,10 @@ static int igb_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -2545,6 +2569,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
wr32(E1000_TXDCTL(reg_idx), txdctl);
+#ifdef DEV_NETMAP
+ igb_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
/**
@@ -5338,6 +5365,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
unsigned int i, eop, count = 0;
bool cleaned = false;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(netdev, tx_ring->queue_index))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
+
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
@@ -5540,6 +5572,11 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
u16 length;
u16 vlan_tag;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(netdev, rx_ring->queue_index, work_done))
+ return 1;
+#endif /* DEV_NETMAP */
+
i = rx_ring->next_to_clean;
buffer_info = &rx_ring->buffer_info[i];
rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
@@ -5668,6 +5705,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
unsigned int i;
int bufsz;
+#ifdef DEV_NETMAP
+ if (igb_netmap_configure_rx_ring(rx_ring))
+ return;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];

View File

@ -0,0 +1,136 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index ced5444..fb7c766 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -225,6 +225,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_igb_netmap.h>
+#endif
+
struct igb_reg_info {
u32 ofs;
char *name;
@@ -1551,6 +1555,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1584,6 +1592,10 @@ void igb_down(struct igb_adapter *adapter)
wrfl();
msleep(10);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
for (i = 0; i < adapter->num_q_vectors; i++)
napi_disable(&(adapter->q_vector[i]->napi));
@@ -2073,6 +2085,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+#ifdef DEV_NETMAP
+ igb_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_IGB_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -2199,6 +2215,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
dev_info(&pdev->dev, "IOV Disabled\n");
}
#endif
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(hw->hw_addr);
if (hw->flash_address)
@@ -2529,6 +2549,10 @@ static int igb_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -2711,6 +2735,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
wr32(E1000_TXDCTL(reg_idx), txdctl);
+#ifdef DEV_NETMAP
+ igb_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
/**
@@ -3088,6 +3115,19 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
/* Only set Drop Enable if we are supporting multiple queues */
if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
srrctl |= E1000_SRRCTL_DROP_EN;
+#ifdef DEV_NETMAP
+ {
+ /* The driver uses split buffers, which are not
+ * supported in netmap mode */
+ struct ifnet *ifp = adapter->netdev;
+ struct netmap_adapter *na = NA(ifp);
+ if (na && ifp->if_capenable & IFCAP_NETMAP) {
+ srrctl &= ~(7 << 25); /* clear descriptor type */
+ srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+ /* XXX we should set tail here */
+ }
+ }
+#endif
wr32(E1000_SRRCTL(reg_idx), srrctl);
@@ -5705,6 +5745,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (test_bit(__IGB_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IGB_TX_DESC(tx_ring, i);
@@ -5980,6 +6024,12 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
u16 cleaned_count = igb_desc_unused(rx_ring);
u16 i = rx_ring->next_to_clean;
+#ifdef DEV_NETMAP
+ int dummy = 1; // select rx irq handling
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return 1;
+#endif /* DEV_NETMAP */
+
rx_desc = IGB_RX_DESC(rx_ring, i);
while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
@@ -6170,6 +6220,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
struct igb_rx_buffer *bi;
u16 i = rx_ring->next_to_use;
+#ifdef DEV_NETMAP
+ if (igb_netmap_configure_rx_ring(rx_ring))
+ return;
+#endif /* DEV_NETMAP */
+
rx_desc = IGB_RX_DESC(rx_ring, i);
bi = &rx_ring->rx_buffer_info[i];
i -= rx_ring->count;

View File

@ -0,0 +1,136 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index 94be6c3..294051b 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -236,6 +236,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_igb_netmap.h>
+#endif
+
struct igb_reg_info {
u32 ofs;
char *name;
@@ -1557,6 +1561,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1590,6 +1598,10 @@ void igb_down(struct igb_adapter *adapter)
wrfl();
msleep(10);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
for (i = 0; i < adapter->num_q_vectors; i++)
napi_disable(&(adapter->q_vector[i]->napi));
@@ -2081,6 +2093,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+#ifdef DEV_NETMAP
+ igb_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_IGB_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -2211,6 +2227,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
dev_info(&pdev->dev, "IOV Disabled\n");
}
#endif
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
iounmap(hw->hw_addr);
if (hw->flash_address)
@@ -2547,6 +2567,10 @@ static int __igb_open(struct net_device *netdev, bool resuming)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
if (!resuming)
pm_runtime_put(&pdev->dev);
@@ -2750,6 +2774,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
wr32(E1000_TXDCTL(reg_idx), txdctl);
+#ifdef DEV_NETMAP
+ igb_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
/**
@@ -3127,6 +3154,19 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
/* Only set Drop Enable if we are supporting multiple queues */
if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
srrctl |= E1000_SRRCTL_DROP_EN;
+#ifdef DEV_NETMAP
+ {
+ /* The driver uses split buffers, which are not
+ * supported in netmap mode */
+ struct ifnet *ifp = adapter->netdev;
+ struct netmap_adapter *na = NA(ifp);
+ if (na && ifp->if_capenable & IFCAP_NETMAP) {
+ srrctl &= ~(7 << 25); /* clear descriptor type */
+ srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+ /* XXX we should set tail here */
+ }
+ }
+#endif
wr32(E1000_SRRCTL(reg_idx), srrctl);
@@ -5753,6 +5793,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (test_bit(__IGB_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IGB_TX_DESC(tx_ring, i);
@@ -6030,6 +6074,12 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
u16 cleaned_count = igb_desc_unused(rx_ring);
u16 i = rx_ring->next_to_clean;
+#ifdef DEV_NETMAP
+ int dummy = 1; // select rx irq handling
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return 1;
+#endif /* DEV_NETMAP */
+
rx_desc = IGB_RX_DESC(rx_ring, i);
while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
@@ -6220,6 +6270,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
struct igb_rx_buffer *bi;
u16 i = rx_ring->next_to_use;
+#ifdef DEV_NETMAP
+ if (igb_netmap_configure_rx_ring(rx_ring))
+ return;
+#endif /* DEV_NETMAP */
+
rx_desc = IGB_RX_DESC(rx_ring, i);
bi = &rx_ring->rx_buffer_info[i];
i -= rx_ring->count;

View File

@ -0,0 +1,114 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index 31cfe2e..8439bc6 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -247,6 +247,10 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_igb_netmap.h>
+#endif
+
struct igb_reg_info {
u32 ofs;
char *name;
@@ -1520,6 +1524,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1553,6 +1561,10 @@ void igb_down(struct igb_adapter *adapter)
wrfl();
msleep(10);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
for (i = 0; i < adapter->num_q_vectors; i++)
napi_disable(&(adapter->q_vector[i]->napi));
@@ -2127,6 +2139,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+#ifdef DEV_NETMAP
+ igb_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_IGB_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -2233,6 +2249,10 @@ static void igb_remove(struct pci_dev *pdev)
wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
}
#endif
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
@@ -2553,6 +2573,10 @@ static int __igb_open(struct net_device *netdev, bool resuming)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
if (!resuming)
pm_runtime_put(&pdev->dev);
@@ -2746,6 +2770,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
wr32(E1000_TXDCTL(reg_idx), txdctl);
+#ifdef DEV_NETMAP
+ igb_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
/**
@@ -5690,6 +5717,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (test_bit(__IGB_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IGB_TX_DESC(tx_ring, i);
@@ -6349,6 +6380,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
unsigned int total_bytes = 0, total_packets = 0;
u16 cleaned_count = igb_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
+ return true;
+#endif /* DEV_NETMAP */
do {
union e1000_adv_rx_desc *rx_desc;
@@ -6461,6 +6496,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
struct igb_rx_buffer *bi;
u16 i = rx_ring->next_to_use;
+#ifdef DEV_NETMAP
+ if (igb_netmap_configure_rx_ring(rx_ring))
+ return;
+#endif /* DEV_NETMAP */
+
/* nothing to do */
if (!cleaned_count)
return;

View File

@ -0,0 +1,113 @@
diff --git a/igb/igb_main.c b/igb/igb_main.c
index c1d72c0..9815796 100644
--- a/igb/igb_main.c
+++ b/igb/igb_main.c
@@ -255,6 +255,10 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_igb_netmap.h>
+#endif
+
struct igb_reg_info {
u32 ofs;
char *name;
@@ -1633,6 +1637,10 @@ int igb_up(struct igb_adapter *adapter)
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif /* DEV_NETMAP */
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -1674,6 +1682,9 @@ void igb_down(struct igb_adapter *adapter)
napi_disable(&(adapter->q_vector[i]->napi));
}
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif /* DEV_NETMAP */
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -2295,6 +2306,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+#ifdef DEV_NETMAP
+ igb_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_IGB_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -2536,6 +2551,10 @@ static void igb_remove(struct pci_dev *pdev)
wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
}
#endif
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant.
@@ -2814,6 +2833,10 @@ static int __igb_open(struct net_device *netdev, bool resuming)
netif_tx_start_all_queues(netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(netdev);
+#endif /* DEV_NETMAP */
+
if (!resuming)
pm_runtime_put(&pdev->dev);
@@ -3007,6 +3030,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
wr32(E1000_TXDCTL(reg_idx), txdctl);
+#ifdef DEV_NETMAP
+ igb_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
/**
@@ -5991,6 +6017,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (test_bit(__IGB_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
+ return 1; /* cleaned ok */
+#endif /* DEV_NETMAP */
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IGB_TX_DESC(tx_ring, i);
@@ -6650,6 +6680,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
unsigned int total_bytes = 0, total_packets = 0;
u16 cleaned_count = igb_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
+ return true;
+#endif /* DEV_NETMAP */
do {
union e1000_adv_rx_desc *rx_desc;
@@ -6767,6 +6801,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
struct igb_rx_buffer *bi;
u16 i = rx_ring->next_to_use;
+#ifdef DEV_NETMAP
+ if (igb_netmap_configure_rx_ring(rx_ring))
+ return;
+#endif /* DEV_NETMAP */
+
/* nothing to do */
if (!cleaned_count)
return;

View File

@ -0,0 +1,113 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index eee0b29..70581eb 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -740,6 +756,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
unsigned int i, eop, count = 0;
unsigned int total_bytes = 0, total_packets = 0;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
@@ -1185,6 +1211,13 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
int ddp_bytes = 0;
#endif /* IXGBE_FCOE */
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done))
+ return;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -2519,6 +2552,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -2833,6 +2869,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
}
@@ -3614,6 +3654,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -3863,6 +3907,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* Cleanup the affinity_hint CPU mask memory and callback */
for (i = 0; i < num_q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
@@ -7048,6 +7096,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,113 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index 30f9ccf..60c0252 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -826,6 +842,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
unsigned int total_bytes = 0, total_packets = 0;
u16 i, eop, count = 0;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
@@ -1308,6 +1334,13 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
u16 cleaned_count = 0;
bool pkt_is_rsc = false;
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done))
+ return;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -2730,6 +2763,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3094,6 +3130,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));
}
@@ -3882,6 +3922,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4121,6 +4165,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
/* Cleanup the affinity_hint CPU mask memory and callback */
for (i = 0; i < num_q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
@@ -7450,6 +7498,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,113 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index 08e8e25..8070930 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -247,6 +247,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -864,6 +880,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
unsigned int total_bytes = 0, total_packets = 0;
u16 i, eop, count = 0;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
@@ -1348,6 +1374,13 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
u16 cleaned_count = 0;
bool pkt_is_rsc = false;
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done))
+ return;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -2808,6 +2841,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3183,6 +3219,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));
}
@@ -3976,6 +4016,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4212,6 +4256,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -7683,6 +7731,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,114 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index e1fcc95..1aab0df 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -801,6 +817,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
unsigned int total_bytes = 0, total_packets = 0;
u16 i, eop, count = 0;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
i = tx_ring->next_to_clean;
eop = tx_ring->tx_buffer_info[i].next_to_watch;
eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
@@ -1303,6 +1330,13 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
u16 cleaned_count = 0;
bool pkt_is_rsc = false;
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done))
+ return;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -2676,6 +2710,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3039,6 +3076,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -3873,6 +3914,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4126,6 +4171,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -7696,6 +7745,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,115 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index 8ef92d1..6a37803 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -745,6 +761,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
unsigned int budget = q_vector->tx.work_limit;
u16 i = tx_ring->next_to_clean;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return true; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
@@ -1253,6 +1280,14 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
u16 cleaned_count = 0;
bool pkt_is_rsc = false;
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ int dummy;
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy))
+ return true;
+#endif /* DEV_NETMAP */
i = rx_ring->next_to_clean;
rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
@@ -2420,6 +2455,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -2783,6 +2821,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -3757,6 +3799,10 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4007,6 +4053,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -7710,6 +7760,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,124 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index 467948e..0aa1511 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -749,6 +765,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (test_bit(__IXGBE_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IXGBE_TX_DESC(tx_ring, i);
i -= tx_ring->count;
@@ -1629,6 +1656,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ int dummy;
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return true; /* no more interrupts */
+#endif /* DEV_NETMAP */
+
do {
struct ixgbe_rx_buffer *rx_buffer;
union ixgbe_adv_rx_desc *rx_desc;
@@ -2683,6 +2719,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3032,6 +3071,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -3986,6 +4029,10 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4249,6 +4296,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4764,6 +4815,7 @@ static int ixgbe_open(struct net_device *netdev)
ixgbe_up_complete(adapter);
+
return 0;
err_req_irq:
@@ -7152,6 +7204,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_dev_info("%s\n", ixgbe_default_device_descr);
cards_found++;
+
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,123 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index e242104..02e1544 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -764,6 +780,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (test_bit(__IXGBE_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IXGBE_TX_DESC(tx_ring, i);
i -= tx_ring->count;
@@ -1665,6 +1692,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ int dummy;
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return true; /* no more interrupts */
+#endif /* DEV_NETMAP */
+
do {
struct ixgbe_rx_buffer *rx_buffer;
union ixgbe_adv_rx_desc *rx_desc;
@@ -2725,6 +2761,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3102,6 +3141,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -4051,6 +4094,10 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4315,6 +4362,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4827,6 +4878,7 @@ static int ixgbe_open(struct net_device *netdev)
ixgbe_up_complete(adapter);
+
return 0;
err_req_irq:
@@ -7358,6 +7410,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
e_err(probe, "failed to allocate sysfs resources\n");
#endif /* CONFIG_IXGBE_HWMON */
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,134 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index 79f4a26..4b8a25b 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -202,6 +202,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -826,6 +842,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (test_bit(__IXGBE_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IXGBE_TX_DESC(tx_ring, i);
i -= tx_ring->count;
@@ -1860,6 +1887,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ int dummy;
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return true; /* no more interrupts */
+#endif /* DEV_NETMAP */
+
do {
union ixgbe_adv_rx_desc *rx_desc;
struct sk_buff *skb;
@@ -2846,6 +2882,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3207,6 +3246,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -4155,6 +4198,10 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4402,6 +4449,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4976,6 +5027,7 @@ static int ixgbe_open(struct net_device *netdev)
ixgbe_up_complete(adapter);
+
return 0;
err_set_queues:
@@ -7619,6 +7671,10 @@ skip_sriov:
ixgbe_dbg_adapter_init(adapter);
#endif /* CONFIG_DEBUG_FS */
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:
@@ -7653,6 +7709,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
+#ifdef DEV_NETMAP
+ netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
#ifdef CONFIG_DEBUG_FS
ixgbe_dbg_adapter_exit(adapter);
#endif /*CONFIG_DEBUG_FS */

View File

@ -0,0 +1,123 @@
diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
index d30fbdd..7418c57 100644
--- a/ixgbe/ixgbe_main.c
+++ b/ixgbe/ixgbe_main.c
@@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
{}
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
+ * be a reference on how to implement netmap support in a driver.
+ * Additional comments are in ixgbe_netmap_linux.h .
+ *
+ * The code is originally developed on FreeBSD and in the interest
+ * of maintainability we try to limit differences between the two systems.
+ *
+ * <ixgbe_netmap_linux.h> contains functions for netmap support
+ * that extend the standard driver.
+ * It also defines DEV_NETMAP so further conditional sections use
+ * that instead of CONFIG_NETMAP
+ */
+#include <ixgbe_netmap_linux.h>
+#endif
/*
* ixgbe_regdump - register printout routine
@@ -872,6 +888,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (test_bit(__IXGBE_DOWN, &adapter->state))
return true;
+#ifdef DEV_NETMAP
+ /*
+ * In netmap mode, all the work is done in the context
+ * of the client thread. Interrupt handlers only wake up
+ * clients, which may be sleeping on individual rings
+ * or on a global resource for all rings.
+ */
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
+ return 1; /* seems to be ignored */
+#endif /* DEV_NETMAP */
+
tx_buffer = &tx_ring->tx_buffer_info[i];
tx_desc = IXGBE_TX_DESC(tx_ring, i);
i -= tx_ring->count;
@@ -1906,6 +1933,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
#endif /* IXGBE_FCOE */
u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+#ifdef DEV_NETMAP
+ /*
+ * Same as the txeof routine: only wakeup clients on intr.
+ */
+ int dummy;
+ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
+ return true; /* no more interrupts */
+#endif /* DEV_NETMAP */
+
do {
union ixgbe_adv_rx_desc *rx_desc;
struct sk_buff *skb;
@@ -2905,6 +2941,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
+#endif /* DEV_NETMAP */
}
static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
@@ -3266,6 +3305,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
ixgbe_rx_desc_queue_enable(adapter, ring);
+#ifdef DEV_NETMAP
+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
+ return;
+#endif /* DEV_NETMAP */
ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
}
@@ -4216,6 +4259,10 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(adapter->netdev);
+#endif
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4463,6 +4510,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(netdev);
+#endif
+
adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
IXGBE_FLAG2_RESET_REQUESTED);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -5037,6 +5088,7 @@ static int ixgbe_open(struct net_device *netdev)
ixgbe_up_complete(adapter);
+
return 0;
err_set_queues:
@@ -7658,6 +7710,10 @@ skip_sriov:
IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
true);
+#ifdef DEV_NETMAP
+ ixgbe_netmap_attach(adapter);
+#endif /* DEV_NETMAP */
+
return 0;
err_register:

View File

@ -0,0 +1,117 @@
diff --git a/r8169.c b/r8169.c
index 0fe2fc9..efee0a4 100644
--- a/r8169.c
+++ b/r8169.c
@@ -537,6 +537,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_re_netmap_linux.h>
+#endif
+
static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
@@ -3210,6 +3214,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
+#ifdef DEV_NETMAP
+ re_netmap_attach(tp);
+#endif /* DEV_NETMAP */
+
out:
return rc;
@@ -3236,6 +3244,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
+#ifdef DEV_NETMAP
+ netmap_detach(dev);
+#endif /* DEV_NETMAP */
+
/* restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);
@@ -3291,6 +3303,10 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -3993,6 +4009,11 @@ err_out:
static void rtl8169_rx_clear(struct rtl8169_private *tp)
{
unsigned int i;
+#ifdef DEV_NETMAP
+ re_netmap_tx_init(tp);
+ if (re_netmap_rx_init(tp))
+ return 0; // success
+#endif /* DEV_NETMAP */
for (i = 0; i < NUM_RX_DESC; i++) {
if (tp->Rx_skbuff[i]) {
@@ -4112,11 +4133,19 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
/* Wait for any pending NAPI task to complete */
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_irq_mask_and_ack(ioaddr);
tp->intr_mask = 0xffff;
RTL_W16(IntrMask, tp->intr_event);
napi_enable(&tp->napi);
+
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -4372,6 +4401,11 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
{
unsigned int dirty_tx, tx_left;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(dev, 0))
+ return;
+#endif /* DEV_NETMAP */
+
dirty_tx = tp->dirty_tx;
smp_rmb();
tx_left = tp->cur_tx - dirty_tx;
@@ -4468,6 +4502,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
unsigned int cur_rx, rx_left;
unsigned int delta, count;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(dev, 0, &count))
+ return count;
+#endif /* DEV_NETMAP */
+
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
rx_left = min(rx_left, budget);
@@ -4687,7 +4726,12 @@ static void rtl8169_down(struct net_device *dev)
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
core_down:
+
spin_lock_irq(&tp->lock);
rtl8169_asic_down(ioaddr);

View File

@ -0,0 +1,115 @@
diff --git a/r8169.c b/r8169.c
index 53b13de..745a59d 100644
--- a/r8169.c
+++ b/r8169.c
@@ -535,6 +535,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_re_netmap_linux.h>
+#endif
+
static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
@@ -3229,6 +3233,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
+#ifdef DEV_NETMAP
+ re_netmap_attach(tp);
+#endif /* DEV_NETMAP */
+
out:
return rc;
@@ -3257,6 +3265,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);
+#ifdef DEV_NETMAP
+ netmap_detach(dev);
+#endif /* DEV_NETMAP */
+
/* restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);
@@ -3303,6 +3315,10 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -4018,6 +4034,11 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
static int rtl8169_rx_fill(struct rtl8169_private *tp)
{
unsigned int i;
+#ifdef DEV_NETMAP
+ re_netmap_tx_init(tp);
+ if (re_netmap_rx_init(tp))
+ return 0; // success
+#endif /* DEV_NETMAP */
for (i = 0; i < NUM_RX_DESC; i++) {
void *data;
@@ -4119,11 +4140,19 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
/* Wait for any pending NAPI task to complete */
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_irq_mask_and_ack(ioaddr);
tp->intr_mask = 0xffff;
RTL_W16(IntrMask, tp->intr_event);
napi_enable(&tp->napi);
+
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -4395,6 +4424,11 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
{
unsigned int dirty_tx, tx_left;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(dev, 0))
+ return;
+#endif /* DEV_NETMAP */
+
dirty_tx = tp->dirty_tx;
smp_rmb();
tx_left = tp->cur_tx - dirty_tx;
@@ -4490,6 +4524,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
unsigned int count;
int polling = (budget != ~(u32)0) ? 1 : 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(dev, 0, &count))
+ return count;
+#endif /* DEV_NETMAP */
+
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
rx_left = min(rx_left, budget);
@@ -4691,6 +4730,10 @@ static void rtl8169_down(struct net_device *dev)
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
spin_lock_irq(&tp->lock);
rtl8169_asic_down(ioaddr);

View File

@ -0,0 +1,114 @@
diff --git a/r8169.c b/r8169.c
index 7ffdb80..6bae7e6 100644
--- a/r8169.c
+++ b/r8169.c
@@ -590,6 +590,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_re_netmap_linux.h>
+#endif
+
static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3207,6 +3211,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
+#ifdef DEV_NETMAP
+ re_netmap_attach(tp);
+#endif /* DEV_NETMAP */
+
netif_carrier_off(dev);
out:
@@ -3238,6 +3246,9 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
cancel_delayed_work_sync(&tp->task);
rtl_release_firmware(tp);
+#ifdef DEV_NETMAP
+ netmap_detach(dev);
+#endif /* DEV_NETMAP */
unregister_netdev(dev);
@@ -3291,6 +3302,10 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_init_phy(dev, tp);
/*
@@ -4074,6 +4089,11 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
static int rtl8169_rx_fill(struct rtl8169_private *tp)
{
unsigned int i;
+#ifdef DEV_NETMAP
+ re_netmap_tx_init(tp);
+ if (re_netmap_rx_init(tp))
+ return 0; // success
+#endif /* DEV_NETMAP */
for (i = 0; i < NUM_RX_DESC; i++) {
void *data;
@@ -4175,11 +4195,19 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
/* Wait for any pending NAPI task to complete */
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_irq_mask_and_ack(ioaddr);
tp->intr_mask = 0xffff;
RTL_W16(IntrMask, tp->intr_event);
napi_enable(&tp->napi);
+
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -4452,6 +4480,11 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
{
unsigned int dirty_tx, tx_left;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(dev, 0))
+ return;
+#endif /* DEV_NETMAP */
+
dirty_tx = tp->dirty_tx;
smp_rmb();
tx_left = tp->cur_tx - dirty_tx;
@@ -4547,6 +4580,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
unsigned int count;
int polling = (budget != ~(u32)0) ? 1 : 0;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(dev, 0, &count))
+ return count;
+#endif /* DEV_NETMAP */
+
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
rx_left = min(rx_left, budget);
@@ -4769,6 +4807,10 @@ static void rtl8169_down(struct net_device *dev)
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
spin_lock_irq(&tp->lock);
rtl8169_asic_down(ioaddr);

View File

@ -0,0 +1,114 @@
diff --git a/r8169.c b/r8169.c
index c8f47f1..a41e878 100644
--- a/r8169.c
+++ b/r8169.c
@@ -787,6 +787,10 @@ static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
}
}
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <if_re_netmap_linux.h>
+#endif
+
static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -4167,6 +4171,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
+#ifdef DEV_NETMAP
+ re_netmap_attach(tp);
+#endif /* DEV_NETMAP */
+
netif_carrier_off(dev);
out:
@@ -4201,6 +4209,9 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
rtl_release_firmware(tp);
+#ifdef DEV_NETMAP
+ netmap_detach(dev);
+#endif /* DEV_NETMAP */
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);
@@ -4298,6 +4309,10 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_init_phy(dev, tp);
rtl8169_set_features(dev, dev->features);
@@ -5252,6 +5267,11 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
static int rtl8169_rx_fill(struct rtl8169_private *tp)
{
unsigned int i;
+#ifdef DEV_NETMAP
+ re_netmap_tx_init(tp);
+ if (re_netmap_rx_init(tp))
+ return 0; // success
+#endif /* DEV_NETMAP */
for (i = 0; i < NUM_RX_DESC; i++) {
void *data;
@@ -5348,11 +5368,19 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
/* Wait for any pending NAPI task to complete */
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
rtl8169_irq_mask_and_ack(tp);
tp->intr_mask = 0xffff;
RTL_W16(IntrMask, tp->intr_event);
napi_enable(&tp->napi);
+
+#ifdef DEV_NETMAP
+ netmap_enable_all_rings(dev);
+#endif /* DEV_NETMAP */
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -5627,6 +5655,11 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
{
unsigned int dirty_tx, tx_left;
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(dev, 0))
+ return;
+#endif /* DEV_NETMAP */
+
dirty_tx = tp->dirty_tx;
smp_rmb();
tx_left = tp->cur_tx - dirty_tx;
@@ -5714,6 +5747,11 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
unsigned int cur_rx, rx_left;
unsigned int count;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(dev, 0, &count))
+ return count;
+#endif /* DEV_NETMAP */
+
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
rx_left = min(rx_left, budget);
@@ -5920,6 +5958,10 @@ static void rtl8169_down(struct net_device *dev)
napi_disable(&tp->napi);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif /* DEV_NETMAP */
+
spin_lock_irq(&tp->lock);
rtl8169_hw_reset(tp);

View File

@ -0,0 +1,85 @@
diff --git a/virtio_net.c b/virtio_net.c
index b0577dd..6516934 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -64,6 +64,10 @@ struct virtnet_info
struct page *pages;
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -121,6 +125,10 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
svq->vq_ops->disable_cb(svq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, 0))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
@@ -470,7 +478,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, 0, &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
@@ -638,6 +655,10 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ virtio_netmap_init_buffers(vi);
+ netmap_enable_all_rings(dev);
+#endif
napi_enable(&vi->napi);
/* If all buffers were filled by other side before we napi_enabled, we
@@ -700,6 +721,9 @@ static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
napi_disable(&vi->napi);
return 0;
@@ -985,6 +1009,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
vi->status = VIRTIO_NET_S_LINK_UP;
virtnet_update_status(vi);
netif_carrier_on(dev);
@@ -1028,6 +1056,9 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
/* Stop all the virtqueues. */
vdev->config->reset(vdev);

View File

@ -0,0 +1,85 @@
diff --git a/virtio_net.c b/virtio_net.c
index b6d4028..a9be38d 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -67,6 +67,10 @@ struct virtnet_info {
struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -124,6 +128,10 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
virtqueue_disable_cb(svq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, 0))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
@@ -467,7 +475,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, 0, &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
@@ -638,6 +655,10 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ virtio_netmap_init_buffers(vi);
+ netmap_enable_all_rings(dev);
+#endif
napi_enable(&vi->napi);
/* If all buffers were filled by other side before we napi_enabled, we
@@ -700,6 +721,9 @@ static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
napi_disable(&vi->napi);
return 0;
@@ -986,6 +1010,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1035,6 +1063,9 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
/* Stop all the virtqueues. */
vdev->config->reset(vdev);

View File

@ -0,0 +1,85 @@
diff --git a/virtio_net.c b/virtio_net.c
index 82dba5a..f217797 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -67,6 +67,10 @@ struct virtnet_info {
struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -124,6 +128,10 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
virtqueue_disable_cb(svq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, 0))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
@@ -481,7 +489,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, 0, &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
@@ -652,6 +669,10 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ virtio_netmap_init_buffers(vi);
+ netmap_enable_all_rings(dev);
+#endif
virtnet_napi_enable(vi);
return 0;
}
@@ -705,6 +726,9 @@ static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
napi_disable(&vi->napi);
return 0;
@@ -991,6 +1015,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1040,6 +1068,9 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
/* Stop all the virtqueues. */
vdev->config->reset(vdev);

View File

@ -0,0 +1,90 @@
diff --git a/virtio_net.c b/virtio_net.c
index 4880aa8..6329c3a 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -80,6 +80,10 @@ struct virtnet_info {
struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -137,6 +141,10 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
virtqueue_disable_cb(svq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, 0))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
@@ -517,7 +525,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, 0, &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
@@ -727,7 +744,15 @@ static void virtnet_netpoll(struct net_device *dev)
static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ int ok = virtio_netmap_init_buffers(vi);
+ netmap_enable_all_rings(dev);
+ if (ok) {
+ virtnet_napi_enable(vi);
+ return 0;
+ }
+#endif
/* Make sure we have some buffers: if oom use wq. */
if (!try_fill_recv(vi, GFP_KERNEL))
queue_delayed_work(system_nrt_wq, &vi->refill, 0);
@@ -785,6 +810,9 @@ static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
/* Make sure refill_work doesn't re-enable napi! */
cancel_delayed_work_sync(&vi->refill);
napi_disable(&vi->napi);
@@ -1107,6 +1135,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1170,6 +1202,9 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
unregister_netdev(vi->dev);
remove_vq_common(vi);

View File

@ -0,0 +1,90 @@
diff --git a/virtio_net.c b/virtio_net.c
index f18149a..95e1580 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -90,6 +90,10 @@ struct virtnet_info {
struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -147,6 +151,10 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
virtqueue_disable_cb(svq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, 0))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
@@ -529,7 +537,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, 0, &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
@@ -742,6 +759,15 @@ static void virtnet_netpoll(struct net_device *dev)
static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ int ok = virtio_netmap_init_buffers(vi);
+
+ netmap_enable_all_rings(dev);
+ if (ok) {
+ virtnet_napi_enable(vi);
+ return 0;
+ }
+#endif
/* Make sure we have some buffers: if oom use wq. */
if (!try_fill_recv(vi, GFP_KERNEL))
@@ -810,6 +836,9 @@ static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
/* Make sure refill_work doesn't re-enable napi! */
cancel_delayed_work_sync(&vi->refill);
napi_disable(&vi->napi);
@@ -1148,6 +1177,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1211,6 +1244,9 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
/* Prevent config work handler from accessing the device. */
mutex_lock(&vi->config_lock);
vi->config_enable = false;

View File

@ -0,0 +1,91 @@
diff --git a/virtio_net.c b/virtio_net.c
index 35c00c5..8aaaa7e 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -132,6 +132,10 @@ struct virtnet_info {
struct notifier_block nb;
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -211,6 +215,10 @@ static void skb_xmit_done(struct virtqueue *vq)
/* Suppress further interrupts. */
virtqueue_disable_cb(vq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, vq2txq(vq)))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_subqueue(vi->dev, vq2txq(vq));
}
@@ -603,7 +611,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = rq->vq->vdev->priv;
void *buf;
unsigned int len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
@@ -635,6 +652,16 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
+#ifdef DEV_NETMAP
+ int ok = virtio_netmap_init_buffers(vi);
+
+ netmap_enable_all_rings(dev);
+ if (ok) {
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ virtnet_napi_enable(&vi->rq[i]);
+ return 0;
+ }
+#endif
for (i = 0; i < vi->max_queue_pairs; i++) {
/* Make sure we have some buffers: if oom use wq. */
@@ -909,6 +936,9 @@ static int virtnet_close(struct net_device *dev)
struct virtnet_info *vi = netdev_priv(dev);
int i;
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
/* Make sure refill_work doesn't re-enable napi! */
cancel_delayed_work_sync(&vi->refill);
@@ -1572,6 +1602,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_recv_bufs;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1618,6 +1652,9 @@ static void virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
unregister_hotcpu_notifier(&vi->nb);
/* Prevent config work handler from accessing the device. */

View File

@ -0,0 +1,91 @@
diff --git a/virtio_net.c b/virtio_net.c
index 3d2a90a..ae899a4 100644
--- a/virtio_net.c
+++ b/virtio_net.c
@@ -131,6 +131,10 @@ struct virtnet_info {
struct notifier_block nb;
};
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <virtio_netmap.h>
+#endif
+
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr;
@@ -210,6 +214,10 @@ static void skb_xmit_done(struct virtqueue *vq)
/* Suppress further interrupts. */
virtqueue_disable_cb(vq);
+#ifdef DEV_NETMAP
+ if (netmap_tx_irq(vi->dev, vq2txq(vq)))
+ return;
+#endif
/* We were probably waiting for more output buffers. */
netif_wake_subqueue(vi->dev, vq2txq(vq));
}
@@ -603,7 +611,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct virtnet_info *vi = rq->vq->vdev->priv;
void *buf;
unsigned int r, len, received = 0;
+#ifdef DEV_NETMAP
+ int work_done = 0;
+ if (netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done)) {
+ napi_complete(napi);
+ ND("called netmap_rx_irq");
+
+ return 1;
+ }
+#endif
again:
while (received < budget &&
(buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
@@ -636,6 +653,16 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
+#ifdef DEV_NETMAP
+ int ok = virtio_netmap_init_buffers(vi);
+
+ netmap_enable_all_rings(dev);
+ if (ok) {
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ virtnet_napi_enable(&vi->rq[i]);
+ return 0;
+ }
+#endif
for (i = 0; i < vi->max_queue_pairs; i++) {
if (i < vi->curr_queue_pairs)
@@ -927,6 +954,9 @@ static int virtnet_close(struct net_device *dev)
struct virtnet_info *vi = netdev_priv(dev);
int i;
+#ifdef DEV_NETMAP
+ netmap_disable_all_rings(dev);
+#endif
/* Make sure refill_work doesn't re-enable napi! */
cancel_delayed_work_sync(&vi->refill);
@@ -1592,6 +1622,10 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_recv_bufs;
}
+#ifdef DEV_NETMAP
+ virtio_netmap_attach(vi);
+#endif
+
/* Assume link up if device can't report link status,
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1638,6 +1672,9 @@ static void virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
+#ifdef DEV_NETMAP
+ netmap_detach(vi->dev);
+#endif
unregister_hotcpu_notifier(&vi->nb);
/* Prevent config work handler from accessing the device. */

View File

@ -0,0 +1,407 @@
/*
* Copyright (C) 2012-2014 Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: forcedeth_netmap.h 10670 2012-02-27 21:15:38Z luigi $
*
* netmap support for: forcedeth (nfe, linux)
* For details on netmap support see ixgbe_netmap.h
The driver supports ORIGinal and EXtended descriptors through unions.
We remove the .orig and .ex suffix for brevity.
Pointers in the ring (N slots) are
first_rx = 0, last_rx = N-1, get_rx = put_rx = 0 at init
Following init there is a call to nv_alloc_rx_optimized() which does
less_rx = get_rx - 1
for (put_rx = 0; put_rx != less_rx; put_rx++)
put_rx.flags = LEN | NV_RX2_AVAIL;
so it leaves one free slot and put_rx pointing at the end.
Basically, get_rx is where new packets arrive, put_rx is where
new buffers are added.
The rx_intr aka nv_rx_process_optimized() scans
while (get_rx != put_rx && !(get_rx.flags & NV_RX2_AVAIL)) {
...
get_rx++
}
followed by a nv_alloc_rx_optimized().
This makes sure that there is always a free slot.
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T fe_priv
/*
* Register/unregister. We are already under netmap lock.
* only called on the first register or the last unregister.
* The "forcedeth" driver is poorly written, the reinit routine
* is replicated multiple times and one way to achieve it is to
* nv_change_mtu twice above ETH_DATA_LEN.
*/
static int
forcedeth_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *np = netdev_priv(ifp);
u8 __iomem *base = get_hwbase(ifp);
// first half of nv_change_mtu() - down
nv_disable_irq(ifp);
nv_napi_disable(ifp);
netif_tx_lock_bh(ifp);
netif_addr_lock(ifp);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(ifp);
nv_txrx_reset(ifp);
/* drain rx queue */
nv_drain_rxtx(ifp);
if (onoff) {
nm_set_native_flags(na);
} else {
nm_clear_native_flags(na);
}
// second half of nv_change_mtu() -- up
if (nv_init_ring(ifp)) {
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
}
/* reinit nic view of the rx queue */
writel(np->rx_buf_sz, base + NvRegOffloadConfig);
setup_hw_rings(ifp, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
writel(((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(ifp) + NvRegTxRxControl);
pci_push(base);
/* restart rx engine */
nv_start_rxtx(ifp);
spin_unlock(&np->lock);
netif_addr_unlock(ifp);
netif_tx_unlock_bh(ifp);
nv_napi_enable(ifp);
nv_enable_irq(ifp);
return (0);
}
/*
* Reconcile kernel and user view of the transmit ring.
*/
static int
forcedeth_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* device-specific */
struct SOFTC_T *np = netdev_priv(ifp);
struct ring_desc_ex *txr = np->tx_ring.ex;
uint32_t lastpkt = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
u_int k;
/*
* First part: process new packets to send.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = np->put_tx.ex - txr; // NIC pointer
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
struct ring_desc_ex *put_tx = txr + nic_i;
// XXX check who needs lastpkt
int cmd = (len - 1) | NV_TX2_VALID | lastpkt;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Fill the slot in the NIC ring. */
put_tx->bufhigh = htole32(dma_high(paddr));
put_tx->buflow = htole32(dma_low(paddr));
put_tx->flaglen = htole32(cmd);
put_tx->txvlan = 0;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
np->put_tx.ex = txr + nic_i;
kring->nr_hwcur = head;
wmb(); /* synchronize writes to the NIC ring */
/* restart tx unit where is the new index ? */
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits,
get_hwbase(ifp) + NvRegTxRxControl);
}
/*
* Second part: reclaim buffers for completed transmissions
*/
/* Sync the TX descriptor list */
rmb();
nic_i = np->get_tx.ex - txr;
k = np->put_tx.ex - txr;
if (nic_i != k) {
for (n = 0; nic_i != k; n++) {
uint32_t cmdstat = le32toh(txr[nic_i].flaglen);
if (cmdstat & NV_TX2_VALID)
break;
if (++nic_i == np->tx_ring_size)
nic_i = 0;
}
if (n > 0) {
np->get_tx.ex = txr + nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
*/
static int
forcedeth_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
struct SOFTC_T *np = netdev_priv(ifp);
struct ring_desc_ex *rxr = np->rx_ring.ex;
u_int refill; // refill position
if (head > lim)
return netmap_ring_reinit(kring);
/*
* First part: import newly received packets.
*/
rmb();
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
nic_i = np->get_rx.ex - rxr; /* next pkt to check */
/* put_rx is the refill position, one before nr_hwcur.
* This slot is not available
*/
refill = np->put_rx.ex - rxr; /* refill position */
nm_i = netmap_idx_n2k(kring, nic_i);
while (nic_i != refill) {
uint32_t statlen = le32toh(rxr[nic_i].flaglen);
if (statlen & NV_RX2_AVAIL) /* still owned by the NIC */
break;
ring->slot[nm_i].len = statlen & LEN_MASK_V2; // XXX crc?
ring->slot[nm_i].flags = slot_flags;
// ifp->stats.rx_packets++;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
np->get_rx.ex = rxr + nic_i;
kring->nr_hwtail = nm_i;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur; // refill is one before nic_i
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
refill = np->put_rx.ex - rxr; /* refill position */
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
struct ring_desc_ex *desc = rxr + nic_i;
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
desc->flaglen = htole32(NETMAP_BUF_SIZE);
desc->bufhigh = htole32(dma_high(paddr));
desc->buflow = htole32(dma_low(paddr));
// enable the previous buffer
rxr[refill].flaglen |= htole32(NV_RX2_AVAIL);
refill = nm_next(refill, lim);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
np->put_rx.ex = rxr + refill;
/* Flush the RX DMA ring */
wmb();
}
/* tell userspace that there are might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/*
* Additional routines to init the tx and rx rings.
* In other drivers we do that inline in the main code.
*/
static int
forcedeth_netmap_tx_init(struct SOFTC_T *np)
{
struct ring_desc_ex *desc;
int i, n;
struct netmap_adapter *na = NA(np->dev);
struct netmap_slot *slot;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_TX, 0, 0);
/* slot is NULL if we are not in netmap mode */
if (!slot)
return 0;
/* in netmap mode, overwrite addresses and maps */
//txd = np->rl_ldata.rl_tx_desc;
desc = np->tx_ring.ex;
n = np->tx_ring_size;
/* l points in the netmap ring, i points in the NIC ring */
for (i = 0; i < n; i++) {
int l = netmap_idx_n2k(&na->tx_rings[0], i);
uint64_t paddr;
PNMB(slot + l, &paddr);
desc[i].flaglen = 0;
desc[i].bufhigh = htole32(dma_high(paddr));
desc[i].buflow = htole32(dma_low(paddr));
}
return 1;
}
static int
forcedeth_netmap_rx_init(struct SOFTC_T *np)
{
struct netmap_adapter *na = NA(np->dev);
struct netmap_slot *slot = netmap_reset(na, NR_RX, 0, 0);
struct ring_desc_ex *desc = np->rx_ring.ex;
uint32_t cmdstat;
int i, lim;
if (!slot)
return 0;
/*
* Do not release the slots owned by userspace,
* and also keep one empty.
*/
lim = np->rx_ring_size - 1 - nm_kr_rxspace(&na->rx_rings[0]);
for (i = 0; i < np->rx_ring_size; i++) {
void *addr;
uint64_t paddr;
int l = netmap_idx_n2k(&na->rx_rings[0], i);
addr = PNMB(slot + l, &paddr);
netmap_reload_map(np->rl_ldata.rl_rx_mtag,
np->rl_ldata.rl_rx_desc[i].rx_dmamap, addr);
desc[i].bufhigh = htole32(dma_high(paddr));
desc[i].buflow = htole32(dma_low(paddr));
cmdstat = NETMAP_BUF_SIZE;
if (i < lim)
cmdstat |= NV_RX2_AVAIL;
desc[i].flaglen = htole32(cmdstat);
}
// XXX ring end anywhere ?
np->get_rx.ex = desc;
np->put_rx.ex = desc + lim;
return 1;
}
static void
forcedeth_netmap_attach(struct SOFTC_T *np)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = np->dev;
na.num_tx_desc = np->tx_ring_size;
na.num_rx_desc = np->tx_ring_size;
na.nm_txsync = forcedeth_netmap_txsync;
na.nm_rxsync = forcedeth_netmap_rxsync;
na.nm_register = forcedeth_netmap_reg;
na.num_tx_rings = na.num_rx_rings = 1;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,352 @@
/*
* Copyright (C) 2012-2014 Gaetano Catalli, Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: if_e1000_netmap.h 10878 2012-04-12 22:28:48Z luigi $
*
* netmap support for: e1000 (linux version)
* For details on netmap support please see ixgbe_netmap.h
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T e1000_adapter
/*
* Register/unregister. We are already under netmap lock.
*/
static int
e1000_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *adapter = netdev_priv(ifp);
/* protect against other reinit */
while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
usleep_range(1000, 2000);
rtnl_lock();
if (netif_running(adapter->netdev))
e1000_down(adapter);
/* enable or disable flags and callbacks in na and ifp */
if (onoff) {
nm_set_native_flags(na);
} else {
nm_clear_native_flags(na);
}
if (netif_running(adapter->netdev))
e1000_up(adapter);
else
e1000_reset(adapter);
rtnl_unlock();
clear_bit(__E1000_RESETTING, &adapter->flags);
return (0);
}
/*
* Reconcile kernel and user view of the transmit ring.
*/
static int
e1000_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* generate an interrupt approximately every half ring */
u_int report_frequency = kring->nkr_num_slots >> 1;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct e1000_tx_ring* txr = &adapter->tx_ring[ring_nr];
rmb();
/*
* First part: process new packets to send.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
int flags = (slot->flags & NS_REPORT ||
nic_i == 0 || nic_i == report_frequency) ?
E1000_TXD_CMD_RS : 0;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, paddr);
curr->buffer_addr = htole64(paddr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Fill the slot in the NIC ring. */
curr->upper.data = 0;
curr->lower.data = htole32(adapter->txd_cmd |
len | flags |
E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb(); /* synchronize writes to the NIC ring */
txr->next_to_use = nic_i; /* XXX what for ? */
/* (re)start the tx unit up to slot nic_i (excluded) */
writel(nic_i, adapter->hw.hw_addr + txr->tdt);
mmiowb(); // XXX where do we need this ?
}
/*
* Second part: reclaim buffers for completed transmissions.
*/
if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
/* record completed transmissions using TDH */
nic_i = readl(adapter->hw.hw_addr + txr->tdh);
if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("TDH wrap %d", nic_i);
nic_i -= kring->nkr_num_slots;
}
txr->next_to_clean = nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
*/
static int
e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct e1000_rx_ring *rxr = &adapter->rx_ring[ring_nr];
if (!netif_carrier_ok(ifp)) {
goto out;
}
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
nic_i = rxr->next_to_clean;
nm_i = netmap_idx_n2k(kring, nic_i);
for (n = 0; ; n++) {
struct e1000_rx_desc *curr = E1000_RX_DESC(*rxr, nic_i);
uint32_t staterr = le32toh(curr->status);
if ((staterr & E1000_RXD_STAT_DD) == 0)
break;
ring->slot[nm_i].len = le16toh(curr->length) - 4;
ring->slot[nm_i].flags = slot_flags;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
if (n) { /* update the state variables */
rxr->next_to_clean = nic_i;
kring->nr_hwtail = nm_i;
}
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur;
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
struct e1000_rx_desc *curr = E1000_RX_DESC(*rxr, nic_i);
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (slot->flags & NS_BUF_CHANGED) {
// netmap_reload_map(...)
curr->buffer_addr = htole64(paddr);
slot->flags &= ~NS_BUF_CHANGED;
}
curr->status = 0;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
rxr->next_to_use = nic_i; // XXX not really used
wmb();
/*
* IMPORTANT: we must leave one free slot in the ring,
* so move nic_i back by one unit
*/
nic_i = nm_prev(nic_i, lim);
writel(nic_i, adapter->hw.hw_addr + rxr->rdt);
}
out:
/* tell userspace that there might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/* diagnostic routine to catch errors */
static void e1000_no_rx_alloc(struct SOFTC_T *adapter,
struct e1000_rx_ring *rxr, int cleaned_count)
{
D("e1000->alloc_rx_buf should not be called");
}
/*
* Make the tx and rx rings point to the netmap buffers.
*/
static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct ifnet *ifp = adapter->netdev;
struct netmap_adapter* na = NA(ifp);
struct netmap_slot* slot;
struct e1000_tx_ring* txr = &adapter->tx_ring[0];
unsigned int i, r, si;
uint64_t paddr;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
adapter->alloc_rx_buf = e1000_no_rx_alloc;
for (r = 0; r < na->num_rx_rings; r++) {
struct e1000_rx_ring *rxr;
slot = netmap_reset(na, NR_RX, r, 0);
if (!slot) {
D("strange, null netmap ring %d", r);
return 0;
}
rxr = &adapter->rx_ring[r];
for (i = 0; i < rxr->count; i++) {
// XXX the skb check and cleanup can go away
struct e1000_buffer *bi = &rxr->buffer_info[i];
si = netmap_idx_n2k(&na->rx_rings[r], i);
PNMB(slot + si, &paddr);
if (bi->skb)
D("rx buf %d was set", i);
bi->skb = NULL;
// netmap_load_map(...)
E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
}
rxr->next_to_use = 0;
/* preserve buffers already made available to clients */
i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
if (i < 0) // XXX something wrong here, can it really happen ?
i += rxr->count;
D("i now is %d", i);
wmb(); /* Force memory writes to complete */
writel(i, hw->hw_addr + rxr->rdt);
}
/* now initialize the tx ring(s) */
slot = netmap_reset(na, NR_TX, 0, 0);
for (i = 0; i < na->num_tx_desc; i++) {
si = netmap_idx_n2k(&na->tx_rings[0], i);
PNMB(slot + si, &paddr);
// netmap_load_map(...)
E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
}
return 1;
}
static void
e1000_netmap_attach(struct SOFTC_T *adapter)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = adapter->netdev;
na.num_tx_desc = adapter->tx_ring[0].count;
na.num_rx_desc = adapter->rx_ring[0].count;
na.nm_register = e1000_netmap_reg;
na.nm_txsync = e1000_netmap_txsync;
na.nm_rxsync = e1000_netmap_rxsync;
na.num_tx_rings = na.num_rx_rings = 1;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,377 @@
/*
* Copyright (C) 2012-2014 Gaetano Catalli, Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: if_e1000e_netmap.h 10670 2012-02-27 21:15:38Z luigi $
*
* netmap support for: e1000e (linux version)
* For details on netmap support please see ixgbe_netmap.h
* The driver supports 1 TX and 1 RX ring. Single lock.
* tx buffer address only written on change.
* Apparently the driver uses extended descriptors on rx from 3.2.32
* Rx Crc stripping ?
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T e1000_adapter
/*
* Adaptation to different versions of the driver.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
#warning this driver uses extended descriptors
#define NM_E1K_RX_DESC_T union e1000_rx_desc_extended
#define NM_E1R_RX_STATUS wb.upper.status_error
#define NM_E1R_RX_LENGTH wb.upper.length
#define NM_E1R_RX_BUFADDR read.buffer_addr
#else
#warning this driver uses regular descriptors
#define E1000_RX_DESC_EXT E1000_RX_DESC // XXX workaround
#define NM_E1K_RX_DESC_T struct e1000_rx_desc
#define NM_E1R_RX_STATUS status
#define NM_E1R_RX_BUFADDR buffer_addr
#define NM_E1R_RX_LENGTH length
#endif /* up to 3.2.x */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
#define NM_WR_TX_TAIL(_x) writel(_x, txr->tail) // XXX tx_ring
#define NM_WR_RX_TAIL(_x) writel(_x, rxr->tail) // XXX rx_ring
#define NM_RD_TX_HEAD() readl(txr->head)
#else
#define NM_WR_TX_TAIL(_x) writel(_x, adapter->hw.hw_addr + txr->tail)
#define NM_WR_RX_TAIL(_x) writel(_x, adapter->hw.hw_addr + rxr->tail)
#define NM_RD_TX_HEAD() readl(adapter->hw.hw_addr + txr->head)
#endif /* < 3.4.0 */
/*
* Register/unregister. We are already under netmap lock.
*/
static int
e1000_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *adapter = netdev_priv(ifp);
/* protect against other reinit */
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
usleep_range(1000, 2000);
rtnl_lock();
if (netif_running(adapter->netdev))
e1000e_down(adapter);
/* enable or disable flags and callbacks in na and ifp */
if (onoff) {
nm_set_native_flags(na);
} else {
nm_clear_native_flags(na);
}
if (netif_running(adapter->netdev))
e1000e_up(adapter);
else
e1000e_reset(adapter); // XXX is it needed ?
rtnl_unlock();
clear_bit(__E1000_RESETTING, &adapter->state);
return (0);
}
/*
* Reconcile kernel and user view of the transmit ring.
*/
static int
e1000_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* generate an interrupt approximately every half ring */
u_int report_frequency = kring->nkr_num_slots >> 1;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct e1000_ring* txr = &adapter->tx_ring[ring_nr];
rmb();
/*
* First part: process new packets to send.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
int flags = (slot->flags & NS_REPORT ||
nic_i == 0 || nic_i == report_frequency) ?
E1000_TXD_CMD_RS : 0;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr)
curr->buffer_addr = htole64(paddr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Fill the slot in the NIC ring. */
curr->upper.data = 0;
curr->lower.data = htole32(adapter->txd_cmd | len | flags |
E1000_TXD_CMD_EOP);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb(); /* synchronize writes to the NIC ring */
txr->next_to_use = nic_i;
NM_WR_TX_TAIL(nic_i);
mmiowb(); // XXX where do we need this ?
}
/*
* Second part: reclaim buffers for completed transmissions.
*/
if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
/* record completed transmissions using TDH */
nic_i = NM_RD_TX_HEAD(); // XXX could scan descriptors ?
if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("TDH wrap %d", nic_i);
nic_i -= kring->nkr_num_slots;
}
txr->next_to_clean = nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
*/
static int
e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct e1000_ring *rxr = &adapter->rx_ring[ring_nr];
if (!netif_carrier_ok(ifp))
return 0;
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
int strip_crc = (adapter->flags2 & FLAG2_CRC_STRIPPING) ? 0 : 4;
nic_i = rxr->next_to_clean;
nm_i = netmap_idx_n2k(kring, nic_i);
for (n = 0; ; n++) {
NM_E1K_RX_DESC_T *curr = E1000_RX_DESC_EXT(*rxr, nic_i);
uint32_t staterr = le32toh(curr->NM_E1R_RX_STATUS);
if ((staterr & E1000_RXD_STAT_DD) == 0)
break;
ring->slot[nm_i].len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
ring->slot[nm_i].flags = slot_flags;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
if (n) { /* update the state variables */
rxr->next_to_clean = nic_i;
kring->nr_hwtail = nm_i;
}
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur;
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
NM_E1K_RX_DESC_T *curr = E1000_RX_DESC_EXT(*rxr, nic_i);
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
curr->NM_E1R_RX_BUFADDR = htole64(paddr); /* reload ext.desc. addr. */
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr)
slot->flags &= ~NS_BUF_CHANGED;
}
curr->NM_E1R_RX_STATUS = 0;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
rxr->next_to_use = nic_i; // XXX not really used
wmb();
/*
* IMPORTANT: we must leave one free slot in the ring,
* so move nic_i back by one unit
*/
nic_i = nm_prev(nic_i, lim);
NM_WR_RX_TAIL(nic_i);
}
/* tell userspace that there might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/* diagnostic routine to catch errors */
static void e1000e_no_rx_alloc(struct SOFTC_T *a, int n)
{
D("e1000->alloc_rx_buf should not be called");
}
/*
* Make the tx and rx rings point to the netmap buffers.
*/
static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
{
struct ifnet *ifp = adapter->netdev;
struct netmap_adapter* na = NA(ifp);
struct netmap_slot* slot;
struct e1000_ring *rxr = adapter->rx_ring;
struct e1000_ring *txr = adapter->tx_ring;
int i, si;
uint64_t paddr;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_RX, 0, 0);
if (!slot)
return 0; // not in netmap mode XXX check is useless
adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
for (i = 0; i < rxr->count; i++) {
// XXX the skb check and cleanup can go away
struct e1000_buffer *bi = &rxr->buffer_info[i];
si = netmap_idx_n2k(&na->rx_rings[0], i);
PNMB(slot + si, &paddr);
if (bi->skb)
D("rx buf %d was set", i);
bi->skb = NULL; // XXX leak if set
// netmap_load_map(...)
E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr);
}
rxr->next_to_use = 0;
/* preserve buffers already made available to clients */
i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
wmb(); /* Force memory writes to complete */
NM_WR_RX_TAIL(i);
/* now initialize the tx ring */
slot = netmap_reset(na, NR_TX, 0, 0);
for (i = 0; i < na->num_tx_desc; i++) {
si = netmap_idx_n2k(&na->tx_rings[0], i);
PNMB(slot + si, &paddr);
// netmap_load_map(...)
E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
}
return 1;
}
static void
e1000_netmap_attach(struct SOFTC_T *adapter)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = adapter->netdev;
na.num_tx_desc = adapter->tx_ring->count;
na.num_rx_desc = adapter->rx_ring->count;
na.nm_register = e1000_netmap_reg;
na.nm_txsync = e1000_netmap_txsync;
na.nm_rxsync = e1000_netmap_rxsync;
na.num_tx_rings = na.num_rx_rings = 1;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,400 @@
/*
* Copyright (C) 2012-2014 Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: if_igb_netmap.h 10878 2012-04-12 22:28:48Z luigi $
*
* netmap support for: igb (linux version)
* For details on netmap support please see ixgbe_netmap.h
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T igb_adapter
/*
* Adapt to different versions of the driver.
* E1000_TX_DESC_ADV etc. have dropped the _ADV suffix at some point.
* Also the first argument is now a pointer not the object.
*/
#ifndef E1000_TX_DESC_ADV
#define E1000_TX_DESC_ADV(_r, _i) IGB_TX_DESC(&(_r), _i)
#define E1000_RX_DESC_ADV(_r, _i) IGB_RX_DESC(&(_r), _i)
#define READ_TDH(_txr) ({struct e1000_hw *hw = &adapter->hw;rd32(E1000_TDH((_txr)->reg_idx));} )
#else /* up to 3.2, approximately */
#define igb_tx_buffer igb_buffer
#define tx_buffer_info buffer_info
#define igb_rx_buffer igb_buffer
#define rx_buffer_info buffer_info
#define READ_TDH(_txr) readl((_txr)->head)
#endif
/*
* Register/unregister. We are already under netmap lock.
* Only called on the first register or the last unregister.
*/
static int
igb_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *adapter = netdev_priv(ifp);
/* protect against other reinit */
while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
usleep_range(1000, 2000);
rtnl_lock();
if (netif_running(adapter->netdev))
igb_down(adapter);
/* enable or disable flags and callbacks in na and ifp */
if (onoff) {
nm_set_native_flags(na);
} else {
nm_clear_native_flags(na);
}
if (netif_running(adapter->netdev))
igb_up(adapter);
else
igb_reset(adapter); // XXX is it needed ?
rtnl_unlock();
clear_bit(__IGB_RESETTING, &adapter->state);
return (0);
}
/*
* Reconcile kernel and user view of the transmit ring.
*/
static int
igb_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* generate an interrupt approximately every half ring */
u_int report_frequency = kring->nkr_num_slots >> 1;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct igb_ring* txr = adapter->tx_ring[ring_nr];
rmb(); // XXX not in ixgbe ?
/*
* First part: process new packets to send.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
uint32_t olinfo_status=0;
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
union e1000_adv_tx_desc *curr =
E1000_TX_DESC_ADV(*txr, nic_i);
int flags = (slot->flags & NS_REPORT ||
nic_i == 0 || nic_i == report_frequency) ?
E1000_TXD_CMD_RS : 0;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Fill the slot in the NIC ring. */
curr->read.buffer_addr = htole64(paddr);
// XXX check olinfo and cmd_type_len
curr->read.olinfo_status =
htole32(olinfo_status |
(len<< E1000_ADVTXD_PAYLEN_SHIFT));
curr->read.cmd_type_len = htole32(len | flags |
E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_DEXT |
E1000_ADVTXD_DCMD_IFCS | E1000_TXD_CMD_EOP);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb(); /* synchronize writes to the NIC ring */
txr->next_to_use = nic_i; /* XXX what for ? */
/* (re)start the tx unit up to slot nic_i (excluded) */
writel(nic_i, txr->tail);
mmiowb(); // XXX where do we need this ?
}
/*
* Second part: reclaim buffers for completed transmissions.
*/
if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
/* record completed transmissions using TDH */
nic_i = READ_TDH(txr);
if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("TDH wrap %d", nic_i);
nic_i -= kring->nkr_num_slots;
}
txr->next_to_use = nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
*/
static int
igb_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct igb_ring *rxr = adapter->rx_ring[ring_nr];
if (!netif_carrier_ok(ifp))
return 0;
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
nic_i = rxr->next_to_clean;
nm_i = netmap_idx_n2k(kring, nic_i);
for (n = 0; ; n++) {
union e1000_adv_rx_desc *curr =
E1000_RX_DESC_ADV(*rxr, nic_i);
uint32_t staterr = le32toh(curr->wb.upper.status_error);
if ((staterr & E1000_RXD_STAT_DD) == 0)
break;
ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
ring->slot[nm_i].flags = slot_flags;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
if (n) { /* update the state variables */
rxr->next_to_clean = nic_i;
kring->nr_hwtail = nm_i;
}
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur;
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
union e1000_adv_rx_desc *curr = E1000_RX_DESC_ADV(*rxr, nic_i);
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (slot->flags & NS_BUF_CHANGED) {
// netmap_reload_map(pdev, DMA_FROM_DEVICE, old_paddr, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
curr->read.pkt_addr = htole64(paddr);
curr->read.hdr_addr = 0;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb();
rxr->next_to_use = nic_i; // XXX not really used
/*
* IMPORTANT: we must leave one free slot in the ring,
* so move nic_i back by one unit
*/
nic_i = nm_prev(nic_i, lim);
writel(nic_i, rxr->tail);
}
/* tell userspace that there might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
static int
igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
{
struct ifnet *ifp = adapter->netdev;
struct netmap_adapter* na = NA(ifp);
struct netmap_slot* slot;
struct igb_ring *txr = adapter->tx_ring[ring_nr];
int i, si;
void *addr;
uint64_t paddr;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_TX, ring_nr, 0);
if (!slot)
return 0; // XXX this should never happen
for (i = 0; i < na->num_tx_desc; i++) {
union e1000_adv_tx_desc *tx_desc;
si = netmap_idx_n2k(&na->tx_rings[ring_nr], i);
addr = PNMB(slot + si, &paddr);
tx_desc = E1000_TX_DESC_ADV(*txr, i);
tx_desc->read.buffer_addr = htole64(paddr);
/* actually we don't care to init the rings here */
}
return 1; // success
}
static int
igb_netmap_configure_rx_ring(struct igb_ring *rxr)
{
struct ifnet *ifp = rxr->netdev;
struct netmap_adapter* na = NA(ifp);
int reg_idx = rxr->reg_idx;
struct netmap_slot* slot;
u_int i;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
/*
* XXX watch out, the main driver must not use
* split headers. The buffer len should be written
* into wr32(E1000_SRRCTL(reg_idx), srrctl) with options
* something like
* srrctl = ALIGN(buffer_len, 1024) >>
* E1000_SRRCTL_BSIZEPKT_SHIFT;
* srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
* srrctl |= E1000_SRRCTL_DROP_EN;
*/
slot = netmap_reset(na, NR_RX, reg_idx, 0);
if (!slot)
return 0; // not in netmap mode
for (i = 0; i < rxr->count; i++) {
union e1000_adv_rx_desc *rx_desc;
uint64_t paddr;
int si = netmap_idx_n2k(&na->rx_rings[reg_idx], i);
#if 0
// XXX the skb check can go away
struct igb_rx_buffer *bi = &rxr->rx_buffer_info[i];
if (bi->skb)
D("rx buf %d was set", i);
bi->skb = NULL; // XXX leak if set
#endif /* useless */
PNMB(slot + si, &paddr);
rx_desc = E1000_RX_DESC_ADV(*rxr, i);
rx_desc->read.hdr_addr = 0;
rx_desc->read.pkt_addr = htole64(paddr);
}
rxr->next_to_use = 0;
/* preserve buffers already made available to clients */
i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[reg_idx]);
wmb(); /* Force memory writes to complete */
ND("%s rxr%d.tail %d", ifp->if_xname, reg_idx, i);
writel(i, rxr->tail);
return 1; // success
}
static void
igb_netmap_attach(struct SOFTC_T *adapter)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = adapter->netdev;
na.num_tx_desc = adapter->tx_ring_count;
na.num_rx_desc = adapter->rx_ring_count;
na.nm_register = igb_netmap_reg;
na.nm_txsync = igb_netmap_txsync;
na.nm_rxsync = igb_netmap_rxsync;
na.num_tx_rings = adapter->num_tx_queues;
na.num_rx_rings = adapter->num_rx_queues;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,350 @@
/*
* Copyright (C) 2011-2014 Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: if_re_netmap_linux.h 10679 2012-02-28 13:42:18Z luigi $
*
* netmap support for: r8169 (re, linux version)
* For details on netmap support please see ixgbe_netmap.h
* 1 tx ring, 1 rx ring, 1 lock, crcstrip ? reinit tx addr,
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
static void rtl8169_wait_for_quiescence(struct ifnet *);
#define SOFTC_T rtl8169_private
/*
* Register/unregister, mostly the reinit task
*/
static int
re_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
int error = 0;
rtnl_lock();
rtl8169_wait_for_quiescence(ifp);
rtl8169_close(ifp);
/* enable or disable flags and callbacks in na and ifp */
if (onoff) {
nm_set_native_flags(na);
if (rtl8169_open(ifp) < 0) {
error = ENOMEM;
goto fail;
}
} else {
fail:
nm_clear_native_flags(na);
error = rtl8169_open(ifp) ? EINVAL : 0;
}
rtnl_unlock();
return (error);
}
/*
* Reconcile kernel and user view of the transmit ring.
*/
static int
re_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* device-specific */
struct SOFTC_T *sc = netdev_priv(ifp);
void __iomem *ioaddr = sc->mmio_addr;
rmb();
/*
* First part: process new packets to send.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = sc->cur_tx; // XXX use internal macro ?
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
struct TxDesc *curr = &sc->TxDescArray[nic_i];
uint32_t flags = slot->len | LastFrag | DescOwn | FirstFrag ;
NM_CHECK_ADDR_LEN(addr, len);
if (nic_i == lim) /* mark end of ring */
flags |= RingEnd;
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
curr->addr = htole64(paddr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
curr->opts1 = htole32(flags);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
sc->cur_tx = nic_i;
wmb(); /* synchronize writes to the NIC ring */
RTL_W8(TxPoll, NPQ); /* start ? */
}
/*
* Second part: reclaim buffers for completed transmissions.
*/
if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
for (n = 0, nic_i = sc->dirty_tx; nic_i != sc->cur_tx; n++) {
if (le32toh(sc->TxDescArray[nic_i].opts1) & DescOwn)
break;
if (++nic_i == NUM_TX_DESC)
nic_i = 0;
}
if (n > 0) {
sc->dirty_tx = nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
*/
static int
re_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct SOFTC_T *sc = netdev_priv(ifp);
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
if (!netif_carrier_ok(ifp))
return 0;
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
*
* NOTE: This device uses all the buffers in the ring, so we
* need another termination condition in addition to DescOwn
* cleared (all buffers could have it cleared. The easiest one
* is to stop right before nm_hwcur.
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
uint32_t stop_i = nm_prev(kring->nr_hwcur, lim);
nic_i = sc->cur_rx; /* next pkt to check */
nm_i = netmap_idx_n2k(kring, nic_i);
while (nm_i != stop_i) {
struct RxDesc *cur_rx = &sc->RxDescArray[nic_i];
uint32_t rxstat = le32toh(cur_rx->opts1);
uint32_t total_len;
if ((rxstat & DescOwn) != 0)
break;
total_len = rxstat & 0x00001FFF;
/* XXX subtract crc */
total_len = (total_len < 4) ? 0 : total_len - 4;
ring->slot[nm_i].len = total_len;
ring->slot[nm_i].flags = slot_flags;
// ifp->stats.rx_packets++;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
sc->cur_rx = nic_i;
kring->nr_hwtail = nm_i;
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur;
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
struct RxDesc *curr = &sc->RxDescArray[nic_i];
uint32_t flags = NETMAP_BUF_SIZE | DescOwn;
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (nic_i == lim) /* mark end of ring */
flags |= RingEnd;
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
curr->addr = htole64(paddr);
slot->flags &= ~NS_BUF_CHANGED;
}
curr->opts1 = htole32(flags);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb(); // XXX needed ?
}
/* tell userspace that there might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/*
* Additional routines to init the tx and rx rings.
* In other drivers we do that inline in the main code.
*/
static int
re_netmap_tx_init(struct SOFTC_T *sc)
{
struct netmap_adapter *na = NA(sc->dev);
struct netmap_slot *slot;
struct TxDesc *desc = sc->TxDescArray;
int i, l;
uint64_t paddr;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_TX, 0, 0);
/* slot is NULL if we are not in netmap mode XXX cannot happen */
if (!slot)
return 0;
/* l points in the netmap ring, i points in the NIC ring */
for (i = 0; i < na->num_tx_desc; i++) {
l = netmap_idx_n2k(&na->tx_rings[0], i);
PNMB(slot + l, &paddr);
desc[i].addr = htole64(paddr);
}
return 1;
}
static int
re_netmap_rx_init(struct SOFTC_T *sc)
{
struct netmap_adapter *na = NA(sc->dev);
struct netmap_slot *slot;
struct RxDesc *desc = sc->RxDescArray;
uint32_t cmdstat;
int i, lim, l;
uint64_t paddr;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_RX, 0, 0);
if (!slot)
return 0; /* XXX cannot happen */
/*
* Do not release the slots owned by userspace
* XXX we use all slots, so no '-1' here
* XXX do we need -1 instead ?
*/
lim = na->num_rx_desc /* - 1 */ - nm_kr_rxspace(&na->rx_rings[0]);
for (i = 0; i < na->num_rx_desc; i++) {
l = netmap_idx_n2k(&na->rx_rings[0], i);
PNMB(slot + l, &paddr);
cmdstat = NETMAP_BUF_SIZE;
if (i == na->num_rx_desc - 1)
cmdstat |= RingEnd;
if (i < lim)
cmdstat |= DescOwn;
desc[i].opts1 = htole32(cmdstat);
desc[i].addr = htole64(paddr);
}
return 1;
}
static void
re_netmap_attach(struct SOFTC_T *sc)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = sc->dev;
na.num_tx_desc = NUM_TX_DESC;
na.num_rx_desc = NUM_RX_DESC;
na.nm_txsync = re_netmap_txsync;
na.nm_rxsync = re_netmap_rxsync;
na.nm_register = re_netmap_reg;
na.num_tx_rings = na.num_rx_rings = 1;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,503 @@
/*
* Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $FreeBSD: head/sys/dev/netmap/ixgbe_netmap.h 230572 2012-01-26 09:55:16Z luigi $
*
* netmap support for: ixgbe (LINUX version)
*
* This file is meant to be a reference on how to implement
* netmap support for a network driver.
* This file contains code but only static or inline functions used
* by a single driver. To avoid replication of code we just #include
* it near the beginning of the standard driver.
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T ixgbe_adapter
/*
* Adaptation to different versions of the driver.
* Recent drivers (3.4 and above) redefine some macros
*/
#ifndef IXGBE_TX_DESC_ADV
#define IXGBE_TX_DESC_ADV IXGBE_TX_DESC
#define IXGBE_RX_DESC_ADV IXGBE_RX_DESC
#endif
/*
* Register/unregister. We are already under netmap lock.
* Only called on the first register or the last unregister.
*/
static int
ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *adapter = netdev_priv(ifp);
// adapter->netdev->trans_start = jiffies; // disable watchdog ?
/* protect against other reinit */
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000);
rtnl_lock();
if (netif_running(adapter->netdev))
ixgbe_down(adapter);
/* enable or disable flags and callbacks in na and ifp */
if (onoff) {
nm_set_native_flags(na);
} else {
nm_clear_native_flags(na);
}
/* XXX SRIOV migth need another 2sec wait */
if (netif_running(adapter->netdev))
ixgbe_up(adapter); /* also enables intr */
rtnl_unlock();
clear_bit(__IXGBE_RESETTING, &adapter->state);
return (0);
}
/*
* Reconcile kernel and user view of the transmit ring.
*
* Userspace wants to send packets up to the one before ring->head,
* kernel knows kring->nr_hwcur is the first unsent packet.
*
* Here we push packets out (as many as possible), and possibly
* reclaim buffers from previously completed transmission.
*
* ring->tail is updated on return.
* ring->head is never used here.
*
* The caller (netmap) guarantees that there is only one instance
* running at any time. Any interference with other driver
* methods should be handled by the individual drivers.
*/
static int
ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/*
* interrupts on every tx packet are expensive so request
* them every half ring, or where NS_REPORT is set
*/
u_int report_frequency = kring->nkr_num_slots >> 1;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct ixgbe_ring *txr = adapter->tx_ring[ring_nr];
int reclaim_tx;
/*
* First part: process new packets to send.
* nm_i is the current index in the netmap ring,
* nic_i is the corresponding index in the NIC ring.
* The two numbers differ because upon a *_init() we reset
* the NIC ring but leave the netmap ring unchanged.
* For the transmit ring, we have
*
* nm_i = kring->nr_hwcur
* nic_i = IXGBE_TDT (not tracked in the driver)
* and
* nm_i == (nic_i + kring->nkr_hwofs) % ring_size
*
* In this driver kring->nkr_hwofs >= 0, but for other
* drivers it might be negative as well.
*/
/*
* If we have packets to send (kring->nr_hwcur != ring->cur)
* iterate over the netmap ring, fetch length and update
* the corresponding slot in the NIC ring. Some drivers also
* need to update the buffer's physical address in the NIC slot
* even NS_BUF_CHANGED is not set (PNMB computes the addresses).
*
* The netmap_reload_map() calls is especially expensive,
* even when (as in this case) the tag is 0, so do only
* when the buffer has actually changed.
*
* If possible do not set the report/intr bit on all slots,
* but only a few times per ring or when NS_REPORT is set.
*
* Finally, on 10G and faster drivers, it might be useful
* to prefetch the next slot and txr entry.
*/
if (!netif_carrier_ok(ifp)) {
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
union ixgbe_adv_tx_desc *curr = IXGBE_TX_DESC_ADV(txr, nic_i);
int flags = (slot->flags & NS_REPORT ||
nic_i == 0 || nic_i == report_frequency) ?
IXGBE_TXD_CMD_RS : 0;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Fill the slot in the NIC ring. */
curr->read.buffer_addr = htole64(paddr);
curr->read.olinfo_status = htole32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
curr->read.cmd_type_len = htole32(len | flags |
IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_DEXT |
IXGBE_ADVTXD_DCMD_IFCS | IXGBE_TXD_CMD_EOP);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
wmb(); /* synchronize writes to the NIC ring */
/* (re)start the tx unit up to slot nic_i (excluded) */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(txr->reg_idx), nic_i);
}
/*
* Second part: reclaim buffers for completed transmissions.
* Because this is expensive (we read a NIC register etc.)
* we only do it in specific cases (see below).
*/
if (flags & NAF_FORCE_RECLAIM) {
reclaim_tx = 1; /* forced reclaim */
} else if (!nm_kr_txempty(kring)) {
reclaim_tx = 0; /* have buffers, no reclaim */
} else {
/*
* No buffers available. Locate previous slot with
* REPORT_STATUS set.
* If the slot has DD set, we can reclaim space,
* otherwise wait for the next interrupt.
* This enables interrupt moderation on the tx
* side though it might reduce throughput.
*/
union ixgbe_adv_tx_desc *txd = IXGBE_TX_DESC_ADV(txr, 0);
nic_i = txr->next_to_clean + report_frequency;
if (nic_i > lim)
nic_i -= lim + 1;
// round to the closest with dd set
nic_i = (nic_i < kring->nkr_num_slots / 4 ||
nic_i >= kring->nkr_num_slots*3/4) ?
0 : report_frequency;
reclaim_tx = txd[nic_i].wb.status & IXGBE_TXD_STAT_DD; // XXX cpu_to_le32 ?
}
if (reclaim_tx) {
/*
* Record completed transmissions.
* We (re)use the driver's txr->next_to_clean to keep
* track of the most recently completed transmission.
*
* The datasheet discourages the use of TDH to find
* out the number of sent packets, but we only set
* REPORT STATUS in a few slots so TDH is the only
* good way.
*/
nic_i = IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(ring_nr));
if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
D("TDH wrap %d", nic_i);
nic_i -= kring->nkr_num_slots;
}
txr->next_to_clean = nic_i;
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
}
out:
nm_txsync_finalize(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
* Same as for the txsync, this routine must be efficient.
* The caller guarantees a single invocations, but races against
* the rest of the driver should be handled here.
*
* When called, userspace has released buffers up to ring->head
* (last one excluded).
*
* If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
* of whether or not we received an interrupt.
*/
static int
ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
struct SOFTC_T *adapter = netdev_priv(ifp);
struct ixgbe_ring *rxr = adapter->rx_ring[ring_nr];
if (!netif_carrier_ok(ifp))
return 0;
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
*
* nm_i is the index of the next free slot in the netmap ring,
* nic_i is the index of the next received packet in the NIC ring,
* and they may differ in case if_init() has been called while
* in netmap mode. For the receive ring we have
*
* nm_i = (kring->nr_hwtail)
* nic_i = rxr->next_to_clean; // really next to check
* and
* nm_i == (nic_i + kring->nkr_hwofs) % ring_size
*
* rxr->next_to_clean is set to 0 on a ring reinit
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
nic_i = rxr->next_to_clean;
nm_i = netmap_idx_n2k(kring, nic_i);
for (n = 0; ; n++) {
union ixgbe_adv_rx_desc *curr = IXGBE_RX_DESC_ADV(rxr, nic_i);
uint32_t staterr = le32toh(curr->wb.upper.status_error);
if ((staterr & IXGBE_RXD_STAT_DD) == 0)
break;
ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
ring->slot[nm_i].flags = slot_flags;
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
if (n) { /* update the state variables */
rxr->next_to_clean = nic_i;
kring->nr_hwtail = nm_i;
}
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
* (kring->nr_hwcur to ring->head excluded),
* and make the buffers available for reception.
* As usual nm_i is the index in the netmap ring,
* nic_i is the index in the NIC ring, and
* nm_i == (nic_i + kring->nkr_hwofs) % ring_size
*/
nm_i = kring->nr_hwcur;
if (nm_i != head) {
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
union ixgbe_adv_rx_desc *curr = IXGBE_RX_DESC_ADV(rxr, nic_i);
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
curr->wb.upper.status_error = 0;
curr->read.pkt_addr = htole64(paddr);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
kring->nr_hwcur = head;
rxr->next_to_use = nic_i; // XXX not really used
wmb();
/*
* IMPORTANT: we must leave one free slot in the ring,
* so move nic_i back by one unit
*/
nic_i = nm_prev(nic_i, lim);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(rxr->reg_idx), nic_i);
}
/* tell userspace that there might be new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/*
* if in netmap mode, attach the netmap buffers to the ring and return true.
* Otherwise return false.
*/
static int
ixgbe_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
{
struct netmap_adapter *na = NA(adapter->netdev);
struct netmap_slot *slot;
//int j;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_TX, ring_nr, 0);
if (!slot)
return 0; // not in netmap; XXX cannot happen
#if 0
/*
* on a generic card we should set the address in the slot.
* But on the ixgbe, the address needs to be rewritten
* after a transmission so there is nothing do to except
* loading the map.
*/
for (j = 0; j < na->num_tx_desc; j++) {
int sj = netmap_idx_n2k(&na->tx_rings[ring_nr], j);
uint64_t paddr;
void *addr = PNMB(slot + sj, &paddr);
}
#endif
return 1;
}
static int
ixgbe_netmap_configure_rx_ring(struct SOFTC_T *adapter, int ring_nr)
{
/*
* In netmap mode, we must preserve the buffers made
* available to userspace before the if_init()
* (this is true by default on the TX side, because
* init makes all buffers available to userspace).
*
* netmap_reset() and the device-specific routines
* (e.g. ixgbe_setup_receive_rings()) map these
* buffers at the end of the NIC ring, so here we
* must set the RDT (tail) register to make sure
* they are not overwritten.
*
* In this driver the NIC ring starts at RDH = 0,
* RDT points to the last slot available for reception (?),
* so RDT = num_rx_desc - 1 means the whole ring is available.
*/
struct netmap_adapter *na = NA(adapter->netdev);
struct netmap_slot *slot;
int lim, i;
struct ixgbe_ring *ring = adapter->rx_ring[ring_nr];
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
slot = netmap_reset(na, NR_RX, ring_nr, 0);
/* same as in ixgbe_setup_transmit_ring() */
if (!slot)
return 0; // not in netmap; XXX cannot happen
lim = na->num_rx_desc - 1 - nm_kr_rxspace(&na->rx_rings[ring_nr]);
for (i = 0; i < na->num_rx_desc; i++) {
/*
* Fill the map and set the buffer address in the NIC ring,
* considering the offset between the netmap and NIC rings
* (see comment in ixgbe_setup_transmit_ring() ).
*/
int si = netmap_idx_n2k(&na->rx_rings[ring_nr], i);
uint64_t paddr;
PNMB(slot + si, &paddr);
// netmap_load_map(rxr->ptag, rxbuf->pmap, addr);
/* Update descriptor */
IXGBE_RX_DESC_ADV(ring, i)->read.pkt_addr = htole64(paddr);
}
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(ring_nr), lim);
return 1;
}
/*
* The attach routine, called near the end of ixgbe_attach(),
* fills the parameters for netmap_attach() and calls it.
* It cannot fail, in the worst case (such as no memory)
* netmap mode will be disabled and the driver will only
* operate in standard mode.
*/
static void
ixgbe_netmap_attach(struct SOFTC_T *adapter)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = adapter->netdev;
na.num_tx_desc = adapter->tx_ring[0]->count;
na.num_rx_desc = adapter->rx_ring[0]->count;
na.nm_txsync = ixgbe_netmap_txsync;
na.nm_rxsync = ixgbe_netmap_rxsync;
na.nm_register = ixgbe_netmap_reg;
na.num_tx_rings = adapter->num_tx_queues;
na.num_rx_rings = adapter->num_rx_queues;
netmap_attach(&na);
}
/* end of file */

View File

@ -0,0 +1,736 @@
/*
* Copyright (C) 2012-2014 Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: mlx4_netmap_linux.h $
*
* netmap support for mlx4 (LINUX version)
*
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T mlx4_en_priv
/*
* This driver is split in multiple small files.
* The main device descriptor has type struct mlx4_en_priv *priv;
* and we attach to the device in mlx4_en_init_netdev()
* (do port numbers start from 1 ?)
*
* The reconfig routine is in mlx4_en_start_port() (also here)
* which is called on a mlx4_en_restart() (watchdog), open and set-mtu.
*
* priv->num_frags ??
* DS_SIZE ??
* apparently each rx desc is followed by frag.descriptors
* and the rx desc is rounded up to a power of 2.
*
* Receive code is in en_rx.c
* priv->rx_ring_num number of rx rings
* rxr = prov->rx_ring[ring_ind] rx ring descriptor
* rxr->size number of slots
* rxr->prod producer
* probably written into a mmio reg at *rxr->wqres.db.db
* trimmed to 16 bits.
*
* Rx init routine:
* mlx4_en_activate_rx_rings()
* mlx4_en_init_rx_desc()
* Transmit code is in en_tx.c
*/
int mlx4_netmap_rx_config(struct SOFTC_T *priv, int ring_nr);
int mlx4_netmap_tx_config(struct SOFTC_T *priv, int ring_nr);
int mlx4_tx_desc_dump(struct mlx4_en_tx_desc *tx_desc);
#ifdef NETMAP_MLX4_MAIN
static inline void
nm_pkt_dump(int i, char *buf, int len)
{
uint8_t *s __attribute__((unused)) = buf+6, *d __attribute__((unused)) = buf;
RD(10, "%d len %4d %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x",
i,
len,
s[0], s[1], s[2], s[3], s[4], s[5],
d[0], d[1], d[2], d[3], d[4], d[5]);
}
/* show the content of the descriptor. Only the first block is printed
* to make sure we do not fail on wraparounds (otherwise we would need
* base, index and ring size).
*/
int
mlx4_tx_desc_dump(struct mlx4_en_tx_desc *tx_desc)
{
struct mlx4_wqe_ctrl_seg *ctrl = &tx_desc->ctrl;
uint32_t *p = (uint32_t *)tx_desc;
int i, l = ctrl->fence_size;
RD(5,"------- txdesc %p size 0x%x", tx_desc, ctrl->fence_size);
if (l > 4)
l = 4;
for (i = 0; i < l; i++) {
RD(20, "[%2d]: 0x%08x 0x%08x 0x%08x 0x%08x", i,
ntohl(p[0]), ntohl(p[1]), ntohl(p[2]), ntohl(p[3]));
p += 4;
}
return 0;
}
/*
* Register/unregister. We are already under (netmap) core lock.
* Only called on the first register or the last unregister.
*/
static int
mlx4_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *priv = netdev_priv(ifp);
int error = 0, need_load = 0;
struct mlx4_en_dev *mdev = priv->mdev;
/*
* On enable, flush pending ops, set flag and reinit rings.
* On disable, flush again, and restart the interface.
*/
D("setting netmap mode for %s to %s", ifp->if_xname, onoff ? "ON" : "OFF");
// rtnl_lock(); // ???
if (netif_running(ifp)) {
D("unloading %s", ifp->if_xname);
//double_mutex_state_lock(mdev);
mutex_lock(&mdev->state_lock);
if (onoff == 0) {
int i;
/* coming from netmap mode, clean up the ring pointers
* so we do not crash in mlx4_en_free_tx_buf()
* XXX should STAMP the txdesc value to pretend the hw got there
* 0x7fffffff plus the bit set to
* !!(ring->cons & ring->size)
*/
for (i = 0; i < na->num_tx_rings; i++) {
struct mlx4_en_tx_ring *txr = &priv->tx_ring[i];
ND("txr %d : cons %d prod %d txbb %d", i, txr->cons, txr->prod, txr->last_nr_txbb);
txr->cons += txr->last_nr_txbb; // XXX should be 1
for (;txr->cons != txr->prod; txr->cons++) {
uint16_t j = txr->cons & txr->size_mask;
uint32_t new_val, *ptr = (uint32_t *)(txr->buf + j * TXBB_SIZE);
new_val = cpu_to_be32(STAMP_VAL | (!!(txr->cons & txr->size) << STAMP_SHIFT));
ND(10, "old 0x%08x new 0x%08x", *ptr, new_val);
*ptr = new_val;
}
}
}
mlx4_en_stop_port(ifp);
need_load = 1;
}
retry:
if (onoff) { /* enable netmap mode */
nm_set_native_flags(na);
} else { /* reset normal mode */
nm_clear_native_flags(na);
}
if (need_load) {
D("loading %s", ifp->if_xname);
error = mlx4_en_start_port(ifp);
D("start_port returns %d", error);
if (error && onoff) {
onoff = 0;
goto retry;
}
mutex_unlock(&mdev->state_lock);
//double_mutex_state_unlock(mdev);
}
// rtnl_unlock();
return (error);
}
/*
* Reconcile kernel and user view of the transmit ring.
* This routine might be called frequently so it must be efficient.
*
OUTGOING (txr->prod)
Tx packets need to fill a 64-byte block with one control block and
one descriptor (both 16-byte). Probably we need to fill the other
two data entries in the block with NULL entries as done in rx_config().
One can request completion reports (intr) on all entries or only
on selected ones. The std. driver reports every 16 packets.
txr->prod points to the first available slot to send.
COMPLETION (txr->cons)
TX events are reported through a Completion Queue (CQ) whose entries
can be 32 or 64 bytes. In case of 64 bytes, the interesting part is
at odd indexes. The "factor" variable does the addressing.
txr->cons points to the last completed block (XXX note so it is 1 behind)
There is no link back from the txring to the completion
queue so we need to track it ourselves. HOWEVER mlx4_en_alloc_resources()
uses the same index for cq and ring so tx_cq and tx_ring correspond,
same for rx_cq and rx_ring.
*/
static int
mlx4_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags)
{
struct ifnet *ifp = na->ifp;
struct netmap_kring *kring = &na->tx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/*
* interrupts on every tx packet are expensive so request
* them every half ring, or where NS_REPORT is set
*/
u_int report_frequency = kring->nkr_num_slots >> 1;
struct SOFTC_T *priv = netdev_priv(ifp);
int error = 0;
if (!netif_carrier_ok(ifp)) {
goto out;
}
// XXX debugging, only print if sending something
n = (txr->prod - txr->cons - 1) & 0xffffff; // should be modulo 2^24 ?
if (n >= txr->size) {
RD(5, "XXXXXXXXXXX txr %d overflow: cons %u prod %u size %d delta %d",
ring_nr, txr->cons, txr->prod, txr->size, n);
}
/*
* First part: process new packets to send.
*/
nm_i = kring->nr_hwcur;
// XXX debugging, assuming lim is 2^x-1
n = 0; // XXX debugging
if (nm_i != head) { /* we have new packets to send */
ND(5,"START: txr %u cons %u prod %u hwcur %u head %u tail %d send %d",
ring_nr, txr->cons, txr->prod, kring->nr_hwcur, ring->head, kring->nr_hwtail,
(head - nm_i) & lim);
// XXX see en_tx.c :: mlx4_en_xmit()
/*
* In netmap the descriptor has one control segment
* and one data segment. The control segment is 16 bytes,
* the data segment is another 16 bytes mlx4_wqe_data_seg.
* The alignment is TXBB_SIZE (64 bytes) though, so we are
* forced to use 64 bytes each.
*/
ND(10,"=======>========== send from %d to %d at bd %d", j, k, txr->prod);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
/* device-specific */
uint32_t l = txr->prod & txr->size_mask;
struct mlx4_en_tx_desc *tx_desc = txr->buf + l * TXBB_SIZE;
struct mlx4_wqe_ctrl_seg *ctrl = &tx_desc->ctrl;
NM_CHECK_ADDR_LEN(addr, len);
if (slot->flags & NS_BUF_CHANGED) {
/* buffer has changed, unload and reload map */
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
}
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/*
* Fill the slot in the NIC ring.
*/
ctrl->vlan_tag = 0; // not used
ctrl->ins_vlan = 0; // NO
ctrl->fence_size = 2; // used descriptor size in 16byte blocks
// request notification. XXX later report only if NS_REPORT or not too often.
ctrl->srcrb_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE |
MLX4_WQE_CTRL_SOLICITED);
// XXX do we need to copy the mac dst address ?
if (1) { // XXX do we need this ?
uint64_t mac = mlx4_en_mac_to_u64(addr);
uint32_t mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16);
uint32_t mac_l = (u32) (mac & 0xffffffff);
ctrl->srcrb_flags |= cpu_to_be32(mac_h);
ctrl->imm = cpu_to_be32(mac_l);
}
tx_desc->data.addr = cpu_to_be64(paddr);
tx_desc->data.lkey = cpu_to_be32(priv->mdev->mr.key);
wmb(); // XXX why here ?
tx_desc->data.byte_count = cpu_to_be32(len); // XXX crc corrupt ?
wmb();
ctrl->owner_opcode = cpu_to_be32(
MLX4_OPCODE_SEND |
((txr->prod & txr->size) ? MLX4_EN_BIT_DESC_OWN : 0) );
txr->prod++;
nm_i = nm_next(nm_i, lim);
}
kring->nr_hwcur = head;
/* XXX Check how to deal with nkr_hwofs */
/* these two are always in sync. */
wmb(); /* synchronize writes to the NIC ring */
/* (re)start the transmitter up to slot l (excluded) */
ND(5, "doorbell cid %d data 0x%x", txdata->cid, txdata->tx_db.raw);
// XXX is this doorbell correct ?
iowrite32be(txr->doorbell_qpn, txr->bf.uar->map + MLX4_SEND_DOORBELL);
}
// XXX debugging, only print if sent something
if (n)
ND(5, "SENT: txr %d cons %u prod %u hwcur %u cur %u tail %d sent %d",
ring_nr, txr->cons, txr->prod, kring->nr_hwcur, ring->cur, kring->nr_hwtail, n);
/*
* Second part: reclaim buffers for completed transmissions.
*/
{
struct mlx4_en_cq *cq = &priv->tx_cq[ring_nr];
struct mlx4_cq *mcq = &cq->mcq;
int size = cq->size; // number of entries
struct mlx4_cqe *buf = cq->buf; // base of cq entries
uint32_t size_mask = txr->size_mask; // same in txq and cq ?.......
uint16_t new_index, ring_index;
int factor = priv->cqe_factor; // 1 for 64 bytes, 0 for 32 bytes
/*
* Reclaim buffers for completed transmissions. The CQE tells us
* where the consumer (NIC) is. Bit 7 of the owner_sr_opcode
* is the ownership bit. It toggles up and down so the
* non-bitwise XNOR trick lets us detect toggles as the ring
* wraps around. On even rounds, the second operand is 0 so
* we exit when the MLX4_CQE_OWNER_MASK bit is 1, viceversa
* on odd rounds.
*/
new_index = ring_index = txr->cons & size_mask;
for (n = 0; n < 2*lim; n++) {
uint16_t index = mcq->cons_index & size_mask;
struct mlx4_cqe *cqe = &buf[(index << factor) + factor];
if (!XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
mcq->cons_index & size))
break;
/*
* make sure we read the CQE after we read the
* ownership bit
*/
rmb();
/* Skip over last polled CQE */
new_index = be16_to_cpu(cqe->wqe_index) & size_mask;
ND(5, "txq %d new_index %d", ring_nr, new_index);
mcq->cons_index++;
}
if (n > lim) {
D("XXXXXXXXXXX too many notifications %d", n);
}
/* now we have updated cons-index, notify the card. */
/* XXX can we make it conditional ? */
wmb();
mlx4_cq_set_ci(mcq);
// XXX the following enables interrupts... */
// mlx4_en_arm_cq(priv, cq); // XXX always ?
wmb();
/* XXX unsigned arithmetic below */
n = (new_index - ring_index) & size_mask;
if (n) {
ND(5, "txr %d completed %d packets", ring_nr, n);
txr->cons += n;
/* XXX watch out, index is probably modulo */
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, (new_index & size_mask)), lim);
}
if (nm_kr_txempty(kring)) {
mlx4_en_arm_cq(priv, cq);
}
}
out:
nm_txsync_finalize(kring);
return 0;
err:
if (error)
return netmap_ring_reinit(kring);
return 0;
}
/*
* Reconcile kernel and user view of the receive ring.
MELLANOX:
the ring has prod and cons indexes, the size is a power of 2,
size and actual_size indicate how many entries can be allocated,
stride is the size of each entry.
mlx4_en_update_rx_prod_db() tells the NIC where it can go
(to be used when new buffers are freed).
*/
static int
mlx4_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags)
{
struct ifnet *ifp = na->ifp;
struct netmap_kring *kring = &na->rx_rings[ring_nr];
struct netmap_ring *ring = kring->ring;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
struct SOFTC_T *priv = netdev_priv(ifp);
struct mlx4_en_rx_ring *rxr = &priv->rx_ring[ring_nr];
if (!priv->port_up) // XXX as in mlx4_en_process_rx_cq()
return 0;
if (!netif_carrier_ok(ifp)) // XXX maybe above is redundant ?
return 0;
if (head > lim)
return netmap_ring_reinit(kring);
ND(5, "START rxr %d cons %d prod %d kcur %d ktail %d cur %d tail %d",
ring_nr, rxr->cons, rxr->prod, kring->nr_hwcur, kring->nr_hwtail, ring->cur, ring->tail);
/*
* First part, import newly received packets.
*/
/* scan the completion queue to see what is going on.
* The mapping is 1:1. The hardware toggles the OWNER bit in the
* descriptor at mcq->cons_index & size_mask, which is mapped 1:1
* to an entry in the RXR.
* XXX there are two notifications sent to the hw:
* mlx4_cq_set_ci(struct mlx4_cq *cq);
* *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff);
* mlx4_en_update_rx_prod_db(rxr);
* *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
* apparently they point to the same memory word
* (see mlx4_en_activate_cq() ) and are initialized to 0
* DB is the doorbell page (sec.15.1.2 ?)
* wqres is set in mlx4_alloc_hwq_res()
* and in turn mlx4_alloc_hwq_res()
*/
if (1 || netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
struct mlx4_en_cq *cq = &priv->rx_cq[ring_nr];
struct mlx4_cq *mcq = &cq->mcq;
int factor = priv->cqe_factor;
uint32_t size_mask = rxr->size_mask;
int size = cq->size;
struct mlx4_cqe *buf = cq->buf;
nm_i = kring->nr_hwtail;
/* Process all completed CQEs, use same logic as in TX */
for (n = 0; n <= 2*lim ; n++) {
int index = mcq->cons_index & size_mask;
struct mlx4_cqe *cqe = &buf[(index << factor) + factor];
prefetch(cqe+1);
if (!XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, mcq->cons_index & size))
break;
rmb(); /* make sure data is up to date */
ring->slot[nm_i].len = be32_to_cpu(cqe->byte_cnt) - rxr->fcs_del;
ring->slot[nm_i].flags = slot_flags;
mcq->cons_index++;
nm_i = nm_next(nm_i, lim);
}
if (n) { /* update the state variables */
if (n >= 2*lim)
D("XXXXXXXXXXXXX too many received packets %d", n);
ND(5, "received %d packets", n);
kring->nr_hwtail = nm_i;
rxr->cons += n;
ND(5, "RECVD %d rxr %d cons %d prod %d kcur %d ktail %d cur %d tail %d",
n,
ring_nr, rxr->cons, rxr->prod, kring->nr_hwcur, kring->nr_hwtail, ring->cur, ring->tail);
/* XXX ack completion queue */
mlx4_cq_set_ci(mcq);
}
kring->nr_kflags &= ~NKR_PENDINTR;
}
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur; /* netmap ring index */
if (nm_i != head) { /* userspace has released some packets. */
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
/* collect per-slot info, with similar validations
struct netmap_slot *slot = &ring->slot[nm_i];
uint64_t paddr;
void *addr = PNMB(slot, &paddr);
struct mlx4_en_rx_desc *rx_desc = rxr->buf + (nic_i * rxr->stride);
if (addr == netmap_buffer_base) /* bad buf */
goto ring_reset;
if (slot->flags & NS_BUF_CHANGED) {
// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
slot->flags &= ~NS_BUF_CHANGED;
}
/* XXX
* The rx descriptor only contains buffer descriptors,
* probably only the length is changed or not even that one.
*/
// see mlx4_en_prepare_rx_desc() and mlx4_en_alloc_frag()
rx_desc->data[0].addr = cpu_to_be64(paddr);
rx_desc->data[0].byte_count = cpu_to_be32(NETMAP_BUF_SIZE);
rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key);
#if 0
int jj, possible_frags;
/* we only use one fragment, so the rest is padding */
possible_frags = (rxr->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE;
for (jj = 1; jj < possible_frags; jj++) {
rx_desc->data[jj].byte_count = 0;
rx_desc->data[jj].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD);
rx_desc->data[jj].addr = 0;
}
#endif
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
/* XXX note that mcq->cons_index and ring->cons are not in sync */
wmb();
rxr->prod += n;
kring->nr_hwcur = head;
/* and now tell the system that there are more buffers available.
* should use mlx4_en_update_rx_prod_db(rxr) but it is static in
* en_rx.c so we do not see it here
*/
*rxr->wqres.db.db = cpu_to_be32(rxr->prod & 0xffff);
ND(5, "FREED rxr %d cons %d prod %d kcur %d ktail %d",
ring_nr, rxr->cons, rxr->prod,
kring->nr_hwcur, kring->nr_hwtail);
}
/* tell userspace that there are new packets */
nm_rxsync_finalize(kring);
return 0;
ring_reset:
return netmap_ring_reinit(kring);
}
/*
* If in netmap mode, attach the netmap buffers to the ring and return true.
* Otherwise return false.
* Called at the end of mlx4_en_start_port().
* XXX TODO: still incomplete.
*/
int
mlx4_netmap_tx_config(struct SOFTC_T *priv, int ring_nr)
{
struct netmap_adapter *na = NA(priv->dev);
struct netmap_slot *slot;
struct mlx4_en_cq *cq;
ND(5, "priv %p ring_nr %d", priv, ring_nr);
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
/*
CONFIGURE TX RINGS IN NETMAP MODE
little if anything to do
The main code does
mlx4_en_activate_cq()
mlx4_en_activate_tx_ring()
<Set initial ownership of all Tx TXBBs to SW (1)>
*/
slot = netmap_reset(na, NR_TX, ring_nr, 0);
if (!slot)
return 0; // not in netmap mode;
ND(5, "init tx ring %d with %d slots (driver %d)", ring_nr,
na->num_tx_desc,
priv->tx_ring[ring_nr].size);
/* enable interrupts on the netmap queues */
cq = &priv->tx_cq[ring_nr]; // derive from the txring
return 1;
}
int
mlx4_netmap_rx_config(struct SOFTC_T *priv, int ring_nr)
{
struct netmap_adapter *na = NA(priv->dev);
struct netmap_slot *slot;
struct mlx4_en_rx_ring *rxr;
struct netmap_kring *kring;
int i, j, possible_frags;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
/*
* on the receive ring, must set buf addresses into the slots.
The ring is activated by mlx4_en_activate_rx_rings(), near the end
the rx ring is also 'started' with mlx4_en_update_rx_prod_db()
so we patch into that routine.
*/
slot = netmap_reset(na, NR_RX, ring_nr, 0);
if (!slot) // XXX should not happen
return 0;
kring = &na->rx_rings[ring_nr];
rxr = &priv->rx_ring[ring_nr];
ND(20, "ring %d slots %d (driver says %d) frags %d stride %d", ring_nr,
kring->nkr_num_slots, rxr->actual_size, priv->num_frags, rxr->stride);
rxr->prod--; // XXX avoid wraparounds ?
if (kring->nkr_num_slots != rxr->actual_size) {
D("mismatch between slots and actual size, %d vs %d",
kring->nkr_num_slots, rxr->actual_size);
return 1; // XXX error
}
possible_frags = (rxr->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE;
RD(1, "stride %d possible frags %d descsize %d DS_SIZE %d", rxr->stride, possible_frags, (int)sizeof(struct mlx4_en_rx_desc), (int)DS_SIZE );
/* then fill the slots with our entries */
for (i = 0; i < kring->nkr_num_slots; i++) {
uint64_t paddr;
struct mlx4_en_rx_desc *rx_desc = rxr->buf + (i * rxr->stride);
PNMB(slot + i, &paddr);
// see mlx4_en_prepare_rx_desc() and mlx4_en_alloc_frag()
rx_desc->data[0].addr = cpu_to_be64(paddr);
rx_desc->data[0].byte_count = cpu_to_be32(NETMAP_BUF_SIZE);
rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key);
/* we only use one fragment, so the rest is padding */
for (j = 1; j < possible_frags; j++) {
rx_desc->data[j].byte_count = 0;
rx_desc->data[j].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD);
rx_desc->data[j].addr = 0;
}
}
RD(5, "ring %d done", ring_nr);
return 1;
}
static int
mlx4_netmap_config(struct netmap_adapter *na,
u_int *txr, u_int *txd, u_int *rxr, u_int *rxd)
{
struct net_device *ifp = na->ifp;
struct SOFTC_T *priv = netdev_priv(ifp);
*txr = priv->tx_ring_num;
*txd = priv->tx_ring[0].size;
*rxr = priv->rx_ring_num;
if (*txr > *rxr) {
D("using only %d out of %d tx queues", *rxr, *txr);
*txr = *rxr;
}
*rxd = priv->rx_ring[0].size;
D("txr %d txd %d bufsize %d -- rxr %d rxd %d act %d bufsize %d",
*txr, *txd, priv->tx_ring[0].buf_size,
*rxr, *rxd, priv->rx_ring[0].actual_size,
priv->rx_ring[0].buf_size);
return 0;
}
/*
* The attach routine, called near the end of mlx4_en_init_netdev(),
* fills the parameters for netmap_attach() and calls it.
* It cannot fail, in the worst case (such as no memory)
* netmap mode will be disabled and the driver will only
* operate in standard mode.
*
* XXX TODO:
* at the moment use a single lock, and only init a max of 4 queues.
*/
static void
mlx4_netmap_attach(struct SOFTC_T *priv)
{
struct netmap_adapter na;
struct net_device *dev = priv->dev;
int rxq, txq;
bzero(&na, sizeof(na));
na.ifp = dev;
rxq = priv->rx_ring_num;
txq = priv->tx_ring_num;
/* this card has 1k tx queues, so better limit the number */
if (rxq > 16)
rxq = 16;
if (txq > rxq)
txq = rxq;
if (txq < 1 && rxq < 1)
txq = rxq = 1;
na.num_tx_rings = txq;
na.num_rx_rings = rxq;
na.num_tx_desc = priv->tx_ring[0].size;
na.num_rx_desc = priv->rx_ring[0].size;
na.nm_txsync = mlx4_netmap_txsync;
na.nm_rxsync = mlx4_netmap_rxsync;
na.nm_register = mlx4_netmap_reg;
na.nm_config = mlx4_netmap_config;
netmap_attach(&na);
}
#endif /* NETMAP_MLX4_MAIN */
/* end of file */

1257
netmap/LINUX/netmap_linux.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
#!/bin/sh
#set -x # for debugging
if [ -z "$NMSRC" ]; then
NMSRC=~/netmap-release
fi
DRIVER="ixgbe"
#IF="eth0" # force an interface
if [ ! -f ${NMSRC}/LINUX/netmap_lin.ko ]; then
echo "LINUX/netmap_lin.ko missing. Please compile netmap."
exit 1
fi
if [ ! -f ${NMSRC}/LINUX/${DRIVER}/${DRIVER}.ko ]; then
echo "LINUX/${DRIVER}/${DRIVER}.ko missing."
echo "Please compile netmap or make sure to have netmap support for ${DRIVER}"
exit 1
fi
NMLOADED=$(lsmod | grep netmap_lin | wc -l)
DRVLOADED=$(lsmod | grep "${DRIVER}" | wc -l)
# Unload the driver
if [ $DRVLOADED != "0" ]; then
sudo rmmod "$DRIVER"
fi
# Load netmap
if [ $NMLOADED == "0" ]; then
sudo insmod ${NMSRC}/LINUX/netmap_lin.ko
fi
if [ "$1" == "g" ]; then
# In order to use generic netmap adapter, load the original driver module, that doesn't
# have netmap support
sudo modprobe ${DRIVER}
echo "Generic netmap adapter."
else
# Use the driver modified with netmap support
sudo insmod ${NMSRC}/LINUX/${DRIVER}/${DRIVER}.ko
echo "Native netmap adapter."
fi
# Wait a bit for interface name changing
sleep 2
# Find all interfaces
IFLIST=$(ip link | grep -o "^[0-9]\+: [^:]\+" | awk '{print $2}')
IFLIST=$(echo ${IFLIST})
# Find the interface that match the driver $DRIVER
for i in $IFLIST; do
drv=$(sudo ethtool -i $i 2> /dev/null | grep "driver" | awk '{print $2}')
if [ "$drv" == "$DRIVER" ]; then
IF=$i
echo " Found interface \"${IF}\""
fi
done
if [ "$IF" == "" ]; then
echo "No interface using ${DRIVER} driver was found."
exit 1
fi
sudo ip link set ${IF} up

1
netmap/LINUX/patches Symbolic link
View File

@ -0,0 +1 @@
final-patches

3
netmap/LINUX/scripts/help Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
sed -n 's/^## \?//p' $1 | fmt

View File

@ -0,0 +1,82 @@
#!/bin/sh
#set -x
function pgset()
{
local result
echo $1 > ${PGDEV}
result=$(cat $PGDEV | fgrep "Result: OK:")
if [ "$result" = "" ]; then
cat $PGDEV | fgrep "Result:"
fi
}
##################### Script configuration ######################
N="$1" # number of TX kthreads minus one
if [ -z "$1" ]; then
N=0
fi
NCPUS="7" # number of CPUs on your machine minus one
IF="enp1s0f1" # network interface to test
DST_IP="10.216.8.1" # destination IP address
DST_MAC="00:1b:21:80:e7:d9" # destination MAC address
PKT_SIZE="60" # packet size
PKT_COUNT="10000000" # number of packets to send
CLONE_SKB="10000" # how many times a sk_buff is recycled
# Load pktgen kernel module
modprobe pktgen
# Clean the configuration for all the CPU-kthread (from 0 to ${NCPUS})
IDX=$(seq 0 1 ${NCPUS})
for cpu in ${IDX}; do
PGDEV="/proc/net/pktgen/kpktgend_${cpu}"
echo "Removing all devices (${cpu})"
pgset "rem_device_all"
done
IDX=$(seq 0 1 ${N})
for cpu in ${IDX}; do
# kthread-device configuration
PGDEV="/proc/net/pktgen/kpktgend_${cpu}"
echo "Configuring $PGDEV"
echo "Adding ${IF}@${cpu}"
pgset "add_device ${IF}@${cpu}"
# Packets/mode configuration
PGDEV="/proc/net/pktgen/${IF}@${cpu}"
echo "Configuring $PGDEV"
pgset "count ${PKT_COUNT}"
pgset "clone_skb ${CLONE_SKB}"
pgset "pkt_size ${PKT_SIZE}"
pgset "delay 0"
pgset "dst $DST_IP"
pgset "dst_mac $DST_MAC"
pgset "flag QUEUE_MAP_CPU"
echo ""
done
# Run
PGDEV="/proc/net/pktgen/pgctrl"
echo "Running... Ctrl-C to stop"
pgset "start"
echo "Done."
# Show results
NUMS=""
for cpu in ${IDX}; do
TMP=$(cat /proc/net/pktgen/${IF}@${cpu} | grep -o "[0-9]\+pps" | grep -o "[0-9]\+")
echo "$cpu $TMP"
NUMS="${NUMS} ${TMP}"
done
echo "Total TX rate: $(echo $NUMS | tr ' ' '+' | bc)"

428
netmap/LINUX/scripts/np Executable file
View File

@ -0,0 +1,428 @@
#!/bin/bash
## Manage linux driver patches for netmap.
## usage (from the dir containing the Makefile):
##
## scripts/np <action> [args...]
##
## where <action> is any of the functions below.
##
[ -f scripts/conf ] && source scripts/conf
## The following enviroment variables must be set:
##
## GITDIR: the absolute path of the netmap linux
## git repository, containing all the required netmap-*
## branches.
[ -n "$GITDIR" -a -d "$GITDIR/.git" ] || {
echo "GITDIR not set or not valid" >&2
exit 1
}
NETMAP_BRANCH=${NETMAP_BRANCH:-master}
function error {
echo "$@" >&2
exit 1
}
function get-params {
local params=$1; shift
err_msg="$PROGNAME $COMMAND $(echo $params| perl -pe 's/\S+/<$&>/g')"
local param
for param in $params; do
[[ -z "$@" ]] && error "$err_msg"
pname=$(echo -n $param | perl -pe 's/\W/_/g')
eval $pname="$1"
shift
done
[[ -n "$@" ]] && error "$err_msg"
}
##
## LINUX_SOURCES: the absolute path of a
## directory used to store all required linux-* source trees
## (The script will extract linux-x.y.z from GITDIR if it needs
## it and $LINUX_SOURCES does not already contain it).
##
## LINUX_CONFIGS: the absolute path of a
## directory containing the configuration files for
## the linux kernel. The file for version x must be named
## config-x. config-all can be used as a default.
##
## The configuration variables can be put in scripts/conf.
##
##
## Available actions:
##
##
## driver-path <driver> <version>
## retrieves the path of <driver> in the linux sources
## for version <version>. The path is output to stdout.
## It uses a local cache to minimize the expensive
## file system search.
function driver-path()
{
get-params "driver version" "$@"
cat cache/$version/$driver/path 2>/dev/null && return
local kern=$(get-kernel $version)
mkdir -p cache/$version/$driver
(
cd $kern
find drivers/net -name $driver
) | tee cache/$version/$driver/path
}
##
## get-patch [-c] <driver> <version>
## extract the netmap patch for the given <driver> and the
## given kernel <version>. The patch is stored in tmp-patches
## and the name of the patch is output to stdout.
## If a patch with the same name already exists in tmp-patches
## it is overwritten, unless the -c option is used,
## in which case the existing patch is kept (the patch name is still output).
function get-patch()
{
local use_cache
[ "$1" = -c ] && { use_cache=1; shift; }
get-params "driver version" "$@"
# convert kernel version to fixed notation
local v1=$(scripts/vers $version -c)
# compute next kernel version (in fixed notation)
local v2=$(scripts/vers $version -i -c)
local patchname=diff--$driver--$v1--$v2
local out=tmp-patches/$patchname
[ -n "$use_cache" -a -s $out ] && { echo $out; return; }
local drvpath=$(driver-path $driver $version)
[ -n "$drvpath" ] || return
local drvdir=$(dirname $drvpath)
(
cd $GITDIR
git diff --relative=$drvdir v$version..netmap-$version -- $drvpath
) > $out
# an empty patch means no netmap support for this driver
[ -s $out ] || { rm $out; return 1; }
echo $out
return 0;
}
##
## get-range <driver> <version1> <version2>
## extracts the netmap patches for the given <driver> for
## all the kernel versions from <version1> (included) to
## <version2> (excluded). All patches are stored in tmp-patches
## and their names are output to stdout.
function get-range()
{
get-params "driver version1 version2" "$@"
local v=$version1
# while version is less than $version2
while scripts/vers -b $v $version2 -L; do
get-patch $driver $v
# compute next version
v=$(scripts/vers $v -i)
done
}
##
## get-src <driver> <version> <dest>
## copies the original sources of the given <driver>,
## from the given kernel <version> to the given <dest>
## directory.
## It uses a local cache to minimize the expensive
## checkouts in GITDIR.
function get-src()
{
get-params "driver version dest" "$@"
local kern=$(get-kernel $version)
local src=$(driver-path $driver $version)
cp -r $kern/$src $dest
}
##
## extend <patch> <version>
## checks wether the range of applicability of the
## given <patch> can be extented to include <version>.
## It returns 0 on success and 1 on failure.
function extend()
{
get-params "patch version" "$@"
local _patch=$(realpath $patch)
# extract the driver name from the patch name
local driver=$(scripts/vers $_patch -s -p -p)
local tmpdir1=$(mktemp -d)
local tmpdir2=$(mktemp -d)
trap "rm -rf $tmpdir1 $tmpdir2" 0
# we get the driver sources for the given <version> and
# we apply two patches separately:
# i) the given <patch>;
# ii) the proper patch from GITDIR.
# We declare <patch> to be extendable if
# - it is still applicable AND
# - we obtain the same files from i) and ii) (ignoring whitespace)
get-src $driver $version $tmpdir1
get-src $driver $version $tmpdir2
(
cd $tmpdir1
patch --no-backup-if-mismatch -p1 < $_patch >/dev/null 2>&1
) || return 1
local patch2=$(get-patch -c $driver $version)
patch2=$(realpath $patch2)
(
cd $tmpdir2
patch -p1 < $patch2 >/dev/null 2>&1
) # this will certainly apply
diff -qbBr $tmpdir1 $tmpdir2 >/dev/null || return 1
return 0
}
##
## minimize <driver>
## tries to minimize the number of patch files for the given
## <driver>. It uses the patches currently found in tmp-patches
## and stores the resulting patches in final-patches.
## If final-patches already contained patches for <driver>,
## they are deleted first.
function minimize()
{
get-params "driver" "$@"
mkdir -p final-patches
local drv=$(basename $driver)
local patches=$(ls tmp-patches/diff--$drv--* 2>/dev/null)
[ -n "$patches" ] || return 1
# put the patch names in $1, $2, ...
set $patches
rm -f final-patches/diff--$drv--*
# the original patches (in tmp-patches) are ordered by version number.
# We consider one patch in turn (the 'pivot') and try
# to extend its range to cover the range of the next
# patch. If this succedes, the merged patch is the new
# pivot, otherwise the current pivot is output and the
# next patch becomes the new pivot. The process
# is repeated until there are no more patches to consider.
local pivot=$1
[ -n "$pivot" -a -e "$pivot" ] || return 1
# extract the left end and right end of the pivot's range
local ple=$(scripts/vers $pivot -s -p -C)
local pre=$(scripts/vers $pivot -s -C)
while [ -n "$pivot" ]; do
shift
if [ -n "$1" ]; then
# extract the left end and right end of the next patch
local nle=$(scripts/vers $1 -s -p -C)
local nre=$(scripts/vers $1 -s -C)
# we admit no gaps in the range
if [ $pre = $nle ] && extend $pivot $nle; then
pre=$nre
continue
fi
fi
# either out of patches or failed merge.
# Compute the file name of the current pivot and store
# the patch in its final location
out=$(scripts/vers diff $drv $ple -c $pre -c -S4)
cp $pivot final-patches/$out
# the new pivot becames the next patch (if any)
pivot=$1
pre=$nre
ple=$nle
done
return 0
}
##
## infty <driver> <version>
## if final-patches contains a patch for <driver> with a range
## ending in <version>, extend it to infinity.
## Do nothing otherwise.
function infty()
{
get-params "driver version" "$@"
local drv=$(basename $driver)
# convert kernel version to fixed notation
local v=$(scripts/vers $version -c)
local last=$(ls final-patches/diff--$drv--*--$v 2>/dev/null|tail -n1)
[ -n "$last" ] || return 1
mv -n $last $(scripts/vers $last -s -p 99999 -S4) 2>/dev/null
}
function get-kernel()
{
get-params "version" "$@"
local dst="$(realpath $LINUX_SOURCES)/linux-$version"
[ -d $dst ] && { echo $dst; return; }
mkdir -p $dst
(
cd $GITDIR
git archive v$v | tar xf - -C $dst
)
echo $dst
}
##
## build-prep <version>
## prepare the linux tree for <version> to be ready
## for external modules compilation.
## The tree is put in $LINUX_SOURCES/linux-<version> and the
## configuration is obtained from $LINUX_CONFIGS/config-<version>
## (or $LINUX_CONFIGS/config-all by default).
## Errors are logged to $LINUX_CONFIGS/linux-<version>.log.
## If $LINUX_SOURCES/linux-<version> already exists,
## nothing is done.
## In all cases, the absolute path of linux-<version> is
## output.
function build-prep()
{
get-params "version" "$@"
local dst=$(get-kernel $version)
exec 3>&1 4>&2 >$dst.log 2>&1
cp $LINUX_CONFIGS/config-$v $dst/.config 2>/dev/null ||
cp $LINUX_CONFIGS/config-all $dst/.config
(
cd $dst
yes '' | make oldconfig
make modules_prepare
)
exec 1>&3 2>&4
echo $dst
}
##
## check-patch <patch>
## check that the given <patch> applies and compiles without
## error for all its declared range of applicability.
## Errors are logged to log/<patch>.
function check-patch()
{
get-params "patch" "$@"
# extract the left version
local v1=$(scripts/vers $patch -s -p -C)
# extract the right version
local v2=$(scripts/vers $patch -s -C)
# extract the driver name
local driver=$(scripts/vers $patch -s -p -p)
local p=$(realpath $patch)
mkdir -p log
local log="$(realpath log)/$(basename $patch)"
local nmcommit=$(cd ..; git show-ref -s heads/$NETMAP_BRANCH)
echo -n $patch...
while scripts/vers -b $v1 $v2 -L; do
# cache lookup
local cache=cache/$v1/$driver
local cpatch=$cache/patch
local cnmcommit=$cache/nmcommit
local cstatus=$cache/status
local clog=$cache/log
if [ -f $cpatch ] &&
cmp -s $cpatch $patch &&
[ "$nmcommit" = "$(cat $cnmcommit)" ]; then
cp $clog $log
ok=$(cat $cstatus)
else
# update cache
cp $patch $cpatch
echo $nmcommit > $cnmcommit
local ksrc=$(build-prep $v1)
local tmpdir=$(mktemp -d)
trap "rm -rf $tmpdir" 0
(cd ..; git archive $NETMAP_BRANCH | tar xf - -C $tmpdir )
pushd $tmpdir/LINUX >/dev/null
mkdir single-patch
rm patches
ln -s single-patch patches
cp $p single-patch
ok=false
make KSRC=$ksrc >$log 2>&1 && ok=true
popd >/dev/null
cp $log $clog
fi
[ $ok = true ] || { echo FAILED; echo false > $cstatus; return 1; }
echo true > $cstatus
rm -rf $tmpdir
# compute next version
v1=$(scripts/vers $v1 -i)
done
echo OK
}
##
## build-check <driver>
## do a check-patch for all the patches of <driver> that are
## currently in tmp-patches. Patches that fail the check
## are moved to failed-patches.
function build-check()
{
get-params "driver" "$@"
mkdir -p failed-patches
local drv=$(basename $driver)
local patches=$(ls tmp-patches/diff--$drv--* 2>/dev/null)
local p
for p in $patches; do
check-patch $p || mv $p failed-patches
done
}
##
## forall <cmd> [args...]
## exec <cmd> <driver> [args...] for all known drivers.
function forall()
{
local cmd=$1
shift
# we obtain the value of DRIVER_SRC from the makefile
# (the +% target is defined in our Makefile and prints
# the contents of variable %)
local driver_srcs=$(make +DRIVER_SRCS)
local driver
for driver in $driver_srcs; do
$cmd $(basename $driver) "$@"
done
}
mkdir -p tmp-patches
PROGNAME=$0
[ -n "$1" ] || {
scripts/help $PROGNAME;
exit 1
}
COMMAND=$1; shift
case $COMMAND in
*-all)
forall ${COMMAND%-all} "$@"
;;
-[hH]|--help|-help|help)
scripts/help $PROGNAME
;;
*)
$COMMAND "$@"
;;
esac

162
netmap/LINUX/scripts/vers Executable file
View File

@ -0,0 +1,162 @@
#!/usr/bin/perl
## Simple stack-based RPN calculator for linux version numbers.
## Usage:
##
## scripts/vers [operand|operation ...]
##
## Operations all start with '-', everything else is an operand
## and is pushed on the stack as-is.
## When all arguments have been processed, the content of the
## top of the stack is printed on stdout and the script ends.
##
## Available operations:
sub badversion
{
my $v = shift;
die "Bad version $v";
}
sub conv
{
my $v = shift;
return sprintf "%x%02x%02x", (split /\./, $v);
}
sub rconv
{
my $v = shift;
$v =~ /(.*)(..)(..)$/;
if ($1 > 2 && (hex $3) == 0) {
return sprintf "%d.%d", (hex $1), (hex $2);
}
return sprintf "%d.%d.%d", (hex $1), (hex $2), (hex $3);
}
sub next
{
my $v = shift;
my ($may, $min, $sub) = split /\./, $v;
if ($may < 2 || ($may == 2 && $min != 6)) {
&badversion($v);
}
if ($may == 2) {
if ($sub < 39) {
return "2.6." . ($sub + 1);
} elsif ($sub == 39) {
return "3.0";
} else {
&badversion($v);
}
} else {
return "$may." . ($min + 1);
}
}
@ARGV or do { system("scripts/help $0"); exit 1; };
for (@ARGV) {
##
## -b (nullary) suppress normal output. On exit, return 1
## if stack top is "false", 0 otherwise.
/^-b$/ && do {
$silent=1;
next;
};
##
## -c (unary) convert from dot to fixed notation
/^-c$/ && do {
$v = pop @stack;
push @stack, &conv($v);
next;
};
##
## -C (unary) convert from fixed to dot notation
/^-C$/ && do {
$v = pop @stack;
push @stack, &rconv($v);
next;
};
##
## -i (unary) increment version number
## (must be in dot notation)
/^-i$/ && do {
$v = pop @stack;
push @stack, &next($v);
next;
};
##
## -s (unary) assume the stack top is a
## string containing several fields separated
## by '--'. Replace the stack top with these
## fields (last on top)
/^-s$/ && do {
$v = pop @stack;
push @stack, split /--/, $v;
next;
};
##
## -SN (N-ary) pop N elements from the stack,
## join them using '--' as a separator
## (top as last) and push the resulting
## string
/^-S(\d+)$/ && do {
$n = $1;
@t = @stack[-$n..-1];
while ($n--) {
pop @stack;
}
push @stack, (join '--', @t);
next;
};
##
## -p (unary) pop
/^-p$/ && do {
pop @stack;
next;
};
##
## -l (binary) push "true" if first version
## number is stricly less then second version
## number (versions in fixed notation)
##
## -L (binary) like -l, but for version numbers
## in dot notation
/^-[lL]$/ && do {
$v1 = pop @stack;
$v2 = pop @stack;
/^-L$/ && do {
$v1 = &conv($v1);
$v2 = &conv($v2);
};
push @stack, (($v2 lt $v1) ? "true" : "false");
next;
};
##
## -a (binary) logical and. Arguments must be
## either "true" or "false".
/^-a$/ && do {
$v1 = pop @stack;
$v2 = pop @stack;
push @stack, (($v1 eq "true" && $v2 eq "true") ? "true" : "false");
next;
};
##
## -n (unary) logical not. Argument must be
## either "true" or "false".
/^-n$/ && do {
$v1 = pop @stack;
push @stack, (($v1 eq "true") ? "false" : "true");
next;
};
push @stack, $_;
}
$v = pop @stack;
if ($silent) {
exit ($v eq "false");
}
print "$v\n";

View File

@ -0,0 +1,538 @@
/*
* Copyright (C) 2014 Vincenzo Maffione. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <bsd_glue.h>
#include <net/netmap.h>
#include <netmap/netmap_kern.h>
#define SOFTC_T virtnet_info
static int virtnet_close(struct ifnet *ifp);
static int virtnet_open(struct ifnet *ifp);
static void free_receive_bufs(struct virtnet_info *vi);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
/* Before 2.6.35 there was no net_device.num_rx_queues, so we assume 1. */
#define DEV_NUM_RX_QUEUES(_netdev) 1
/* A scatterlist struct is needed by functions that invoke
virtqueue_add_buf() methods, but before 2.6.35 these struct were
not part of virtio-net data structures, but were defined in those
function. This macro does this definition, which is not necessary
for subsequent versions. */
#define COMPAT_DECL_SG struct scatterlist _compat_sg;
#else /* >= 2.6.35 */
#define DEV_NUM_RX_QUEUES(_netdev) (_netdev)->num_rx_queues
#define COMPAT_DECL_SG
#endif /* >= 2.6.35 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
/* Before 2.6.35, the virtio interface was not exported with functions,
but using virtqueue callbacks. */
#define virtqueue_detach_unused_buf(_vq) \
(_vq)->vq_ops->detach_unused_buf(_vq)
#define virtqueue_get_buf(_vq, _lp) \
(_vq)->vq_ops->get_buf(_vq, _lp)
#define virtqueue_add_inbuf(_vq, _sg, _num, _tok, _gfp) \
(_vq)->vq_ops->add_buf(_vq, _sg, 0, _num, _tok)
#define virtqueue_add_outbuf(_vq, _sg, _num, _tok, _gfp) \
(_vq)->vq_ops->add_buf(_vq, _sg, _num, 0, _tok)
#define virtqueue_kick(_vq) \
(_vq)->vq_ops->kick(_vq)
#define virtqueue_enable_cb(_vq) \
(_vq)->vq_ops->enable_cb(_vq)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
/* Some simple renaming due to virtio interface changes. */
#define virtqueue_add_inbuf(_vq, _sg, _num, _tok, _gfp) \
virtqueue_add_buf_gfp(_vq, _sg, 0, _num, _tok, _gfp)
#define virtqueue_add_outbuf(_vq, _sg, _num, _tok, _gfp) \
virtqueue_add_buf_gfp(_vq, _sg, _num, 0, _tok, _gfp)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
/* Some simple renaming due to virtio interface changes. */
#define virtqueue_add_inbuf(_vq, _sg, _num, _tok, _gfp) \
virtqueue_add_buf(_vq, _sg, 0, _num, _tok, _gfp)
#define virtqueue_add_outbuf(_vq, _sg, _num, _tok, _gfp) \
virtqueue_add_buf(_vq, _sg, _num, 0, _tok, _gfp)
#endif /* 3.3 <= VER < 3.10.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
/* The delayed optimization did not exists before version 3.0. */
#define virtqueue_enable_cb_delayed(_vq) virtqueue_enable_cb(_vq)
#endif /* < 3.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
/* Not yet found a way to find out virtqueue length in these
kernel series. Use the virtio default value. */
#define virtqueue_get_vring_size(_vq) 256
#endif /* < 3.2 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
/* Before 3.8.0 virtio did not have multiple queues, and therefore
it did not have per-queue data structures. We then abstract the
way data structure are accessed, ignoring the queue indexes. */
#define DECR_NUM(_vi, _i) --(_vi)->num
#define GET_RX_VQ(_vi, _i) (_vi)->rvq
#define GET_TX_VQ(_vi, _i) (_vi)->svq
#define VQ_FULL(_vq, _err) (_err > 0)
static void give_pages(struct SOFTC_T *vi, struct page *page);
static struct page *get_a_page(struct SOFTC_T *vi, gfp_t gfp_mask);
#define GIVE_PAGES(_vi, _i, _buf) give_pages(_vi, _buf)
/* This function did not exists, there was just the code. */
static void free_receive_bufs(struct SOFTC_T *vi)
{
while (vi->pages)
__free_pages(get_a_page(vi, GFP_KERNEL), 0);
}
#else /* >= 3.8.0 */
static void give_pages(struct receive_queue *rq, struct page *page);
#define GIVE_PAGES(_vi, _i, _buf) give_pages(&(_vi)->rq[_i], _buf)
#define DECR_NUM(_vi, _i) --(_vi)->rq[_i].num
#define GET_RX_VQ(_vi, _i) (_vi)->rq[_i].vq
#define GET_TX_VQ(_vi, _i) (_vi)->sq[_i].vq
#define VQ_FULL(_vq, _err) ((_vq)->num_free == 0)
#endif /* >= 3.8.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
/* Use the scatterlist struct defined in the current function
(see above). */
#define GET_RX_SG(_vi, _i) &_compat_sg
#define GET_TX_SG(_vi, _i) &_compat_sg
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
/* Also here we create an abstraction because of multiqueue support
(see above). */
#define GET_RX_SG(_vi, _i) (_vi)->rx_sg
#define GET_TX_SG(_vi, _i) (_vi)->tx_sg
#else /* >= 3.8.0 */
#define GET_RX_SG(_vi, _i) (_vi)->rq[_i].sg
#define GET_TX_SG(_vi, _i) (_vi)->sq[_i].sg
#endif /* >= 3.8.0 */
/* Free all the unused buffer in all the RX virtqueues.
* This function is called when entering and exiting netmap mode.
* In the former case, the unused buffers point to memory allocated by
* the virtio-driver (e.g. sk_buffs). We need to free that
* memory, otherwise we have leakage.
* In the latter case, the unused buffers point to memory allocated by
* netmap, and so we don't need to free anything.
* We scan all the RX virtqueues, even those that have not been
* activated (by 'ethtool --set-channels eth0 combined $N').
*/
static void virtio_netmap_free_rx_unused_bufs(struct SOFTC_T* vi, int onoff)
{
void *buf;
int i, c;
for (i = 0; i < DEV_NUM_RX_QUEUES(vi->dev); i++) {
struct virtqueue *vq = GET_RX_VQ(vi, i);
c = 0;
while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
if (onoff) {
if (vi->mergeable_rx_bufs || vi->big_packets)
GIVE_PAGES(vi, i, buf);
else
dev_kfree_skb(buf);
}
DECR_NUM(vi, i);
c++;
}
D("[%d] freed %d rx unused bufs on queue %d", onoff, c, i);
}
}
/* Register and unregister. */
static int
virtio_netmap_reg(struct netmap_adapter *na, int onoff)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *vi = netdev_priv(ifp);
struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter*)na;
int error = 0;
if (na == NULL)
return EINVAL;
/* It's important to deny the registration if the interface is
not up, otherwise the virtnet_close() is not matched by a
virtnet_open(), and so a napi_disable() is not matched by
a napi_enable(), which results in a deadlock. */
if (!netif_running(ifp))
return EBUSY;
rtnl_lock();
/* Down the interface. This also disables napi. */
virtnet_close(ifp);
if (onoff) {
/* We have to drain the RX virtqueues, otherwise the
* virtio_netmap_init_buffer() called by the subsequent
* virtnet_open() cannot link the netmap buffers to the
* virtio RX ring. */
virtio_netmap_free_rx_unused_bufs(vi, onoff);
/* Also free the pages allocated by the driver. */
free_receive_bufs(vi);
/* enable netmap mode */
ifp->if_capenable |= IFCAP_NETMAP;
na->na_flags |= NAF_NATIVE_ON;
na->if_transmit = (void *)ifp->netdev_ops;
ifp->netdev_ops = &hwna->nm_ndo;
} else {
ifp->if_capenable &= ~IFCAP_NETMAP;
na->na_flags &= ~NAF_NATIVE_ON;
ifp->netdev_ops = (void *)na->if_transmit;
/* Drain the RX virtqueues, otherwise the driver will
* interpret the netmap buffers currently linked to the
* netmap ring as buffers allocated by the driver. This
* would break the driver (and kernel panic/ooops). */
virtio_netmap_free_rx_unused_bufs(vi, onoff);
}
/* Up the interface. This also enables the napi. */
virtnet_open(ifp);
rtnl_unlock();
return (error);
}
/* Reconcile kernel and user view of the transmit ring. */
static int
virtio_netmap_txsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = kring->rhead;
/* device-specific */
COMPAT_DECL_SG
struct SOFTC_T *vi = netdev_priv(ifp);
struct virtqueue *vq = GET_TX_VQ(vi, ring_nr);
struct scatterlist *sg = GET_TX_SG(vi, ring_nr);
struct netmap_adapter *token;
// XXX invert the order
/* Free used slots. We only consider our own used buffers, recognized
* by the token we passed to virtqueue_add_outbuf.
*/
n = 0;
for (;;) {
token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
if (token == NULL)
break;
if (likely(token == na))
n++;
}
kring->nr_hwtail += n;
if (kring->nr_hwtail > lim)
kring->nr_hwtail -= lim + 1;
/*
* First part: process new packets to send.
*/
rmb();
if (!netif_carrier_ok(ifp)) {
/* All the new slots are now unavailable. */
goto out;
}
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
nic_i = netmap_idx_k2n(kring, nm_i);
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
u_int len = slot->len;
void *addr = NMB(slot);
int err;
NM_CHECK_ADDR_LEN(addr, len);
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
/* Initialize the scatterlist, expose it to the hypervisor,
* and kick the hypervisor (if necessary).
*/
sg_set_buf(sg, addr, len);
err = virtqueue_add_outbuf(vq, sg, 1, na, GFP_ATOMIC);
if (err < 0) {
D("virtqueue_add_outbuf failed");
break;
}
virtqueue_kick(vq);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
/* Update hwcur depending on where we stopped. */
kring->nr_hwcur = nm_i; /* note we migth break early */
/* No more free TX slots? Ask the hypervisor for notifications,
* possibly only when a considerable amount of work has been
* done.
*/
if (nm_kr_txempty(kring))
virtqueue_enable_cb_delayed(vq);
}
out:
nm_txsync_finalize(kring);
return 0;
}
/* Reconcile kernel and user view of the receive ring. */
static int
virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
{
struct netmap_adapter *na = kring->na;
struct ifnet *ifp = na->ifp;
struct netmap_ring *ring = kring->ring;
u_int ring_nr = kring->ring_id;
u_int nm_i; /* index into the netmap ring */
// u_int nic_i; /* index into the NIC ring */
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
u_int const head = nm_rxsync_prologue(kring);
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
/* device-specific */
COMPAT_DECL_SG
struct SOFTC_T *vi = netdev_priv(ifp);
struct virtqueue *vq = GET_RX_VQ(vi, ring_nr);
struct scatterlist *sg = GET_RX_SG(vi, ring_nr);
/* XXX netif_carrier_ok ? */
if (head > lim)
return netmap_ring_reinit(kring);
rmb();
/*
* First part: import newly received packets.
* Only accept our
* own buffers (matching the token). We should only get
* matching buffers, because of virtio_netmap_free_rx_unused_bufs()
* and virtio_netmap_init_buffers().
*/
if (netmap_no_pendintr || force_update) {
uint16_t slot_flags = kring->nkr_slot_flags;
struct netmap_adapter *token;
nm_i = kring->nr_hwtail;
n = 0;
for (;;) {
int len;
token = virtqueue_get_buf(vq, &len);
if (token == NULL)
break;
if (likely(token == na)) {
ring->slot[nm_i].len = len;
ring->slot[nm_i].flags = slot_flags;
nm_i = nm_next(nm_i, lim);
n++;
} else {
D("This should not happen");
}
}
kring->nr_hwtail = nm_i;
kring->nr_kflags &= ~NKR_PENDINTR;
}
ND("[B] h %d c %d hwcur %d hwtail %d",
ring->head, ring->cur, kring->nr_hwcur,
kring->nr_hwtail);
/*
* Second part: skip past packets that userspace has released.
*/
nm_i = kring->nr_hwcur; /* netmap ring index */
if (nm_i != head) {
for (n = 0; nm_i != head; n++) {
struct netmap_slot *slot = &ring->slot[nm_i];
void *addr = NMB(slot);
int err;
if (addr == netmap_buffer_base) /* bad buf */
return netmap_ring_reinit(kring);
slot->flags &= ~NS_BUF_CHANGED;
/* Initialize the scatterlist, expose it to the hypervisor,
* and kick the hypervisor (if necessary).
*/
sg_set_buf(sg, addr, ring->nr_buf_size);
err = virtqueue_add_inbuf(vq, sg, 1, na, GFP_ATOMIC);
if (err < 0) {
D("virtqueue_add_inbuf failed");
return err;
}
virtqueue_kick(vq);
nm_i = nm_next(nm_i, lim);
}
kring->nr_hwcur = head;
}
/* We have finished processing used RX buffers, so we have to tell
* the hypervisor to make a call when more used RX buffers will be
* ready.
*/
virtqueue_enable_cb(vq);
/* tell userspace that there might be new packets. */
nm_rxsync_finalize(kring);
ND("[C] h %d c %d t %d hwcur %d hwtail %d",
ring->head, ring->cur, ring->tail,
kring->nr_hwcur, kring->nr_hwtail);
return 0;
}
/* Make RX virtqueues buffers pointing to netmap buffers. */
static int virtio_netmap_init_buffers(struct SOFTC_T *vi)
{
struct ifnet *ifp = vi->dev;
struct netmap_adapter* na = NA(ifp);
unsigned int r;
if (!na || !(na->na_flags & NAF_NATIVE_ON)) {
return 0;
}
for (r = 0; r < na->num_rx_rings; r++) {
COMPAT_DECL_SG
struct netmap_ring *ring = na->rx_rings[r].ring;
struct virtqueue *vq = GET_RX_VQ(vi, r);
struct scatterlist *sg = GET_RX_SG(vi, r);
struct netmap_slot* slot;
unsigned int i;
int err = 0;
slot = netmap_reset(na, NR_RX, r, 0);
if (!slot) {
D("strange, null netmap ring %d", r);
return 0;
}
/* Add up to na>-num_rx_desc-1 buffers to this RX virtqueue.
* It's important to leave one virtqueue slot free, otherwise
* we can run into ring->cur/ring->tail wraparounds.
*/
for (i = 0; i < na->num_rx_desc-1; i++) {
void *addr;
slot = &ring->slot[i];
addr = NMB(slot);
sg_set_buf(sg, addr, ring->nr_buf_size);
err = virtqueue_add_inbuf(vq, sg, 1, na, GFP_ATOMIC);
if (err < 0) {
D("virtqueue_add_inbuf failed");
return 0;
}
if (VQ_FULL(vq, err))
break;
}
D("added %d inbufs on queue %d", i, r);
virtqueue_kick(vq);
}
return 1;
}
/* Update the virtio-net device configurations. Number of queues can
* change dinamically, by 'ethtool --set-channels $IFNAME combined $N'.
* This is actually the only way virtio-net can currently enable
* the multiqueue mode.
*/
static int
virtio_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
u_int *rxr, u_int *rxd)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *vi = netdev_priv(ifp);
*txr = ifp->real_num_tx_queues;
*txd = virtqueue_get_vring_size(GET_TX_VQ(vi, 0));
*rxr = 1;
*rxd = virtqueue_get_vring_size(GET_RX_VQ(vi, 0));
D("virtio config txq=%d, txd=%d rxq=%d, rxd=%d",
*txr, *txd, *rxr, *rxd);
return 0;
}
static void
virtio_netmap_attach(struct SOFTC_T *vi)
{
struct netmap_adapter na;
bzero(&na, sizeof(na));
na.ifp = vi->dev;
na.num_tx_desc = virtqueue_get_vring_size(GET_TX_VQ(vi, 0));
na.num_rx_desc = virtqueue_get_vring_size(GET_RX_VQ(vi, 0));
na.nm_register = virtio_netmap_reg;
na.nm_txsync = virtio_netmap_txsync;
na.nm_rxsync = virtio_netmap_rxsync;
na.nm_config = virtio_netmap_config;
na.num_tx_rings = na.num_rx_rings = 1;
netmap_attach(&na);
D("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d",
na.num_tx_rings, na.num_tx_desc,
na.num_tx_rings, na.num_rx_desc);
}
/* end of file */

View File

@ -0,0 +1,145 @@
diff -urp --exclude '*.o' --exclude '*.cmd' --exclude '*mod.c' drivers/net/ethernet/mellanox/mlx4/en_netdev.c ./mellanox/mlx4/en_netdev.c
--- drivers/net/ethernet/mellanox/mlx4/en_netdev.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mellanox/mlx4/en_netdev.c 2012-09-27 00:05:22.703523430 -0700
@@ -48,6 +48,39 @@
#include "mlx4_en.h"
#include "en_port.h"
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * This driver is split in multiple small files.
+ * The main device descriptor has type struct mlx4_en_priv *priv;
+ * and we attach to the device in mlx4_en_init_netdev()
+ * (do port numbers start from 1 ?)
+ *
+ * The reconfig routine is in mlx4_en_start_port() (also here)
+ * which is called on a mlx4_en_restart() (watchdog), open and set-mtu.
+ *
+ * priv->num_frags ??
+ * DS_SIZE ??
+ * apparently each rx desc is followed by frag.descriptors
+ * and the rx desc is rounded up to a power of 2.
+ *
+ * Receive code is in en_rx.c
+ * priv->rx_ring_num number of rx rings
+ * rxr = prov->rx_ring[ring_ind] rx ring descriptor
+ * rxr->size number of slots
+ * rxr->prod producer
+ * probably written into a mmio reg at *rxr->wqres.db.db
+ * trimmed to 16 bits.
+ *
+ * Rx init routine:
+ * mlx4_en_activate_rx_rings()
+ * mlx4_en_init_rx_desc()
+ * Transmit code is in en_tx.c
+ */
+
+#define NETMAP_MLX4_MAIN
+#include <mlx4_netmap_linux.h> /* extern stuff */
+#endif /* CONFIG_NETMAP */
+
int mlx4_en_setup_tc(struct net_device *dev, u8 up)
{
if (up != MLX4_EN_NUM_UP)
@@ -1042,6 +1075,9 @@ int mlx4_en_start_port(struct net_device
/* Set initial ownership of all Tx TXBBs to SW (1) */
for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE)
*((u32 *) (tx_ring->buf + j)) = 0xffffffff;
+#ifdef DEV_NETMAP
+ mlx4_netmap_tx_config(priv, i);
+#endif /* DEV_NETMAP */
++tx_index;
}
@@ -1639,6 +1675,9 @@ int mlx4_en_init_netdev(struct mlx4_en_d
en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+#ifdef DEV_NETMAP
+ mlx4_netmap_attach(priv);
+#endif /* DEV_NETMAP */
return 0;
out:
--- drivers/net/ethernet/mellanox/mlx4/en_rx.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mellanox/mlx4/en_rx.c 2012-09-27 00:13:16.099550954 -0700
@@ -41,6 +41,9 @@
#include "mlx4_en.h"
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <mlx4_netmap_linux.h>
+#endif /* !DEV_NETMAP */
static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
@@ -365,9 +368,16 @@ int mlx4_en_activate_rx_rings(struct mlx
ring = &priv->rx_ring[ring_ind];
ring->size_mask = ring->actual_size - 1;
+#ifdef DEV_NETMAP
+ if (priv->dev->if_capenable & IFCAP_NETMAP) {
+ int saved_cons = ring->cons;
+ mlx4_en_free_rx_buf(priv, ring);
+ ring->cons = saved_cons;
+ mlx4_netmap_rx_config(priv, ring_ind);
+ }
+#endif /* DEV_NETMAP */
mlx4_en_update_rx_prod_db(ring);
}
-
return 0;
err_buffers:
@@ -402,6 +412,11 @@ void mlx4_en_destroy_rx_ring(struct mlx4
void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring)
{
+#ifdef DEV_NETMAP
+ if (priv->dev->if_capenable & IFCAP_NETMAP)
+ ND("netmap mode, rx buf already freed");
+ else
+#endif /* DEV_NETMAP */
mlx4_en_free_rx_buf(priv, ring);
if (ring->stride <= TXBB_SIZE)
ring->buf -= TXBB_SIZE;
@@ -718,6 +739,11 @@ int mlx4_en_poll_rx_cq(struct napi_struc
struct mlx4_en_priv *priv = netdev_priv(dev);
int done;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(cq->dev, cq->ring, &done)) {
+ ND("rx_irq %d for netmap, budget %d done %d", cq->ring, budget, done);
+ } else
+#endif /* DEV_NETMAP */
done = mlx4_en_process_rx_cq(dev, cq, budget);
/* If we used up all the quota - we're probably not done yet... */
--- drivers/net/ethernet/mellanox/mlx4/en_tx.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mellanox/mlx4/en_tx.c 2012-09-27 00:05:22.713523348 -0700
@@ -55,6 +55,10 @@ MODULE_PARM_DESC(inline_thold, "threshol
static u32 hashrnd __read_mostly;
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <mlx4_netmap_linux.h> /* extern stuff */
+#endif /* CONFIG_NETMAP */
+
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring, u32 size,
u16 stride)
@@ -396,6 +400,13 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq)
if (!spin_trylock(&ring->comp_lock))
return;
+#ifdef DEV_NETMAP
+ /* XXX should be integrated with appropriate lock_wrapper manner? */
+ if (netmap_tx_irq(cq->dev, cq->ring)) {
+ ND(5, "wakeup queue %d", cq->ring);
+ spin_unlock(&ring->comp_lock);
+ return;
+ }
+#endif /* DEV_NETMAP */
mlx4_en_process_tx_cq(cq->dev, cq);
mod_timer(&cq->timer, jiffies + 1);
spin_unlock(&ring->comp_lock);

View File

@ -0,0 +1,163 @@
diff -urp --exclude '*.o' --exclude '*.cmd' --exclude '*mod.c' drivers/net/ethernet/mellanox/mlx4/en_netdev.c ./mellanox/mlx4/en_netdev.c
--- drivers/net/ethernet/mellanox/mlx4/en_netdev.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mlx4/en_netdev.c 2012-09-27 00:05:22.703523430 -0700
@@ -48,6 +48,39 @@
#include "mlx4_en.h"
#include "en_port.h"
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * This driver is split in multiple small files.
+ * The main device descriptor has type struct mlx4_en_priv *priv;
+ * and we attach to the device in mlx4_en_init_netdev()
+ * (do port numbers start from 1 ?)
+ *
+ * The reconfig routine is in mlx4_en_start_port() (also here)
+ * which is called on a mlx4_en_restart() (watchdog), open and set-mtu.
+ *
+ * priv->num_frags ??
+ * DS_SIZE ??
+ * apparently each rx desc is followed by frag.descriptors
+ * and the rx desc is rounded up to a power of 2.
+ *
+ * Receive code is in en_rx.c
+ * priv->rx_ring_num number of rx rings
+ * rxr = prov->rx_ring[ring_ind] rx ring descriptor
+ * rxr->size number of slots
+ * rxr->prod producer
+ * probably written into a mmio reg at *rxr->wqres.db.db
+ * trimmed to 16 bits.
+ *
+ * Rx init routine:
+ * mlx4_en_activate_rx_rings()
+ * mlx4_en_init_rx_desc()
+ * Transmit code is in en_tx.c
+ */
+
+#define NETMAP_MLX4_MAIN
+#include <mlx4_netmap_linux.h> /* extern stuff */
+#endif /* CONFIG_NETMAP */
+
int mlx4_en_setup_tc(struct net_device *dev, u8 up)
{
if (up != MLX4_EN_NUM_UP)
@@ -1042,6 +1075,9 @@ int mlx4_en_start_port(struct net_device
/* Set initial ownership of all Tx TXBBs to SW (1) */
for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE)
*((u32 *) (tx_ring->buf + j)) = 0xffffffff;
+#ifdef DEV_NETMAP
+ mlx4_netmap_tx_config(priv, i);
+#endif /* DEV_NETMAP */
++tx_index;
}
@@ -1639,6 +1675,9 @@ int mlx4_en_init_netdev(struct mlx4_en_d
en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+#ifdef DEV_NETMAP
+ mlx4_netmap_attach(priv);
+#endif /* DEV_NETMAP */
return 0;
out:
--- drivers/net/ethernet/mellanox/mlx4/en_rx.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mlx4/en_rx.c 2012-09-27 00:13:16.099550954 -0700
@@ -41,6 +41,9 @@
#include "mlx4_en.h"
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <mlx4_netmap_linux.h>
+#endif /* !DEV_NETMAP */
static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
struct mlx4_en_rx_desc *rx_desc,
@@ -365,9 +368,16 @@ int mlx4_en_activate_rx_rings(struct mlx
ring = &priv->rx_ring[ring_ind];
ring->size_mask = ring->actual_size - 1;
+#ifdef DEV_NETMAP
+ if (priv->dev->if_capenable & IFCAP_NETMAP) {
+ int saved_cons = ring->cons;
+ mlx4_en_free_rx_buf(priv, ring);
+ ring->cons = saved_cons;
+ mlx4_netmap_rx_config(priv, ring_ind);
+ }
+#endif /* DEV_NETMAP */
mlx4_en_update_rx_prod_db(ring);
}
-
return 0;
err_buffers:
@@ -402,6 +412,11 @@ void mlx4_en_destroy_rx_ring(struct mlx4
void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring)
{
+#ifdef DEV_NETMAP
+ if (priv->dev->if_capenable & IFCAP_NETMAP)
+ ND("netmap mode, rx buf already freed");
+ else
+#endif /* DEV_NETMAP */
mlx4_en_free_rx_buf(priv, ring);
if (ring->stride <= TXBB_SIZE)
ring->buf -= TXBB_SIZE;
@@ -692,6 +707,12 @@ out:
wmb(); /* ensure HW sees CQ consumer before we post new buffers */
ring->cons = mcq->cons_index;
ring->prod += polled; /* Polled descriptors were realocated in place */
+
+ ND(5, "set_ci %d 0x%p val %d prod_db 0x%p val %d",
+ cq->ring,
+ mcq->set_ci_db, mcq->cons_index & 0xffffff,
+ ring->wqres.db.db, ring->prod & 0xffff);
+
mlx4_en_update_rx_prod_db(ring);
ring->csum_ok += csum_ok;
ring->csum_none += csum_none;
@@ -718,6 +739,13 @@ int mlx4_en_poll_rx_cq(struct napi_struc
struct mlx4_en_priv *priv = netdev_priv(dev);
int done;
+#ifdef DEV_NETMAP
+ static int cnt = 0;
+ ND(5,"XXXXXX-------XXXXXXXXXXX-------- poll-rx-cq %d count %d", (int)cq->ring, cnt++);
+ if (netmap_rx_irq(cq->dev, cq->ring, &done)) {
+ ND("rx_irq %d for netmap, budget %d done %d", cq->ring, budget, done);
+ } else
+#endif /* DEV_NETMAP */
done = mlx4_en_process_rx_cq(dev, cq, budget);
/* If we used up all the quota - we're probably not done yet... */
--- drivers/net/ethernet/mellanox/mlx4/en_tx.c 2012-09-11 20:50:55.982624673 -0700
+++ ./mlx4/en_tx.c 2012-09-27 00:05:22.713523348 -0700
@@ -55,6 +55,10 @@ MODULE_PARM_DESC(inline_thold, "threshol
static u32 hashrnd __read_mostly;
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+#include <mlx4_netmap_linux.h> /* extern stuff */
+#endif /* CONFIG_NETMAP */
+
int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring, u32 size,
u16 stride)
@@ -396,6 +400,17 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq)
if (!spin_trylock(&ring->comp_lock))
return;
+#ifdef DEV_NETMAP // XXX unlock and return should be in the 'if' branch
+ static int cnt = 0;
+ ND(5,"XXXXXX-------XXXXXXXXXXX-------- tx-irq %d count %d", (int)cq->ring, cnt++);
+ if (netmap_tx_irq(cq->dev, cq->ring)) {
+ ND(5, "wakeup queue %d", cq->ring);
+ } else {
+ RD(5, "XXXXXXXXX tx_irq %d unexpected, ignoring", cq->ring);
+ }
+ spin_unlock(&ring->comp_lock);
+ return;
+#endif /* DEV_NETMAP */
mlx4_en_process_tx_cq(cq->dev, cq);
mod_timer(&cq->timer, jiffies + 1);
spin_unlock(&ring->comp_lock);