DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] kni: remove unused ethtool files
From: Ferruh Yigit @ 2016-09-30 10:10 UTC (permalink / raw)
  To: dev; +Cc: Ferruh Yigit

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 lib/librte_eal/linuxapp/kni/Makefile               |    2 -
 lib/librte_eal/linuxapp/kni/ethtool/igb/igb_ptp.c  |  944 -------------
 lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat.c  | 1482 --------------------
 .../linuxapp/kni/ethtool/igb/kcompat_ethtool.c     | 1171 ----------------
 .../linuxapp/kni/ethtool/ixgbe/ixgbe_sriov.h       |   73 -
 5 files changed, 3672 deletions(-)
 delete mode 100644 lib/librte_eal/linuxapp/kni/ethtool/igb/igb_ptp.c
 delete mode 100644 lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat.c
 delete mode 100644 lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat_ethtool.c
 delete mode 100644 lib/librte_eal/linuxapp/kni/ethtool/ixgbe/ixgbe_sriov.h

diff --git a/lib/librte_eal/linuxapp/kni/Makefile b/lib/librte_eal/linuxapp/kni/Makefile
index 8cc6b61..35861b9 100644
--- a/lib/librte_eal/linuxapp/kni/Makefile
+++ b/lib/librte_eal/linuxapp/kni/Makefile
@@ -82,8 +82,6 @@ SRCS-y += ethtool/igb/igb_debugfs.c
 SRCS-y += ethtool/igb/igb_param.c
 SRCS-y += ethtool/igb/igb_procfs.c
 SRCS-y += ethtool/igb/igb_vmdq.c
-#SRCS-y += ethtool/igb/igb_ptp.c
-#SRCS-y += ethtool/igb/kcompat.c
 
 SRCS-y += kni_misc.c
 SRCS-y += kni_net.c
diff --git a/lib/librte_eal/linuxapp/kni/ethtool/igb/igb_ptp.c b/lib/librte_eal/linuxapp/kni/ethtool/igb/igb_ptp.c
deleted file mode 100644
index 910e399..0000000
--- a/lib/librte_eal/linuxapp/kni/ethtool/igb/igb_ptp.c
+++ /dev/null
@@ -1,944 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "LICENSE.GPL".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/******************************************************************************
- Copyright(c) 2011 Richard Cochran <richardcochran@gmail.com> for some of the
- 82576 and 82580 code
-******************************************************************************/
-
-#include "igb.h"
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/ptp_classify.h>
-
-#define INCVALUE_MASK		0x7fffffff
-#define ISGN			0x80000000
-
-/*
- * The 82580 timesync updates the system timer every 8ns by 8ns,
- * and this update value cannot be reprogrammed.
- *
- * Neither the 82576 nor the 82580 offer registers wide enough to hold
- * nanoseconds time values for very long. For the 82580, SYSTIM always
- * counts nanoseconds, but the upper 24 bits are not available. The
- * frequency is adjusted by changing the 32 bit fractional nanoseconds
- * register, TIMINCA.
- *
- * For the 82576, the SYSTIM register time unit is affect by the
- * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this
- * field are needed to provide the nominal 16 nanosecond period,
- * leaving 19 bits for fractional nanoseconds.
- *
- * We scale the NIC clock cycle by a large factor so that relatively
- * small clock corrections can be added or subtracted at each clock
- * tick. The drawbacks of a large factor are a) that the clock
- * register overflows more quickly (not such a big deal) and b) that
- * the increment per tick has to fit into 24 bits.  As a result we
- * need to use a shift of 19 so we can fit a value of 16 into the
- * TIMINCA register.
- *
- *
- *             SYSTIMH            SYSTIML
- *        +--------------+   +---+---+------+
- *  82576 |      32      |   | 8 | 5 |  19  |
- *        +--------------+   +---+---+------+
- *         \________ 45 bits _______/  fract
- *
- *        +----------+---+   +--------------+
- *  82580 |    24    | 8 |   |      32      |
- *        +----------+---+   +--------------+
- *          reserved  \______ 40 bits _____/
- *
- *
- * The 45 bit 82576 SYSTIM overflows every
- *   2^45 * 10^-9 / 3600 = 9.77 hours.
- *
- * The 40 bit 82580 SYSTIM overflows every
- *   2^40 * 10^-9 /  60  = 18.3 minutes.
- */
-
-#define IGB_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 9)
-#define IGB_PTP_TX_TIMEOUT		(HZ * 15)
-#define INCPERIOD_82576			(1 << E1000_TIMINCA_16NS_SHIFT)
-#define INCVALUE_82576_MASK		((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
-#define INCVALUE_82576			(16 << IGB_82576_TSYNC_SHIFT)
-#define IGB_NBITS_82580			40
-
-/*
- * SYSTIM read access for the 82576
- */
-
-static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
-{
-	struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
-	struct e1000_hw *hw = &igb->hw;
-	u64 val;
-	u32 lo, hi;
-
-	lo = E1000_READ_REG(hw, E1000_SYSTIML);
-	hi = E1000_READ_REG(hw, E1000_SYSTIMH);
-
-	val = ((u64) hi) << 32;
-	val |= lo;
-
-	return val;
-}
-
-/*
- * SYSTIM read access for the 82580
- */
-
-static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
-{
-	struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
-	struct e1000_hw *hw = &igb->hw;
-	u64 val;
-	u32 lo, hi;
-
-	/* The timestamp latches on lowest register read. For the 82580
-	 * the lowest register is SYSTIMR instead of SYSTIML.  However we only
-	 * need to provide nanosecond resolution, so we just ignore it.
-	 */
-	E1000_READ_REG(hw, E1000_SYSTIMR);
-	lo = E1000_READ_REG(hw, E1000_SYSTIML);
-	hi = E1000_READ_REG(hw, E1000_SYSTIMH);
-
-	val = ((u64) hi) << 32;
-	val |= lo;
-
-	return val;
-}
-
-/*
- * SYSTIM read access for I210/I211
- */
-
-static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 sec, nsec;
-
-	/* The timestamp latches on lowest register read. For I210/I211, the
-	 * lowest register is SYSTIMR. Since we only need to provide nanosecond
-	 * resolution, we can ignore it.
-	 */
-	E1000_READ_REG(hw, E1000_SYSTIMR);
-	nsec = E1000_READ_REG(hw, E1000_SYSTIML);
-	sec = E1000_READ_REG(hw, E1000_SYSTIMH);
-
-	ts->tv_sec = sec;
-	ts->tv_nsec = nsec;
-}
-
-static void igb_ptp_write_i210(struct igb_adapter *adapter,
-			       const struct timespec *ts)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	/*
-	 * Writing the SYSTIMR register is not necessary as it only provides
-	 * sub-nanosecond resolution.
-	 */
-	E1000_WRITE_REG(hw, E1000_SYSTIML, ts->tv_nsec);
-	E1000_WRITE_REG(hw, E1000_SYSTIMH, ts->tv_sec);
-}
-
-/**
- * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp
- * @adapter: board private structure
- * @hwtstamps: timestamp structure to update
- * @systim: unsigned 64bit system time value.
- *
- * We need to convert the system time value stored in the RX/TXSTMP registers
- * into a hwtstamp which can be used by the upper level timestamping functions.
- *
- * The 'tmreg_lock' spinlock is used to protect the consistency of the
- * system time value. This is needed because reading the 64 bit time
- * value involves reading two (or three) 32 bit registers. The first
- * read latches the value. Ditto for writing.
- *
- * In addition, here have extended the system time with an overflow
- * counter in software.
- **/
-static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
-				       struct skb_shared_hwtstamps *hwtstamps,
-				       u64 systim)
-{
-	unsigned long flags;
-	u64 ns;
-
-	switch (adapter->hw.mac.type) {
-	case e1000_82576:
-	case e1000_82580:
-	case e1000_i350:
-	case e1000_i354:
-		spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
-		ns = timecounter_cyc2time(&adapter->tc, systim);
-
-		spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-
-		memset(hwtstamps, 0, sizeof(*hwtstamps));
-		hwtstamps->hwtstamp = ns_to_ktime(ns);
-		break;
-	case e1000_i210:
-	case e1000_i211:
-		memset(hwtstamps, 0, sizeof(*hwtstamps));
-		/* Upper 32 bits contain s, lower 32 bits contain ns. */
-		hwtstamps->hwtstamp = ktime_set(systim >> 32,
-						systim & 0xFFFFFFFF);
-		break;
-	default:
-		break;
-	}
-}
-
-/*
- * PTP clock operations
- */
-
-static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	struct e1000_hw *hw = &igb->hw;
-	int neg_adj = 0;
-	u64 rate;
-	u32 incvalue;
-
-	if (ppb < 0) {
-		neg_adj = 1;
-		ppb = -ppb;
-	}
-	rate = ppb;
-	rate <<= 14;
-	rate = div_u64(rate, 1953125);
-
-	incvalue = 16 << IGB_82576_TSYNC_SHIFT;
-
-	if (neg_adj)
-		incvalue -= rate;
-	else
-		incvalue += rate;
-
-	E1000_WRITE_REG(hw, E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK));
-
-	return 0;
-}
-
-static int igb_ptp_adjfreq_82580(struct ptp_clock_info *ptp, s32 ppb)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	struct e1000_hw *hw = &igb->hw;
-	int neg_adj = 0;
-	u64 rate;
-	u32 inca;
-
-	if (ppb < 0) {
-		neg_adj = 1;
-		ppb = -ppb;
-	}
-	rate = ppb;
-	rate <<= 26;
-	rate = div_u64(rate, 1953125);
-
-	/* At 2.5G speeds, the TIMINCA register on I354 updates the clock 2.5x
-	 * as quickly. Account for this by dividing the adjustment by 2.5.
-	 */
-	if (hw->mac.type == e1000_i354) {
-		u32 status = E1000_READ_REG(hw, E1000_STATUS);
-
-		if ((status & E1000_STATUS_2P5_SKU) &&
-		    !(status & E1000_STATUS_2P5_SKU_OVER)) {
-			rate <<= 1;
-			rate = div_u64(rate, 5);
-		}
-	}
-
-	inca = rate & INCVALUE_MASK;
-	if (neg_adj)
-		inca |= ISGN;
-
-	E1000_WRITE_REG(hw, E1000_TIMINCA, inca);
-
-	return 0;
-}
-
-static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-	s64 now;
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	now = timecounter_read(&igb->tc);
-	now += delta;
-	timecounter_init(&igb->tc, &igb->cc, now);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	return 0;
-}
-
-static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-	struct timespec now, then = ns_to_timespec(delta);
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	igb_ptp_read_i210(igb, &now);
-	now = timespec_add(now, then);
-	igb_ptp_write_i210(igb, (const struct timespec *)&now);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	return 0;
-}
-
-static int igb_ptp_gettime_82576(struct ptp_clock_info *ptp,
-				 struct timespec *ts)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-	u64 ns;
-	u32 remainder;
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	ns = timecounter_read(&igb->tc);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
-	ts->tv_nsec = remainder;
-
-	return 0;
-}
-
-static int igb_ptp_gettime_i210(struct ptp_clock_info *ptp,
-				struct timespec *ts)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	igb_ptp_read_i210(igb, ts);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	return 0;
-}
-
-static int igb_ptp_settime_82576(struct ptp_clock_info *ptp,
-				 const struct timespec *ts)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-	u64 ns;
-
-	ns = ts->tv_sec * 1000000000ULL;
-	ns += ts->tv_nsec;
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	timecounter_init(&igb->tc, &igb->cc, ns);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	return 0;
-}
-
-static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
-				const struct timespec *ts)
-{
-	struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
-					       ptp_caps);
-	unsigned long flags;
-
-	spin_lock_irqsave(&igb->tmreg_lock, flags);
-
-	igb_ptp_write_i210(igb, ts);
-
-	spin_unlock_irqrestore(&igb->tmreg_lock, flags);
-
-	return 0;
-}
-
-static int igb_ptp_enable(struct ptp_clock_info *ptp,
-			  struct ptp_clock_request *rq, int on)
-{
-	return -EOPNOTSUPP;
-}
-
-/**
- * igb_ptp_tx_work
- * @work: pointer to work struct
- *
- * This work function polls the TSYNCTXCTL valid bit to determine when a
- * timestamp has been taken for the current stored skb.
- */
-void igb_ptp_tx_work(struct work_struct *work)
-{
-	struct igb_adapter *adapter = container_of(work, struct igb_adapter,
-						   ptp_tx_work);
-	struct e1000_hw *hw = &adapter->hw;
-	u32 tsynctxctl;
-
-	if (!adapter->ptp_tx_skb)
-		return;
-
-	if (time_is_before_jiffies(adapter->ptp_tx_start +
-				   IGB_PTP_TX_TIMEOUT)) {
-		dev_kfree_skb_any(adapter->ptp_tx_skb);
-		adapter->ptp_tx_skb = NULL;
-		adapter->tx_hwtstamp_timeouts++;
-		dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
-		return;
-	}
-
-	tsynctxctl = E1000_READ_REG(hw, E1000_TSYNCTXCTL);
-	if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
-		igb_ptp_tx_hwtstamp(adapter);
-	else
-		/* reschedule to check later */
-		schedule_work(&adapter->ptp_tx_work);
-}
-
-static void igb_ptp_overflow_check(struct work_struct *work)
-{
-	struct igb_adapter *igb =
-		container_of(work, struct igb_adapter, ptp_overflow_work.work);
-	struct timespec ts;
-
-	igb->ptp_caps.gettime(&igb->ptp_caps, &ts);
-
-	pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
-
-	schedule_delayed_work(&igb->ptp_overflow_work,
-			      IGB_SYSTIM_OVERFLOW_PERIOD);
-}
-
-/**
- * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
- * @adapter: private network adapter structure
- *
- * This watchdog task is scheduled to detect error case where hardware has
- * dropped an Rx packet that was timestamped when the ring is full. The
- * particular error is rare but leaves the device in a state unable to timestamp
- * any future packets.
- */
-void igb_ptp_rx_hang(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct igb_ring *rx_ring;
-	u32 tsyncrxctl = E1000_READ_REG(hw, E1000_TSYNCRXCTL);
-	unsigned long rx_event;
-	int n;
-
-	if (hw->mac.type != e1000_82576)
-		return;
-
-	/* If we don't have a valid timestamp in the registers, just update the
-	 * timeout counter and exit
-	 */
-	if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
-		adapter->last_rx_ptp_check = jiffies;
-		return;
-	}
-
-	/* Determine the most recent watchdog or rx_timestamp event */
-	rx_event = adapter->last_rx_ptp_check;
-	for (n = 0; n < adapter->num_rx_queues; n++) {
-		rx_ring = adapter->rx_ring[n];
-		if (time_after(rx_ring->last_rx_timestamp, rx_event))
-			rx_event = rx_ring->last_rx_timestamp;
-	}
-
-	/* Only need to read the high RXSTMP register to clear the lock */
-	if (time_is_before_jiffies(rx_event + 5 * HZ)) {
-		E1000_READ_REG(hw, E1000_RXSTMPH);
-		adapter->last_rx_ptp_check = jiffies;
-		adapter->rx_hwtstamp_cleared++;
-		dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
-	}
-}
-
-/**
- * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
- * @adapter: Board private structure.
- *
- * If we were asked to do hardware stamping and such a time stamp is
- * available, then it must have been for this skb here because we only
- * allow only one such packet into the queue.
- */
-void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct skb_shared_hwtstamps shhwtstamps;
-	u64 regval;
-
-	regval = E1000_READ_REG(hw, E1000_TXSTMPL);
-	regval |= (u64)E1000_READ_REG(hw, E1000_TXSTMPH) << 32;
-
-	igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
-	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
-	dev_kfree_skb_any(adapter->ptp_tx_skb);
-	adapter->ptp_tx_skb = NULL;
-}
-
-/**
- * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp
- * @q_vector: Pointer to interrupt specific structure
- * @va: Pointer to address containing Rx buffer
- * @skb: Buffer containing timestamp and packet
- *
- * This function is meant to retrieve a timestamp from the first buffer of an
- * incoming frame.  The value is stored in little endian format starting on
- * byte 8.
- */
-void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector,
-			 unsigned char *va,
-			 struct sk_buff *skb)
-{
-	__le64 *regval = (__le64 *)va;
-
-	/*
-	 * The timestamp is recorded in little endian format.
-	 * DWORD: 0        1        2        3
-	 * Field: Reserved Reserved SYSTIML  SYSTIMH
-	 */
-	igb_ptp_systim_to_hwtstamp(q_vector->adapter, skb_hwtstamps(skb),
-				   le64_to_cpu(regval[1]));
-}
-
-/**
- * igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register
- * @q_vector: Pointer to interrupt specific structure
- * @skb: Buffer containing timestamp and packet
- *
- * This function is meant to retrieve a timestamp from the internal registers
- * of the adapter and store it in the skb.
- */
-void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
-			 struct sk_buff *skb)
-{
-	struct igb_adapter *adapter = q_vector->adapter;
-	struct e1000_hw *hw = &adapter->hw;
-	u64 regval;
-
-	/*
-	 * If this bit is set, then the RX registers contain the time stamp. No
-	 * other packet will be time stamped until we read these registers, so
-	 * read the registers to make them available again. Because only one
-	 * packet can be time stamped at a time, we know that the register
-	 * values must belong to this one here and therefore we don't need to
-	 * compare any of the additional attributes stored for it.
-	 *
-	 * If nothing went wrong, then it should have a shared tx_flags that we
-	 * can turn into a skb_shared_hwtstamps.
-	 */
-	if (!(E1000_READ_REG(hw, E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
-		return;
-
-	regval = E1000_READ_REG(hw, E1000_RXSTMPL);
-	regval |= (u64)E1000_READ_REG(hw, E1000_RXSTMPH) << 32;
-
-	igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
-}
-
-/**
- * igb_ptp_hwtstamp_ioctl - control hardware time stamping
- * @netdev:
- * @ifreq:
- * @cmd:
- *
- * Outgoing time stamping can be enabled and disabled. Play nice and
- * disable it when requested, although it shouldn't case any overhead
- * when no packet needs it. At most one packet in the queue may be
- * marked for time stamping, otherwise it would be impossible to tell
- * for sure to which packet the hardware time stamp belongs.
- *
- * Incoming time stamping has to be configured via the hardware
- * filters. Not all combinations are supported, in particular event
- * type has to be specified. Matching the kind of event packet is
- * not supported, with the exception of "all V2 events regardless of
- * level 2 or 4".
- *
- **/
-int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
-			   struct ifreq *ifr, int cmd)
-{
-	struct igb_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-	struct hwtstamp_config config;
-	u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
-	u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
-	u32 tsync_rx_cfg = 0;
-	bool is_l4 = false;
-	bool is_l2 = false;
-	u32 regval;
-
-	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
-		return -EFAULT;
-
-	/* reserved for future extensions */
-	if (config.flags)
-		return -EINVAL;
-
-	switch (config.tx_type) {
-	case HWTSTAMP_TX_OFF:
-		tsync_tx_ctl = 0;
-	case HWTSTAMP_TX_ON:
-		break;
-	default:
-		return -ERANGE;
-	}
-
-	switch (config.rx_filter) {
-	case HWTSTAMP_FILTER_NONE:
-		tsync_rx_ctl = 0;
-		break;
-	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
-		tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
-		is_l4 = true;
-		break;
-	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
-		tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
-		is_l4 = true;
-		break;
-	case HWTSTAMP_FILTER_PTP_V2_EVENT:
-	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
-	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
-	case HWTSTAMP_FILTER_PTP_V2_SYNC:
-	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
-	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
-	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
-	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
-	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
-		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
-		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
-		is_l2 = true;
-		is_l4 = true;
-		break;
-	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
-	case HWTSTAMP_FILTER_ALL:
-		/*
-		 * 82576 cannot timestamp all packets, which it needs to do to
-		 * support both V1 Sync and Delay_Req messages
-		 */
-		if (hw->mac.type != e1000_82576) {
-			tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
-			config.rx_filter = HWTSTAMP_FILTER_ALL;
-			break;
-		}
-		/* fall through */
-	default:
-		config.rx_filter = HWTSTAMP_FILTER_NONE;
-		return -ERANGE;
-	}
-
-	if (hw->mac.type == e1000_82575) {
-		if (tsync_rx_ctl | tsync_tx_ctl)
-			return -EINVAL;
-		return 0;
-	}
-
-	/*
-	 * Per-packet timestamping only works if all packets are
-	 * timestamped, so enable timestamping in all packets as
-	 * long as one rx filter was configured.
-	 */
-	if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
-		tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
-		tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
-		config.rx_filter = HWTSTAMP_FILTER_ALL;
-		is_l2 = true;
-		is_l4 = true;
-
-		if ((hw->mac.type == e1000_i210) ||
-		    (hw->mac.type == e1000_i211)) {
-			regval = E1000_READ_REG(hw, E1000_RXPBS);
-			regval |= E1000_RXPBS_CFG_TS_EN;
-			E1000_WRITE_REG(hw, E1000_RXPBS, regval);
-		}
-	}
-
-	/* enable/disable TX */
-	regval = E1000_READ_REG(hw, E1000_TSYNCTXCTL);
-	regval &= ~E1000_TSYNCTXCTL_ENABLED;
-	regval |= tsync_tx_ctl;
-	E1000_WRITE_REG(hw, E1000_TSYNCTXCTL, regval);
-
-	/* enable/disable RX */
-	regval = E1000_READ_REG(hw, E1000_TSYNCRXCTL);
-	regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
-	regval |= tsync_rx_ctl;
-	E1000_WRITE_REG(hw, E1000_TSYNCRXCTL, regval);
-
-	/* define which PTP packets are time stamped */
-	E1000_WRITE_REG(hw, E1000_TSYNCRXCFG, tsync_rx_cfg);
-
-	/* define ethertype filter for timestamped packets */
-	if (is_l2)
-		E1000_WRITE_REG(hw, E1000_ETQF(3),
-		     (E1000_ETQF_FILTER_ENABLE | /* enable filter */
-		      E1000_ETQF_1588 | /* enable timestamping */
-		      ETH_P_1588));     /* 1588 eth protocol type */
-	else
-		E1000_WRITE_REG(hw, E1000_ETQF(3), 0);
-
-	/* L4 Queue Filter[3]: filter by destination port and protocol */
-	if (is_l4) {
-		u32 ftqf = (IPPROTO_UDP /* UDP */
-			| E1000_FTQF_VF_BP /* VF not compared */
-			| E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */
-			| E1000_FTQF_MASK); /* mask all inputs */
-		ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
-
-		E1000_WRITE_REG(hw, E1000_IMIR(3), htons(PTP_EV_PORT));
-		E1000_WRITE_REG(hw, E1000_IMIREXT(3),
-		     (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
-		if (hw->mac.type == e1000_82576) {
-			/* enable source port check */
-			E1000_WRITE_REG(hw, E1000_SPQF(3), htons(PTP_EV_PORT));
-			ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
-		}
-		E1000_WRITE_REG(hw, E1000_FTQF(3), ftqf);
-	} else {
-		E1000_WRITE_REG(hw, E1000_FTQF(3), E1000_FTQF_MASK);
-	}
-	E1000_WRITE_FLUSH(hw);
-
-	/* clear TX/RX time stamp registers, just to be sure */
-	regval = E1000_READ_REG(hw, E1000_TXSTMPL);
-	regval = E1000_READ_REG(hw, E1000_TXSTMPH);
-	regval = E1000_READ_REG(hw, E1000_RXSTMPL);
-	regval = E1000_READ_REG(hw, E1000_RXSTMPH);
-
-	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-		-EFAULT : 0;
-}
-
-void igb_ptp_init(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct net_device *netdev = adapter->netdev;
-
-	switch (hw->mac.type) {
-	case e1000_82576:
-		snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
-		adapter->ptp_caps.owner = THIS_MODULE;
-		adapter->ptp_caps.max_adj = 999999881;
-		adapter->ptp_caps.n_ext_ts = 0;
-		adapter->ptp_caps.pps = 0;
-		adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
-		adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
-		adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
-		adapter->ptp_caps.settime = igb_ptp_settime_82576;
-		adapter->ptp_caps.enable = igb_ptp_enable;
-		adapter->cc.read = igb_ptp_read_82576;
-		adapter->cc.mask = CLOCKSOURCE_MASK(64);
-		adapter->cc.mult = 1;
-		adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
-		/* Dial the nominal frequency. */
-		E1000_WRITE_REG(hw, E1000_TIMINCA, INCPERIOD_82576 |
-						   INCVALUE_82576);
-		break;
-	case e1000_82580:
-	case e1000_i350:
-	case e1000_i354:
-		snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
-		adapter->ptp_caps.owner = THIS_MODULE;
-		adapter->ptp_caps.max_adj = 62499999;
-		adapter->ptp_caps.n_ext_ts = 0;
-		adapter->ptp_caps.pps = 0;
-		adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
-		adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
-		adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
-		adapter->ptp_caps.settime = igb_ptp_settime_82576;
-		adapter->ptp_caps.enable = igb_ptp_enable;
-		adapter->cc.read = igb_ptp_read_82580;
-		adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
-		adapter->cc.mult = 1;
-		adapter->cc.shift = 0;
-		/* Enable the timer functions by clearing bit 31. */
-		E1000_WRITE_REG(hw, E1000_TSAUXC, 0x0);
-		break;
-	case e1000_i210:
-	case e1000_i211:
-		snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
-		adapter->ptp_caps.owner = THIS_MODULE;
-		adapter->ptp_caps.max_adj = 62499999;
-		adapter->ptp_caps.n_ext_ts = 0;
-		adapter->ptp_caps.pps = 0;
-		adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
-		adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
-		adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
-		adapter->ptp_caps.settime = igb_ptp_settime_i210;
-		adapter->ptp_caps.enable = igb_ptp_enable;
-		/* Enable the timer functions by clearing bit 31. */
-		E1000_WRITE_REG(hw, E1000_TSAUXC, 0x0);
-		break;
-	default:
-		adapter->ptp_clock = NULL;
-		return;
-	}
-
-	E1000_WRITE_FLUSH(hw);
-
-	spin_lock_init(&adapter->tmreg_lock);
-	INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
-
-	/* Initialize the clock and overflow work for devices that need it. */
-	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
-		struct timespec ts = ktime_to_timespec(ktime_get_real());
-
-		igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
-	} else {
-		timecounter_init(&adapter->tc, &adapter->cc,
-				 ktime_to_ns(ktime_get_real()));
-
-		INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
-				  igb_ptp_overflow_check);
-
-		schedule_delayed_work(&adapter->ptp_overflow_work,
-				      IGB_SYSTIM_OVERFLOW_PERIOD);
-	}
-
-	/* Initialize the time sync interrupts for devices that support it. */
-	if (hw->mac.type >= e1000_82580) {
-		E1000_WRITE_REG(hw, E1000_TSIM, E1000_TSIM_TXTS);
-		E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_TS);
-	}
-
-	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
-						&adapter->pdev->dev);
-	if (IS_ERR(adapter->ptp_clock)) {
-		adapter->ptp_clock = NULL;
-		dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n");
-	} else {
-		dev_info(&adapter->pdev->dev, "added PHC on %s\n",
-			 adapter->netdev->name);
-		adapter->flags |= IGB_FLAG_PTP;
-	}
-}
-
-/**
- * igb_ptp_stop - Disable PTP device and stop the overflow check.
- * @adapter: Board private structure.
- *
- * This function stops the PTP support and cancels the delayed work.
- **/
-void igb_ptp_stop(struct igb_adapter *adapter)
-{
-	switch (adapter->hw.mac.type) {
-	case e1000_82576:
-	case e1000_82580:
-	case e1000_i350:
-	case e1000_i354:
-		cancel_delayed_work_sync(&adapter->ptp_overflow_work);
-		break;
-	case e1000_i210:
-	case e1000_i211:
-		/* No delayed work to cancel. */
-		break;
-	default:
-		return;
-	}
-
-	cancel_work_sync(&adapter->ptp_tx_work);
-	if (adapter->ptp_tx_skb) {
-		dev_kfree_skb_any(adapter->ptp_tx_skb);
-		adapter->ptp_tx_skb = NULL;
-	}
-
-	if (adapter->ptp_clock) {
-		ptp_clock_unregister(adapter->ptp_clock);
-		dev_info(&adapter->pdev->dev, "removed PHC on %s\n",
-			 adapter->netdev->name);
-		adapter->flags &= ~IGB_FLAG_PTP;
-	}
-}
-
-/**
- * igb_ptp_reset - Re-enable the adapter for PTP following a reset.
- * @adapter: Board private structure.
- *
- * This function handles the reset work required to re-enable the PTP device.
- **/
-void igb_ptp_reset(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	if (!(adapter->flags & IGB_FLAG_PTP))
-		return;
-
-	switch (adapter->hw.mac.type) {
-	case e1000_82576:
-		/* Dial the nominal frequency. */
-		E1000_WRITE_REG(hw, E1000_TIMINCA, INCPERIOD_82576 |
-						   INCVALUE_82576);
-		break;
-	case e1000_82580:
-	case e1000_i350:
-	case e1000_i354:
-	case e1000_i210:
-	case e1000_i211:
-		/* Enable the timer functions and interrupts. */
-		E1000_WRITE_REG(hw, E1000_TSAUXC, 0x0);
-		E1000_WRITE_REG(hw, E1000_TSIM, E1000_TSIM_TXTS);
-		E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_TS);
-		break;
-	default:
-		/* No work to do. */
-		return;
-	}
-
-	/* Re-initialize the timer. */
-	if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
-		struct timespec ts = ktime_to_timespec(ktime_get_real());
-
-		igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
-	} else {
-		timecounter_init(&adapter->tc, &adapter->cc,
-				 ktime_to_ns(ktime_get_real()));
-	}
-}
diff --git a/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat.c b/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat.c
deleted file mode 100644
index e42ad32..0000000
--- a/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat.c
+++ /dev/null
@@ -1,1482 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "LICENSE.GPL".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include "igb.h"
-#include "kcompat.h"
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,8) )
-/* From lib/vsprintf.c */
-#include <asm/div64.h>
-
-static int skip_atoi(const char **s)
-{
-	int i=0;
-
-	while (isdigit(**s))
-		i = i*10 + *((*s)++) - '0';
-	return i;
-}
-
-#define _kc_ZEROPAD	1		/* pad with zero */
-#define _kc_SIGN	2		/* unsigned/signed long */
-#define _kc_PLUS	4		/* show plus */
-#define _kc_SPACE	8		/* space if plus */
-#define _kc_LEFT	16		/* left justified */
-#define _kc_SPECIAL	32		/* 0x */
-#define _kc_LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
-
-static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
-{
-	char c,sign,tmp[66];
-	const char *digits;
-	const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-	const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	int i;
-
-	digits = (type & _kc_LARGE) ? large_digits : small_digits;
-	if (type & _kc_LEFT)
-		type &= ~_kc_ZEROPAD;
-	if (base < 2 || base > 36)
-		return 0;
-	c = (type & _kc_ZEROPAD) ? '0' : ' ';
-	sign = 0;
-	if (type & _kc_SIGN) {
-		if (num < 0) {
-			sign = '-';
-			num = -num;
-			size--;
-		} else if (type & _kc_PLUS) {
-			sign = '+';
-			size--;
-		} else if (type & _kc_SPACE) {
-			sign = ' ';
-			size--;
-		}
-	}
-	if (type & _kc_SPECIAL) {
-		if (base == 16)
-			size -= 2;
-		else if (base == 8)
-			size--;
-	}
-	i = 0;
-	if (num == 0)
-		tmp[i++]='0';
-	else while (num != 0)
-		tmp[i++] = digits[do_div(num,base)];
-	if (i > precision)
-		precision = i;
-	size -= precision;
-	if (!(type&(_kc_ZEROPAD+_kc_LEFT))) {
-		while(size-->0) {
-			if (buf <= end)
-				*buf = ' ';
-			++buf;
-		}
-	}
-	if (sign) {
-		if (buf <= end)
-			*buf = sign;
-		++buf;
-	}
-	if (type & _kc_SPECIAL) {
-		if (base==8) {
-			if (buf <= end)
-				*buf = '0';
-			++buf;
-		} else if (base==16) {
-			if (buf <= end)
-				*buf = '0';
-			++buf;
-			if (buf <= end)
-				*buf = digits[33];
-			++buf;
-		}
-	}
-	if (!(type & _kc_LEFT)) {
-		while (size-- > 0) {
-			if (buf <= end)
-				*buf = c;
-			++buf;
-		}
-	}
-	while (i < precision--) {
-		if (buf <= end)
-			*buf = '0';
-		++buf;
-	}
-	while (i-- > 0) {
-		if (buf <= end)
-			*buf = tmp[i];
-		++buf;
-	}
-	while (size-- > 0) {
-		if (buf <= end)
-			*buf = ' ';
-		++buf;
-	}
-	return buf;
-}
-
-int _kc_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
-{
-	int len;
-	unsigned long long num;
-	int i, base;
-	char *str, *end, c;
-	const char *s;
-
-	int flags;		/* flags to number() */
-
-	int field_width;	/* width of output field */
-	int precision;		/* min. # of digits for integers; max
-				   number of chars for from string */
-	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
-				/* 'z' support added 23/7/1999 S.H.    */
-				/* 'z' changed to 'Z' --davidm 1/25/99 */
-
-	str = buf;
-	end = buf + size - 1;
-
-	if (end < buf - 1) {
-		end = ((void *) -1);
-		size = end - buf + 1;
-	}
-
-	for (; *fmt ; ++fmt) {
-		if (*fmt != '%') {
-			if (str <= end)
-				*str = *fmt;
-			++str;
-			continue;
-		}
-
-		/* process flags */
-		flags = 0;
-		repeat:
-			++fmt;		/* this also skips first '%' */
-			switch (*fmt) {
-				case '-': flags |= _kc_LEFT; goto repeat;
-				case '+': flags |= _kc_PLUS; goto repeat;
-				case ' ': flags |= _kc_SPACE; goto repeat;
-				case '#': flags |= _kc_SPECIAL; goto repeat;
-				case '0': flags |= _kc_ZEROPAD; goto repeat;
-			}
-
-		/* get field width */
-		field_width = -1;
-		if (isdigit(*fmt))
-			field_width = skip_atoi(&fmt);
-		else if (*fmt == '*') {
-			++fmt;
-			/* it's the next argument */
-			field_width = va_arg(args, int);
-			if (field_width < 0) {
-				field_width = -field_width;
-				flags |= _kc_LEFT;
-			}
-		}
-
-		/* get the precision */
-		precision = -1;
-		if (*fmt == '.') {
-			++fmt;
-			if (isdigit(*fmt))
-				precision = skip_atoi(&fmt);
-			else if (*fmt == '*') {
-				++fmt;
-				/* it's the next argument */
-				precision = va_arg(args, int);
-			}
-			if (precision < 0)
-				precision = 0;
-		}
-
-		/* get the conversion qualifier */
-		qualifier = -1;
-		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
-			qualifier = *fmt;
-			++fmt;
-		}
-
-		/* default base */
-		base = 10;
-
-		switch (*fmt) {
-			case 'c':
-				if (!(flags & _kc_LEFT)) {
-					while (--field_width > 0) {
-						if (str <= end)
-							*str = ' ';
-						++str;
-					}
-				}
-				c = (unsigned char) va_arg(args, int);
-				if (str <= end)
-					*str = c;
-				++str;
-				while (--field_width > 0) {
-					if (str <= end)
-						*str = ' ';
-					++str;
-				}
-				continue;
-
-			case 's':
-				s = va_arg(args, char *);
-				if (!s)
-					s = "<NULL>";
-
-				len = strnlen(s, precision);
-
-				if (!(flags & _kc_LEFT)) {
-					while (len < field_width--) {
-						if (str <= end)
-							*str = ' ';
-						++str;
-					}
-				}
-				for (i = 0; i < len; ++i) {
-					if (str <= end)
-						*str = *s;
-					++str; ++s;
-				}
-				while (len < field_width--) {
-					if (str <= end)
-						*str = ' ';
-					++str;
-				}
-				continue;
-
-			case 'p':
-				if (field_width == -1) {
-					field_width = 2*sizeof(void *);
-					flags |= _kc_ZEROPAD;
-				}
-				str = number(str, end,
-						(unsigned long) va_arg(args, void *),
-						16, field_width, precision, flags);
-				continue;
-
-
-			case 'n':
-				/* FIXME:
-				* What does C99 say about the overflow case here? */
-				if (qualifier == 'l') {
-					long * ip = va_arg(args, long *);
-					*ip = (str - buf);
-				} else if (qualifier == 'Z') {
-					size_t * ip = va_arg(args, size_t *);
-					*ip = (str - buf);
-				} else {
-					int * ip = va_arg(args, int *);
-					*ip = (str - buf);
-				}
-				continue;
-
-			case '%':
-				if (str <= end)
-					*str = '%';
-				++str;
-				continue;
-
-				/* integer number formats - set up the flags and "break" */
-			case 'o':
-				base = 8;
-				break;
-
-			case 'X':
-				flags |= _kc_LARGE;
-			case 'x':
-				base = 16;
-				break;
-
-			case 'd':
-			case 'i':
-				flags |= _kc_SIGN;
-			case 'u':
-				break;
-
-			default:
-				if (str <= end)
-					*str = '%';
-				++str;
-				if (*fmt) {
-					if (str <= end)
-						*str = *fmt;
-					++str;
-				} else {
-					--fmt;
-				}
-				continue;
-		}
-		if (qualifier == 'L')
-			num = va_arg(args, long long);
-		else if (qualifier == 'l') {
-			num = va_arg(args, unsigned long);
-			if (flags & _kc_SIGN)
-				num = (signed long) num;
-		} else if (qualifier == 'Z') {
-			num = va_arg(args, size_t);
-		} else if (qualifier == 'h') {
-			num = (unsigned short) va_arg(args, int);
-			if (flags & _kc_SIGN)
-				num = (signed short) num;
-		} else {
-			num = va_arg(args, unsigned int);
-			if (flags & _kc_SIGN)
-				num = (signed int) num;
-		}
-		str = number(str, end, num, base,
-				field_width, precision, flags);
-	}
-	if (str <= end)
-		*str = '\0';
-	else if (size > 0)
-		/* don't write out a null byte if the buf size is zero */
-		*end = '\0';
-	/* the trailing null byte doesn't count towards the total
-	* ++str;
-	*/
-	return str-buf;
-}
-
-int _kc_snprintf(char * buf, size_t size, const char *fmt, ...)
-{
-	va_list args;
-	int i;
-
-	va_start(args, fmt);
-	i = _kc_vsnprintf(buf,size,fmt,args);
-	va_end(args);
-	return i;
-}
-#endif /* < 2.4.8 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) )
-
-/**************************************/
-/* PCI DMA MAPPING */
-
-#if defined(CONFIG_HIGHMEM)
-
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET 0
-#endif
-
-u64
-_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
-                 size_t size, int direction)
-{
-	return (((u64) (page - mem_map) << PAGE_SHIFT) + offset +
-		PCI_DRAM_OFFSET);
-}
-
-#else /* CONFIG_HIGHMEM */
-
-u64
-_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
-                 size_t size, int direction)
-{
-	return pci_map_single(dev, (void *)page_address(page) + offset, size,
-			      direction);
-}
-
-#endif /* CONFIG_HIGHMEM */
-
-void
-_kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size,
-                   int direction)
-{
-	return pci_unmap_single(dev, dma_addr, size, direction);
-}
-
-#endif /* 2.4.13 => 2.4.3 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) )
-
-/**************************************/
-/* PCI DRIVER API */
-
-int
-_kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
-{
-	if (!pci_dma_supported(dev, mask))
-		return -EIO;
-	dev->dma_mask = mask;
-	return 0;
-}
-
-int
-_kc_pci_request_regions(struct pci_dev *dev, char *res_name)
-{
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(dev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
-			if (!request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
-				pci_release_regions(dev);
-				return -EBUSY;
-			}
-		} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
-			if (!request_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
-				pci_release_regions(dev);
-				return -EBUSY;
-			}
-		}
-	}
-	return 0;
-}
-
-void
-_kc_pci_release_regions(struct pci_dev *dev)
-{
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(dev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
-			release_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
-
-		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
-			release_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
-	}
-}
-
-/**************************************/
-/* NETWORK DRIVER API */
-
-struct net_device *
-_kc_alloc_etherdev(int sizeof_priv)
-{
-	struct net_device *dev;
-	int alloc_size;
-
-	alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 31;
-	dev = kzalloc(alloc_size, GFP_KERNEL);
-	if (!dev)
-		return NULL;
-
-	if (sizeof_priv)
-		dev->priv = (void *) (((unsigned long)(dev + 1) + 31) & ~31);
-	dev->name[0] = '\0';
-	ether_setup(dev);
-
-	return dev;
-}
-
-int
-_kc_is_valid_ether_addr(u8 *addr)
-{
-	const char zaddr[6] = { 0, };
-
-	return !(addr[0] & 1) && memcmp(addr, zaddr, 6);
-}
-
-#endif /* 2.4.3 => 2.4.0 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) )
-
-int
-_kc_pci_set_power_state(struct pci_dev *dev, int state)
-{
-	return 0;
-}
-
-int
-_kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable)
-{
-	return 0;
-}
-
-#endif /* 2.4.6 => 2.4.3 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
-void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page,
-                            int off, int size)
-{
-	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-	frag->page = page;
-	frag->page_offset = off;
-	frag->size = size;
-	skb_shinfo(skb)->nr_frags = i + 1;
-}
-
-/*
- * Original Copyright:
- * find_next_bit.c: fallback find next bit implementation
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- */
-
-/**
- * find_next_bit - find the next set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
-                            unsigned long offset)
-{
-	const unsigned long *p = addr + BITOP_WORD(offset);
-	unsigned long result = offset & ~(BITS_PER_LONG-1);
-	unsigned long tmp;
-
-	if (offset >= size)
-		return size;
-	size -= result;
-	offset %= BITS_PER_LONG;
-	if (offset) {
-		tmp = *(p++);
-		tmp &= (~0UL << offset);
-		if (size < BITS_PER_LONG)
-			goto found_first;
-		if (tmp)
-			goto found_middle;
-		size -= BITS_PER_LONG;
-		result += BITS_PER_LONG;
-	}
-	while (size & ~(BITS_PER_LONG-1)) {
-		if ((tmp = *(p++)))
-			goto found_middle;
-		result += BITS_PER_LONG;
-		size -= BITS_PER_LONG;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-
-found_first:
-	tmp &= (~0UL >> (BITS_PER_LONG - size));
-	if (tmp == 0UL)		/* Are any bits set? */
-		return result + size;	/* Nope. */
-found_middle:
-	return result + ffs(tmp);
-}
-
-size_t _kc_strlcpy(char *dest, const char *src, size_t size)
-{
-	size_t ret = strlen(src);
-
-	if (size) {
-		size_t len = (ret >= size) ? size - 1 : ret;
-		memcpy(dest, src, len);
-		dest[len] = '\0';
-	}
-	return ret;
-}
-
-#ifndef do_div
-#if BITS_PER_LONG == 32
-uint32_t __attribute__((weak)) _kc__div64_32(uint64_t *n, uint32_t base)
-{
-	uint64_t rem = *n;
-	uint64_t b = base;
-	uint64_t res, d = 1;
-	uint32_t high = rem >> 32;
-
-	/* Reduce the thing a bit first */
-	res = 0;
-	if (high >= base) {
-		high /= base;
-		res = (uint64_t) high << 32;
-		rem -= (uint64_t) (high*base) << 32;
-	}
-
-	while ((int64_t)b > 0 && b < rem) {
-		b = b+b;
-		d = d+d;
-	}
-
-	do {
-		if (rem >= b) {
-			rem -= b;
-			res += d;
-		}
-		b >>= 1;
-		d >>= 1;
-	} while (d);
-
-	*n = res;
-	return rem;
-}
-#endif /* BITS_PER_LONG == 32 */
-#endif /* do_div */
-#endif /* 2.6.0 => 2.4.6 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) )
-int _kc_scnprintf(char * buf, size_t size, const char *fmt, ...)
-{
-	va_list args;
-	int i;
-
-	va_start(args, fmt);
-	i = vsnprintf(buf, size, fmt, args);
-	va_end(args);
-	return (i >= size) ? (size - 1) : i;
-}
-#endif /* < 2.6.4 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) )
-DECLARE_BITMAP(_kcompat_node_online_map, MAX_NUMNODES) = {1};
-#endif /* < 2.6.10 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) )
-char *_kc_kstrdup(const char *s, unsigned int gfp)
-{
-	size_t len;
-	char *buf;
-
-	if (!s)
-		return NULL;
-
-	len = strlen(s) + 1;
-	buf = kmalloc(len, gfp);
-	if (buf)
-		memcpy(buf, s, len);
-	return buf;
-}
-#endif /* < 2.6.13 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) )
-void *_kc_kzalloc(size_t size, int flags)
-{
-	void *ret = kmalloc(size, flags);
-	if (ret)
-		memset(ret, 0, size);
-	return ret;
-}
-#endif /* <= 2.6.13 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) )
-int _kc_skb_pad(struct sk_buff *skb, int pad)
-{
-	int ntail;
-
-        /* If the skbuff is non linear tailroom is always zero.. */
-        if(!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
-		memset(skb->data+skb->len, 0, pad);
-		return 0;
-        }
-
-	ntail = skb->data_len + pad - (skb->end - skb->tail);
-	if (likely(skb_cloned(skb) || ntail > 0)) {
-		if (pskb_expand_head(skb, 0, ntail, GFP_ATOMIC));
-			goto free_skb;
-	}
-
-#ifdef MAX_SKB_FRAGS
-	if (skb_is_nonlinear(skb) &&
-	    !__pskb_pull_tail(skb, skb->data_len))
-		goto free_skb;
-
-#endif
-	memset(skb->data + skb->len, 0, pad);
-        return 0;
-
-free_skb:
-	kfree_skb(skb);
-	return -ENOMEM;
-}
-
-#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,4)))
-int _kc_pci_save_state(struct pci_dev *pdev)
-{
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct adapter_struct *adapter = netdev_priv(netdev);
-	int size = PCI_CONFIG_SPACE_LEN, i;
-	u16 pcie_cap_offset, pcie_link_status;
-
-#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) )
-	/* no ->dev for 2.4 kernels */
-	WARN_ON(pdev->dev.driver_data == NULL);
-#endif
-	pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-	if (pcie_cap_offset) {
-		if (!pci_read_config_word(pdev,
-		                          pcie_cap_offset + PCIE_LINK_STATUS,
-		                          &pcie_link_status))
-		size = PCIE_CONFIG_SPACE_LEN;
-	}
-	pci_config_space_ich8lan();
-#ifdef HAVE_PCI_ERS
-	if (adapter->config_space == NULL)
-#else
-	WARN_ON(adapter->config_space != NULL);
-#endif
-		adapter->config_space = kmalloc(size, GFP_KERNEL);
-	if (!adapter->config_space) {
-		printk(KERN_ERR "Out of memory in pci_save_state\n");
-		return -ENOMEM;
-	}
-	for (i = 0; i < (size / 4); i++)
-		pci_read_config_dword(pdev, i * 4, &adapter->config_space[i]);
-	return 0;
-}
-
-void _kc_pci_restore_state(struct pci_dev *pdev)
-{
-	struct net_device *netdev = pci_get_drvdata(pdev);
-	struct adapter_struct *adapter = netdev_priv(netdev);
-	int size = PCI_CONFIG_SPACE_LEN, i;
-	u16 pcie_cap_offset;
-	u16 pcie_link_status;
-
-	if (adapter->config_space != NULL) {
-		pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-		if (pcie_cap_offset &&
-		    !pci_read_config_word(pdev,
-		                          pcie_cap_offset + PCIE_LINK_STATUS,
-		                          &pcie_link_status))
-			size = PCIE_CONFIG_SPACE_LEN;
-
-		pci_config_space_ich8lan();
-		for (i = 0; i < (size / 4); i++)
-		pci_write_config_dword(pdev, i * 4, adapter->config_space[i]);
-#ifndef HAVE_PCI_ERS
-		kfree(adapter->config_space);
-		adapter->config_space = NULL;
-#endif
-	}
-}
-#endif /* !(RHEL_RELEASE_CODE >= RHEL 5.4) */
-
-#ifdef HAVE_PCI_ERS
-void _kc_free_netdev(struct net_device *netdev)
-{
-	struct adapter_struct *adapter = netdev_priv(netdev);
-
-	if (adapter->config_space != NULL)
-		kfree(adapter->config_space);
-#ifdef CONFIG_SYSFS
-	if (netdev->reg_state == NETREG_UNINITIALIZED) {
-		kfree((char *)netdev - netdev->padded);
-	} else {
-		BUG_ON(netdev->reg_state != NETREG_UNREGISTERED);
-		netdev->reg_state = NETREG_RELEASED;
-		class_device_put(&netdev->class_dev);
-	}
-#else
-	kfree((char *)netdev - netdev->padded);
-#endif
-}
-#endif
-
-void *_kc_kmemdup(const void *src, size_t len, unsigned gfp)
-{
-	void *p;
-
-	p = kzalloc(len, gfp);
-	if (p)
-		memcpy(p, src, len);
-	return p;
-}
-#endif /* <= 2.6.19 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) )
-struct pci_dev *_kc_netdev_to_pdev(struct net_device *netdev)
-{
-	return ((struct adapter_struct *)netdev_priv(netdev))->pdev;
-}
-#endif /* < 2.6.21 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) )
-/* hexdump code taken from lib/hexdump.c */
-static void _kc_hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
-			int groupsize, unsigned char *linebuf,
-			size_t linebuflen, bool ascii)
-{
-	const u8 *ptr = buf;
-	u8 ch;
-	int j, lx = 0;
-	int ascii_column;
-
-	if (rowsize != 16 && rowsize != 32)
-		rowsize = 16;
-
-	if (!len)
-		goto nil;
-	if (len > rowsize)		/* limit to one line at a time */
-		len = rowsize;
-	if ((len % groupsize) != 0)	/* no mixed size output */
-		groupsize = 1;
-
-	switch (groupsize) {
-	case 8: {
-		const u64 *ptr8 = buf;
-		int ngroups = len / groupsize;
-
-		for (j = 0; j < ngroups; j++)
-			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
-				"%s%16.16llx", j ? " " : "",
-				(unsigned long long)*(ptr8 + j));
-		ascii_column = 17 * ngroups + 2;
-		break;
-	}
-
-	case 4: {
-		const u32 *ptr4 = buf;
-		int ngroups = len / groupsize;
-
-		for (j = 0; j < ngroups; j++)
-			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
-				"%s%8.8x", j ? " " : "", *(ptr4 + j));
-		ascii_column = 9 * ngroups + 2;
-		break;
-	}
-
-	case 2: {
-		const u16 *ptr2 = buf;
-		int ngroups = len / groupsize;
-
-		for (j = 0; j < ngroups; j++)
-			lx += scnprintf((char *)(linebuf + lx), linebuflen - lx,
-				"%s%4.4x", j ? " " : "", *(ptr2 + j));
-		ascii_column = 5 * ngroups + 2;
-		break;
-	}
-
-	default:
-		for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
-			ch = ptr[j];
-			linebuf[lx++] = hex_asc(ch >> 4);
-			linebuf[lx++] = hex_asc(ch & 0x0f);
-			linebuf[lx++] = ' ';
-		}
-		if (j)
-			lx--;
-
-		ascii_column = 3 * rowsize + 2;
-		break;
-	}
-	if (!ascii)
-		goto nil;
-
-	while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
-		linebuf[lx++] = ' ';
-	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
-		linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
-				: '.';
-nil:
-	linebuf[lx++] = '\0';
-}
-
-void _kc_print_hex_dump(const char *level,
-			const char *prefix_str, int prefix_type,
-			int rowsize, int groupsize,
-			const void *buf, size_t len, bool ascii)
-{
-	const u8 *ptr = buf;
-	int i, linelen, remaining = len;
-	unsigned char linebuf[200];
-
-	if (rowsize != 16 && rowsize != 32)
-		rowsize = 16;
-
-	for (i = 0; i < len; i += rowsize) {
-		linelen = min(remaining, rowsize);
-		remaining -= rowsize;
-		_kc_hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
-				linebuf, sizeof(linebuf), ascii);
-
-		switch (prefix_type) {
-		case DUMP_PREFIX_ADDRESS:
-			printk("%s%s%*p: %s\n", level, prefix_str,
-				(int)(2 * sizeof(void *)), ptr + i, linebuf);
-			break;
-		case DUMP_PREFIX_OFFSET:
-			printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
-			break;
-		default:
-			printk("%s%s%s\n", level, prefix_str, linebuf);
-			break;
-		}
-	}
-}
-
-#ifdef HAVE_I2C_SUPPORT
-struct i2c_client *
-_kc_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
-{
-	struct i2c_client	*client;
-	int			status;
-
-	client = kzalloc(sizeof *client, GFP_KERNEL);
-	if (!client)
-		return NULL;
-
-	client->adapter = adap;
-
-	client->dev.platform_data = info->platform_data;
-
-	client->flags = info->flags;
-	client->addr = info->addr;
-
-	strlcpy(client->name, info->type, sizeof(client->name));
-
-	/* Check for address business */
-	status = i2c_check_addr(adap, client->addr);
-	if (status)
-		goto out_err;
-
-	client->dev.parent = &client->adapter->dev;
-	client->dev.bus = &i2c_bus_type;
-
-	status = i2c_attach_client(client);
-	if (status)
-		goto out_err;
-
-	dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
-		client->name, dev_name(&client->dev));
-
-	return client;
-
-out_err:
-	dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
-		"(%d)\n", client->name, client->addr, status);
-	kfree(client);
-	return NULL;
-}
-#endif /* HAVE_I2C_SUPPORT */
-#endif /* < 2.6.22 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) )
-#ifdef NAPI
-struct net_device *napi_to_poll_dev(const struct napi_struct *napi)
-{
-	struct adapter_q_vector *q_vector = container_of(napi,
-	                                                struct adapter_q_vector,
-	                                                napi);
-	return &q_vector->poll_dev;
-}
-
-int __kc_adapter_clean(struct net_device *netdev, int *budget)
-{
-	int work_done;
-	int work_to_do = min(*budget, netdev->quota);
-	/* kcompat.h netif_napi_add puts napi struct in "fake netdev->priv" */
-	struct napi_struct *napi = netdev->priv;
-	work_done = napi->poll(napi, work_to_do);
-	*budget -= work_done;
-	netdev->quota -= work_done;
-	return (work_done >= work_to_do) ? 1 : 0;
-}
-#endif /* NAPI */
-#endif /* <= 2.6.24 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) )
-void _kc_pci_disable_link_state(struct pci_dev *pdev, int state)
-{
-	struct pci_dev *parent = pdev->bus->self;
-	u16 link_state;
-	int pos;
-
-	if (!parent)
-		return;
-
-	pos = pci_find_capability(parent, PCI_CAP_ID_EXP);
-	if (pos) {
-		pci_read_config_word(parent, pos + PCI_EXP_LNKCTL, &link_state);
-		link_state &= ~state;
-		pci_write_config_word(parent, pos + PCI_EXP_LNKCTL, link_state);
-	}
-}
-#endif /* < 2.6.26 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) )
-#ifdef HAVE_TX_MQ
-void _kc_netif_tx_stop_all_queues(struct net_device *netdev)
-{
-	struct adapter_struct *adapter = netdev_priv(netdev);
-	int i;
-
-	netif_stop_queue(netdev);
-	if (netif_is_multiqueue(netdev))
-		for (i = 0; i < adapter->num_tx_queues; i++)
-			netif_stop_subqueue(netdev, i);
-}
-void _kc_netif_tx_wake_all_queues(struct net_device *netdev)
-{
-	struct adapter_struct *adapter = netdev_priv(netdev);
-	int i;
-
-	netif_wake_queue(netdev);
-	if (netif_is_multiqueue(netdev))
-		for (i = 0; i < adapter->num_tx_queues; i++)
-			netif_wake_subqueue(netdev, i);
-}
-void _kc_netif_tx_start_all_queues(struct net_device *netdev)
-{
-	struct adapter_struct *adapter = netdev_priv(netdev);
-	int i;
-
-	netif_start_queue(netdev);
-	if (netif_is_multiqueue(netdev))
-		for (i = 0; i < adapter->num_tx_queues; i++)
-			netif_start_subqueue(netdev, i);
-}
-#endif /* HAVE_TX_MQ */
-
-#ifndef __WARN_printf
-void __kc_warn_slowpath(const char *file, int line, const char *fmt, ...)
-{
-	va_list args;
-
-	printk(KERN_WARNING "------------[ cut here ]------------\n");
-	printk(KERN_WARNING "WARNING: at %s:%d %s()\n", file, line);
-	va_start(args, fmt);
-	vprintk(fmt, args);
-	va_end(args);
-
-	dump_stack();
-}
-#endif /* __WARN_printf */
-#endif /* < 2.6.27 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) )
-
-int
-_kc_pci_prepare_to_sleep(struct pci_dev *dev)
-{
-	pci_power_t target_state;
-	int error;
-
-	target_state = pci_choose_state(dev, PMSG_SUSPEND);
-
-	pci_enable_wake(dev, target_state, true);
-
-	error = pci_set_power_state(dev, target_state);
-
-	if (error)
-		pci_enable_wake(dev, target_state, false);
-
-	return error;
-}
-
-int
-_kc_pci_wake_from_d3(struct pci_dev *dev, bool enable)
-{
-	int err;
-
-	err = pci_enable_wake(dev, PCI_D3cold, enable);
-	if (err)
-		goto out;
-
-	err = pci_enable_wake(dev, PCI_D3hot, enable);
-
-out:
-	return err;
-}
-#endif /* < 2.6.28 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) )
-static void __kc_pci_set_master(struct pci_dev *pdev, bool enable)
-{
-	u16 old_cmd, cmd;
-
-	pci_read_config_word(pdev, PCI_COMMAND, &old_cmd);
-	if (enable)
-		cmd = old_cmd | PCI_COMMAND_MASTER;
-	else
-		cmd = old_cmd & ~PCI_COMMAND_MASTER;
-	if (cmd != old_cmd) {
-		dev_dbg(pci_dev_to_dev(pdev), "%s bus mastering\n",
-			enable ? "enabling" : "disabling");
-		pci_write_config_word(pdev, PCI_COMMAND, cmd);
-	}
-#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) )
-	pdev->is_busmaster = enable;
-#endif
-}
-
-void _kc_pci_clear_master(struct pci_dev *dev)
-{
-	__kc_pci_set_master(dev, false);
-}
-#endif /* < 2.6.29 */
-
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) )
-#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6,0))
-int _kc_pci_num_vf(struct pci_dev *dev)
-{
-	int num_vf = 0;
-#ifdef CONFIG_PCI_IOV
-	struct pci_dev *vfdev;
-
-	/* loop through all ethernet devices starting at PF dev */
-	vfdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, NULL);
-	while (vfdev) {
-		if (vfdev->is_virtfn && vfdev->physfn == dev)
-			num_vf++;
-
-		vfdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, vfdev);
-	}
-
-#endif
-	return num_vf;
-}
-#endif /* RHEL_RELEASE_CODE */
-#endif /* < 2.6.34 */
-
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) )
-#ifdef HAVE_TX_MQ
-#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)))
-#ifndef CONFIG_NETDEVICES_MULTIQUEUE
-void _kc_netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
-{
-	unsigned int real_num = dev->real_num_tx_queues;
-	struct Qdisc *qdisc;
-	int i;
-
-	if (unlikely(txq > dev->num_tx_queues))
-		;
-	else if (txq > real_num)
-		dev->real_num_tx_queues = txq;
-	else if ( txq < real_num) {
-		dev->real_num_tx_queues = txq;
-		for (i = txq; i < dev->num_tx_queues; i++) {
-			qdisc = netdev_get_tx_queue(dev, i)->qdisc;
-			if (qdisc) {
-				spin_lock_bh(qdisc_lock(qdisc));
-				qdisc_reset(qdisc);
-				spin_unlock_bh(qdisc_lock(qdisc));
-			}
-		}
-	}
-}
-#endif /* CONFIG_NETDEVICES_MULTIQUEUE */
-#endif /* !(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,0)) */
-#endif /* HAVE_TX_MQ */
-
-ssize_t _kc_simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
-				   const void __user *from, size_t count)
-{
-        loff_t pos = *ppos;
-        size_t res;
-
-        if (pos < 0)
-                return -EINVAL;
-        if (pos >= available || !count)
-                return 0;
-        if (count > available - pos)
-                count = available - pos;
-        res = copy_from_user(to + pos, from, count);
-        if (res == count)
-                return -EFAULT;
-        count -= res;
-        *ppos = pos + count;
-        return count;
-}
-
-#endif /* < 2.6.35 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) )
-static const u32 _kc_flags_dup_features =
-	(ETH_FLAG_LRO | ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH);
-
-u32 _kc_ethtool_op_get_flags(struct net_device *dev)
-{
-	return dev->features & _kc_flags_dup_features;
-}
-
-int _kc_ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
-{
-	if (data & ~supported)
-		return -EINVAL;
-
-	dev->features = ((dev->features & ~_kc_flags_dup_features) |
-			 (data & _kc_flags_dup_features));
-	return 0;
-}
-#endif /* < 2.6.36 */
-
-/******************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) )
-#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,0)))
-
-
-
-#endif /* !(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(6,0)) */
-#endif /* < 2.6.39 */
-
-/******************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) )
-void _kc_skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
-			 int off, int size, unsigned int truesize)
-{
-	skb_fill_page_desc(skb, i, page, off, size);
-	skb->len += size;
-	skb->data_len += size;
-	skb->truesize += truesize;
-}
-
-int _kc_simple_open(struct inode *inode, struct file *file)
-{
-        if (inode->i_private)
-                file->private_data = inode->i_private;
-
-        return 0;
-}
-
-#endif /* < 3.4.0 */
-
-/******************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) )
-#if !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0)) && \
-    !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,5))
-static inline int __kc_pcie_cap_version(struct pci_dev *dev)
-{
-	int pos;
-	u16 reg16;
-
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (!pos)
-		return 0;
-	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
-	return reg16 & PCI_EXP_FLAGS_VERS;
-}
-
-static inline bool __kc_pcie_cap_has_devctl(const struct pci_dev __always_unused *dev)
-{
-	return true;
-}
-
-static inline bool __kc_pcie_cap_has_lnkctl(struct pci_dev *dev)
-{
-	int type = pci_pcie_type(dev);
-
-	return __kc_pcie_cap_version(dev) > 1 ||
-	       type == PCI_EXP_TYPE_ROOT_PORT ||
-	       type == PCI_EXP_TYPE_ENDPOINT ||
-	       type == PCI_EXP_TYPE_LEG_END;
-}
-
-static inline bool __kc_pcie_cap_has_sltctl(struct pci_dev *dev)
-{
-	int type = pci_pcie_type(dev);
-	int pos;
-	u16 pcie_flags_reg;
-
-	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
-	if (!pos)
-		return 0;
-	pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &pcie_flags_reg);
-
-	return __kc_pcie_cap_version(dev) > 1 ||
-	       type == PCI_EXP_TYPE_ROOT_PORT ||
-	       (type == PCI_EXP_TYPE_DOWNSTREAM &&
-		pcie_flags_reg & PCI_EXP_FLAGS_SLOT);
-}
-
-static inline bool __kc_pcie_cap_has_rtctl(struct pci_dev *dev)
-{
-	int type = pci_pcie_type(dev);
-
-	return __kc_pcie_cap_version(dev) > 1 ||
-	       type == PCI_EXP_TYPE_ROOT_PORT ||
-	       type == PCI_EXP_TYPE_RC_EC;
-}
-
-static bool __kc_pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
-{
-	if (!pci_is_pcie(dev))
-		return false;
-
-	switch (pos) {
-	case PCI_EXP_FLAGS_TYPE:
-		return true;
-	case PCI_EXP_DEVCAP:
-	case PCI_EXP_DEVCTL:
-	case PCI_EXP_DEVSTA:
-		return __kc_pcie_cap_has_devctl(dev);
-	case PCI_EXP_LNKCAP:
-	case PCI_EXP_LNKCTL:
-	case PCI_EXP_LNKSTA:
-		return __kc_pcie_cap_has_lnkctl(dev);
-	case PCI_EXP_SLTCAP:
-	case PCI_EXP_SLTCTL:
-	case PCI_EXP_SLTSTA:
-		return __kc_pcie_cap_has_sltctl(dev);
-	case PCI_EXP_RTCTL:
-	case PCI_EXP_RTCAP:
-	case PCI_EXP_RTSTA:
-		return __kc_pcie_cap_has_rtctl(dev);
-	case PCI_EXP_DEVCAP2:
-	case PCI_EXP_DEVCTL2:
-	case PCI_EXP_LNKCAP2:
-	case PCI_EXP_LNKCTL2:
-	case PCI_EXP_LNKSTA2:
-		return __kc_pcie_cap_version(dev) > 1;
-	default:
-		return false;
-	}
-}
-
-/*
- * Note that these accessor functions are only for the "PCI Express
- * Capability" (see PCIe spec r3.0, sec 7.8).  They do not apply to the
- * other "PCI Express Extended Capabilities" (AER, VC, ACS, MFVC, etc.)
- */
-int __kc_pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
-{
-	int ret;
-
-	*val = 0;
-	if (pos & 1)
-		return -EINVAL;
-
-	if (__kc_pcie_capability_reg_implemented(dev, pos)) {
-		ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
-		/*
-		 * Reset *val to 0 if pci_read_config_word() fails, it may
-		 * have been written as 0xFFFF if hardware error happens
-		 * during pci_read_config_word().
-		 */
-		if (ret)
-			*val = 0;
-		return ret;
-	}
-
-	/*
-	 * For Functions that do not implement the Slot Capabilities,
-	 * Slot Status, and Slot Control registers, these spaces must
-	 * be hardwired to 0b, with the exception of the Presence Detect
-	 * State bit in the Slot Status register of Downstream Ports,
-	 * which must be hardwired to 1b.  (PCIe Base Spec 3.0, sec 7.8)
-	 */
-	if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
-	    pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
-		*val = PCI_EXP_SLTSTA_PDS;
-	}
-
-	return 0;
-}
-
-int __kc_pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
-{
-	if (pos & 1)
-		return -EINVAL;
-
-	if (!__kc_pcie_capability_reg_implemented(dev, pos))
-		return 0;
-
-	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
-}
-
-int __kc_pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
-					    u16 clear, u16 set)
-{
-	int ret;
-	u16 val;
-
-	ret = __kc_pcie_capability_read_word(dev, pos, &val);
-	if (!ret) {
-		val &= ~clear;
-		val |= set;
-		ret = __kc_pcie_capability_write_word(dev, pos, val);
-	}
-
-	return ret;
-}
-#endif /* !(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(11,3,0)) && \
-          !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,5)) */
-#endif /* < 3.7.0 */
-
-/******************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) )
-#endif /* 3.9.0 */
-
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) )
-#ifdef CONFIG_PCI_IOV
-int __kc_pci_vfs_assigned(struct pci_dev *dev)
-{
-	unsigned int vfs_assigned = 0;
-#ifdef HAVE_PCI_DEV_FLAGS_ASSIGNED
-	int pos;
-	struct pci_dev *vfdev;
-	unsigned short dev_id;
-
-	/* only search if we are a PF */
-	if (!dev->is_physfn)
-		return 0;
-
-	/* find SR-IOV capability */
-	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
-	if (!pos)
-		return 0;
-
-	/*
-	 * determine the device ID for the VFs, the vendor ID will be the
-	 * same as the PF so there is no need to check for that one
-	 */
-	pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &dev_id);
-
-	/* loop through all the VFs to see if we own any that are assigned */
-	vfdev = pci_get_device(dev->vendor, dev_id, NULL);
-	while (vfdev) {
-		/*
-		 * It is considered assigned if it is a virtual function with
-		 * our dev as the physical function and the assigned bit is set
-		 */
-		if (vfdev->is_virtfn && (vfdev->physfn == dev) &&
-		    (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED))
-			vfs_assigned++;
-
-		vfdev = pci_get_device(dev->vendor, dev_id, vfdev);
-	}
-
-#endif /* HAVE_PCI_DEV_FLAGS_ASSIGNED */
-	return vfs_assigned;
-}
-
-#endif /* CONFIG_PCI_IOV */
-#endif /* 3.10.0 */
diff --git a/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat_ethtool.c b/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat_ethtool.c
deleted file mode 100644
index 126c582..0000000
--- a/lib/librte_eal/linuxapp/kni/ethtool/igb/kcompat_ethtool.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "LICENSE.GPL".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/*
- * net/core/ethtool.c - Ethtool ioctl handler
- * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
- *
- * This file is where we call all the ethtool_ops commands to get
- * the information ethtool needs.  We fall back to calling do_ioctl()
- * for drivers which haven't been converted to ethtool_ops yet.
- *
- * It's GPL, stupid.
- *
- * Modification by sfeldma@pobox.com to work as backward compat
- * solution for pre-ethtool_ops kernels.
- *	- copied struct ethtool_ops from ethtool.h
- *	- defined SET_ETHTOOL_OPS
- *	- put in some #ifndef NETIF_F_xxx wrappers
- *	- changes refs to dev->ethtool_ops to ethtool_ops
- *	- changed dev_ethtool to ethtool_ioctl
- *      - remove EXPORT_SYMBOL()s
- *      - added _kc_ prefix in built-in ethtool_op_xxx ops.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <asm/uaccess.h>
-
-#include "kcompat.h"
-
-#undef SUPPORTED_10000baseT_Full
-#define SUPPORTED_10000baseT_Full	(1 << 12)
-#undef ADVERTISED_10000baseT_Full
-#define ADVERTISED_10000baseT_Full	(1 << 12)
-#undef SPEED_10000
-#define SPEED_10000		10000
-
-#undef ethtool_ops
-#define ethtool_ops _kc_ethtool_ops
-
-struct _kc_ethtool_ops {
-	int  (*get_settings)(struct net_device *, struct ethtool_cmd *);
-	int  (*set_settings)(struct net_device *, struct ethtool_cmd *);
-	void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
-	int  (*get_regs_len)(struct net_device *);
-	void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
-	void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
-	int  (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
-	u32  (*get_msglevel)(struct net_device *);
-	void (*set_msglevel)(struct net_device *, u32);
-	int  (*nway_reset)(struct net_device *);
-	u32  (*get_link)(struct net_device *);
-	int  (*get_eeprom_len)(struct net_device *);
-	int  (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
-	int  (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
-	int  (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
-	int  (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
-	void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
-	int  (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
-	void (*get_pauseparam)(struct net_device *,
-	                       struct ethtool_pauseparam*);
-	int  (*set_pauseparam)(struct net_device *,
-	                       struct ethtool_pauseparam*);
-	u32  (*get_rx_csum)(struct net_device *);
-	int  (*set_rx_csum)(struct net_device *, u32);
-	u32  (*get_tx_csum)(struct net_device *);
-	int  (*set_tx_csum)(struct net_device *, u32);
-	u32  (*get_sg)(struct net_device *);
-	int  (*set_sg)(struct net_device *, u32);
-	u32  (*get_tso)(struct net_device *);
-	int  (*set_tso)(struct net_device *, u32);
-	int  (*self_test_count)(struct net_device *);
-	void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
-	void (*get_strings)(struct net_device *, u32 stringset, u8 *);
-	int  (*phys_id)(struct net_device *, u32);
-	int  (*get_stats_count)(struct net_device *);
-	void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *,
-	                          u64 *);
-} *ethtool_ops = NULL;
-
-#undef SET_ETHTOOL_OPS
-#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops))
-
-/*
- * Some useful ethtool_ops methods that are device independent. If we find that
- * all drivers want to do the same thing here, we can turn these into dev_()
- * function calls.
- */
-
-#undef ethtool_op_get_link
-#define ethtool_op_get_link _kc_ethtool_op_get_link
-u32 _kc_ethtool_op_get_link(struct net_device *dev)
-{
-	return netif_carrier_ok(dev) ? 1 : 0;
-}
-
-#undef ethtool_op_get_tx_csum
-#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum
-u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev)
-{
-#ifdef NETIF_F_IP_CSUM
-	return (dev->features & NETIF_F_IP_CSUM) != 0;
-#else
-	return 0;
-#endif
-}
-
-#undef ethtool_op_set_tx_csum
-#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum
-int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
-#ifdef NETIF_F_IP_CSUM
-	if (data)
-#ifdef NETIF_F_IPV6_CSUM
-		dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-	else
-		dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-#else
-		dev->features |= NETIF_F_IP_CSUM;
-	else
-		dev->features &= ~NETIF_F_IP_CSUM;
-#endif
-#endif
-
-	return 0;
-}
-
-#undef ethtool_op_get_sg
-#define ethtool_op_get_sg _kc_ethtool_op_get_sg
-u32 _kc_ethtool_op_get_sg(struct net_device *dev)
-{
-#ifdef NETIF_F_SG
-	return (dev->features & NETIF_F_SG) != 0;
-#else
-	return 0;
-#endif
-}
-
-#undef ethtool_op_set_sg
-#define ethtool_op_set_sg _kc_ethtool_op_set_sg
-int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data)
-{
-#ifdef NETIF_F_SG
-	if (data)
-		dev->features |= NETIF_F_SG;
-	else
-		dev->features &= ~NETIF_F_SG;
-#endif
-
-	return 0;
-}
-
-#undef ethtool_op_get_tso
-#define ethtool_op_get_tso _kc_ethtool_op_get_tso
-u32 _kc_ethtool_op_get_tso(struct net_device *dev)
-{
-#ifdef NETIF_F_TSO
-	return (dev->features & NETIF_F_TSO) != 0;
-#else
-	return 0;
-#endif
-}
-
-#undef ethtool_op_set_tso
-#define ethtool_op_set_tso _kc_ethtool_op_set_tso
-int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-#ifdef NETIF_F_TSO
-	if (data)
-		dev->features |= NETIF_F_TSO;
-	else
-		dev->features &= ~NETIF_F_TSO;
-#endif
-
-	return 0;
-}
-
-/* Handlers for each ethtool command */
-
-static int ethtool_get_settings(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_cmd cmd = { ETHTOOL_GSET };
-	int err;
-
-	if (!ethtool_ops->get_settings)
-		return -EOPNOTSUPP;
-
-	err = ethtool_ops->get_settings(dev, &cmd);
-	if (err < 0)
-		return err;
-
-	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_settings(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_cmd cmd;
-
-	if (!ethtool_ops->set_settings)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
-		return -EFAULT;
-
-	return ethtool_ops->set_settings(dev, &cmd);
-}
-
-static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_drvinfo info;
-	struct ethtool_ops *ops = ethtool_ops;
-
-	if (!ops->get_drvinfo)
-		return -EOPNOTSUPP;
-
-	memset(&info, 0, sizeof(info));
-	info.cmd = ETHTOOL_GDRVINFO;
-	ops->get_drvinfo(dev, &info);
-
-	if (ops->self_test_count)
-		info.testinfo_len = ops->self_test_count(dev);
-	if (ops->get_stats_count)
-		info.n_stats = ops->get_stats_count(dev);
-	if (ops->get_regs_len)
-		info.regdump_len = ops->get_regs_len(dev);
-	if (ops->get_eeprom_len)
-		info.eedump_len = ops->get_eeprom_len(dev);
-
-	if (copy_to_user(useraddr, &info, sizeof(info)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_get_regs(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_regs regs;
-	struct ethtool_ops *ops = ethtool_ops;
-	void *regbuf;
-	int reglen, ret;
-
-	if (!ops->get_regs || !ops->get_regs_len)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&regs, useraddr, sizeof(regs)))
-		return -EFAULT;
-
-	reglen = ops->get_regs_len(dev);
-	if (regs.len > reglen)
-		regs.len = reglen;
-
-	regbuf = kmalloc(reglen, GFP_USER);
-	if (!regbuf)
-		return -ENOMEM;
-
-	ops->get_regs(dev, &regs, regbuf);
-
-	ret = -EFAULT;
-	if (copy_to_user(useraddr, &regs, sizeof(regs)))
-		goto out;
-	useraddr += offsetof(struct ethtool_regs, data);
-	if (copy_to_user(useraddr, regbuf, reglen))
-		goto out;
-	ret = 0;
-
-out:
-	kfree(regbuf);
-	return ret;
-}
-
-static int ethtool_get_wol(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
-
-	if (!ethtool_ops->get_wol)
-		return -EOPNOTSUPP;
-
-	ethtool_ops->get_wol(dev, &wol);
-
-	if (copy_to_user(useraddr, &wol, sizeof(wol)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_wol(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_wolinfo wol;
-
-	if (!ethtool_ops->set_wol)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&wol, useraddr, sizeof(wol)))
-		return -EFAULT;
-
-	return ethtool_ops->set_wol(dev, &wol);
-}
-
-static int ethtool_get_msglevel(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-
-	if (!ethtool_ops->get_msglevel)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_msglevel(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_msglevel(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata;
-
-	if (!ethtool_ops->set_msglevel)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-		return -EFAULT;
-
-	ethtool_ops->set_msglevel(dev, edata.data);
-	return 0;
-}
-
-static int ethtool_nway_reset(struct net_device *dev)
-{
-	if (!ethtool_ops->nway_reset)
-		return -EOPNOTSUPP;
-
-	return ethtool_ops->nway_reset(dev);
-}
-
-static int ethtool_get_link(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GLINK };
-
-	if (!ethtool_ops->get_link)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_link(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_eeprom eeprom;
-	struct ethtool_ops *ops = ethtool_ops;
-	u8 *data;
-	int ret;
-
-	if (!ops->get_eeprom || !ops->get_eeprom_len)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
-		return -EFAULT;
-
-	/* Check for wrap and zero */
-	if (eeprom.offset + eeprom.len <= eeprom.offset)
-		return -EINVAL;
-
-	/* Check for exceeding total eeprom len */
-	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
-		return -EINVAL;
-
-	data = kmalloc(eeprom.len, GFP_USER);
-	if (!data)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
-		goto out;
-
-	ret = ops->get_eeprom(dev, &eeprom, data);
-	if (ret)
-		goto out;
-
-	ret = -EFAULT;
-	if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
-		goto out;
-	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
-		goto out;
-	ret = 0;
-
-out:
-	kfree(data);
-	return ret;
-}
-
-static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_eeprom eeprom;
-	struct ethtool_ops *ops = ethtool_ops;
-	u8 *data;
-	int ret;
-
-	if (!ops->set_eeprom || !ops->get_eeprom_len)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
-		return -EFAULT;
-
-	/* Check for wrap and zero */
-	if (eeprom.offset + eeprom.len <= eeprom.offset)
-		return -EINVAL;
-
-	/* Check for exceeding total eeprom len */
-	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
-		return -EINVAL;
-
-	data = kmalloc(eeprom.len, GFP_USER);
-	if (!data)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
-		goto out;
-
-	ret = ops->set_eeprom(dev, &eeprom, data);
-	if (ret)
-		goto out;
-
-	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
-		ret = -EFAULT;
-
-out:
-	kfree(data);
-	return ret;
-}
-
-static int ethtool_get_coalesce(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
-
-	if (!ethtool_ops->get_coalesce)
-		return -EOPNOTSUPP;
-
-	ethtool_ops->get_coalesce(dev, &coalesce);
-
-	if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_coalesce(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_coalesce coalesce;
-
-	if (!ethtool_ops->get_coalesce)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
-		return -EFAULT;
-
-	return ethtool_ops->set_coalesce(dev, &coalesce);
-}
-
-static int ethtool_get_ringparam(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
-
-	if (!ethtool_ops->get_ringparam)
-		return -EOPNOTSUPP;
-
-	ethtool_ops->get_ringparam(dev, &ringparam);
-
-	if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_ringparam ringparam;
-
-	if (!ethtool_ops->get_ringparam)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
-		return -EFAULT;
-
-	return ethtool_ops->set_ringparam(dev, &ringparam);
-}
-
-static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
-
-	if (!ethtool_ops->get_pauseparam)
-		return -EOPNOTSUPP;
-
-	ethtool_ops->get_pauseparam(dev, &pauseparam);
-
-	if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_pauseparam pauseparam;
-
-	if (!ethtool_ops->get_pauseparam)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
-		return -EFAULT;
-
-	return ethtool_ops->set_pauseparam(dev, &pauseparam);
-}
-
-static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GRXCSUM };
-
-	if (!ethtool_ops->get_rx_csum)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_rx_csum(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata;
-
-	if (!ethtool_ops->set_rx_csum)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-		return -EFAULT;
-
-	ethtool_ops->set_rx_csum(dev, edata.data);
-	return 0;
-}
-
-static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GTXCSUM };
-
-	if (!ethtool_ops->get_tx_csum)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_tx_csum(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata;
-
-	if (!ethtool_ops->set_tx_csum)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-		return -EFAULT;
-
-	return ethtool_ops->set_tx_csum(dev, edata.data);
-}
-
-static int ethtool_get_sg(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GSG };
-
-	if (!ethtool_ops->get_sg)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_sg(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_sg(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata;
-
-	if (!ethtool_ops->set_sg)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-		return -EFAULT;
-
-	return ethtool_ops->set_sg(dev, edata.data);
-}
-
-static int ethtool_get_tso(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata = { ETHTOOL_GTSO };
-
-	if (!ethtool_ops->get_tso)
-		return -EOPNOTSUPP;
-
-	edata.data = ethtool_ops->get_tso(dev);
-
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-		return -EFAULT;
-	return 0;
-}
-
-static int ethtool_set_tso(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_value edata;
-
-	if (!ethtool_ops->set_tso)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-		return -EFAULT;
-
-	return ethtool_ops->set_tso(dev, edata.data);
-}
-
-static int ethtool_self_test(struct net_device *dev, char *useraddr)
-{
-	struct ethtool_test test;
-	struct ethtool_ops *ops = ethtool_ops;
-	u64 *data;
-	int ret;
-
-	if (!ops->self_test || !ops->self_test_count)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&test, useraddr, sizeof(test)))
-		return -EFAULT;
-
-	test.len = ops->self_test_count(dev);
-	data = kmalloc(test.len * sizeof(u64), GFP_USER);
-	if (!data)
-		return -ENOMEM;
-
-	ops->self_test(dev, &test, data);
-
-	ret = -EFAULT;
-	if (copy_to_user(useraddr, &test, sizeof(test)))
-		goto out;
-	useraddr += sizeof(test);
-	if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
-		goto out;
-	ret = 0;
-
-out:
-	kfree(data);
-	return ret;
-}
-
-static int ethtool_get_strings(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_gstrings gstrings;
-	struct ethtool_ops *ops = ethtool_ops;
-	u8 *data;
-	int ret;
-
-	if (!ops->get_strings)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
-		return -EFAULT;
-
-	switch (gstrings.string_set) {
-	case ETH_SS_TEST:
-		if (!ops->self_test_count)
-			return -EOPNOTSUPP;
-		gstrings.len = ops->self_test_count(dev);
-		break;
-	case ETH_SS_STATS:
-		if (!ops->get_stats_count)
-			return -EOPNOTSUPP;
-		gstrings.len = ops->get_stats_count(dev);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
-	if (!data)
-		return -ENOMEM;
-
-	ops->get_strings(dev, gstrings.string_set, data);
-
-	ret = -EFAULT;
-	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
-		goto out;
-	useraddr += sizeof(gstrings);
-	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
-		goto out;
-	ret = 0;
-
-out:
-	kfree(data);
-	return ret;
-}
-
-static int ethtool_phys_id(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_value id;
-
-	if (!ethtool_ops->phys_id)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&id, useraddr, sizeof(id)))
-		return -EFAULT;
-
-	return ethtool_ops->phys_id(dev, id.data);
-}
-
-static int ethtool_get_stats(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_stats stats;
-	struct ethtool_ops *ops = ethtool_ops;
-	u64 *data;
-	int ret;
-
-	if (!ops->get_ethtool_stats || !ops->get_stats_count)
-		return -EOPNOTSUPP;
-
-	if (copy_from_user(&stats, useraddr, sizeof(stats)))
-		return -EFAULT;
-
-	stats.n_stats = ops->get_stats_count(dev);
-	data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER);
-	if (!data)
-		return -ENOMEM;
-
-	ops->get_ethtool_stats(dev, &stats, data);
-
-	ret = -EFAULT;
-	if (copy_to_user(useraddr, &stats, sizeof(stats)))
-		goto out;
-	useraddr += sizeof(stats);
-	if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
-		goto out;
-	ret = 0;
-
-out:
-	kfree(data);
-	return ret;
-}
-
-/* The main entry point in this file.  Called from net/core/dev.c */
-
-#define ETHTOOL_OPS_COMPAT
-int ethtool_ioctl(struct ifreq *ifr)
-{
-	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
-	void *useraddr = (void *) ifr->ifr_data;
-	u32 ethcmd;
-
-	/*
-	 * XXX: This can be pushed down into the ethtool_* handlers that
-	 * need it.  Keep existing behavior for the moment.
-	 */
-	if (!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if (!dev || !netif_device_present(dev))
-		return -ENODEV;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GSET:
-		return ethtool_get_settings(dev, useraddr);
-	case ETHTOOL_SSET:
-		return ethtool_set_settings(dev, useraddr);
-	case ETHTOOL_GDRVINFO:
-		return ethtool_get_drvinfo(dev, useraddr);
-	case ETHTOOL_GREGS:
-		return ethtool_get_regs(dev, useraddr);
-	case ETHTOOL_GWOL:
-		return ethtool_get_wol(dev, useraddr);
-	case ETHTOOL_SWOL:
-		return ethtool_set_wol(dev, useraddr);
-	case ETHTOOL_GMSGLVL:
-		return ethtool_get_msglevel(dev, useraddr);
-	case ETHTOOL_SMSGLVL:
-		return ethtool_set_msglevel(dev, useraddr);
-	case ETHTOOL_NWAY_RST:
-		return ethtool_nway_reset(dev);
-	case ETHTOOL_GLINK:
-		return ethtool_get_link(dev, useraddr);
-	case ETHTOOL_GEEPROM:
-		return ethtool_get_eeprom(dev, useraddr);
-	case ETHTOOL_SEEPROM:
-		return ethtool_set_eeprom(dev, useraddr);
-	case ETHTOOL_GCOALESCE:
-		return ethtool_get_coalesce(dev, useraddr);
-	case ETHTOOL_SCOALESCE:
-		return ethtool_set_coalesce(dev, useraddr);
-	case ETHTOOL_GRINGPARAM:
-		return ethtool_get_ringparam(dev, useraddr);
-	case ETHTOOL_SRINGPARAM:
-		return ethtool_set_ringparam(dev, useraddr);
-	case ETHTOOL_GPAUSEPARAM:
-		return ethtool_get_pauseparam(dev, useraddr);
-	case ETHTOOL_SPAUSEPARAM:
-		return ethtool_set_pauseparam(dev, useraddr);
-	case ETHTOOL_GRXCSUM:
-		return ethtool_get_rx_csum(dev, useraddr);
-	case ETHTOOL_SRXCSUM:
-		return ethtool_set_rx_csum(dev, useraddr);
-	case ETHTOOL_GTXCSUM:
-		return ethtool_get_tx_csum(dev, useraddr);
-	case ETHTOOL_STXCSUM:
-		return ethtool_set_tx_csum(dev, useraddr);
-	case ETHTOOL_GSG:
-		return ethtool_get_sg(dev, useraddr);
-	case ETHTOOL_SSG:
-		return ethtool_set_sg(dev, useraddr);
-	case ETHTOOL_GTSO:
-		return ethtool_get_tso(dev, useraddr);
-	case ETHTOOL_STSO:
-		return ethtool_set_tso(dev, useraddr);
-	case ETHTOOL_TEST:
-		return ethtool_self_test(dev, useraddr);
-	case ETHTOOL_GSTRINGS:
-		return ethtool_get_strings(dev, useraddr);
-	case ETHTOOL_PHYS_ID:
-		return ethtool_phys_id(dev, useraddr);
-	case ETHTOOL_GSTATS:
-		return ethtool_get_stats(dev, useraddr);
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return -EOPNOTSUPP;
-}
-
-#define mii_if_info _kc_mii_if_info
-struct _kc_mii_if_info {
-	int phy_id;
-	int advertising;
-	int phy_id_mask;
-	int reg_num_mask;
-
-	unsigned int full_duplex : 1;	/* is full duplex? */
-	unsigned int force_media : 1;	/* is autoneg. disabled? */
-
-	struct net_device *dev;
-	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
-	void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
-};
-
-struct ethtool_cmd;
-struct mii_ioctl_data;
-
-#undef mii_link_ok
-#define mii_link_ok _kc_mii_link_ok
-#undef mii_nway_restart
-#define mii_nway_restart _kc_mii_nway_restart
-#undef mii_ethtool_gset
-#define mii_ethtool_gset _kc_mii_ethtool_gset
-#undef mii_ethtool_sset
-#define mii_ethtool_sset _kc_mii_ethtool_sset
-#undef mii_check_link
-#define mii_check_link _kc_mii_check_link
-extern int _kc_mii_link_ok (struct mii_if_info *mii);
-extern int _kc_mii_nway_restart (struct mii_if_info *mii);
-extern int _kc_mii_ethtool_gset(struct mii_if_info *mii,
-                                struct ethtool_cmd *ecmd);
-extern int _kc_mii_ethtool_sset(struct mii_if_info *mii,
-                                struct ethtool_cmd *ecmd);
-extern void _kc_mii_check_link (struct mii_if_info *mii);
-#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,4,6) )
-#undef generic_mii_ioctl
-#define generic_mii_ioctl _kc_generic_mii_ioctl
-extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
-                                 struct mii_ioctl_data *mii_data, int cmd,
-                                 unsigned int *duplex_changed);
-#endif /* > 2.4.6 */
-
-
-struct _kc_pci_dev_ext {
-	struct pci_dev *dev;
-	void *pci_drvdata;
-	struct pci_driver *driver;
-};
-
-struct _kc_net_dev_ext {
-	struct net_device *dev;
-	unsigned int carrier;
-};
-
-
-/**************************************/
-/* mii support */
-
-int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
-{
-	struct net_device *dev = mii->dev;
-	u32 advert, bmcr, lpa, nego;
-
-	ecmd->supported =
-	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
-	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
-	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
-
-	/* only supports twisted-pair */
-	ecmd->port = PORT_MII;
-
-	/* only supports internal transceiver */
-	ecmd->transceiver = XCVR_INTERNAL;
-
-	/* this isn't fully supported at higher layers */
-	ecmd->phy_address = mii->phy_id;
-
-	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
-	advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
-	if (advert & ADVERTISE_10HALF)
-		ecmd->advertising |= ADVERTISED_10baseT_Half;
-	if (advert & ADVERTISE_10FULL)
-		ecmd->advertising |= ADVERTISED_10baseT_Full;
-	if (advert & ADVERTISE_100HALF)
-		ecmd->advertising |= ADVERTISED_100baseT_Half;
-	if (advert & ADVERTISE_100FULL)
-		ecmd->advertising |= ADVERTISED_100baseT_Full;
-
-	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
-	lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
-	if (bmcr & BMCR_ANENABLE) {
-		ecmd->advertising |= ADVERTISED_Autoneg;
-		ecmd->autoneg = AUTONEG_ENABLE;
-
-		nego = mii_nway_result(advert & lpa);
-		if (nego == LPA_100FULL || nego == LPA_100HALF)
-			ecmd->speed = SPEED_100;
-		else
-			ecmd->speed = SPEED_10;
-		if (nego == LPA_100FULL || nego == LPA_10FULL) {
-			ecmd->duplex = DUPLEX_FULL;
-			mii->full_duplex = 1;
-		} else {
-			ecmd->duplex = DUPLEX_HALF;
-			mii->full_duplex = 0;
-		}
-	} else {
-		ecmd->autoneg = AUTONEG_DISABLE;
-
-		ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
-		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-	}
-
-	/* ignore maxtxpkt, maxrxpkt for now */
-
-	return 0;
-}
-
-int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
-{
-	struct net_device *dev = mii->dev;
-
-	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
-		return -EINVAL;
-	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
-		return -EINVAL;
-	if (ecmd->port != PORT_MII)
-		return -EINVAL;
-	if (ecmd->transceiver != XCVR_INTERNAL)
-		return -EINVAL;
-	if (ecmd->phy_address != mii->phy_id)
-		return -EINVAL;
-	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
-		return -EINVAL;
-
-	/* ignore supported, maxtxpkt, maxrxpkt */
-
-	if (ecmd->autoneg == AUTONEG_ENABLE) {
-		u32 bmcr, advert, tmp;
-
-		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
-					  ADVERTISED_10baseT_Full |
-					  ADVERTISED_100baseT_Half |
-					  ADVERTISED_100baseT_Full)) == 0)
-			return -EINVAL;
-
-		/* advertise only what has been requested */
-		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
-		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
-		if (ADVERTISED_10baseT_Half)
-			tmp |= ADVERTISE_10HALF;
-		if (ADVERTISED_10baseT_Full)
-			tmp |= ADVERTISE_10FULL;
-		if (ADVERTISED_100baseT_Half)
-			tmp |= ADVERTISE_100HALF;
-		if (ADVERTISED_100baseT_Full)
-			tmp |= ADVERTISE_100FULL;
-		if (advert != tmp) {
-			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
-			mii->advertising = tmp;
-		}
-
-		/* turn on autonegotiation, and force a renegotiate */
-		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
-		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
-		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
-
-		mii->force_media = 0;
-	} else {
-		u32 bmcr, tmp;
-
-		/* turn off auto negotiation, set speed and duplexity */
-		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
-		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
-		if (ecmd->speed == SPEED_100)
-			tmp |= BMCR_SPEED100;
-		if (ecmd->duplex == DUPLEX_FULL) {
-			tmp |= BMCR_FULLDPLX;
-			mii->full_duplex = 1;
-		} else
-			mii->full_duplex = 0;
-		if (bmcr != tmp)
-			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
-
-		mii->force_media = 1;
-	}
-	return 0;
-}
-
-int _kc_mii_link_ok (struct mii_if_info *mii)
-{
-	/* first, a dummy read, needed to latch some MII phys */
-	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
-	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
-		return 1;
-	return 0;
-}
-
-int _kc_mii_nway_restart (struct mii_if_info *mii)
-{
-	int bmcr;
-	int r = -EINVAL;
-
-	/* if autoneg is off, it's an error */
-	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
-
-	if (bmcr & BMCR_ANENABLE) {
-		bmcr |= BMCR_ANRESTART;
-		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
-		r = 0;
-	}
-
-	return r;
-}
-
-void _kc_mii_check_link (struct mii_if_info *mii)
-{
-	int cur_link = mii_link_ok(mii);
-	int prev_link = netif_carrier_ok(mii->dev);
-
-	if (cur_link && !prev_link)
-		netif_carrier_on(mii->dev);
-	else if (prev_link && !cur_link)
-		netif_carrier_off(mii->dev);
-}
-
-#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,4,6) )
-int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
-                          struct mii_ioctl_data *mii_data, int cmd,
-                          unsigned int *duplex_chg_out)
-{
-	int rc = 0;
-	unsigned int duplex_changed = 0;
-
-	if (duplex_chg_out)
-		*duplex_chg_out = 0;
-
-	mii_data->phy_id &= mii_if->phy_id_mask;
-	mii_data->reg_num &= mii_if->reg_num_mask;
-
-	switch(cmd) {
-	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
-	case SIOCGMIIPHY:
-		mii_data->phy_id = mii_if->phy_id;
-		/* fall through */
-
-	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
-	case SIOCGMIIREG:
-		mii_data->val_out =
-			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
-					  mii_data->reg_num);
-		break;
-
-	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
-	case SIOCSMIIREG: {
-		u16 val = mii_data->val_in;
-
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-
-		if (mii_data->phy_id == mii_if->phy_id) {
-			switch(mii_data->reg_num) {
-			case MII_BMCR: {
-				unsigned int new_duplex = 0;
-				if (val & (BMCR_RESET|BMCR_ANENABLE))
-					mii_if->force_media = 0;
-				else
-					mii_if->force_media = 1;
-				if (mii_if->force_media &&
-				    (val & BMCR_FULLDPLX))
-					new_duplex = 1;
-				if (mii_if->full_duplex != new_duplex) {
-					duplex_changed = 1;
-					mii_if->full_duplex = new_duplex;
-				}
-				break;
-			}
-			case MII_ADVERTISE:
-				mii_if->advertising = val;
-				break;
-			default:
-				/* do nothing */
-				break;
-			}
-		}
-
-		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
-				   mii_data->reg_num, val);
-		break;
-	}
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
-		*duplex_chg_out = 1;
-
-	return rc;
-}
-#endif /* > 2.4.6 */
diff --git a/lib/librte_eal/linuxapp/kni/ethtool/ixgbe/ixgbe_sriov.h b/lib/librte_eal/linuxapp/kni/ethtool/ixgbe/ixgbe_sriov.h
deleted file mode 100644
index 5de0b31..0000000
--- a/lib/librte_eal/linuxapp/kni/ethtool/ixgbe/ixgbe_sriov.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*******************************************************************************
-
-  Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "LICENSE.GPL".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-
-#ifndef _IXGBE_SRIOV_H_
-#define _IXGBE_SRIOV_H_
-
-int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
-			    int entries, u16 *hash_list, u32 vf);
-void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter);
-int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf);
-void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe);
-void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf);
-void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf);
-void ixgbe_msg_task(struct ixgbe_adapter *adapter);
-int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
-		     int vf, unsigned char *mac_addr);
-void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
-void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
-#ifdef IFLA_VF_MAX
-int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
-int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
-			  u8 qos);
-int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
-#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
-int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
-#endif
-int ixgbe_ndo_get_vf_config(struct net_device *netdev,
-			    int vf, struct ifla_vf_info *ivi);
-#endif
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
-#ifdef CONFIG_PCI_IOV
-int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter);
-#endif
-int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter);
-#ifdef IFLA_VF_MAX
-void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
-#endif /* IFLA_VF_MAX */
-void ixgbe_dump_registers(struct ixgbe_adapter *adapter);
-
-/*
- * These are defined in ixgbe_type.h on behalf of the VF driver
- * but we need them here unwrapped for the PF driver.
- */
-#define IXGBE_DEV_ID_82599_VF			0x10ED
-#define IXGBE_DEV_ID_X540_VF			0x1515
-
-#endif /* _IXGBE_SRIOV_H_ */
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v4 0/6] add Tx preparation
From: Ananyev, Konstantin @ 2016-09-30  9:55 UTC (permalink / raw)
  To: Kulasek, TomaszX, dev@dpdk.org
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>



> 
> As discussed in that thread:
> 
> http://dpdk.org/ml/archives/dev/2015-September/023603.html
> 
> Different NIC models depending on HW offload requested might impose different requirements on packets to be TX-ed in terms of:
> 
>  - Max number of fragments per packet allowed
>  - Max number of fragments per TSO segments
>  - The way pseudo-header checksum should be pre-calculated
>  - L3/L4 header fields filling
>  - etc.
> 
> 
> MOTIVATION:
> -----------
> 
> 1) Some work cannot (and didn't should) be done in rte_eth_tx_burst.
>    However, this work is sometimes required, and now, it's an
>    application issue.
> 
> 2) Different hardware may have different requirements for TX offloads,
>    other subset can be supported and so on.
> 
> 3) Some parameters (e.g. number of segments in ixgbe driver) may hung
>    device. These parameters may be vary for different devices.
> 
>    For example i40e HW allows 8 fragments per packet, but that is after
>    TSO segmentation. While ixgbe has a 38-fragment pre-TSO limit.
> 
> 4) Fields in packet may require different initialization (like e.g. will
>    require pseudo-header checksum precalculation, sometimes in a
>    different way depending on packet type, and so on). Now application
>    needs to care about it.
> 
> 5) Using additional API (rte_eth_tx_prep) before rte_eth_tx_burst let to
>    prepare packet burst in acceptable form for specific device.
> 
> 6) Some additional checks may be done in debug mode keeping tx_burst
>    implementation clean.
> 
> 
> PROPOSAL:
> ---------
> 
> To help user to deal with all these varieties we propose to:
> 
> 1) Introduce rte_eth_tx_prep() function to do necessary preparations of
>    packet burst to be safely transmitted on device for desired HW
>    offloads (set/reset checksum field according to the hardware
>    requirements) and check HW constraints (number of segments per
>    packet, etc).
> 
>    While the limitations and requirements may differ for devices, it
>    requires to extend rte_eth_dev structure with new function pointer
>    "tx_pkt_prep" which can be implemented in the driver to prepare and
>    verify packets, in devices specific way, before burst, what should to
>    prevent application to send malformed packets.
> 
> 2) Also new fields will be introduced in rte_eth_desc_lim:
>    nb_seg_max and nb_mtu_seg_max, providing an information about max
>    segments in TSO and non-TSO packets acceptable by device.
> 
>    This information is useful for application to not create/limit
>    malicious packet.
> 
> 
> APPLICATION (CASE OF USE):
> --------------------------
> 
> 1) Application should to initialize burst of packets to send, set
>    required tx offload flags and required fields, like l2_len, l3_len,
>    l4_len, and tso_segsz
> 
> 2) Application passes burst to the rte_eth_tx_prep to check conditions
>    required to send packets through the NIC.
> 
> 3) The result of rte_eth_tx_prep can be used to send valid packets
>    and/or restore invalid if function fails.
> 
> e.g.
> 
> 	for (i = 0; i < nb_pkts; i++) {
> 
> 		/* initialize or process packet */
> 
> 		bufs[i]->tso_segsz = 800;
> 		bufs[i]->ol_flags = PKT_TX_TCP_SEG | PKT_TX_IPV4
> 				| PKT_TX_IP_CKSUM;
> 		bufs[i]->l2_len = sizeof(struct ether_hdr);
> 		bufs[i]->l3_len = sizeof(struct ipv4_hdr);
> 		bufs[i]->l4_len = sizeof(struct tcp_hdr);
> 	}
> 
> 	/* Prepare burst of TX packets */
> 	nb_prep = rte_eth_tx_prep(port, 0, bufs, nb_pkts);
> 
> 	if (nb_prep < nb_pkts) {
> 		printf("tx_prep failed\n");
> 
> 		/* nb_prep indicates here first invalid packet. rte_eth_tx_prep
> 		 * can be used on remaining packets to find another ones.
> 		 */
> 
> 	}
> 
> 	/* Send burst of TX packets */
> 	nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_prep);
> 
> 	/* Free any unsent packets. */
> 
> v4 changes:
>  - tx_prep is now set to default behavior (NULL) for simple/vector path
>    in fm10k, i40e and ixgbe drivers to increase performance, when
>    Tx offloads are not intentionally available
> 
> v3 changes:
>  - reworked csum testpmd engine instead adding new one,
>  - fixed checksum initialization procedure to include also outer
>    checksum offloads,
>  - some minor formattings and optimalizations
> 
> v2 changes:
>  - rte_eth_tx_prep() returns number of packets when device doesn't
>    support tx_prep functionality,
>  - introduced CONFIG_RTE_ETHDEV_TX_PREP allowing to turn off tx_prep
> 
> 
> Tomasz Kulasek (6):
>   ethdev: add Tx preparation
>   e1000: add Tx preparation
>   fm10k: add Tx preparation
>   i40e: add Tx preparation
>   ixgbe: add Tx preparation
>   testpmd: use Tx preparation in csum engine
> 
>  app/test-pmd/csumonly.c          |   97 +++++++++++++++------------
>  config/common_base               |    1 +
>  drivers/net/e1000/e1000_ethdev.h |   11 ++++
>  drivers/net/e1000/em_ethdev.c    |    5 +-
>  drivers/net/e1000/em_rxtx.c      |   48 +++++++++++++-
>  drivers/net/e1000/igb_ethdev.c   |    4 ++
>  drivers/net/e1000/igb_rxtx.c     |   52 ++++++++++++++-
>  drivers/net/fm10k/fm10k.h        |    6 ++
>  drivers/net/fm10k/fm10k_ethdev.c |    5 ++
>  drivers/net/fm10k/fm10k_rxtx.c   |   50 +++++++++++++-
>  drivers/net/i40e/i40e_ethdev.c   |    3 +
>  drivers/net/i40e/i40e_rxtx.c     |   72 ++++++++++++++++++++-
>  drivers/net/i40e/i40e_rxtx.h     |    8 +++
>  drivers/net/ixgbe/ixgbe_ethdev.c |    3 +
>  drivers/net/ixgbe/ixgbe_ethdev.h |    5 +-
>  drivers/net/ixgbe/ixgbe_rxtx.c   |   56 +++++++++++++++-
>  drivers/net/ixgbe/ixgbe_rxtx.h   |    2 +
>  lib/librte_ether/rte_ethdev.h    |   85 ++++++++++++++++++++++++
>  lib/librte_mbuf/rte_mbuf.h       |    8 +++
>  lib/librte_net/Makefile          |    2 +-
>  lib/librte_net/rte_pkt.h         |  133 ++++++++++++++++++++++++++++++++++++++
>  21 files changed, 605 insertions(+), 51 deletions(-)  create mode 100644 lib/librte_net/rte_pkt.h
> 
> --

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

> 1.7.9.5

^ permalink raw reply

* Re: [PATCH] log: do not drop debug logs at compile time
From: Thomas Monjalon @ 2016-09-30  9:33 UTC (permalink / raw)
  To: dev; +Cc: Olivier Matz, david.marchand
In-Reply-To: <1474011832-29987-1-git-send-email-olivier.matz@6wind.com>

2016-09-16 09:43, Olivier Matz:
> Today, all logs whose level is lower than INFO are dropped at
> compile-time. This prevents from enabling debug logs at runtime using
> --log-level=8.
> 
> The rationale was to remove debug logs from the data path at
> compile-time, avoiding a test at run-time.
> 
> This patch changes the behavior of RTE_LOG() to avoid the compile-time
> optimization, and introduces the RTE_LOG_DP() macro that has the same
> behavior than the previous RTE_LOG(), for the rare cases where debug
> logs are in the data path.
> 
> So it is now possible to enable debug logs at run-time by just
> specifying --log-level=8. Some drivers still have special compile-time
> options to enable more debug log. Maintainers may consider to
> remove/reduce them.
> 
> Signed-off-by: Olivier Matz <olivier.matz@6wind.com>

I think it is a good change.
However I'm not sure we should take it for 16.11 as it was sent late and
there is no review comment.
It is neither really a fix nor really a feature.
If there are some +1, and no opinions against, it will go in 16.11.
Note that some drivers would need some changes to fully benefit of
debug logs enabled at run-time.

^ permalink raw reply

* Re: [RFC PATCH v2 3/5] librte_ether: add API's for VF management
From: Bruce Richardson @ 2016-09-30  9:21 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: Ananyev, Konstantin, Iremonger, Bernard, dev, Jerin Jacob,
	Shah, Rahul R, Lu, Wenzhuo, azelezniak
In-Reply-To: <5655161.kOlSb9MaAr@xps13>

On Wed, Sep 28, 2016 at 08:02:21PM +0200, Thomas Monjalon wrote:
> 2016-09-28 16:52, Ananyev, Konstantin:
> > 
> > > 
> > > 2016-09-28 14:30, Ananyev, Konstantin:
> > > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > > 2016-09-28 13:26, Ananyev, Konstantin:
> > > > > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > > > > 2016-09-28 11:23, Ananyev, Konstantin:
> > > > > > > > If we  this way (force user to include driver specific headers
> > > > > > > > and call driver specific functions), how you guys plan to make this functionality available for multiple driver types.
> > > > > > >
> > > > > > > Multiple drivers won't have exactly the same specific features.
> > > > > > > But yes, there are some things common to several Intel NICs.
> > > > > > >
> > > > > > > > From discussion with Bernard  understand that customers would need similar functionality for i40e.
> > > > > > > > Does it mean that they'll have to re-implement this part of their code again?
> > > > > > > > Or would have to create (and maintain) their own shim layer that would provide some s of abstraction?
> > > > > > > > Basically their own version of rte_ethdev?
> > > > > > >
> > > > > > > No definitive answer.
> > > > > > > But we can argue the contrary: how to handle a generic API which
> > > > > > > is implemented only in 1 or 2 drivers? If the application tries to use it, we can imagine that a specific range of hardware is
> > > expected.
> > > > > >
> > > > > > Yes, as I understand, it is a specific subset of supported HW (just Inel NICs for now, but different models/drivers).
> > > > > > Obviously users would like to have an ability to run their app on all HW from this subset without rebuilding/implementing the
> > > app.
> > > > > >
> > > > > > >
> > > > > > > I think it is an important question.
> > > > > > > Previously we had the issue of having some API which are too
> > > > > > > specific and need a rework to be used with other NICs. In order
> > > > > > > to avoid such rework and API break, we can try to make them
> > > > > > > available in a driver-specific or vendor-specific staging area,
> > > > > > > waiting for
> > > > > a later generalization.
> > > > > >
> > > > > > Could you remind me why you guys were that opposed to ioctl style approach?
> > > > > > It is not my favorite thing either, but it seems pretty generic way to handle such situations.
> > > > >
> > > > > We prefer having well-defined functions instead of opaque ioctl-style encoding.
> > > > > And it was not clear what is the benefit of ioctl.
> > > > > Now I think I understand you would like to have a common ioctl service for features available on 2 drivers. Right?
> > > >
> > > > Yes.
> > > >
> > > > > Example (trying to  read your mind):
> > > > > 	rte_ethdev_ioctl(port_id, <TLV encoding VF_PING service and VF id>); instead of
> > > > > 	rte_pmd_ixgbe_vf_ping(port_id, vf_id);
> > > > > 	rte_pmd_i40e_vf_ping(port_id, vf_id); Please confirm I understand
> > > > > what you are thinking about.
> > > >
> > > > Yep, you read my mind correctly :)
> > > 
> > > Both could coexist (if ioctl was accepted by community).
> > 
> > True.
> > 
> > > What about starting to implement the PMD functions and postpone ioctl to later with a dedicated thread?
> > 
> > You mean something like:
> > - 16.11: implement rte_pmd_ixgbe_vf_ping()
> > - 17.02:
> > 	a) implement rte_pmd_i40e_vf_ping()
> > 	b) introduce ioctl PMD API
> > 	c) make possible to vf_ping via ioctl API
> > ?
> > If so, then it sounds like reasonable approach to me.
> > Though would be inserting to hear what other guys think.
> 
> Yes.
> I would just add that we have to start a discussion thread to decide
> wether we'll add an ioctl call in 17.02 or not.

I still don't like IOCTLs as an option, I still think that they are awkward to
use and hinder code readability. Here is an addition suggestion to get people
thinking.

How about allowing a set of "vendor-specific" operations for each device. We
could do this using Bernard's suggestion of adding a set of additional 
function pointers to the device struct. The reason for doing this is that it
would allow us to group functionality into families of functionality, rather
than having to things either fully generically or specifically to each NIC. If
we look at the capabilities of most NICs, the other NICs which support similar
functions are generally other NICs from the same vendor. We could therefore
have ops common across ixgbe and i40e and other ops mlx4 and mlx5 drivers.

Could such a scheme work? Would it be worth doing?

/Bruce

^ permalink raw reply

* Re: [PATCH] drivers/i40e: fix the hash filter invalid calculation in X722
From: Ferruh Yigit @ 2016-09-30  9:09 UTC (permalink / raw)
  To: Wu, Jingjing, Guo, Jia, Zhang, Helin; +Cc: dev@dpdk.org
In-Reply-To: <9BB6961774997848B5B42BEC655768F80E274D11@SHSMSX103.ccr.corp.intel.com>

Hi Jingjing,

On 9/30/2016 7:05 AM, Wu, Jingjing wrote:
> 
> 
>> -----Original Message-----
>> From: Yigit, Ferruh
>> Sent: Friday, September 30, 2016 2:16 AM
>> To: Guo, Jia; Zhang, Helin; Wu, Jingjing
>> Cc: dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH] drivers/i40e: fix the hash filter invalid
>> calculation in X722
>>
>> On 9/26/2016 11:51 AM, Jeff Guo wrote:
>>> As X722 extracts IPv4 header to Field Vector different with
>>> XL710/X710, need to corresponding to modify the fields of IPv4 header
>>> in input set to map different default Field Vector Table of different nics.
>>>
>>> Signed-off-by: Jeff Guo <jia.guo@intel.com>

<...>

>>> +#ifdef X722_SUPPORT
>>> +/* Source IPv4 address for X722 */
>>> +#define I40E_X722_REG_INSET_L3_SRC_IP4           0x0006000000000000ULL
>>
>> These macros defined here within "#ifdef X722_SUPPORT" and later used
>> unconditionally, this will cause a compile error when "X722_SUPPORT" not
>> defined.
> These macros defined are used in condition later. 

No they are not used in condition, please check that macros have been
used in inset_map1[] without an ifdef.

> Maybe the compile error
> Already exist in current driver. We need to check that and fix this.

And yes compile error already exist in driver! but lets not add a new ones.

>>
>>> +/* Destination IPv4 address for X722 */
>>> +#define I40E_X722_REG_INSET_L3_DST_IP4           0x0000060000000000ULL
>>> +/* IPv4 Type of Service (TOS) */
>>> +#define I40E_X722_REG_INSET_L3_IP4_TOS           0x0040000000000000ULL
>>
>> This value seems same as I40E_REG_INSET_L3_IP4_TOS, why creating a X722
>> version of this?
>>
>>> +/* IPv4 Protocol */
>>> +#define I40E_X722_REG_INSET_L3_IP4_PROTO
>> 0x0010000000000000ULL
>>> +/* IPv4 Time to Live */
>>> +#define I40E_X722_REG_INSET_L3_IP4_TTL           0x0010000000000000ULL
>>> +#endif

Overall, these new values seems like not conflicting with existing
values, can you please confirm that, if this is the case why not define
these values without ifdef?

<...>

>>
>> ---->
>>> +		{I40E_INSET_IPV4_SRC, I40E_X722_REG_INSET_L3_SRC_IP4},
>>> +		{I40E_INSET_IPV4_DST, I40E_X722_REG_INSET_L3_DST_IP4},
>>> +		{I40E_INSET_IPV4_TOS, I40E_X722_REG_INSET_L3_IP4_TOS},
>>> +		{I40E_INSET_IPV4_PROTO,
>> I40E_X722_REG_INSET_L3_IP4_PROTO},
>>> +		{I40E_INSET_IPV4_TTL, I40E_X722_REG_INSET_L3_IP4_TTL},
>> <----
>> Since limited number of values are different from inset_map[], and most of
>> them are duplication, is it possible to prevent duplication?
> Didn't find and proposal on that. Because we need to support
> I40E_X722_REG_INSET_XX and I40E_REG_INSET_XX at the same time. So it
> Cannot be achieved by #ifdef and #endif.

It doesn't have to be with #ifdef #endif, whole array duplicated for 5
changes, there must be a way to remove duplication. First thing I can
think of is extracting common part into a new array?

<...>

>>>  	/* Translate input set to register aware inset */
>>> +#ifdef X722_SUPPORT
>>> +	if (type == I40E_MAC_X722) {
>>> +		for (i = 0; i < RTE_DIM(inset_map1); i++) {
>>> +			if (input & inset_map1[i].inset)
>>> +				val |= inset_map1[i].inset_reg;
>>> +		}
>>> +	} else {
>>> +		for (i = 0; i < RTE_DIM(inset_map); i++) {
>>> +			if (input & inset_map[i].inset)
>>> +				val |= inset_map[i].inset_reg;
>>> +		}
>>> +	}
>>> +#else
>>>  	for (i = 0; i < RTE_DIM(inset_map); i++) {
>>>  		if (input & inset_map[i].inset)
>>>  			val |= inset_map[i].inset_reg;
>>>  	}
>>> +#endif
>>
>> What about something like this, to prevent duplication:
>>
>> inset_map_x = inset_map;
>>
>> #ifdef X722_SUPPORT
>> if (type == I40E_MAC_X722)
>> 	inset_map_x = inset_map1;
>> #endif
>>
>> for (i = 0; i < RTE_DIM(inset_map_x); i++) {
>> 	if (input & inset_map_x[i].inset)
>> 		val |= inset_map_x[i].inset_reg;
>> }
>>
> Also thought about that way, but if X722_SUPPORT is not set
> Compile error will report because of unused parameter.

I believe there won't be a unused parameter warning for above suggestion
but the intention here is to simplify the logic, which I think can be
done, it doesn't have to be like suggested way.

^ permalink raw reply

* [PATCH v4 6/6] testpmd: use Tx preparation in csum engine
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 app/test-pmd/csumonly.c |   97 ++++++++++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 43 deletions(-)

diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 21cb78f..8fcf814 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   Copyright 2014 6WIND S.A.
  *   All rights reserved.
  *
@@ -110,15 +110,6 @@ struct simple_gre_hdr {
 } __attribute__((__packed__));
 
 static uint16_t
-get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags)
-{
-	if (ethertype == _htons(ETHER_TYPE_IPv4))
-		return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
-	else /* assume ethertype == ETHER_TYPE_IPv6 */
-		return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
-}
-
-static uint16_t
 get_udptcp_checksum(void *l3_hdr, void *l4_hdr, uint16_t ethertype)
 {
 	if (ethertype == _htons(ETHER_TYPE_IPv4))
@@ -368,11 +359,9 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 		/* do not recalculate udp cksum if it was 0 */
 		if (udp_hdr->dgram_cksum != 0) {
 			udp_hdr->dgram_cksum = 0;
-			if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_UDP_CKSUM) {
+			if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_UDP_CKSUM)
 				ol_flags |= PKT_TX_UDP_CKSUM;
-				udp_hdr->dgram_cksum = get_psd_sum(l3_hdr,
-					info->ethertype, ol_flags);
-			} else {
+			else {
 				udp_hdr->dgram_cksum =
 					get_udptcp_checksum(l3_hdr, udp_hdr,
 						info->ethertype);
@@ -381,15 +370,11 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 	} else if (info->l4_proto == IPPROTO_TCP) {
 		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
 		tcp_hdr->cksum = 0;
-		if (info->tso_segsz != 0) {
+		if (info->tso_segsz != 0)
 			ol_flags |= PKT_TX_TCP_SEG;
-			tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype,
-				ol_flags);
-		} else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) {
+		else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM)
 			ol_flags |= PKT_TX_TCP_CKSUM;
-			tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype,
-				ol_flags);
-		} else {
+		else {
 			tcp_hdr->cksum =
 				get_udptcp_checksum(l3_hdr, tcp_hdr,
 					info->ethertype);
@@ -639,7 +624,8 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
 	void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */
 	uint16_t nb_rx;
 	uint16_t nb_tx;
-	uint16_t i;
+	uint16_t nb_prep;
+	uint16_t i, n;
 	uint64_t ol_flags;
 	uint16_t testpmd_ol_flags;
 	uint32_t retry;
@@ -847,31 +833,56 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
 			printf("\n");
 		}
 	}
-	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
-	/*
-	 * Retry if necessary
-	 */
-	if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
-		retry = 0;
-		while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
-			rte_delay_us(burst_tx_delay_time);
-			nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
-					&pkts_burst[nb_tx], nb_rx - nb_tx);
+
+	n = 0;
+
+	do {
+		nb_prep = rte_eth_tx_prep(fs->tx_port, fs->tx_queue, &pkts_burst[n],
+				nb_rx - n);
+
+		if (nb_prep != nb_rx - n) {
+			printf("Preparing packet burst to transmit failed: %s\n",
+					rte_strerror(rte_errno));
+			/* Drop malicious packet */
+			rte_pktmbuf_free(pkts_burst[n + nb_prep]);
+			fs->fwd_dropped++;
+		}
+
+		nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, &pkts_burst[n],
+				nb_prep);
+
+		/*
+		 * Retry if necessary
+		 */
+		if (unlikely(nb_tx < nb_prep) && fs->retry_enabled) {
+			retry = 0;
+			while ((nb_tx < nb_prep) && (retry++ < burst_tx_retry_num)) {
+				rte_delay_us(burst_tx_delay_time);
+				nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+						&pkts_burst[nb_tx + n], nb_prep - nb_tx);
+			}
 		}
-	}
-	fs->tx_packets += nb_tx;
-	fs->rx_bad_ip_csum += rx_bad_ip_csum;
-	fs->rx_bad_l4_csum += rx_bad_l4_csum;
+
+		fs->tx_packets += nb_tx;
 
 #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
-	fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+		fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
 #endif
-	if (unlikely(nb_tx < nb_rx)) {
-		fs->fwd_dropped += (nb_rx - nb_tx);
-		do {
-			rte_pktmbuf_free(pkts_burst[nb_tx]);
-		} while (++nb_tx < nb_rx);
-	}
+		if (unlikely(nb_tx < nb_prep)) {
+			fs->fwd_dropped += (nb_prep - nb_tx);
+			do {
+				rte_pktmbuf_free(pkts_burst[nb_tx]);
+			} while (++nb_tx < nb_prep);
+		}
+
+		/* If tx_prep failed, skip malicious packet */
+		n += (nb_prep + 1);
+
+	} while (n < nb_rx);
+
+	fs->rx_bad_ip_csum += rx_bad_ip_csum;
+	fs->rx_bad_l4_csum += rx_bad_l4_csum;
+
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
 	end_tsc = rte_rdtsc();
 	core_cycles = (end_tsc - start_tsc);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 5/6] ixgbe: add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethdev.c |    3 ++
 drivers/net/ixgbe/ixgbe_ethdev.h |    5 +++-
 drivers/net/ixgbe/ixgbe_rxtx.c   |   56 +++++++++++++++++++++++++++++++++++++-
 drivers/net/ixgbe/ixgbe_rxtx.h   |    2 ++
 4 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index 73a406b..fa6f045 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -515,6 +515,8 @@ static const struct rte_eth_desc_lim tx_desc_lim = {
 	.nb_max = IXGBE_MAX_RING_DESC,
 	.nb_min = IXGBE_MIN_RING_DESC,
 	.nb_align = IXGBE_TXD_ALIGN,
+	.nb_seg_max = IXGBE_TX_MAX_SEG,
+	.nb_mtu_seg_max = IXGBE_TX_MAX_SEG,
 };
 
 static const struct eth_dev_ops ixgbe_eth_dev_ops = {
@@ -1101,6 +1103,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
 	eth_dev->dev_ops = &ixgbe_eth_dev_ops;
 	eth_dev->rx_pkt_burst = &ixgbe_recv_pkts;
 	eth_dev->tx_pkt_burst = &ixgbe_xmit_pkts;
+	eth_dev->tx_pkt_prep = &ixgbe_prep_pkts;
 
 	/*
 	 * For secondary processes, we don't initialise any further as primary
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.h b/drivers/net/ixgbe/ixgbe_ethdev.h
index 4ff6338..e229cf5 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.h
+++ b/drivers/net/ixgbe/ixgbe_ethdev.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -396,6 +396,9 @@ uint16_t ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 uint16_t ixgbe_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 
+uint16_t ixgbe_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+
 int ixgbe_dev_rss_hash_update(struct rte_eth_dev *dev,
 			      struct rte_eth_rss_conf *rss_conf);
 
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 8b99282..a0caa74 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   Copyright 2014 6WIND S.A.
  *   All rights reserved.
  *
@@ -70,6 +70,7 @@
 #include <rte_string_fns.h>
 #include <rte_errno.h>
 #include <rte_ip.h>
+#include <rte_pkt.h>
 
 #include "ixgbe_logs.h"
 #include "base/ixgbe_api.h"
@@ -87,6 +88,9 @@
 		PKT_TX_TCP_SEG |		 \
 		PKT_TX_OUTER_IP_CKSUM)
 
+#define IXGBE_TX_OFFLOAD_NOTSUP_MASK \
+		(PKT_TX_OFFLOAD_MASK ^ IXGBE_TX_OFFLOAD_MASK)
+
 #if 1
 #define RTE_PMD_USE_PREFETCH
 #endif
@@ -905,6 +909,54 @@ end_of_tx:
 
 /*********************************************************************
  *
+ *  TX prep functions
+ *
+ **********************************************************************/
+uint16_t
+ixgbe_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	int i, ret;
+	struct rte_mbuf *m;
+	struct ixgbe_tx_queue *txq = (struct ixgbe_tx_queue *)tx_queue;
+
+	for (i = 0; i < nb_pkts; i++) {
+		m = tx_pkts[i];
+
+		/**
+		 * Check if packet meets requirements for number of segments
+		 *
+		 * NOTE: for ixgbe it's always (40 - WTHRESH) for both TSO and non-TSO
+		 */
+
+		if (m->nb_segs > IXGBE_TX_MAX_SEG - txq->wthresh) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+		if (m->ol_flags & IXGBE_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		ret = rte_validate_tx_offload(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+#endif
+		ret = rte_phdr_cksum_fix(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+	}
+
+	return i;
+}
+
+/*********************************************************************
+ *
  *  RX functions
  *
  **********************************************************************/
@@ -2280,6 +2332,7 @@ ixgbe_set_tx_function(struct rte_eth_dev *dev, struct ixgbe_tx_queue *txq)
 	if (((txq->txq_flags & IXGBE_SIMPLE_FLAGS) == IXGBE_SIMPLE_FLAGS)
 			&& (txq->tx_rs_thresh >= RTE_PMD_IXGBE_TX_MAX_BURST)) {
 		PMD_INIT_LOG(DEBUG, "Using simple tx code path");
+		dev->tx_pkt_prep = NULL;
 #ifdef RTE_IXGBE_INC_VECTOR
 		if (txq->tx_rs_thresh <= RTE_IXGBE_TX_MAX_FREE_BUF_SZ &&
 				(rte_eal_process_type() != RTE_PROC_PRIMARY ||
@@ -2300,6 +2353,7 @@ ixgbe_set_tx_function(struct rte_eth_dev *dev, struct ixgbe_tx_queue *txq)
 				(unsigned long)txq->tx_rs_thresh,
 				(unsigned long)RTE_PMD_IXGBE_TX_MAX_BURST);
 		dev->tx_pkt_burst = ixgbe_xmit_pkts;
+		dev->tx_pkt_prep = ixgbe_prep_pkts;
 	}
 }
 
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.h b/drivers/net/ixgbe/ixgbe_rxtx.h
index 2608b36..7bbd9b8 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.h
+++ b/drivers/net/ixgbe/ixgbe_rxtx.h
@@ -80,6 +80,8 @@
 #define RTE_IXGBE_WAIT_100_US               100
 #define RTE_IXGBE_VMTXSW_REGISTER_COUNT     2
 
+#define IXGBE_TX_MAX_SEG                    40
+
 #define IXGBE_PACKET_TYPE_MASK_82599        0X7F
 #define IXGBE_PACKET_TYPE_MASK_X550         0X10FF
 #define IXGBE_PACKET_TYPE_MASK_TUNNEL       0XFF
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 4/6] i40e: add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 drivers/net/i40e/i40e_ethdev.c |    3 ++
 drivers/net/i40e/i40e_rxtx.c   |   72 +++++++++++++++++++++++++++++++++++++++-
 drivers/net/i40e/i40e_rxtx.h   |    8 +++++
 3 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index b04c833..c1ee7e6 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -948,6 +948,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 	dev->dev_ops = &i40e_eth_dev_ops;
 	dev->rx_pkt_burst = i40e_recv_pkts;
 	dev->tx_pkt_burst = i40e_xmit_pkts;
+	dev->tx_pkt_prep = i40e_prep_pkts;
 
 	/* for secondary processes, we don't initialise any further as primary
 	 * has already done this work. Only check we don't need a different
@@ -2614,6 +2615,8 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 		.nb_max = I40E_MAX_RING_DESC,
 		.nb_min = I40E_MIN_RING_DESC,
 		.nb_align = I40E_ALIGN_RING_DESC,
+		.nb_seg_max = I40E_TX_MAX_SEG,
+		.nb_mtu_seg_max = I40E_TX_MAX_MTU_SEG,
 	};
 
 	if (pf->flags & I40E_FLAG_VMDQ) {
diff --git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c
index 554d167..bb69175 100644
--- a/drivers/net/i40e/i40e_rxtx.c
+++ b/drivers/net/i40e/i40e_rxtx.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,8 @@
 #include <rte_tcp.h>
 #include <rte_sctp.h>
 #include <rte_udp.h>
+#include <rte_ip.h>
+#include <rte_pkt.h>
 
 #include "i40e_logs.h"
 #include "base/i40e_prototype.h"
@@ -79,6 +81,17 @@
 		PKT_TX_TCP_SEG |		 \
 		PKT_TX_OUTER_IP_CKSUM)
 
+#define I40E_TX_OFFLOAD_MASK (  \
+		PKT_TX_IP_CKSUM |       \
+		PKT_TX_L4_MASK |        \
+		PKT_TX_OUTER_IP_CKSUM | \
+		PKT_TX_TCP_SEG |        \
+		PKT_TX_QINQ_PKT |       \
+		PKT_TX_VLAN_PKT)
+
+#define I40E_TX_OFFLOAD_NOTSUP_MASK \
+		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
+
 static uint16_t i40e_xmit_pkts_simple(void *tx_queue,
 				      struct rte_mbuf **tx_pkts,
 				      uint16_t nb_pkts);
@@ -1930,6 +1943,61 @@ i40e_xmit_pkts_simple(void *tx_queue,
 	return nb_tx;
 }
 
+/*********************************************************************
+ *
+ *  TX prep functions
+ *
+ **********************************************************************/
+uint16_t
+i40e_prep_pkts(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	int i, ret;
+	uint64_t ol_flags;
+	struct rte_mbuf *m;
+
+	for (i = 0; i < nb_pkts; i++) {
+		m = tx_pkts[i];
+		ol_flags = m->ol_flags;
+
+		/**
+		 * m->nb_segs is uint8_t, so m->nb_segs is always less than
+		 * I40E_TX_MAX_SEG.
+		 * We check only a condition for m->nb_segs > I40E_TX_MAX_MTU_SEG.
+		 */
+		if (!(ol_flags & PKT_TX_TCP_SEG)) {
+			if (m->nb_segs > I40E_TX_MAX_MTU_SEG) {
+				rte_errno = -1;
+				return i;
+			}
+		} else if ((m->tso_segsz < I40E_MIN_TSO_MSS) ||
+				(m->tso_segsz > I40E_MAX_TSO_MSS)) {
+			/* MSS outside the range (256B - 9674B) are considered malicious */
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+		if (ol_flags & I40E_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		ret = rte_validate_tx_offload(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+#endif
+		ret = rte_phdr_cksum_fix(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+	}
+	return i;
+}
+
 /*
  * Find the VSI the queue belongs to. 'queue_idx' is the queue index
  * application used, which assume having sequential ones. But from driver's
@@ -3271,9 +3339,11 @@ i40e_set_tx_function(struct rte_eth_dev *dev)
 			PMD_INIT_LOG(DEBUG, "Simple tx finally be used.");
 			dev->tx_pkt_burst = i40e_xmit_pkts_simple;
 		}
+		dev->tx_pkt_prep = NULL;
 	} else {
 		PMD_INIT_LOG(DEBUG, "Xmit tx finally be used.");
 		dev->tx_pkt_burst = i40e_xmit_pkts;
+		dev->tx_pkt_prep = i40e_prep_pkts;
 	}
 }
 
diff --git a/drivers/net/i40e/i40e_rxtx.h b/drivers/net/i40e/i40e_rxtx.h
index 98179f0..e7eb89c 100644
--- a/drivers/net/i40e/i40e_rxtx.h
+++ b/drivers/net/i40e/i40e_rxtx.h
@@ -63,6 +63,12 @@
 #define	I40E_MIN_RING_DESC	64
 #define	I40E_MAX_RING_DESC	4096
 
+#define I40E_MIN_TSO_MSS          256
+#define I40E_MAX_TSO_MSS          9674
+
+#define I40E_TX_MAX_SEG     UINT8_MAX
+#define I40E_TX_MAX_MTU_SEG 8
+
 #undef container_of
 #define container_of(ptr, type, member) ({ \
 		typeof(((type *)0)->member)(*__mptr) = (ptr); \
@@ -223,6 +229,8 @@ uint16_t i40e_recv_scattered_pkts(void *rx_queue,
 uint16_t i40e_xmit_pkts(void *tx_queue,
 			struct rte_mbuf **tx_pkts,
 			uint16_t nb_pkts);
+uint16_t i40e_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
 int i40e_tx_queue_init(struct i40e_tx_queue *txq);
 int i40e_rx_queue_init(struct i40e_rx_queue *rxq);
 void i40e_free_tx_resources(struct i40e_tx_queue *txq);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 3/6] fm10k: add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 drivers/net/fm10k/fm10k.h        |    6 +++++
 drivers/net/fm10k/fm10k_ethdev.c |    5 ++++
 drivers/net/fm10k/fm10k_rxtx.c   |   50 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/net/fm10k/fm10k.h b/drivers/net/fm10k/fm10k.h
index 05aa1a2..c6fed21 100644
--- a/drivers/net/fm10k/fm10k.h
+++ b/drivers/net/fm10k/fm10k.h
@@ -69,6 +69,9 @@
 #define FM10K_MAX_RX_DESC  (FM10K_MAX_RX_RING_SZ / sizeof(union fm10k_rx_desc))
 #define FM10K_MAX_TX_DESC  (FM10K_MAX_TX_RING_SZ / sizeof(struct fm10k_tx_desc))
 
+#define FM10K_TX_MAX_SEG     UINT8_MAX
+#define FM10K_TX_MAX_MTU_SEG UINT8_MAX
+
 /*
  * byte aligment for HW RX data buffer
  * Datasheet requires RX buffer addresses shall either be 512-byte aligned or
@@ -356,6 +359,9 @@ fm10k_dev_rx_descriptor_done(void *rx_queue, uint16_t offset);
 uint16_t fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
 
+uint16_t fm10k_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+	uint16_t nb_pkts);
+
 int fm10k_rxq_vec_setup(struct fm10k_rx_queue *rxq);
 int fm10k_rx_vec_condition_check(struct rte_eth_dev *);
 void fm10k_rx_queue_release_mbufs_vec(struct fm10k_rx_queue *rxq);
diff --git a/drivers/net/fm10k/fm10k_ethdev.c b/drivers/net/fm10k/fm10k_ethdev.c
index 0ecc167..8dacba7 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1441,6 +1441,8 @@ fm10k_dev_infos_get(struct rte_eth_dev *dev,
 		.nb_max = FM10K_MAX_TX_DESC,
 		.nb_min = FM10K_MIN_TX_DESC,
 		.nb_align = FM10K_MULT_TX_DESC,
+		.nb_seg_max = FM10K_TX_MAX_SEG,
+		.nb_mtu_seg_max = FM10K_TX_MAX_MTU_SEG,
 	};
 
 	dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G |
@@ -2749,8 +2751,10 @@ fm10k_set_tx_function(struct rte_eth_dev *dev)
 			fm10k_txq_vec_setup(txq);
 		}
 		dev->tx_pkt_burst = fm10k_xmit_pkts_vec;
+		dev->tx_pkt_prep = NULL;
 	} else {
 		dev->tx_pkt_burst = fm10k_xmit_pkts;
+		dev->tx_pkt_prep = fm10k_prep_pkts;
 		PMD_INIT_LOG(DEBUG, "Use regular Tx func");
 	}
 }
@@ -2829,6 +2833,7 @@ eth_fm10k_dev_init(struct rte_eth_dev *dev)
 	dev->dev_ops = &fm10k_eth_dev_ops;
 	dev->rx_pkt_burst = &fm10k_recv_pkts;
 	dev->tx_pkt_burst = &fm10k_xmit_pkts;
+	dev->tx_pkt_prep = &fm10k_prep_pkts;
 
 	/* only initialize in the primary process */
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
diff --git a/drivers/net/fm10k/fm10k_rxtx.c b/drivers/net/fm10k/fm10k_rxtx.c
index 5b2d04b..fa5bf9c 100644
--- a/drivers/net/fm10k/fm10k_rxtx.c
+++ b/drivers/net/fm10k/fm10k_rxtx.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2013-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 
 #include <rte_ethdev.h>
 #include <rte_common.h>
+#include <rte_pkt.h>
 #include "fm10k.h"
 #include "base/fm10k_type.h"
 
@@ -65,6 +66,15 @@ static inline void dump_rxd(union fm10k_rx_desc *rxd)
 }
 #endif
 
+#define FM10K_TX_OFFLOAD_MASK (  \
+		PKT_TX_VLAN_PKT |        \
+		PKT_TX_IP_CKSUM |        \
+		PKT_TX_L4_MASK |         \
+		PKT_TX_TCP_SEG)
+
+#define FM10K_TX_OFFLOAD_NOTSUP_MASK \
+		(PKT_TX_OFFLOAD_MASK ^ FM10K_TX_OFFLOAD_MASK)
+
 /* @note: When this function is changed, make corresponding change to
  * fm10k_dev_supported_ptypes_get()
  */
@@ -583,3 +593,41 @@ fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 	return count;
 }
+
+uint16_t
+fm10k_prep_pkts(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	int i, ret;
+	struct rte_mbuf *m;
+
+	for (i = 0; i < nb_pkts; i++) {
+		m = tx_pkts[i];
+
+		if ((m->ol_flags & PKT_TX_TCP_SEG) &&
+				(m->tso_segsz < FM10K_TSO_MINMSS)) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+		if (m->ol_flags & FM10K_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		ret = rte_validate_tx_offload(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+#endif
+		ret = rte_phdr_cksum_fix(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+	}
+
+	return i;
+}
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 2/6] e1000: add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 drivers/net/e1000/e1000_ethdev.h |   11 ++++++++
 drivers/net/e1000/em_ethdev.c    |    5 +++-
 drivers/net/e1000/em_rxtx.c      |   48 ++++++++++++++++++++++++++++++++++-
 drivers/net/e1000/igb_ethdev.c   |    4 +++
 drivers/net/e1000/igb_rxtx.c     |   52 +++++++++++++++++++++++++++++++++++++-
 5 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/drivers/net/e1000/e1000_ethdev.h b/drivers/net/e1000/e1000_ethdev.h
index 6c25c8d..bd0f277 100644
--- a/drivers/net/e1000/e1000_ethdev.h
+++ b/drivers/net/e1000/e1000_ethdev.h
@@ -138,6 +138,11 @@
 #define E1000_MISC_VEC_ID               RTE_INTR_VEC_ZERO_OFFSET
 #define E1000_RX_VEC_START              RTE_INTR_VEC_RXTX_OFFSET
 
+#define IGB_TX_MAX_SEG     UINT8_MAX
+#define IGB_TX_MAX_MTU_SEG UINT8_MAX
+#define EM_TX_MAX_SEG      UINT8_MAX
+#define EM_TX_MAX_MTU_SEG  UINT8_MAX
+
 /* structure for interrupt relative data */
 struct e1000_interrupt {
 	uint32_t flags;
@@ -315,6 +320,9 @@ void eth_igb_tx_init(struct rte_eth_dev *dev);
 uint16_t eth_igb_xmit_pkts(void *txq, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 
+uint16_t eth_igb_prep_pkts(void *txq, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+
 uint16_t eth_igb_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
 		uint16_t nb_pkts);
 
@@ -376,6 +384,9 @@ void eth_em_tx_init(struct rte_eth_dev *dev);
 uint16_t eth_em_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 		uint16_t nb_pkts);
 
+uint16_t eth_em_prep_pkts(void *txq, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+
 uint16_t eth_em_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 		uint16_t nb_pkts);
 
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index c5bf294..46515d4 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -300,6 +300,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev)
 	eth_dev->dev_ops = &eth_em_ops;
 	eth_dev->rx_pkt_burst = (eth_rx_burst_t)&eth_em_recv_pkts;
 	eth_dev->tx_pkt_burst = (eth_tx_burst_t)&eth_em_xmit_pkts;
+	eth_dev->tx_pkt_prep = (eth_tx_prep_t)&eth_em_prep_pkts;
 
 	/* for secondary processes, we don't initialise any further as primary
 	 * has already done this work. Only check we don't need a different
@@ -1073,6 +1074,8 @@ eth_em_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 		.nb_max = E1000_MAX_RING_DESC,
 		.nb_min = E1000_MIN_RING_DESC,
 		.nb_align = EM_TXD_ALIGN,
+		.nb_seg_max = EM_TX_MAX_SEG,
+		.nb_mtu_seg_max = EM_TX_MAX_MTU_SEG,
 	};
 
 	dev_info->speed_capa = ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |
diff --git a/drivers/net/e1000/em_rxtx.c b/drivers/net/e1000/em_rxtx.c
index 41f51c0..44009d6 100644
--- a/drivers/net/e1000/em_rxtx.c
+++ b/drivers/net/e1000/em_rxtx.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -66,6 +66,7 @@
 #include <rte_udp.h>
 #include <rte_tcp.h>
 #include <rte_sctp.h>
+#include <rte_pkt.h>
 #include <rte_string_fns.h>
 
 #include "e1000_logs.h"
@@ -77,6 +78,14 @@
 
 #define E1000_RXDCTL_GRAN	0x01000000 /* RXDCTL Granularity */
 
+#define E1000_TX_OFFLOAD_MASK ( \
+		PKT_TX_IP_CKSUM |       \
+		PKT_TX_L4_MASK |        \
+		PKT_TX_VLAN_PKT)
+
+#define E1000_TX_OFFLOAD_NOTSUP_MASK \
+		(PKT_TX_OFFLOAD_MASK ^ E1000_TX_OFFLOAD_MASK)
+
 /**
  * Structure associated with each descriptor of the RX ring of a RX queue.
  */
@@ -618,6 +627,43 @@ end_of_tx:
 
 /*********************************************************************
  *
+ *  TX prep functions
+ *
+ **********************************************************************/
+uint16_t
+eth_em_prep_pkts(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	int i, ret;
+	struct rte_mbuf *m;
+
+	for (i = 0; i < nb_pkts; i++) {
+		m = tx_pkts[i];
+
+		if (m->ol_flags & E1000_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		ret = rte_validate_tx_offload(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+#endif
+		ret = rte_phdr_cksum_fix(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+	}
+
+	return i;
+}
+
+/*********************************************************************
+ *
  *  RX functions
  *
  **********************************************************************/
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index f7cfa18..5baacd0 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -369,6 +369,8 @@ static const struct rte_eth_desc_lim tx_desc_lim = {
 	.nb_max = E1000_MAX_RING_DESC,
 	.nb_min = E1000_MIN_RING_DESC,
 	.nb_align = IGB_RXD_ALIGN,
+	.nb_seg_max = IGB_TX_MAX_SEG,
+	.nb_mtu_seg_max = IGB_TX_MAX_MTU_SEG,
 };
 
 static const struct eth_dev_ops eth_igb_ops = {
@@ -760,6 +762,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 	eth_dev->dev_ops = &eth_igb_ops;
 	eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
 	eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
+	eth_dev->tx_pkt_prep = &eth_igb_prep_pkts;
 
 	/* for secondary processes, we don't initialise any further as primary
 	 * has already done this work. Only check we don't need a different
@@ -963,6 +966,7 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 	eth_dev->dev_ops = &igbvf_eth_dev_ops;
 	eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
 	eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
+	eth_dev->tx_pkt_prep = &eth_igb_prep_pkts;
 
 	/* for secondary processes, we don't initialise any further as primary
 	 * has already done this work. Only check we don't need a different
diff --git a/drivers/net/e1000/igb_rxtx.c b/drivers/net/e1000/igb_rxtx.c
index a47c640..d466888 100644
--- a/drivers/net/e1000/igb_rxtx.c
+++ b/drivers/net/e1000/igb_rxtx.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -65,6 +65,7 @@
 #include <rte_udp.h>
 #include <rte_tcp.h>
 #include <rte_sctp.h>
+#include <rte_pkt.h>
 #include <rte_string_fns.h>
 
 #include "e1000_logs.h"
@@ -78,6 +79,9 @@
 		PKT_TX_L4_MASK |		 \
 		PKT_TX_TCP_SEG)
 
+#define IGB_TX_OFFLOAD_NOTSUP_MASK \
+		(PKT_TX_OFFLOAD_MASK ^ IGB_TX_OFFLOAD_MASK)
+
 /**
  * Structure associated with each descriptor of the RX ring of a RX queue.
  */
@@ -616,6 +620,51 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
 /*********************************************************************
  *
+ *  TX prep functions
+ *
+ **********************************************************************/
+uint16_t
+eth_igb_prep_pkts(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	int i, ret;
+	struct rte_mbuf *m;
+
+	for (i = 0; i < nb_pkts; i++) {
+		m = tx_pkts[i];
+
+		/* Check some limitations for TSO in hardware */
+		if (m->ol_flags & PKT_TX_TCP_SEG)
+			if ((m->tso_segsz > IGB_TSO_MAX_MSS) || (m->l2_len + m->l3_len +
+					m->l4_len > IGB_TSO_MAX_HDRLEN)) {
+				rte_errno = -EINVAL;
+				return i;
+			}
+
+		if (m->ol_flags & IGB_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -EINVAL;
+			return i;
+		}
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		ret = rte_validate_tx_offload(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+#endif
+		ret = rte_phdr_cksum_fix(m);
+		if (ret != 0) {
+			rte_errno = ret;
+			return i;
+		}
+	}
+
+	return i;
+}
+
+/*********************************************************************
+ *
  *  RX functions
  *
  **********************************************************************/
@@ -1362,6 +1411,7 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
 
 	igb_reset_tx_queue(txq, dev);
 	dev->tx_pkt_burst = eth_igb_xmit_pkts;
+	dev->tx_pkt_prep = &eth_igb_prep_pkts;
 	dev->data->tx_queues[queue_idx] = txq;
 
 	return 0;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 1/6] ethdev: add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160930090039.10164-1-tomaszx.kulasek@intel.com>

Added API for `rte_eth_tx_prep`

uint16_t rte_eth_tx_prep(uint8_t port_id, uint16_t queue_id,
	struct rte_mbuf **tx_pkts, uint16_t nb_pkts)

Added fields to the `struct rte_eth_desc_lim`:

	uint16_t nb_seg_max;
		/**< Max number of segments per whole packet. */

	uint16_t nb_mtu_seg_max;
		/**< Max number of segments per one MTU */

Created `rte_pkt.h` header with common used functions:

int rte_validate_tx_offload(struct rte_mbuf *m)
	to validate general requirements for tx offload in packet such a
	flag completness. In current implementation this function is called
	optionaly when RTE_LIBRTE_ETHDEV_DEBUG is enabled.

int rte_phdr_cksum_fix(struct rte_mbuf *m)
	to fix pseudo header checksum for TSO and non-TSO tcp/udp packets
	before hardware tx checksum offload.
	 - for non-TSO tcp/udp packets full pseudo-header checksum is
	   counted and set.
	 - for TSO the IP payload length is not included.

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 config/common_base            |    1 +
 lib/librte_ether/rte_ethdev.h |   85 ++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h    |    8 +++
 lib/librte_net/Makefile       |    2 +-
 lib/librte_net/rte_pkt.h      |  133 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_net/rte_pkt.h

diff --git a/config/common_base b/config/common_base
index 7830535..7ada9e0 100644
--- a/config/common_base
+++ b/config/common_base
@@ -120,6 +120,7 @@ CONFIG_RTE_MAX_QUEUES_PER_PORT=1024
 CONFIG_RTE_LIBRTE_IEEE1588=n
 CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16
 CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
+CONFIG_RTE_ETHDEV_TX_PREP=y
 
 #
 # Support NIC bypass logic
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 96575e8..6594544 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -182,6 +182,7 @@ extern "C" {
 #include <rte_pci.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
+#include <rte_errno.h>
 #include "rte_ether.h"
 #include "rte_eth_ctrl.h"
 #include "rte_dev_info.h"
@@ -699,6 +700,8 @@ struct rte_eth_desc_lim {
 	uint16_t nb_max;   /**< Max allowed number of descriptors. */
 	uint16_t nb_min;   /**< Min allowed number of descriptors. */
 	uint16_t nb_align; /**< Number of descriptors should be aligned to. */
+	uint16_t nb_seg_max;     /**< Max number of segments per whole packet. */
+	uint16_t nb_mtu_seg_max; /**< Max number of segments per one MTU */
 };
 
 /**
@@ -1184,6 +1187,11 @@ typedef uint16_t (*eth_tx_burst_t)(void *txq,
 				   uint16_t nb_pkts);
 /**< @internal Send output packets on a transmit queue of an Ethernet device. */
 
+typedef uint16_t (*eth_tx_prep_t)(void *txq,
+				   struct rte_mbuf **tx_pkts,
+				   uint16_t nb_pkts);
+/**< @internal Prepare output packets on a transmit queue of an Ethernet device. */
+
 typedef int (*flow_ctrl_get_t)(struct rte_eth_dev *dev,
 			       struct rte_eth_fc_conf *fc_conf);
 /**< @internal Get current flow control parameter on an Ethernet device */
@@ -1629,6 +1637,7 @@ enum rte_eth_dev_type {
 struct rte_eth_dev {
 	eth_rx_burst_t rx_pkt_burst; /**< Pointer to PMD receive function. */
 	eth_tx_burst_t tx_pkt_burst; /**< Pointer to PMD transmit function. */
+	eth_tx_prep_t tx_pkt_prep; /**< Pointer to PMD transmit prepare function. */
 	struct rte_eth_dev_data *data;  /**< Pointer to device data */
 	const struct eth_driver *driver;/**< Driver for this device */
 	const struct eth_dev_ops *dev_ops; /**< Functions exported by PMD */
@@ -2837,6 +2846,82 @@ rte_eth_tx_burst(uint8_t port_id, uint16_t queue_id,
 	return (*dev->tx_pkt_burst)(dev->data->tx_queues[queue_id], tx_pkts, nb_pkts);
 }
 
+/**
+ * Process a burst of output packets on a transmit queue of an Ethernet device.
+ *
+ * The rte_eth_tx_prep() function is invoked to prepare output packets to be
+ * transmitted on the output queue *queue_id* of the Ethernet device designated
+ * by its *port_id*.
+ * The *nb_pkts* parameter is the number of packets to be prepared which are
+ * supplied in the *tx_pkts* array of *rte_mbuf* structures, each of them
+ * allocated from a pool created with rte_pktmbuf_pool_create().
+ * For each packet to send, the rte_eth_tx_prep() function performs
+ * the following operations:
+ *
+ * - Check if packet meets devices requirements for tx offloads.
+ *
+ * - Check limitations about number of segments.
+ *
+ * - Check additional requirements when debug is enabled.
+ *
+ * - Update and/or reset required checksums when tx offload is set for packet.
+ *
+ * The rte_eth_tx_prep() function returns the number of packets ready to be
+ * sent. A return value equal to *nb_pkts* means that all packets are valid and
+ * ready to be sent.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The index of the transmit queue through which output packets must be
+ *   sent.
+ *   The value must be in the range [0, nb_tx_queue - 1] previously supplied
+ *   to rte_eth_dev_configure().
+ * @param tx_pkts
+ *   The address of an array of *nb_pkts* pointers to *rte_mbuf* structures
+ *   which contain the output packets.
+ * @param nb_pkts
+ *   The maximum number of packets to process.
+ * @return
+ *   The number of packets correct and ready to be sent. The return value can be
+ *   less than the value of the *tx_pkts* parameter when some packet doesn't
+ *   meet devices requirements with rte_errno set appropriately.
+ */
+
+#ifdef RTE_ETHDEV_TX_PREP
+
+static inline uint16_t
+rte_eth_tx_prep(uint8_t port_id, uint16_t queue_id, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	if (!dev->tx_pkt_prep)
+		return nb_pkts;
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+	if (queue_id >= dev->data->nb_tx_queues) {
+		RTE_PMD_DEBUG_TRACE("Invalid TX queue_id=%d\n", queue_id);
+		rte_errno = -EINVAL;
+		return 0;
+	}
+#endif
+
+	return (*dev->tx_pkt_prep)(dev->data->tx_queues[queue_id],
+			tx_pkts, nb_pkts);
+}
+
+#else
+
+static inline uint16_t
+rte_eth_tx_prep(uint8_t port_id __rte_unused, uint16_t queue_id __rte_unused,
+		struct rte_mbuf **tx_pkts __rte_unused, uint16_t nb_pkts)
+{
+	return nb_pkts;
+}
+
+#endif
+
 typedef void (*buffer_tx_error_fn)(struct rte_mbuf **unsent, uint16_t count,
 		void *userdata);
 
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index 23b7bf8..8b73261 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -211,6 +211,14 @@ extern "C" {
  */
 #define PKT_TX_OUTER_IPV4   (1ULL << 59)
 
+#define PKT_TX_OFFLOAD_MASK (    \
+		PKT_TX_IP_CKSUM |        \
+		PKT_TX_L4_MASK |         \
+		PKT_TX_OUTER_IP_CKSUM |  \
+		PKT_TX_TCP_SEG |         \
+		PKT_TX_QINQ_PKT |        \
+		PKT_TX_VLAN_PKT)
+
 /**
  * Packet outer header is IPv6. This flag must be set when using any
  * outer offload feature (L4 checksum) to tell the NIC that the outer
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index ad2e482..b5abe84 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -34,7 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h rte_pkt.h
 
 
 include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_net/rte_pkt.h b/lib/librte_net/rte_pkt.h
new file mode 100644
index 0000000..72903ac
--- /dev/null
+++ b/lib/librte_net/rte_pkt.h
@@ -0,0 +1,133 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ *   OWNER 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.
+ */
+
+#ifndef _RTE_PKT_H_
+#define _RTE_PKT_H_
+
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+#include <rte_sctp.h>
+
+/**
+ * Validate general requirements for tx offload in packet.
+ */
+static inline int
+rte_validate_tx_offload(struct rte_mbuf *m)
+{
+	uint64_t ol_flags = m->ol_flags;
+
+	/* Does packet set any of available offloads? */
+	if (!(ol_flags & PKT_TX_OFFLOAD_MASK))
+		return 0;
+
+	/* IP checksum can be counted only for IPv4 packet */
+	if ((ol_flags & PKT_TX_IP_CKSUM) && (ol_flags & PKT_TX_IPV6))
+		return -EINVAL;
+
+	if (ol_flags & (PKT_TX_L4_MASK | PKT_TX_TCP_SEG))
+		/* IP type not set */
+		if (!(ol_flags & (PKT_TX_IPV4 | PKT_TX_IPV6)))
+			return -EINVAL;
+
+	if (ol_flags & PKT_TX_TCP_SEG)
+		/* PKT_TX_IP_CKSUM offload not set for IPv4 TSO packet */
+		if ((m->tso_segsz == 0) ||
+				((ol_flags & PKT_TX_IPV4) && !(ol_flags & PKT_TX_IP_CKSUM)))
+			return -EINVAL;
+
+	/* PKT_TX_OUTER_IP_CKSUM set for non outer IPv4 packet. */
+	if ((ol_flags & PKT_TX_OUTER_IP_CKSUM) && !(ol_flags & PKT_TX_OUTER_IPV4))
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * Fix pseudo header checksum for TSO and non-TSO tcp/udp packets before
+ * hardware tx checksum.
+ * For non-TSO tcp/udp packets full pseudo-header checksum is counted and set.
+ * For TSO the IP payload length is not included.
+ */
+static inline int
+rte_phdr_cksum_fix(struct rte_mbuf *m)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	struct ipv6_hdr *ipv6_hdr;
+	struct tcp_hdr *tcp_hdr;
+	struct udp_hdr *udp_hdr;
+	uint64_t inner_l3_offset = m->l2_len;
+
+	if (m->ol_flags & PKT_TX_OUTER_IP_CKSUM)
+		inner_l3_offset += m->outer_l2_len + m->outer_l3_len;
+
+	if (m->ol_flags & PKT_TX_IPV4) {
+		ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *,
+				inner_l3_offset);
+
+		if (m->ol_flags & PKT_TX_IP_CKSUM)
+			ipv4_hdr->hdr_checksum = 0;
+
+		if ((m->ol_flags & PKT_TX_UDP_CKSUM) == PKT_TX_UDP_CKSUM) {
+			/* non-TSO udp */
+			udp_hdr = rte_pktmbuf_mtod_offset(m, struct udp_hdr *,
+					inner_l3_offset + m->l3_len);
+			udp_hdr->dgram_cksum = rte_ipv4_phdr_cksum(ipv4_hdr, m->ol_flags);
+		} else if ((m->ol_flags & PKT_TX_TCP_CKSUM) ||
+				(m->ol_flags & PKT_TX_TCP_SEG)) {
+			/* non-TSO tcp or TSO */
+			tcp_hdr = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *,
+					inner_l3_offset + m->l3_len);
+			tcp_hdr->cksum = rte_ipv4_phdr_cksum(ipv4_hdr, m->ol_flags);
+		}
+	} else if (m->ol_flags & PKT_TX_IPV6) {
+		ipv6_hdr = rte_pktmbuf_mtod_offset(m, struct ipv6_hdr *,
+				inner_l3_offset);
+
+		if ((m->ol_flags & PKT_TX_UDP_CKSUM) == PKT_TX_UDP_CKSUM) {
+			/* non-TSO udp */
+			udp_hdr = rte_pktmbuf_mtod_offset(m, struct udp_hdr *,
+					inner_l3_offset + m->l3_len);
+			udp_hdr->dgram_cksum = rte_ipv6_phdr_cksum(ipv6_hdr, m->ol_flags);
+		} else if ((m->ol_flags & PKT_TX_TCP_CKSUM) ||
+				(m->ol_flags & PKT_TX_TCP_SEG)) {
+			/* non-TSO tcp or TSO */
+			tcp_hdr = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *,
+					inner_l3_offset + m->l3_len);
+			tcp_hdr->cksum = rte_ipv6_phdr_cksum(ipv6_hdr, m->ol_flags);
+		}
+	}
+	return 0;
+}
+
+#endif /* _RTE_PKT_H_ */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 0/6] add Tx preparation
From: Tomasz Kulasek @ 2016-09-30  9:00 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Tomasz Kulasek
In-Reply-To: <20160928111052.9968-1-tomaszx.kulasek@intel.com>

As discussed in that thread:

http://dpdk.org/ml/archives/dev/2015-September/023603.html

Different NIC models depending on HW offload requested might impose
different requirements on packets to be TX-ed in terms of:

 - Max number of fragments per packet allowed
 - Max number of fragments per TSO segments
 - The way pseudo-header checksum should be pre-calculated
 - L3/L4 header fields filling
 - etc.


MOTIVATION:
-----------

1) Some work cannot (and didn't should) be done in rte_eth_tx_burst.
   However, this work is sometimes required, and now, it's an
   application issue.

2) Different hardware may have different requirements for TX offloads,
   other subset can be supported and so on.

3) Some parameters (e.g. number of segments in ixgbe driver) may hung
   device. These parameters may be vary for different devices.

   For example i40e HW allows 8 fragments per packet, but that is after
   TSO segmentation. While ixgbe has a 38-fragment pre-TSO limit.

4) Fields in packet may require different initialization (like e.g. will
   require pseudo-header checksum precalculation, sometimes in a
   different way depending on packet type, and so on). Now application
   needs to care about it.

5) Using additional API (rte_eth_tx_prep) before rte_eth_tx_burst let to
   prepare packet burst in acceptable form for specific device.

6) Some additional checks may be done in debug mode keeping tx_burst
   implementation clean.


PROPOSAL:
---------

To help user to deal with all these varieties we propose to:

1) Introduce rte_eth_tx_prep() function to do necessary preparations of
   packet burst to be safely transmitted on device for desired HW
   offloads (set/reset checksum field according to the hardware
   requirements) and check HW constraints (number of segments per
   packet, etc).

   While the limitations and requirements may differ for devices, it
   requires to extend rte_eth_dev structure with new function pointer
   "tx_pkt_prep" which can be implemented in the driver to prepare and
   verify packets, in devices specific way, before burst, what should to
   prevent application to send malformed packets.

2) Also new fields will be introduced in rte_eth_desc_lim: 
   nb_seg_max and nb_mtu_seg_max, providing an information about max
   segments in TSO and non-TSO packets acceptable by device.

   This information is useful for application to not create/limit
   malicious packet.


APPLICATION (CASE OF USE):
--------------------------

1) Application should to initialize burst of packets to send, set
   required tx offload flags and required fields, like l2_len, l3_len,
   l4_len, and tso_segsz

2) Application passes burst to the rte_eth_tx_prep to check conditions
   required to send packets through the NIC.

3) The result of rte_eth_tx_prep can be used to send valid packets
   and/or restore invalid if function fails.

e.g.

	for (i = 0; i < nb_pkts; i++) {

		/* initialize or process packet */

		bufs[i]->tso_segsz = 800;
		bufs[i]->ol_flags = PKT_TX_TCP_SEG | PKT_TX_IPV4
				| PKT_TX_IP_CKSUM;
		bufs[i]->l2_len = sizeof(struct ether_hdr);
		bufs[i]->l3_len = sizeof(struct ipv4_hdr);
		bufs[i]->l4_len = sizeof(struct tcp_hdr);
	}

	/* Prepare burst of TX packets */
	nb_prep = rte_eth_tx_prep(port, 0, bufs, nb_pkts);

	if (nb_prep < nb_pkts) {
		printf("tx_prep failed\n");

		/* nb_prep indicates here first invalid packet. rte_eth_tx_prep
		 * can be used on remaining packets to find another ones.
		 */

	}

	/* Send burst of TX packets */
	nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_prep);

	/* Free any unsent packets. */

v4 changes:
 - tx_prep is now set to default behavior (NULL) for simple/vector path
   in fm10k, i40e and ixgbe drivers to increase performance, when
   Tx offloads are not intentionally available

v3 changes:
 - reworked csum testpmd engine instead adding new one,
 - fixed checksum initialization procedure to include also outer
   checksum offloads,
 - some minor formattings and optimalizations

v2 changes:
 - rte_eth_tx_prep() returns number of packets when device doesn't
   support tx_prep functionality,
 - introduced CONFIG_RTE_ETHDEV_TX_PREP allowing to turn off tx_prep


Tomasz Kulasek (6):
  ethdev: add Tx preparation
  e1000: add Tx preparation
  fm10k: add Tx preparation
  i40e: add Tx preparation
  ixgbe: add Tx preparation
  testpmd: use Tx preparation in csum engine

 app/test-pmd/csumonly.c          |   97 +++++++++++++++------------
 config/common_base               |    1 +
 drivers/net/e1000/e1000_ethdev.h |   11 ++++
 drivers/net/e1000/em_ethdev.c    |    5 +-
 drivers/net/e1000/em_rxtx.c      |   48 +++++++++++++-
 drivers/net/e1000/igb_ethdev.c   |    4 ++
 drivers/net/e1000/igb_rxtx.c     |   52 ++++++++++++++-
 drivers/net/fm10k/fm10k.h        |    6 ++
 drivers/net/fm10k/fm10k_ethdev.c |    5 ++
 drivers/net/fm10k/fm10k_rxtx.c   |   50 +++++++++++++-
 drivers/net/i40e/i40e_ethdev.c   |    3 +
 drivers/net/i40e/i40e_rxtx.c     |   72 ++++++++++++++++++++-
 drivers/net/i40e/i40e_rxtx.h     |    8 +++
 drivers/net/ixgbe/ixgbe_ethdev.c |    3 +
 drivers/net/ixgbe/ixgbe_ethdev.h |    5 +-
 drivers/net/ixgbe/ixgbe_rxtx.c   |   56 +++++++++++++++-
 drivers/net/ixgbe/ixgbe_rxtx.h   |    2 +
 lib/librte_ether/rte_ethdev.h    |   85 ++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h       |    8 +++
 lib/librte_net/Makefile          |    2 +-
 lib/librte_net/rte_pkt.h         |  133 ++++++++++++++++++++++++++++++++++++++
 21 files changed, 605 insertions(+), 51 deletions(-)
 create mode 100644 lib/librte_net/rte_pkt.h

-- 
1.7.9.5

^ permalink raw reply

* Re: [PATCH] cryptodev: fix compilation error in SUSE 11 SP2
From: Adrien Mazarguil @ 2016-09-30  8:33 UTC (permalink / raw)
  To: De Lara Guarch, Pablo; +Cc: dev@dpdk.org, Doherty, Declan
In-Reply-To: <E115CCD9D858EF4F90C690B0DCB4D8973CA02375@IRSMSX108.ger.corp.intel.com>

On Thu, Sep 29, 2016 at 07:30:31PM +0000, De Lara Guarch, Pablo wrote:
> > -----Original Message-----
> > From: Adrien Mazarguil [mailto:adrien.mazarguil@6wind.com]
> > Sent: Tuesday, September 27, 2016 12:45 AM
> > To: De Lara Guarch, Pablo
> > Cc: dev@dpdk.org; Doherty, Declan
> > Subject: Re: [PATCH] cryptodev: fix compilation error in SUSE 11 SP2
> > 
> > On Mon, Sep 26, 2016 at 10:50:35PM +0100, Pablo de Lara wrote:
> > > This commit fixes following build error, which happens in SUSE 11 SP2,
> > > with gcc 4.5.1:
> > >
> > > In file included from lib/librte_cryptodev/rte_cryptodev.c:71:0:
> > > lib/librte_cryptodev/rte_cryptodev_pmd.h:76:7:
> > > error: flexible array member in otherwise empty struct
> > >
> > > Fixes: 347a1e037fd3 ("lib: use C99 syntax for zero-size arrays")
> > >
> > > Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> > 
> > Hmm, this error message does not seem related to your patch. Assuming a
> > similar error is caused by the original code, I think there is a more
> > important issue as the struct should not be empty. Can you check the
> > error?
> 
> Well, I don't really understand what is the difference between array[] and array[0],
> I thought both were the same, but some compilers only accept the latter.

Before array[] got standardized by C99, a common trick was to use array[0],
in a sense they are similar except for this one case: a struct with a single
array[] field is explicitly not allowed in C99 since it causes the structure
to be empty (this syntax only provides an alignment constraint for what
follows in case padding is required), no such problem with array[0] which
although nonstandard, is an accepted behavior, sizeof(struct foo) may yield
0 without complaint.

> In any case, the struct will not be empty, as there are other fields, that are not variable sized.
> 
> I saw that in your patch you made these two changes (among others):
> 
> diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
> index affbdec..1e30a19 100644
> --- a/lib/librte_cryptodev/rte_cryptodev.h
> +++ b/lib/librte_cryptodev/rte_cryptodev.h
> @@ -759,7 +759,7 @@ struct rte_cryptodev_sym_session {
>         } __rte_aligned(8);
>         /**< Public symmetric session details */
> 
> -       char _private[0];
> +       char _private[];
>         /**< Private session material */
>  };
> 
> diff --git a/lib/librte_cryptodev/rte_cryptodev_pmd.h b/lib/librte_cryptodev/rte_cryptodev_pmd.h
> index 7d049ea..42e7b79 100644
> --- a/lib/librte_cryptodev/rte_cryptodev_pmd.h
> +++ b/lib/librte_cryptodev/rte_cryptodev_pmd.h
> @@ -71,7 +71,7 @@ struct rte_cryptodev_session {
>                 struct rte_mempool *mp;
>         } __rte_aligned(8);
> 
> -       char _private[0];
> +       __extension__ char _private[0];
>  };
> 
> So I would expect the same change in both, as they are almost identical,
> but you took different approaches (do you know why? I would like to know :))

Yes, this was done to address the exact same error (probably with the same
old GCC version (4.4.7 perhaps?)), hence my surprise to see it fixed once
again according to your commit log, I think your only mistake was to paste
the error message for the wrong header in there (rte_cryptodev_pmd.h instead
of rte_cryptodev.h), nothing wrong with your patch besides this.

> Basically, I noticed that gcc 4.5 doesn't complain when using your second approach,
> that's why I changed it.

For the record GCC wrongly thinks the structure is empty because a unnamed
struct field is declared inside. Before C11 such declarations only created a
new type that did not occupy any space and not an actual field, hence why it
complains when faced with [] instead of the well-behaved [0].

In this particular case it's a parsing error fixed in subsequent GCC
versions, the unnamed struct actually uses some space otherwise it would
have crashed during non-regression testing (right?)

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply

* [PATCH v4 4/4] hash: modify lookup bulk pipeline
From: Pablo de Lara @ 2016-09-30  7:38 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, Byron Marohn, Saikrishna Edupuganti,
	Pablo de Lara
In-Reply-To: <1475221136-213246-1-git-send-email-pablo.de.lara.guarch@intel.com>

From: Byron Marohn <byron.marohn@intel.com>

This patch replaces the pipelined rte_hash lookup mechanism with a
loop-and-jump model, which performs significantly better,
especially for smaller table sizes and smaller table occupancies.

Signed-off-by: Byron Marohn <byron.marohn@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 lib/librte_hash/rte_cuckoo_hash.c | 377 ++++++++++++--------------------------
 lib/librte_hash/rte_cuckoo_hash.h |   3 +-
 2 files changed, 117 insertions(+), 263 deletions(-)

diff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c
index 397aa8e..1443ee1 100644
--- a/lib/librte_hash/rte_cuckoo_hash.c
+++ b/lib/librte_hash/rte_cuckoo_hash.c
@@ -914,43 +914,8 @@ rte_hash_get_key_with_position(const struct rte_hash *h, const int32_t position,
 	return 0;
 }
 
-/* Lookup bulk stage 0: Prefetch input key */
 static inline void
-lookup_stage0(unsigned *idx, uint64_t *lookup_mask,
-		const void * const *keys)
-{
-	*idx = __builtin_ctzl(*lookup_mask);
-	if (*lookup_mask == 0)
-		*idx = 0;
-
-	rte_prefetch0(keys[*idx]);
-	*lookup_mask &= ~(1llu << *idx);
-}
-
-/*
- * Lookup bulk stage 1: Calculate primary/secondary hashes
- * and prefetch primary/secondary buckets
- */
-static inline void
-lookup_stage1(unsigned idx, hash_sig_t *prim_hash, hash_sig_t *sec_hash,
-		const struct rte_hash_bucket **primary_bkt,
-		const struct rte_hash_bucket **secondary_bkt,
-		hash_sig_t *hash_vals, const void * const *keys,
-		const struct rte_hash *h)
-{
-	*prim_hash = rte_hash_hash(h, keys[idx]);
-	hash_vals[idx] = *prim_hash;
-	*sec_hash = rte_hash_secondary_hash(*prim_hash);
-
-	*primary_bkt = &h->buckets[*prim_hash & h->bucket_bitmask];
-	*secondary_bkt = &h->buckets[*sec_hash & h->bucket_bitmask];
-
-	rte_prefetch0(*primary_bkt);
-	rte_prefetch0(*secondary_bkt);
-}
-
-static inline void
-compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
+compare_signatures(uint32_t *prim_hash_matches, uint32_t *sec_hash_matches,
 				const struct rte_hash_bucket *prim_bkt,
 				const struct rte_hash_bucket *sec_bkt,
 				hash_sig_t prim_hash, hash_sig_t sec_hash,
@@ -961,11 +926,11 @@ compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
 	switch (sig_cmp_fn) {
 #ifdef RTE_MACHINE_CPUFLAG_AVX2
 	case RTE_HASH_COMPARE_AVX2:
-		*prim_hash_matches |= _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
+		*prim_hash_matches = _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
 				_mm256_load_si256(
 					(__m256i const *)prim_bkt->sig_current),
 				_mm256_set1_epi32(prim_hash)));
-		*sec_hash_matches |= _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
+		*sec_hash_matches = _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
 				_mm256_load_si256(
 					(__m256i const *)sec_bkt->sig_current),
 				_mm256_set1_epi32(sec_hash)));
@@ -974,7 +939,7 @@ compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
 #ifdef RTE_MACHINE_CPUFLAG_SSE2
 	case RTE_HASH_COMPARE_SSE:
 		/* Compare the first 4 signatures in the bucket */
-		*prim_hash_matches |= _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+		*prim_hash_matches = _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
 				_mm_load_si128(
 					(__m128i const *)prim_bkt->sig_current),
 				_mm_set1_epi32(prim_hash)));
@@ -983,7 +948,7 @@ compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
 					(__m128i const *)&prim_bkt->sig_current[4]),
 				_mm_set1_epi32(prim_hash)))) << 4;
 		/* Compare the first 4 signatures in the bucket */
-		*sec_hash_matches |= _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+		*sec_hash_matches = _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
 				_mm_load_si128(
 					(__m128i const *)sec_bkt->sig_current),
 				_mm_set1_epi32(sec_hash)));
@@ -1004,244 +969,134 @@ compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
 
 }
 
-/*
- * Lookup bulk stage 2:  Search for match hashes in primary/secondary locations
- * and prefetch first key slot
- */
+#define PREFETCH_OFFSET 4
 static inline void
-lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,
-		const struct rte_hash_bucket *prim_bkt,
-		const struct rte_hash_bucket *sec_bkt,
-		const struct rte_hash_key **key_slot, int32_t *positions,
-		uint64_t *extra_hits_mask, const void *keys,
-		const struct rte_hash *h)
+__rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,
+			int32_t num_keys, int32_t *positions,
+			uint64_t *hit_mask, void *data[])
 {
-	unsigned prim_hash_matches, sec_hash_matches, key_idx;
-	unsigned total_hash_matches;
+	uint64_t hits = 0;
+	int32_t i;
+	uint32_t prim_hash[RTE_HASH_LOOKUP_BULK_MAX];
+	uint32_t sec_hash[RTE_HASH_LOOKUP_BULK_MAX];
+	const struct rte_hash_bucket *primary_bkt[RTE_HASH_LOOKUP_BULK_MAX];
+	const struct rte_hash_bucket *secondary_bkt[RTE_HASH_LOOKUP_BULK_MAX];
+	uint32_t prim_hitmask[RTE_HASH_LOOKUP_BULK_MAX] = {0};
+	uint32_t sec_hitmask[RTE_HASH_LOOKUP_BULK_MAX] = {0};
+
+	/* Prefetch first keys */
+	for (i = 0; i < PREFETCH_OFFSET && i < num_keys; i++)
+		rte_prefetch0(keys[i]);
 
-	prim_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
-	sec_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
+	/*
+	 * Prefetch rest of the keys, calculate primary and
+	 * secondary bucket and prefetch them
+	 */
+	for (i = 0; i < (num_keys - PREFETCH_OFFSET); i++) {
+		rte_prefetch0(keys[i + PREFETCH_OFFSET]);
 
-	compare_signatures(&prim_hash_matches, &sec_hash_matches, prim_bkt,
-				sec_bkt, prim_hash, sec_hash, h->sig_cmp_fn);
+		prim_hash[i] = rte_hash_hash(h, keys[i]);
+		sec_hash[i] = rte_hash_secondary_hash(prim_hash[i]);
 
-	key_idx = prim_bkt->key_idx[__builtin_ctzl(prim_hash_matches)];
-	if (key_idx == 0)
-		key_idx = sec_bkt->key_idx[__builtin_ctzl(sec_hash_matches)];
+		primary_bkt[i] = &h->buckets[prim_hash[i] & h->bucket_bitmask];
+		secondary_bkt[i] = &h->buckets[sec_hash[i] & h->bucket_bitmask];
 
-	total_hash_matches = (prim_hash_matches |
-				(sec_hash_matches << (RTE_HASH_BUCKET_ENTRIES + 1)));
-	*key_slot = (const struct rte_hash_key *) ((const char *)keys +
-					key_idx * h->key_entry_size);
+		rte_prefetch0(primary_bkt[i]);
+		rte_prefetch0(secondary_bkt[i]);
+	}
 
-	rte_prefetch0(*key_slot);
-	/*
-	 * Return index where key is stored,
-	 * substracting the first dummy index
-	 */
-	positions[idx] = (key_idx - 1);
+	/* Calculate and prefetch rest of the buckets */
+	for (; i < num_keys; i++) {
+		prim_hash[i] = rte_hash_hash(h, keys[i]);
+		sec_hash[i] = rte_hash_secondary_hash(prim_hash[i]);
 
-	*extra_hits_mask |= (uint64_t)(__builtin_popcount(total_hash_matches) > 3) << idx;
+		primary_bkt[i] = &h->buckets[prim_hash[i] & h->bucket_bitmask];
+		secondary_bkt[i] = &h->buckets[sec_hash[i] & h->bucket_bitmask];
 
-}
+		rte_prefetch0(primary_bkt[i]);
+		rte_prefetch0(secondary_bkt[i]);
+	}
 
+	/* Compare signatures and prefetch key slot of first hit */
+	for (i = 0; i < num_keys; i++) {
+		compare_signatures(&prim_hitmask[i], &sec_hitmask[i],
+				primary_bkt[i], secondary_bkt[i],
+				prim_hash[i], sec_hash[i], h->sig_cmp_fn);
+
+		if (prim_hitmask[i]) {
+			uint32_t first_hit = __builtin_ctzl(prim_hitmask[i]);
+			uint32_t key_idx = primary_bkt[i]->key_idx[first_hit];
+			const struct rte_hash_key *key_slot =
+				(const struct rte_hash_key *)(
+				(const char *)h->key_store +
+				key_idx * h->key_entry_size);
+			rte_prefetch0(key_slot);
+			continue;
+		}
 
-/* Lookup bulk stage 3: Check if key matches, update hit mask and return data */
-static inline void
-lookup_stage3(unsigned idx, const struct rte_hash_key *key_slot, const void * const *keys,
-		const int32_t *positions, void *data[], uint64_t *hits,
-		const struct rte_hash *h)
-{
-	unsigned hit;
-	unsigned key_idx;
+		if (sec_hitmask[i]) {
+			uint32_t first_hit = __builtin_ctzl(sec_hitmask[i]);
+			uint32_t key_idx = secondary_bkt[i]->key_idx[first_hit];
+			const struct rte_hash_key *key_slot =
+				(const struct rte_hash_key *)(
+				(const char *)h->key_store +
+				key_idx * h->key_entry_size);
+			rte_prefetch0(key_slot);
+		}
+	}
 
-	hit = !rte_hash_cmp_eq(key_slot->key, keys[idx], h);
-	if (data != NULL)
-		data[idx] = key_slot->pdata;
+	/* Compare keys, first hits in primary first */
+	for (i = 0; i < num_keys; i++) {
+		positions[i] = -ENOENT;
+		while (prim_hitmask[i]) {
+			uint32_t hit_index = __builtin_ctzl(prim_hitmask[i]);
+
+			uint32_t key_idx = primary_bkt[i]->key_idx[hit_index];
+			const struct rte_hash_key *key_slot =
+				(const struct rte_hash_key *)(
+				(const char *)h->key_store +
+				key_idx * h->key_entry_size);
+			/*
+			 * If key index is 0, do not compare key,
+			 * as it is checking the dummy slot
+			 */
+			if (!!key_idx & !rte_hash_cmp_eq(key_slot->key, keys[i], h)) {
+				if (data != NULL)
+					data[i] = key_slot->pdata;
 
-	key_idx = positions[idx] + 1;
-	/*
-	 * If key index is 0, force hit to be 0, in case key to be looked up
-	 * is all zero (as in the dummy slot), which would result in a wrong hit
-	 */
-	*hits |= (uint64_t)(hit && !!key_idx)  << idx;
-}
+				hits |= 1ULL << i;
+				positions[i] = key_idx - 1;
+				goto next_key;
+			}
+			prim_hitmask[i] &= ~(1 << (hit_index));
+		}
 
-static inline void
-__rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys,
-			uint32_t num_keys, int32_t *positions,
-			uint64_t *hit_mask, void *data[])
-{
-	uint64_t hits = 0;
-	uint64_t extra_hits_mask = 0;
-	uint64_t lookup_mask, miss_mask;
-	unsigned idx;
-	const void *key_store = h->key_store;
-	int ret;
-	hash_sig_t hash_vals[RTE_HASH_LOOKUP_BULK_MAX];
-
-	unsigned idx00, idx01, idx10, idx11, idx20, idx21, idx30, idx31;
-	const struct rte_hash_bucket *primary_bkt10, *primary_bkt11;
-	const struct rte_hash_bucket *secondary_bkt10, *secondary_bkt11;
-	const struct rte_hash_bucket *primary_bkt20, *primary_bkt21;
-	const struct rte_hash_bucket *secondary_bkt20, *secondary_bkt21;
-	const struct rte_hash_key *k_slot20, *k_slot21, *k_slot30, *k_slot31;
-	hash_sig_t primary_hash10, primary_hash11;
-	hash_sig_t secondary_hash10, secondary_hash11;
-	hash_sig_t primary_hash20, primary_hash21;
-	hash_sig_t secondary_hash20, secondary_hash21;
-
-	lookup_mask = (uint64_t) -1 >> (64 - num_keys);
-	miss_mask = lookup_mask;
-
-	lookup_stage0(&idx00, &lookup_mask, keys);
-	lookup_stage0(&idx01, &lookup_mask, keys);
-
-	idx10 = idx00, idx11 = idx01;
-
-	lookup_stage0(&idx00, &lookup_mask, keys);
-	lookup_stage0(&idx01, &lookup_mask, keys);
-	lookup_stage1(idx10, &primary_hash10, &secondary_hash10,
-			&primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
-	lookup_stage1(idx11, &primary_hash11, &secondary_hash11,
-			&primary_bkt11,	&secondary_bkt11, hash_vals, keys, h);
-
-	primary_bkt20 = primary_bkt10;
-	primary_bkt21 = primary_bkt11;
-	secondary_bkt20 = secondary_bkt10;
-	secondary_bkt21 = secondary_bkt11;
-	primary_hash20 = primary_hash10;
-	primary_hash21 = primary_hash11;
-	secondary_hash20 = secondary_hash10;
-	secondary_hash21 = secondary_hash11;
-	idx20 = idx10, idx21 = idx11;
-	idx10 = idx00, idx11 = idx01;
-
-	lookup_stage0(&idx00, &lookup_mask, keys);
-	lookup_stage0(&idx01, &lookup_mask, keys);
-	lookup_stage1(idx10, &primary_hash10, &secondary_hash10,
-			&primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
-	lookup_stage1(idx11, &primary_hash11, &secondary_hash11,
-			&primary_bkt11,	&secondary_bkt11, hash_vals, keys, h);
-	lookup_stage2(idx20, primary_hash20, secondary_hash20, primary_bkt20,
-			secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
-			key_store, h);
-	lookup_stage2(idx21, primary_hash21, secondary_hash21, primary_bkt21,
-			secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
-			key_store, h);
-
-	while (lookup_mask) {
-		k_slot30 = k_slot20, k_slot31 = k_slot21;
-		idx30 = idx20, idx31 = idx21;
-		primary_bkt20 = primary_bkt10;
-		primary_bkt21 = primary_bkt11;
-		secondary_bkt20 = secondary_bkt10;
-		secondary_bkt21 = secondary_bkt11;
-		primary_hash20 = primary_hash10;
-		primary_hash21 = primary_hash11;
-		secondary_hash20 = secondary_hash10;
-		secondary_hash21 = secondary_hash11;
-		idx20 = idx10, idx21 = idx11;
-		idx10 = idx00, idx11 = idx01;
-
-		lookup_stage0(&idx00, &lookup_mask, keys);
-		lookup_stage0(&idx01, &lookup_mask, keys);
-		lookup_stage1(idx10, &primary_hash10, &secondary_hash10,
-			&primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
-		lookup_stage1(idx11, &primary_hash11, &secondary_hash11,
-			&primary_bkt11,	&secondary_bkt11, hash_vals, keys, h);
-		lookup_stage2(idx20, primary_hash20, secondary_hash20,
-			primary_bkt20, secondary_bkt20, &k_slot20, positions,
-			&extra_hits_mask, key_store, h);
-		lookup_stage2(idx21, primary_hash21, secondary_hash21,
-			primary_bkt21, secondary_bkt21,	&k_slot21, positions,
-			&extra_hits_mask, key_store, h);
-		lookup_stage3(idx30, k_slot30, keys, positions, data, &hits, h);
-		lookup_stage3(idx31, k_slot31, keys, positions, data, &hits, h);
-	}
+		while (sec_hitmask[i]) {
+			uint32_t hit_index = __builtin_ctzl(sec_hitmask[i]);
+
+			uint32_t key_idx = secondary_bkt[i]->key_idx[hit_index];
+			const struct rte_hash_key *key_slot =
+				(const struct rte_hash_key *)(
+				(const char *)h->key_store +
+				key_idx * h->key_entry_size);
+			/*
+			 * If key index is 0, do not compare key,
+			 * as it is checking the dummy slot
+			 */
+
+			if (!!key_idx & !rte_hash_cmp_eq(key_slot->key, keys[i], h)) {
+				if (data != NULL)
+					data[i] = key_slot->pdata;
 
-	k_slot30 = k_slot20, k_slot31 = k_slot21;
-	idx30 = idx20, idx31 = idx21;
-	primary_bkt20 = primary_bkt10;
-	primary_bkt21 = primary_bkt11;
-	secondary_bkt20 = secondary_bkt10;
-	secondary_bkt21 = secondary_bkt11;
-	primary_hash20 = primary_hash10;
-	primary_hash21 = primary_hash11;
-	secondary_hash20 = secondary_hash10;
-	secondary_hash21 = secondary_hash11;
-	idx20 = idx10, idx21 = idx11;
-	idx10 = idx00, idx11 = idx01;
-
-	lookup_stage1(idx10, &primary_hash10, &secondary_hash10,
-		&primary_bkt10, &secondary_bkt10, hash_vals, keys, h);
-	lookup_stage1(idx11, &primary_hash11, &secondary_hash11,
-		&primary_bkt11,	&secondary_bkt11, hash_vals, keys, h);
-	lookup_stage2(idx20, primary_hash20, secondary_hash20, primary_bkt20,
-		secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
-		key_store, h);
-	lookup_stage2(idx21, primary_hash21, secondary_hash21, primary_bkt21,
-		secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
-		key_store, h);
-	lookup_stage3(idx30, k_slot30, keys, positions, data, &hits, h);
-	lookup_stage3(idx31, k_slot31, keys, positions, data, &hits, h);
-
-	k_slot30 = k_slot20, k_slot31 = k_slot21;
-	idx30 = idx20, idx31 = idx21;
-	primary_bkt20 = primary_bkt10;
-	primary_bkt21 = primary_bkt11;
-	secondary_bkt20 = secondary_bkt10;
-	secondary_bkt21 = secondary_bkt11;
-	primary_hash20 = primary_hash10;
-	primary_hash21 = primary_hash11;
-	secondary_hash20 = secondary_hash10;
-	secondary_hash21 = secondary_hash11;
-	idx20 = idx10, idx21 = idx11;
-
-	lookup_stage2(idx20, primary_hash20, secondary_hash20, primary_bkt20,
-		secondary_bkt20, &k_slot20, positions, &extra_hits_mask,
-		key_store, h);
-	lookup_stage2(idx21, primary_hash21, secondary_hash21, primary_bkt21,
-		secondary_bkt21, &k_slot21, positions, &extra_hits_mask,
-		key_store, h);
-	lookup_stage3(idx30, k_slot30, keys, positions, data, &hits, h);
-	lookup_stage3(idx31, k_slot31, keys, positions, data, &hits, h);
-
-	k_slot30 = k_slot20, k_slot31 = k_slot21;
-	idx30 = idx20, idx31 = idx21;
-
-	lookup_stage3(idx30, k_slot30, keys, positions, data, &hits, h);
-	lookup_stage3(idx31, k_slot31, keys, positions, data, &hits, h);
-
-	/* ignore any items we have already found */
-	extra_hits_mask &= ~hits;
-
-	if (unlikely(extra_hits_mask)) {
-		/* run a single search for each remaining item */
-		do {
-			idx = __builtin_ctzl(extra_hits_mask);
-			if (data != NULL) {
-				ret = rte_hash_lookup_with_hash_data(h,
-						keys[idx], hash_vals[idx], &data[idx]);
-				if (ret >= 0)
-					hits |= 1ULL << idx;
-			} else {
-				positions[idx] = rte_hash_lookup_with_hash(h,
-							keys[idx], hash_vals[idx]);
-				if (positions[idx] >= 0)
-					hits |= 1llu << idx;
+				hits |= 1ULL << i;
+				positions[i] = key_idx - 1;
+				goto next_key;
 			}
-			extra_hits_mask &= ~(1llu << idx);
-		} while (extra_hits_mask);
-	}
+			sec_hitmask[i] &= ~(1 << (hit_index));
+		}
 
-	miss_mask &= ~hits;
-	if (unlikely(miss_mask)) {
-		do {
-			idx = __builtin_ctzl(miss_mask);
-			positions[idx] = -ENOENT;
-			miss_mask &= ~(1llu << idx);
-		} while (miss_mask);
+next_key:
+		continue;
 	}
 
 	if (hit_mask != NULL)
diff --git a/lib/librte_hash/rte_cuckoo_hash.h b/lib/librte_hash/rte_cuckoo_hash.h
index 9ff79c0..2172b2c 100644
--- a/lib/librte_hash/rte_cuckoo_hash.h
+++ b/lib/librte_hash/rte_cuckoo_hash.h
@@ -173,8 +173,7 @@ enum rte_hash_sig_compare_function {
 struct rte_hash_bucket {
 	hash_sig_t sig_current[RTE_HASH_BUCKET_ENTRIES];
 
-	/* Includes dummy key index that always contains index 0 */
-	uint32_t key_idx[RTE_HASH_BUCKET_ENTRIES + 1];
+	uint32_t key_idx[RTE_HASH_BUCKET_ENTRIES];
 
 	hash_sig_t sig_alt[RTE_HASH_BUCKET_ENTRIES];
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 3/4] hash: add vectorized comparison
From: Pablo de Lara @ 2016-09-30  7:38 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, Byron Marohn, Saikrishna Edupuganti,
	Pablo de Lara
In-Reply-To: <1475221136-213246-1-git-send-email-pablo.de.lara.guarch@intel.com>

From: Byron Marohn <byron.marohn@intel.com>

In lookup bulk function, the signatures of all entries
are compared against the signature of the key that is being looked up.
Now that all the signatures are together, they can be compared
with vector instructions (SSE, AVX2), achieving higher lookup performance.

Also, entries per bucket are increased to 8 when using processors
with AVX2, as 256 bits can be compared at once, which is the size of
8x32-bit signatures.

Signed-off-by: Byron Marohn <byron.marohn@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 lib/librte_hash/rte_cuckoo_hash.c | 73 ++++++++++++++++++++++++++++++++++++---
 lib/librte_hash/rte_cuckoo_hash.h | 12 ++++++-
 2 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c
index a7ee2b9..397aa8e 100644
--- a/lib/librte_hash/rte_cuckoo_hash.c
+++ b/lib/librte_hash/rte_cuckoo_hash.c
@@ -284,6 +284,15 @@ rte_hash_create(const struct rte_hash_parameters *params)
 	h->free_slots = r;
 	h->hw_trans_mem_support = hw_trans_mem_support;
 
+#if defined(RTE_ARCH_X86)
+	if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+		h->sig_cmp_fn = RTE_HASH_COMPARE_AVX2;
+	else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE2))
+		h->sig_cmp_fn = RTE_HASH_COMPARE_SSE;
+	else
+#endif
+		h->sig_cmp_fn = RTE_HASH_COMPARE_SCALAR;
+
 	/* Turn on multi-writer only with explicit flat from user and TM
 	 * support.
 	 */
@@ -940,6 +949,61 @@ lookup_stage1(unsigned idx, hash_sig_t *prim_hash, hash_sig_t *sec_hash,
 	rte_prefetch0(*secondary_bkt);
 }
 
+static inline void
+compare_signatures(unsigned *prim_hash_matches, unsigned *sec_hash_matches,
+				const struct rte_hash_bucket *prim_bkt,
+				const struct rte_hash_bucket *sec_bkt,
+				hash_sig_t prim_hash, hash_sig_t sec_hash,
+				enum rte_hash_sig_compare_function sig_cmp_fn)
+{
+	unsigned i;
+
+	switch (sig_cmp_fn) {
+#ifdef RTE_MACHINE_CPUFLAG_AVX2
+	case RTE_HASH_COMPARE_AVX2:
+		*prim_hash_matches |= _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
+				_mm256_load_si256(
+					(__m256i const *)prim_bkt->sig_current),
+				_mm256_set1_epi32(prim_hash)));
+		*sec_hash_matches |= _mm256_movemask_ps((__m256)_mm256_cmpeq_epi32(
+				_mm256_load_si256(
+					(__m256i const *)sec_bkt->sig_current),
+				_mm256_set1_epi32(sec_hash)));
+		break;
+#endif
+#ifdef RTE_MACHINE_CPUFLAG_SSE2
+	case RTE_HASH_COMPARE_SSE:
+		/* Compare the first 4 signatures in the bucket */
+		*prim_hash_matches |= _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+				_mm_load_si128(
+					(__m128i const *)prim_bkt->sig_current),
+				_mm_set1_epi32(prim_hash)));
+		*prim_hash_matches |= (_mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+				_mm_load_si128(
+					(__m128i const *)&prim_bkt->sig_current[4]),
+				_mm_set1_epi32(prim_hash)))) << 4;
+		/* Compare the first 4 signatures in the bucket */
+		*sec_hash_matches |= _mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+				_mm_load_si128(
+					(__m128i const *)sec_bkt->sig_current),
+				_mm_set1_epi32(sec_hash)));
+		*sec_hash_matches |= (_mm_movemask_ps((__m128)_mm_cmpeq_epi16(
+				_mm_load_si128(
+					(__m128i const *)&sec_bkt->sig_current[4]),
+				_mm_set1_epi32(sec_hash)))) << 4;
+		break;
+#endif
+	default:
+		for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
+			*prim_hash_matches |=
+				((prim_hash == prim_bkt->sig_current[i]) << i);
+			*sec_hash_matches |=
+				((sec_hash == sec_bkt->sig_current[i]) << i);
+		}
+	}
+
+}
+
 /*
  * Lookup bulk stage 2:  Search for match hashes in primary/secondary locations
  * and prefetch first key slot
@@ -952,15 +1016,14 @@ lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,
 		uint64_t *extra_hits_mask, const void *keys,
 		const struct rte_hash *h)
 {
-	unsigned prim_hash_matches, sec_hash_matches, key_idx, i;
+	unsigned prim_hash_matches, sec_hash_matches, key_idx;
 	unsigned total_hash_matches;
 
 	prim_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
 	sec_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
-	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		prim_hash_matches |= ((prim_hash == prim_bkt->sig_current[i]) << i);
-		sec_hash_matches |= ((sec_hash == sec_bkt->sig_current[i]) << i);
-	}
+
+	compare_signatures(&prim_hash_matches, &sec_hash_matches, prim_bkt,
+				sec_bkt, prim_hash, sec_hash, h->sig_cmp_fn);
 
 	key_idx = prim_bkt->key_idx[__builtin_ctzl(prim_hash_matches)];
 	if (key_idx == 0)
diff --git a/lib/librte_hash/rte_cuckoo_hash.h b/lib/librte_hash/rte_cuckoo_hash.h
index 24f8437..9ff79c0 100644
--- a/lib/librte_hash/rte_cuckoo_hash.h
+++ b/lib/librte_hash/rte_cuckoo_hash.h
@@ -130,7 +130,7 @@ enum add_key_case {
 };
 
 /** Number of items per bucket. */
-#define RTE_HASH_BUCKET_ENTRIES		4
+#define RTE_HASH_BUCKET_ENTRIES		8
 
 #define NULL_SIGNATURE			0
 
@@ -161,6 +161,14 @@ struct rte_hash_key {
 	char key[0];
 } __attribute__((aligned(KEY_ALIGNMENT)));
 
+/* All different signature compare functions */
+enum rte_hash_sig_compare_function {
+	RTE_HASH_COMPARE_SCALAR = 0,
+	RTE_HASH_COMPARE_SSE,
+	RTE_HASH_COMPARE_AVX2,
+	RTE_HASH_COMPARE_NUM
+};
+
 /** Bucket structure */
 struct rte_hash_bucket {
 	hash_sig_t sig_current[RTE_HASH_BUCKET_ENTRIES];
@@ -198,6 +206,8 @@ struct rte_hash {
 	/**< Custom function used to compare keys. */
 	enum cmp_jump_table_case cmp_jump_table_idx;
 	/**< Indicates which compare function to use. */
+	enum rte_hash_sig_compare_function sig_cmp_fn;
+	/**< Indicates which signature compare function to use. */
 	uint32_t bucket_bitmask;        /**< Bitmask for getting bucket index
 						from hash signature. */
 	uint32_t key_entry_size;         /**< Size of each key entry. */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 2/4] hash: reorganize bucket structure
From: Pablo de Lara @ 2016-09-30  7:38 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, Byron Marohn, Saikrishna Edupuganti
In-Reply-To: <1475221136-213246-1-git-send-email-pablo.de.lara.guarch@intel.com>

From: Byron Marohn <byron.marohn@intel.com>

Move current signatures of all entries together in the bucket
and same with all alternative signatures, instead of having
current and alternative signatures together per entry in the bucket.
This will be benefitial in the next commits, where a vectorized
comparison will be performed, achieving better performance.

The alternative signatures have been moved away from
the current signatures, to make the key indices be consecutive
to the current signatures, as these two fields are used by lookup,
so they are in the same cache line.

Signed-off-by: Byron Marohn <byron.marohn@intel.com>
Signed-off-by: Saikrishna Edupuganti <saikrishna.edupuganti@intel.com>
---
 lib/librte_hash/rte_cuckoo_hash.c     | 43 ++++++++++++++++++-----------------
 lib/librte_hash/rte_cuckoo_hash.h     | 17 ++++----------
 lib/librte_hash/rte_cuckoo_hash_x86.h | 20 ++++++++--------
 3 files changed, 37 insertions(+), 43 deletions(-)

diff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c
index 4de4422..a7ee2b9 100644
--- a/lib/librte_hash/rte_cuckoo_hash.c
+++ b/lib/librte_hash/rte_cuckoo_hash.c
@@ -421,7 +421,7 @@ make_space_bucket(const struct rte_hash *h, struct rte_hash_bucket *bkt)
 	 */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
 		/* Search for space in alternative locations */
-		next_bucket_idx = bkt->signatures[i].alt & h->bucket_bitmask;
+		next_bucket_idx = bkt->sig_alt[i] & h->bucket_bitmask;
 		next_bkt[i] = &h->buckets[next_bucket_idx];
 		for (j = 0; j < RTE_HASH_BUCKET_ENTRIES; j++) {
 			if (next_bkt[i]->key_idx[j] == EMPTY_SLOT)
@@ -434,8 +434,8 @@ make_space_bucket(const struct rte_hash *h, struct rte_hash_bucket *bkt)
 
 	/* Alternative location has spare room (end of recursive function) */
 	if (i != RTE_HASH_BUCKET_ENTRIES) {
-		next_bkt[i]->signatures[j].alt = bkt->signatures[i].current;
-		next_bkt[i]->signatures[j].current = bkt->signatures[i].alt;
+		next_bkt[i]->sig_alt[j] = bkt->sig_current[i];
+		next_bkt[i]->sig_current[j] = bkt->sig_alt[i];
 		next_bkt[i]->key_idx[j] = bkt->key_idx[i];
 		return i;
 	}
@@ -461,8 +461,8 @@ make_space_bucket(const struct rte_hash *h, struct rte_hash_bucket *bkt)
 	 */
 	bkt->flag[i] = 0;
 	if (ret >= 0) {
-		next_bkt[i]->signatures[ret].alt = bkt->signatures[i].current;
-		next_bkt[i]->signatures[ret].current = bkt->signatures[i].alt;
+		next_bkt[i]->sig_alt[ret] = bkt->sig_current[i];
+		next_bkt[i]->sig_current[ret] = bkt->sig_alt[i];
 		next_bkt[i]->key_idx[ret] = bkt->key_idx[i];
 		return i;
 	} else
@@ -544,8 +544,8 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is already inserted in primary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (prim_bkt->signatures[i].current == sig &&
-				prim_bkt->signatures[i].alt == alt_hash) {
+		if (prim_bkt->sig_current[i] == sig &&
+				prim_bkt->sig_alt[i] == alt_hash) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					prim_bkt->key_idx[i] * h->key_entry_size);
 			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
@@ -564,8 +564,8 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is already inserted in secondary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (sec_bkt->signatures[i].alt == sig &&
-				sec_bkt->signatures[i].current == alt_hash) {
+		if (sec_bkt->sig_alt[i] == sig &&
+				sec_bkt->sig_current[i] == alt_hash) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					sec_bkt->key_idx[i] * h->key_entry_size);
 			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
@@ -611,8 +611,8 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 		for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
 			/* Check if slot is available */
 			if (likely(prim_bkt->key_idx[i] == EMPTY_SLOT)) {
-				prim_bkt->signatures[i].current = sig;
-				prim_bkt->signatures[i].alt = alt_hash;
+				prim_bkt->sig_current[i] = sig;
+				prim_bkt->sig_alt[i] = alt_hash;
 				prim_bkt->key_idx[i] = new_idx;
 				break;
 			}
@@ -632,8 +632,8 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,
 		 */
 		ret = make_space_bucket(h, prim_bkt);
 		if (ret >= 0) {
-			prim_bkt->signatures[ret].current = sig;
-			prim_bkt->signatures[ret].alt = alt_hash;
+			prim_bkt->sig_current[ret] = sig;
+			prim_bkt->sig_alt[ret] = alt_hash;
 			prim_bkt->key_idx[ret] = new_idx;
 			if (h->add_key == ADD_KEY_MULTIWRITER)
 				rte_spinlock_unlock(h->multiwriter_lock);
@@ -707,7 +707,7 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is in primary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (bkt->signatures[i].current == sig &&
+		if (bkt->sig_current[i] == sig &&
 				bkt->key_idx[i] != EMPTY_SLOT) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
@@ -730,8 +730,8 @@ __rte_hash_lookup_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is in secondary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (bkt->signatures[i].current == alt_hash &&
-				bkt->signatures[i].alt == sig) {
+		if (bkt->sig_current[i] == alt_hash &&
+				bkt->sig_alt[i] == sig) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
 			if (rte_hash_cmp_eq(key, k->key, h) == 0) {
@@ -785,7 +785,8 @@ remove_entry(const struct rte_hash *h, struct rte_hash_bucket *bkt, unsigned i)
 	unsigned lcore_id, n_slots;
 	struct lcore_cache *cached_free_slots;
 
-	bkt->signatures[i].sig = NULL_SIGNATURE;
+	bkt->sig_current[i] = NULL_SIGNATURE;
+	bkt->sig_alt[i] = NULL_SIGNATURE;
 	if (h->hw_trans_mem_support) {
 		lcore_id = rte_lcore_id();
 		cached_free_slots = &h->local_free_slots[lcore_id];
@@ -823,7 +824,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is in primary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (bkt->signatures[i].current == sig &&
+		if (bkt->sig_current[i] == sig &&
 				bkt->key_idx[i] != EMPTY_SLOT) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
@@ -848,7 +849,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,
 
 	/* Check if key is in secondary location */
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		if (bkt->signatures[i].current == alt_hash &&
+		if (bkt->sig_current[i] == alt_hash &&
 				bkt->key_idx[i] != EMPTY_SLOT) {
 			k = (struct rte_hash_key *) ((char *)keys +
 					bkt->key_idx[i] * h->key_entry_size);
@@ -957,8 +958,8 @@ lookup_stage2(unsigned idx, hash_sig_t prim_hash, hash_sig_t sec_hash,
 	prim_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
 	sec_hash_matches = 1 << RTE_HASH_BUCKET_ENTRIES;
 	for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
-		prim_hash_matches |= ((prim_hash == prim_bkt->signatures[i].current) << i);
-		sec_hash_matches |= ((sec_hash == sec_bkt->signatures[i].current) << i);
+		prim_hash_matches |= ((prim_hash == prim_bkt->sig_current[i]) << i);
+		sec_hash_matches |= ((sec_hash == sec_bkt->sig_current[i]) << i);
 	}
 
 	key_idx = prim_bkt->key_idx[__builtin_ctzl(prim_hash_matches)];
diff --git a/lib/librte_hash/rte_cuckoo_hash.h b/lib/librte_hash/rte_cuckoo_hash.h
index 5a32ea6..24f8437 100644
--- a/lib/librte_hash/rte_cuckoo_hash.h
+++ b/lib/librte_hash/rte_cuckoo_hash.h
@@ -151,17 +151,6 @@ struct lcore_cache {
 	void *objs[LCORE_CACHE_SIZE]; /**< Cache objects */
 } __rte_cache_aligned;
 
-/* Structure storing both primary and secondary hashes */
-struct rte_hash_signatures {
-	union {
-		struct {
-			hash_sig_t current;
-			hash_sig_t alt;
-		};
-		uint64_t sig;
-	};
-};
-
 /* Structure that stores key-value pair */
 struct rte_hash_key {
 	union {
@@ -174,9 +163,13 @@ struct rte_hash_key {
 
 /** Bucket structure */
 struct rte_hash_bucket {
-	struct rte_hash_signatures signatures[RTE_HASH_BUCKET_ENTRIES];
+	hash_sig_t sig_current[RTE_HASH_BUCKET_ENTRIES];
+
 	/* Includes dummy key index that always contains index 0 */
 	uint32_t key_idx[RTE_HASH_BUCKET_ENTRIES + 1];
+
+	hash_sig_t sig_alt[RTE_HASH_BUCKET_ENTRIES];
+
 	uint8_t flag[RTE_HASH_BUCKET_ENTRIES];
 } __rte_cache_aligned;
 
diff --git a/lib/librte_hash/rte_cuckoo_hash_x86.h b/lib/librte_hash/rte_cuckoo_hash_x86.h
index e16d69c..494c160 100644
--- a/lib/librte_hash/rte_cuckoo_hash_x86.h
+++ b/lib/librte_hash/rte_cuckoo_hash_x86.h
@@ -54,8 +54,8 @@ rte_hash_cuckoo_insert_mw_tm(struct rte_hash_bucket *prim_bkt,
 			for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) {
 				/* Check if slot is available */
 				if (likely(prim_bkt->key_idx == EMPTY_SLOT)) {
-					prim_bkt->signatures[i].current = sig;
-					prim_bkt->signatures[i].alt = alt_hash;
+					prim_bkt->sig_current[i] = sig;
+					prim_bkt->sig_alt[i] = alt_hash;
 					prim_bkt->key_idx[i] = new_idx;
 					break;
 				}
@@ -101,7 +101,7 @@ rte_hash_cuckoo_move_insert_mw_tm(const struct rte_hash *h,
 				prev_slot = curr_node->prev_slot;
 
 				prev_alt_bkt_idx
-					= prev_bkt->signatures[prev_slot].alt
+					= prev_bkt->sig_alt[prev_slot]
 					    & h->bucket_bitmask;
 
 				if (unlikely(&h->buckets[prev_alt_bkt_idx]
@@ -113,10 +113,10 @@ rte_hash_cuckoo_move_insert_mw_tm(const struct rte_hash *h,
 				 * Cuckoo insert to move elements back to its
 				 * primary bucket if available
 				 */
-				curr_bkt->signatures[curr_slot].alt =
-				    prev_bkt->signatures[prev_slot].current;
-				curr_bkt->signatures[curr_slot].current =
-				    prev_bkt->signatures[prev_slot].alt;
+				curr_bkt->sig_alt[curr_slot] =
+				    prev_bkt->sig_current[prev_slot];
+				curr_bkt->sig_current[curr_slot] =
+				    prev_bkt->sig_alt[prev_slot];
 				curr_bkt->key_idx[curr_slot]
 				    = prev_bkt->key_idx[prev_slot];
 
@@ -125,8 +125,8 @@ rte_hash_cuckoo_move_insert_mw_tm(const struct rte_hash *h,
 				curr_bkt = curr_node->bkt;
 			}
 
-			curr_bkt->signatures[curr_slot].current = sig;
-			curr_bkt->signatures[curr_slot].alt = alt_hash;
+			curr_bkt->sig_current[curr_slot] = sig;
+			curr_bkt->sig_alt[curr_slot] = alt_hash;
 			curr_bkt->key_idx[curr_slot] = new_idx;
 
 			rte_xend();
@@ -178,7 +178,7 @@ rte_hash_cuckoo_make_space_mw_tm(const struct rte_hash *h,
 			}
 
 			/* Enqueue new node and keep prev node info */
-			alt_bkt = &(h->buckets[curr_bkt->signatures[i].alt
+			alt_bkt = &(h->buckets[curr_bkt->sig_alt[i]
 						    & h->bucket_bitmask]);
 			head->bkt = alt_bkt;
 			head->prev = tail;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 1/4] hash: reorder hash structure
From: Pablo de Lara @ 2016-09-30  7:38 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, Pablo de Lara
In-Reply-To: <1475221136-213246-1-git-send-email-pablo.de.lara.guarch@intel.com>

In order to optimize lookup performance, hash structure
is reordered, so all fields used for lookup will be
in the first cache line.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 lib/librte_hash/rte_cuckoo_hash.h | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/lib/librte_hash/rte_cuckoo_hash.h b/lib/librte_hash/rte_cuckoo_hash.h
index e290dab..5a32ea6 100644
--- a/lib/librte_hash/rte_cuckoo_hash.h
+++ b/lib/librte_hash/rte_cuckoo_hash.h
@@ -185,7 +185,20 @@ struct rte_hash {
 	char name[RTE_HASH_NAMESIZE];   /**< Name of the hash. */
 	uint32_t entries;               /**< Total table entries. */
 	uint32_t num_buckets;           /**< Number of buckets in table. */
-	uint32_t key_len;               /**< Length of hash key. */
+
+	struct rte_ring *free_slots;    /**< Ring that stores all indexes
+						of the free slots in the key table */
+	uint8_t hw_trans_mem_support;	/**< Hardware transactional
+							memory support */
+	struct lcore_cache *local_free_slots;
+	/**< Local cache per lcore, storing some indexes of the free slots */
+	enum add_key_case add_key; /**< Multi-writer hash add behavior */
+
+	rte_spinlock_t *multiwriter_lock; /**< Multi-writer spinlock for w/o TM */
+
+	/* Fields used in lookup */
+	uint32_t key_len __rte_cache_aligned;
+	/**< Length of hash key. */
 	rte_hash_function hash_func;    /**< Function used to calculate hash. */
 	uint32_t hash_func_init_val;    /**< Init value used by hash_func. */
 	rte_hash_cmp_eq_t rte_hash_custom_cmp_eq;
@@ -196,19 +209,10 @@ struct rte_hash {
 						from hash signature. */
 	uint32_t key_entry_size;         /**< Size of each key entry. */
 
-	struct rte_ring *free_slots;    /**< Ring that stores all indexes
-						of the free slots in the key table */
 	void *key_store;                /**< Table storing all keys and data */
 	struct rte_hash_bucket *buckets;	/**< Table with buckets storing all the
 							hash values and key indexes
 							to the key table*/
-	uint8_t hw_trans_mem_support;	/**< Hardware transactional
-							memory support */
-	struct lcore_cache *local_free_slots;
-	/**< Local cache per lcore, storing some indexes of the free slots */
-	enum add_key_case add_key; /**< Multi-writer hash add behavior */
-
-	rte_spinlock_t *multiwriter_lock; /**< Multi-writer spinlock for w/o TM */
 } __rte_cache_aligned;
 
 struct queue_node {
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 0/4] Cuckoo hash enhancements
From: Pablo de Lara @ 2016-09-30  7:38 UTC (permalink / raw)
  To: dev; +Cc: bruce.richardson, Pablo de Lara
In-Reply-To: <1473190397-120741-1-git-send-email-pablo.de.lara.guarch@intel.com>

This patchset improves lookup performance on the current hash library
by changing the existing lookup bulk pipeline, with an improved pipeline,
based on a loop-and-jump model, instead of the current 4-stage 2-entry pipeline.
Also, x86 vectorized intrinsics are used to improve performance when comparing signatures.

First patch reorganizes the order of the hash structure.
The structure takes more than one 64-byte cache line, but not all
the fields are used in the lookup operation (the most common operation).
Therefore, all these fields have been moved to the first part of the structure,
so they all fit in one cache line, improving slightly the performance in some
scenarios.

Second patch modifies the order of the bucket structure.
Currently, the buckets store all the signatures together (current and alternative).
In order to be able to perform a vectorized signature comparison,
all current signatures have to be together, so the order of the bucket has been changed,
having separated all the current signatures from the alternative signatures.

Third patch introduces x86 vectorized intrinsics.
When performing a lookup bulk operation, all current signatures in a bucket
are compared against the signature of the key being looked up.
Now that they all are together, a vectorized comparison can be performed,
which takes less instructions to be carried out.
In case of having a machine with AVX2, number of entries per bucket are
increased from 4 to 8, as AVX2 allows comparing two 256-bit values, with 8x32-bit integers,
which are the 8 signatures on the bucket.

Fourth (and last) patch modifies the current pipeline of the lookup bulk function.
The new pipeline is based on a loop-and-jump model. The two key improvements are:

- Better prefetching: in this case, first 4 keys to be looked up are prefetched,
  and after that, the rest of the keys are prefetched at the time the calculation
  of the signatures are being performed. This gives more time for the CPU to
  prefetch the data requesting before actually need it, which result in less
  cache misses and therefore, higher throughput.

- Lower performance penalty when using fallback: the lookup bulk algorithm
  assumes that most times there will not be a collision in a bucket, but it might
  happen that two or more signatures are equal, which means that more than one
  key comparison might be necessary. In that case, only the key of the first hit is prefetched,
  like in the current implementation. The difference now is that if this comparison
  results in a miss, the information of the other keys to be compared has been stored,
  unlike the current implementation, which needs to perform an entire simple lookup again.

Changes in v4:
- Reordered hash structure, so alt signature is at the start
  of the next cache line, and explain in the commit message
  why it has been moved
- Reordered hash structure, so name field is on top of the structure,
  leaving all the fields used in lookup in the next cache line
  (instead of the first cache line)

Changes in v3:
- Corrected the cover letter (wrong number of patches)

Changes in v2:
- Increased entries per bucket from 4 to 8 for all cases,
  so it is not architecture dependent any longer.
- Replaced compile-time signature comparison function election
  with run-time election, so best optimization available
  will be used from a single binary.
- Reordered the hash structure, so all the fields used by lookup
  are in the same cache line (first).

Byron Marohn (3):
  hash: reorganize bucket structure
  hash: add vectorized comparison
  hash: modify lookup bulk pipeline

Pablo de Lara (1):
  hash: reorder hash structure

 lib/librte_hash/rte_cuckoo_hash.c     | 455 ++++++++++++++--------------------
 lib/librte_hash/rte_cuckoo_hash.h     |  56 +++--
 lib/librte_hash/rte_cuckoo_hash_x86.h |  20 +-
 3 files changed, 228 insertions(+), 303 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH v2 22/22] qede: update driver version
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Rasesh Mody
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

This patch updates the qede pmd version to 1.2.2.1.

Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
---
 drivers/net/qede/qede_ethdev.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/qede/qede_ethdev.h b/drivers/net/qede/qede_ethdev.h
index dfbbcf4..91d3c90 100644
--- a/drivers/net/qede/qede_ethdev.h
+++ b/drivers/net/qede/qede_ethdev.h
@@ -42,8 +42,8 @@
 /* Driver versions */
 #define QEDE_PMD_VER_PREFIX		"QEDE PMD"
 #define QEDE_PMD_VERSION_MAJOR		1
-#define QEDE_PMD_VERSION_MINOR	        1
-#define QEDE_PMD_VERSION_REVISION       0
+#define QEDE_PMD_VERSION_MINOR	        2
+#define QEDE_PMD_VERSION_REVISION       2
 #define QEDE_PMD_VERSION_PATCH	        1
 
 #define QEDE_PMD_VERSION qede_stringify(QEDE_PMD_VERSION_MAJOR) "."     \
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 21/22] doc: update qede pmd documentation
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Rasesh Mody
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
---
 doc/guides/nics/qede.rst | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst
index d32fba2..105ae37 100644
--- a/doc/guides/nics/qede.rst
+++ b/doc/guides/nics/qede.rst
@@ -65,6 +65,8 @@ Non-supported Features
 
 - SR-IOV PF
 - Tunneling offloads
+- LRO/TSO
+- NPAR
 
 Supported QLogic Adapters
 -------------------------
@@ -239,7 +241,7 @@ SR-IOV: Prerequisites and Sample Application Notes
 
 This section provides instructions to configure SR-IOV with Linux OS.
 
-**Note**: librte_pmd_qede will be used to bind to SR-IOV VF device and Linux native kernel driver (QEDE) will function as SR-IOV PF driver.
+**Note**: librte_pmd_qede will be used to bind to SR-IOV VF device and Linux native kernel driver (QEDE) will function as SR-IOV PF driver. Requires PF driver to be 8.10.x.x or higher.
 
 #. Verify SR-IOV and ARI capability is enabled on the adapter using ``lspci``:
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 20/22] qede: remove external dependency and enable by default
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Rasesh Mody
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

The qede driver doesn't depend on libz anymore. Hence remove the LDLIBS
entry form the Makefile.

This patch enables the qede PMD by default.

Fixes: 6adac0bf ("qede: add missing external dependency and disable by default")

Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
---
 config/common_base            | 2 +-
 doc/guides/nics/qede.rst      | 5 +----
 drivers/net/qede/Makefile     | 2 --
 drivers/net/qede/base/ecore.h | 2 +-
 drivers/net/qede/qede_main.c  | 2 +-
 mk/rte.app.mk                 | 2 +-
 6 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/config/common_base b/config/common_base
index 7830535..2b03d61 100644
--- a/config/common_base
+++ b/config/common_base
@@ -317,7 +317,7 @@ CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
 
 # QLogic 25G/40G/100G PMD
 #
-CONFIG_RTE_LIBRTE_QEDE_PMD=n
+CONFIG_RTE_LIBRTE_QEDE_PMD=y
 CONFIG_RTE_LIBRTE_QEDE_DEBUG_INIT=n
 CONFIG_RTE_LIBRTE_QEDE_DEBUG_INFO=n
 CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER=n
diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst
index 50e6f87..d32fba2 100644
--- a/doc/guides/nics/qede.rst
+++ b/doc/guides/nics/qede.rst
@@ -77,14 +77,11 @@ Prerequisites
 - Requires firmware version **8.10.x.** and management firmware
   version **8.10.x or higher**. Firmware may be available
   inbox in certain newer Linux distros under the standard directory
-  ``E.g. /lib/firmware/qed/qed_init_values_zipped-8.10.9.0.bin``
+  ``E.g. /lib/firmware/qed/qed_init_values-8.10.9.0.bin``
 
 - If the required firmware files are not available then visit
   `QLogic Driver Download Center <http://driverdownloads.qlogic.com>`_.
 
-- This driver relies on external zlib library (-lz) for uncompressing
-  the firmware file.
-
 Performance note
 ~~~~~~~~~~~~~~~~
 
diff --git a/drivers/net/qede/Makefile b/drivers/net/qede/Makefile
index 7965a83..39751e4 100644
--- a/drivers/net/qede/Makefile
+++ b/drivers/net/qede/Makefile
@@ -14,8 +14,6 @@ LIB = librte_pmd_qede.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 
-LDLIBS += -lz
-
 EXPORT_MAP := rte_pmd_qede_version.map
 
 LIBABIVER := 1
diff --git a/drivers/net/qede/base/ecore.h b/drivers/net/qede/base/ecore.h
index 4359343..f99a045 100644
--- a/drivers/net/qede/base/ecore.h
+++ b/drivers/net/qede/base/ecore.h
@@ -15,7 +15,7 @@
 #include <unistd.h>
 
 #define CONFIG_ECORE_BINARY_FW
-#define CONFIG_ECORE_ZIPPED_FW
+#undef CONFIG_ECORE_ZIPPED_FW
 
 #ifdef CONFIG_ECORE_ZIPPED_FW
 #include <zlib.h>
diff --git a/drivers/net/qede/qede_main.c b/drivers/net/qede/qede_main.c
index 0483116..a0a146a 100644
--- a/drivers/net/qede/qede_main.c
+++ b/drivers/net/qede/qede_main.c
@@ -21,7 +21,7 @@ static uint8_t npar_tx_switching = 1;
 char fw_file[PATH_MAX];
 
 const char *QEDE_DEFAULT_FIRMWARE =
-	"/lib/firmware/qed/qed_init_values_zipped-8.10.9.0.bin";
+	"/lib/firmware/qed/qed_init_values-8.10.9.0.bin";
 
 static void
 qed_update_pf_params(struct ecore_dev *edev, struct ecore_pf_params *params)
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a0095b..9b12da3 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -120,7 +120,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MPIPE_PMD)      += -lrte_pmd_mpipe -lgxio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp -lm
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
-_LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede -lz
+_LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf -lm
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 19/22] qede: add support for queue statistics
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Rasesh Mody
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

This patch adds support for pulling per queue statistics.

Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
---
 drivers/net/qede/qede_ethdev.c | 98 +++++++++++++++++++++++++++++++++++++-----
 drivers/net/qede/qede_ethdev.h |  3 ++
 drivers/net/qede/qede_rxtx.c   | 23 +++++-----
 drivers/net/qede/qede_rxtx.h   |  4 +-
 4 files changed, 107 insertions(+), 21 deletions(-)

diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index 73b3b54..d1b5edc 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -160,6 +160,15 @@ static const struct rte_qede_xstats_name_off qede_xstats_strings[] = {
 		offsetof(struct ecore_eth_stats, tpa_coalesced_bytes)},
 };
 
+static const struct rte_qede_xstats_name_off qede_rxq_xstats_strings[] = {
+	{"rx_q_segments",
+		offsetof(struct qede_rx_queue, rx_segs)},
+	{"rx_q_hw_errors",
+		offsetof(struct qede_rx_queue, rx_hw_errors)},
+	{"rx_q_allocation_errors",
+		offsetof(struct qede_rx_queue, rx_alloc_errors)}
+};
+
 static void qede_interrupt_action(struct ecore_hwfn *p_hwfn)
 {
 	ecore_int_sp_dpc((osal_int_ptr_t)(p_hwfn));
@@ -825,6 +834,8 @@ qede_get_stats(struct rte_eth_dev *eth_dev, struct rte_eth_stats *eth_stats)
 	struct qede_dev *qdev = eth_dev->data->dev_private;
 	struct ecore_dev *edev = &qdev->edev;
 	struct ecore_eth_stats stats;
+	unsigned int i = 0, j = 0, qid;
+	struct qede_tx_queue *txq;
 
 	qdev->ops->get_vport_stats(edev, &stats);
 
@@ -855,20 +866,73 @@ qede_get_stats(struct rte_eth_dev *eth_dev, struct rte_eth_stats *eth_stats)
 	    stats.tx_mcast_bytes + stats.tx_bcast_bytes;
 
 	eth_stats->oerrors = stats.tx_err_drop_pkts;
+
+	/* Queue stats */
+	for (qid = 0; qid < QEDE_QUEUE_CNT(qdev); qid++) {
+		if (qdev->fp_array[qid].type & QEDE_FASTPATH_RX) {
+			eth_stats->q_ipackets[i] =
+				*(uint64_t *)(
+					((char *)(qdev->fp_array[(qid)].rxq)) +
+					offsetof(struct qede_rx_queue,
+					rcv_pkts));
+			eth_stats->q_errors[i] =
+				*(uint64_t *)(
+					((char *)(qdev->fp_array[(qid)].rxq)) +
+					offsetof(struct qede_rx_queue,
+					rx_hw_errors)) +
+				*(uint64_t *)(
+					((char *)(qdev->fp_array[(qid)].rxq)) +
+					offsetof(struct qede_rx_queue,
+					rx_alloc_errors));
+			i++;
+		}
+
+		if (qdev->fp_array[qid].type & QEDE_FASTPATH_TX) {
+			txq = qdev->fp_array[(qid)].txqs[0];
+			eth_stats->q_opackets[j] =
+				*((uint64_t *)(uintptr_t)
+					(((uint64_t)(uintptr_t)(txq)) +
+					 offsetof(struct qede_tx_queue,
+						  xmit_pkts)));
+			j++;
+		}
+	}
+}
+
+static unsigned
+qede_get_xstats_count(struct qede_dev *qdev) {
+	return RTE_DIM(qede_xstats_strings) +
+		(RTE_DIM(qede_rxq_xstats_strings) * QEDE_RSS_COUNT(qdev));
 }
 
 static int
 qede_get_xstats_names(__rte_unused struct rte_eth_dev *dev,
 		      struct rte_eth_xstat_name *xstats_names, unsigned limit)
 {
-	unsigned int i, stat_cnt = RTE_DIM(qede_xstats_strings);
+	struct qede_dev *qdev = dev->data->dev_private;
+	const unsigned int stat_cnt = qede_get_xstats_count(qdev);
+	unsigned int i, qid, stat_idx = 0;
 
-	if (xstats_names != NULL)
-		for (i = 0; i < stat_cnt; i++)
-			snprintf(xstats_names[i].name,
-				sizeof(xstats_names[i].name),
+	if (xstats_names != NULL) {
+		for (i = 0; i < RTE_DIM(qede_xstats_strings); i++) {
+			snprintf(xstats_names[stat_idx].name,
+				sizeof(xstats_names[stat_idx].name),
 				"%s",
 				qede_xstats_strings[i].name);
+			stat_idx++;
+		}
+
+		for (qid = 0; qid < QEDE_RSS_COUNT(qdev); qid++) {
+			for (i = 0; i < RTE_DIM(qede_rxq_xstats_strings); i++) {
+				snprintf(xstats_names[stat_idx].name,
+					sizeof(xstats_names[stat_idx].name),
+					"%.4s%d%s",
+					qede_rxq_xstats_strings[i].name, qid,
+					qede_rxq_xstats_strings[i].name + 4);
+				stat_idx++;
+			}
+		}
+	}
 
 	return stat_cnt;
 }
@@ -880,18 +944,32 @@ qede_get_xstats(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 	struct qede_dev *qdev = dev->data->dev_private;
 	struct ecore_dev *edev = &qdev->edev;
 	struct ecore_eth_stats stats;
-	unsigned int num = RTE_DIM(qede_xstats_strings);
+	const unsigned int num = qede_get_xstats_count(qdev);
+	unsigned int i, qid, stat_idx = 0;
 
 	if (n < num)
 		return num;
 
 	qdev->ops->get_vport_stats(edev, &stats);
 
-	for (num = 0; num < n; num++)
-		xstats[num].value = *(u64 *)(((char *)&stats) +
-					     qede_xstats_strings[num].offset);
+	for (i = 0; i < RTE_DIM(qede_xstats_strings); i++) {
+		xstats[stat_idx].value = *(uint64_t *)(((char *)&stats) +
+					     qede_xstats_strings[i].offset);
+		stat_idx++;
+	}
+
+	for (qid = 0; qid < QEDE_QUEUE_CNT(qdev); qid++) {
+		if (qdev->fp_array[qid].type & QEDE_FASTPATH_RX) {
+			for (i = 0; i < RTE_DIM(qede_rxq_xstats_strings); i++) {
+				xstats[stat_idx].value = *(uint64_t *)(
+					((char *)(qdev->fp_array[(qid)].rxq)) +
+					 qede_rxq_xstats_strings[i].offset);
+				stat_idx++;
+			}
+		}
+	}
 
-	return num;
+	return stat_idx;
 }
 
 static void
diff --git a/drivers/net/qede/qede_ethdev.h b/drivers/net/qede/qede_ethdev.h
index c3b87e8..dfbbcf4 100644
--- a/drivers/net/qede/qede_ethdev.h
+++ b/drivers/net/qede/qede_ethdev.h
@@ -68,6 +68,9 @@
 #define QEDE_TSS_COUNT(qdev) (((qdev)->num_queues - (qdev)->fp_num_rx) * \
 					(qdev)->num_tc)
 
+#define QEDE_FASTPATH_TX        (1 << 0)
+#define QEDE_FASTPATH_RX        (1 << 1)
+
 #define QEDE_DUPLEX_FULL	1
 #define QEDE_DUPLEX_HALF	2
 #define QEDE_DUPLEX_UNKNOWN     0xff
diff --git a/drivers/net/qede/qede_rxtx.c b/drivers/net/qede/qede_rxtx.c
index d903a84..9d7e704 100644
--- a/drivers/net/qede/qede_rxtx.c
+++ b/drivers/net/qede/qede_rxtx.c
@@ -10,9 +10,6 @@
 
 static bool gro_disable = 1;	/* mod_param */
 
-#define QEDE_FASTPATH_TX        (1 << 0)
-#define QEDE_FASTPATH_RX        (1 << 1)
-
 static inline int qede_alloc_rx_buffer(struct qede_rx_queue *rxq)
 {
 	struct rte_mbuf *new_mb = NULL;
@@ -814,7 +811,7 @@ static inline uint32_t qede_rx_cqe_to_pkt_type(uint16_t flags)
 }
 
 int qede_process_sg_pkts(void *p_rxq,  struct rte_mbuf *rx_mb,
-			 int num_frags, uint16_t pkt_len)
+			 int num_segs, uint16_t pkt_len)
 {
 	struct qede_rx_queue *rxq = p_rxq;
 	struct qede_dev *qdev = rxq->qdev;
@@ -825,13 +822,13 @@ int qede_process_sg_pkts(void *p_rxq,  struct rte_mbuf *rx_mb,
 	register struct rte_mbuf *seg2 = NULL;
 
 	seg1 = rx_mb;
-	while (num_frags) {
+	while (num_segs) {
 		cur_size = pkt_len > rxq->rx_buf_size ?
 				rxq->rx_buf_size : pkt_len;
 		if (!cur_size) {
 			PMD_RX_LOG(DEBUG, rxq,
 				   "SG packet, len and num BD mismatch\n");
-			qede_recycle_rx_bd_ring(rxq, qdev, num_frags);
+			qede_recycle_rx_bd_ring(rxq, qdev, num_segs);
 			return -EINVAL;
 		}
 
@@ -852,7 +849,8 @@ int qede_process_sg_pkts(void *p_rxq,  struct rte_mbuf *rx_mb,
 		seg2->data_len = cur_size;
 		seg1->next = seg2;
 		seg1 = seg1->next;
-		num_frags--;
+		num_segs--;
+		rxq->rx_segs++;
 		continue;
 	}
 	seg1 = NULL;
@@ -880,7 +878,7 @@ qede_recv_pkts(void *p_rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	register struct rte_mbuf *seg1 = NULL;
 	enum eth_rx_cqe_type cqe_type;
 	uint16_t len, pad, preload_idx, pkt_len, parse_flag;
-	uint8_t csum_flag, num_frags;
+	uint8_t csum_flag, num_segs;
 	enum rss_hash_type htype;
 	int ret;
 
@@ -954,11 +952,13 @@ qede_recv_pkts(void *p_rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
 		if (fp_cqe->bd_num > 1) {
 			pkt_len = rte_le_to_cpu_16(fp_cqe->pkt_len);
-			num_frags = fp_cqe->bd_num - 1;
+			num_segs = fp_cqe->bd_num - 1;
+
+			rxq->rx_segs++;
 
 			pkt_len -= len;
 			seg1 = rx_mb;
-			ret = qede_process_sg_pkts(p_rxq, seg1, num_frags,
+			ret = qede_process_sg_pkts(p_rxq, seg1, num_segs,
 						   pkt_len);
 			if (ret != ECORE_SUCCESS) {
 				qede_recycle_rx_bd_ring(rxq, qdev,
@@ -1021,6 +1021,8 @@ next_cqe:
 
 	qede_update_rx_prod(qdev, rxq);
 
+	rxq->rcv_pkts += rx_pkt;
+
 	PMD_RX_LOG(DEBUG, rxq, "rx_pkts=%u core=%d\n", rx_pkt, rte_lcore_id());
 
 	return rx_pkt;
@@ -1213,6 +1215,7 @@ qede_xmit_pkts(void *p_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		bd_prod =
 		    rte_cpu_to_le_16(ecore_chain_get_prod_idx(&txq->tx_pbl));
 		nb_pkt_sent++;
+		txq->xmit_pkts++;
 	}
 
 	/* Write value of prod idx into bd_prod */
diff --git a/drivers/net/qede/qede_rxtx.h b/drivers/net/qede/qede_rxtx.h
index da47b21..ed9a529 100644
--- a/drivers/net/qede/qede_rxtx.h
+++ b/drivers/net/qede/qede_rxtx.h
@@ -99,6 +99,8 @@ struct qede_rx_queue {
 	uint16_t queue_id;
 	uint16_t port_id;
 	uint16_t rx_buf_size;
+	uint64_t rcv_pkts;
+	uint64_t rx_segs;
 	uint64_t rx_hw_errors;
 	uint64_t rx_alloc_errors;
 	struct qede_dev *qdev;
@@ -130,7 +132,7 @@ struct qede_tx_queue {
 	void OSAL_IOMEM *doorbell_addr;
 	volatile union db_prod tx_db;
 	uint16_t port_id;
-	uint64_t txq_counter;
+	uint64_t xmit_pkts;
 	struct qede_dev *qdev;
 };
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 18/22] qede: fix driver version string
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Harish Patil
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

From: Harish Patil <harish.patil@qlogic.com>

This patch fixes the base driver version display.
The driver version notation is:
<Base-Version_PMD-Version>

Fixes: 2ea6f76 ("qede: add core driver")

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
---
 drivers/net/qede/qede_ethdev.c | 43 +++++++++++++++++++++---------------------
 drivers/net/qede/qede_ethdev.h | 17 ++++++++---------
 drivers/net/qede/qede_if.h     |  3 +--
 drivers/net/qede/qede_main.c   |  4 ++--
 4 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index ae188ed..73b3b54 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -8,6 +8,7 @@
 
 #include "qede_ethdev.h"
 #include <rte_alarm.h>
+#include <rte_version.h>
 
 /* Globals */
 static const struct qed_eth_ops *qed_ops;
@@ -188,31 +189,28 @@ static void qede_print_adapter_info(struct qede_dev *qdev)
 {
 	struct ecore_dev *edev = &qdev->edev;
 	struct qed_dev_info *info = &qdev->dev_info.common;
-	static char ver_str[QED_DRV_VER_STR_SIZE];
+	static char drv_ver[QEDE_PMD_DRV_VER_STR_SIZE];
+	static char ver_str[QEDE_PMD_DRV_VER_STR_SIZE];
 
 	DP_INFO(edev, "*********************************\n");
+	DP_INFO(edev, " DPDK version:%s\n", rte_version());
 	DP_INFO(edev, " Chip details : %s%d\n",
-		ECORE_IS_BB(edev) ? "BB" : "AH",
-		CHIP_REV_IS_A0(edev) ? 0 : 1);
-
-	sprintf(ver_str, "%s %s_%d.%d.%d.%d", QEDE_PMD_VER_PREFIX,
-		edev->ver_str, QEDE_PMD_VERSION_MAJOR, QEDE_PMD_VERSION_MINOR,
-		QEDE_PMD_VERSION_REVISION, QEDE_PMD_VERSION_PATCH);
-	strcpy(qdev->drv_ver, ver_str);
-	DP_INFO(edev, " Driver version : %s\n", ver_str);
-
-	sprintf(ver_str, "%d.%d.%d.%d", info->fw_major, info->fw_minor,
-		info->fw_rev, info->fw_eng);
+		  ECORE_IS_BB(edev) ? "BB" : "AH",
+		  CHIP_REV_IS_A0(edev) ? 0 : 1);
+	snprintf(ver_str, QEDE_PMD_DRV_VER_STR_SIZE, "%d.%d.%d.%d",
+		 info->fw_major, info->fw_minor, info->fw_rev, info->fw_eng);
+	snprintf(drv_ver, QEDE_PMD_DRV_VER_STR_SIZE, "%s_%s",
+		 ver_str, QEDE_PMD_VERSION);
+	DP_INFO(edev, " Driver version : %s\n", drv_ver);
 	DP_INFO(edev, " Firmware version : %s\n", ver_str);
 
-	sprintf(ver_str, "%d.%d.%d.%d",
+	snprintf(ver_str, MCP_DRV_VER_STR_SIZE,
+		 "%d.%d.%d.%d",
 		(info->mfw_rev >> 24) & 0xff,
 		(info->mfw_rev >> 16) & 0xff,
 		(info->mfw_rev >> 8) & 0xff, (info->mfw_rev) & 0xff);
-	DP_INFO(edev, " Management firmware version : %s\n", ver_str);
-
+	DP_INFO(edev, " Management Firmware version : %s\n", ver_str);
 	DP_INFO(edev, " Firmware file : %s\n", fw_file);
-
 	DP_INFO(edev, "*********************************\n");
 }
 
@@ -1359,11 +1357,12 @@ static int qede_common_dev_init(struct rte_eth_dev *eth_dev, bool is_vf)
 	/* Start the Slowpath-process */
 	memset(&params, 0, sizeof(struct qed_slowpath_params));
 	params.int_mode = ECORE_INT_MODE_MSIX;
-	params.drv_major = QEDE_MAJOR_VERSION;
-	params.drv_minor = QEDE_MINOR_VERSION;
-	params.drv_rev = QEDE_REVISION_VERSION;
-	params.drv_eng = QEDE_ENGINEERING_VERSION;
-	strncpy((char *)params.name, "qede LAN", QED_DRV_VER_STR_SIZE);
+	params.drv_major = QEDE_PMD_VERSION_MAJOR;
+	params.drv_minor = QEDE_PMD_VERSION_MINOR;
+	params.drv_rev = QEDE_PMD_VERSION_REVISION;
+	params.drv_eng = QEDE_PMD_VERSION_PATCH;
+	strncpy((char *)params.name, QEDE_PMD_VER_PREFIX,
+		QEDE_PMD_DRV_VER_STR_SIZE);
 
 	/* For CMT mode device do periodic polling for slowpath events.
 	 * This is required since uio device uses only one MSI-x
@@ -1400,7 +1399,7 @@ static int qede_common_dev_init(struct rte_eth_dev *eth_dev, bool is_vf)
 
 	qede_alloc_etherdev(adapter, &dev_info);
 
-	adapter->ops->common->set_id(edev, edev->name, QEDE_DRV_MODULE_VERSION);
+	adapter->ops->common->set_id(edev, edev->name, QEDE_PMD_VERSION);
 
 	if (!is_vf)
 		adapter->dev_info.num_mac_addrs =
diff --git a/drivers/net/qede/qede_ethdev.h b/drivers/net/qede/qede_ethdev.h
index 5838f33..c3b87e8 100644
--- a/drivers/net/qede/qede_ethdev.h
+++ b/drivers/net/qede/qede_ethdev.h
@@ -46,15 +46,14 @@
 #define QEDE_PMD_VERSION_REVISION       0
 #define QEDE_PMD_VERSION_PATCH	        1
 
-#define QEDE_MAJOR_VERSION		8
-#define QEDE_MINOR_VERSION		7
-#define QEDE_REVISION_VERSION		9
-#define QEDE_ENGINEERING_VERSION	0
+#define QEDE_PMD_VERSION qede_stringify(QEDE_PMD_VERSION_MAJOR) "."     \
+			 qede_stringify(QEDE_PMD_VERSION_MINOR) "."     \
+			 qede_stringify(QEDE_PMD_VERSION_REVISION) "."  \
+			 qede_stringify(QEDE_PMD_VERSION_PATCH)
+
+#define QEDE_PMD_DRV_VER_STR_SIZE NAME_SIZE
+#define QEDE_PMD_VER_PREFIX "QEDE PMD"
 
-#define QEDE_DRV_MODULE_VERSION qede_stringify(QEDE_MAJOR_VERSION) "."	\
-		qede_stringify(QEDE_MINOR_VERSION) "."			\
-		qede_stringify(QEDE_REVISION_VERSION) "."		\
-		qede_stringify(QEDE_ENGINEERING_VERSION)
 
 #define QEDE_RSS_INDIR_INITED     (1 << 0)
 #define QEDE_RSS_KEY_INITED       (1 << 1)
@@ -144,7 +143,7 @@ struct qede_dev {
 	bool accept_any_vlan;
 	struct ether_addr primary_mac;
 	bool handle_hw_err;
-	char drv_ver[QED_DRV_VER_STR_SIZE];
+	char drv_ver[QEDE_PMD_DRV_VER_STR_SIZE];
 };
 
 /* Static functions */
diff --git a/drivers/net/qede/qede_if.h b/drivers/net/qede/qede_if.h
index 935eed8..2d38b1b 100644
--- a/drivers/net/qede/qede_if.h
+++ b/drivers/net/qede/qede_if.h
@@ -76,14 +76,13 @@ struct qed_link_output {
 	uint32_t pause_config;
 };
 
-#define QED_DRV_VER_STR_SIZE 80
 struct qed_slowpath_params {
 	uint32_t int_mode;
 	uint8_t drv_major;
 	uint8_t drv_minor;
 	uint8_t drv_rev;
 	uint8_t drv_eng;
-	uint8_t name[QED_DRV_VER_STR_SIZE];
+	uint8_t name[NAME_SIZE];
 };
 
 #define ILT_PAGE_SIZE_TCFC 0x8000	/* 32KB */
diff --git a/drivers/net/qede/qede_main.c b/drivers/net/qede/qede_main.c
index c83893d..0483116 100644
--- a/drivers/net/qede/qede_main.c
+++ b/drivers/net/qede/qede_main.c
@@ -426,7 +426,7 @@ qed_fill_eth_dev_info(struct ecore_dev *edev, struct qed_dev_eth_info *info)
 
 static void
 qed_set_id(struct ecore_dev *edev, char name[NAME_SIZE],
-	   const char ver_str[VER_SIZE])
+	   const char ver_str[NAME_SIZE])
 {
 	int i;
 
@@ -434,7 +434,7 @@ qed_set_id(struct ecore_dev *edev, char name[NAME_SIZE],
 	for_each_hwfn(edev, i) {
 		snprintf(edev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i);
 	}
-	rte_memcpy(edev->ver_str, ver_str, VER_SIZE);
+	memcpy(edev->ver_str, ver_str, NAME_SIZE);
 	edev->drv_type = DRV_ID_DRV_TYPE_LINUX;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 17/22] qede: skip slowpath polling for 100G VF device
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Harish Patil
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

From: Harish Patil <harish.patil@qlogic.com>

There is no need to poll for slowpath events for VF
device since the ramrod responses are received over
PF-VF backchannel synchronously. So the fix is to
restrict the slowpath polling for PF device only.

Fixes 2af14ca ("net/qede: support 100G")

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
---
 drivers/net/qede/qede_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
index eb9b8aa..ae188ed 100644
--- a/drivers/net/qede/qede_ethdev.c
+++ b/drivers/net/qede/qede_ethdev.c
@@ -1369,7 +1369,7 @@ static int qede_common_dev_init(struct rte_eth_dev *eth_dev, bool is_vf)
 	 * This is required since uio device uses only one MSI-x
 	 * interrupt vector but we need one for each engine.
 	 */
-	if (edev->num_hwfns > 1) {
+	if (edev->num_hwfns > 1 && IS_PF(edev)) {
 		rc = rte_eal_alarm_set(timer_period * US_PER_S,
 				       qede_poll_sp_sb_cb,
 				       (void *)eth_dev);
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v2 16/22] qede/base: add support to initiate PF FLR
From: Rasesh Mody @ 2016-09-30  7:06 UTC (permalink / raw)
  To: dev; +Cc: Dept-EngDPDKDev, Harish Patil
In-Reply-To: <1475219169-8774-1-git-send-email-rasesh.mody@qlogic.com>

From: Harish Patil <harish.patil@qlogic.com>

Add support to send PF FLR request to the management firmware to
bringup the device in clean slate. This cleanup is necessary
in some corner cases where the device would be left in a bad
state from its previous operations. The driver will send PF FLR
request before slowpath initialization.

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
---
 doc/guides/nics/qede.rst          |  1 -
 drivers/net/qede/base/ecore_dev.c | 15 +++++++++++----
 drivers/net/qede/base/ecore_mcp.c |  9 +++++++++
 drivers/net/qede/base/ecore_mcp.h | 11 +++++++++++
 4 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst
index 2a585e7..50e6f87 100644
--- a/doc/guides/nics/qede.rst
+++ b/doc/guides/nics/qede.rst
@@ -65,7 +65,6 @@ Non-supported Features
 
 - SR-IOV PF
 - Tunneling offloads
-- Reload of the PMD after a non-graceful termination
 
 Supported QLogic Adapters
 -------------------------
diff --git a/drivers/net/qede/base/ecore_dev.c b/drivers/net/qede/base/ecore_dev.c
index c530934..0f814f2 100644
--- a/drivers/net/qede/base/ecore_dev.c
+++ b/drivers/net/qede/base/ecore_dev.c
@@ -2954,13 +2954,14 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
 			void OSAL_IOMEM *p_doorbells,
 			struct ecore_hw_prepare_params *p_params)
 {
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
 	enum _ecore_status_t rc = ECORE_SUCCESS;
 
 	/* Split PCI bars evenly between hwfns */
 	p_hwfn->regview = p_regview;
 	p_hwfn->doorbells = p_doorbells;
 
-	if (IS_VF(p_hwfn->p_dev))
+	if (IS_VF(p_dev))
 		return ecore_vf_hw_prepare(p_hwfn);
 
 	/* Validate that chip access is feasible */
@@ -2984,7 +2985,7 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
 
 	/* First hwfn learns basic information, e.g., number of hwfns */
 	if (!p_hwfn->my_id) {
-		rc = ecore_get_dev_info(p_hwfn->p_dev);
+		rc = ecore_get_dev_info(p_dev);
 		if (rc != ECORE_SUCCESS)
 			goto err1;
 	}
@@ -2998,6 +2999,12 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
 		goto err1;
 	}
 
+	if (p_hwfn == ECORE_LEADING_HWFN(p_dev) && !p_dev->recov_in_prog) {
+		rc = ecore_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt);
+		if (rc != ECORE_SUCCESS)
+			DP_NOTICE(p_hwfn, false, "Failed to initiate PF FLR\n");
+	}
+
 	/* Read the device configuration information from the HW and SHMEM */
 	rc = ecore_get_hw_info(p_hwfn, p_hwfn->p_main_ptt,
 			       p_params->personality, p_params->drv_resc_alloc);
@@ -3013,7 +3020,7 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
 		goto err2;
 	}
 #ifndef ASIC_ONLY
-	if (CHIP_REV_IS_FPGA(p_hwfn->p_dev)) {
+	if (CHIP_REV_IS_FPGA(p_dev)) {
 		DP_NOTICE(p_hwfn, false,
 			  "FPGA: workaround; Prevent DMAE parities\n");
 		ecore_wr(p_hwfn, p_hwfn->p_main_ptt, PCIE_REG_PRTY_MASK, 7);
@@ -3028,7 +3035,7 @@ ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
 	return rc;
  err2:
 	if (IS_LEAD_HWFN(p_hwfn))
-		ecore_iov_free_hw_info(p_hwfn->p_dev);
+		ecore_iov_free_hw_info(p_dev);
 	ecore_mcp_free(p_hwfn);
  err1:
 	ecore_hw_hwfn_free(p_hwfn);
diff --git a/drivers/net/qede/base/ecore_mcp.c b/drivers/net/qede/base/ecore_mcp.c
index 500368e..2ff9715 100644
--- a/drivers/net/qede/base/ecore_mcp.c
+++ b/drivers/net/qede/base/ecore_mcp.c
@@ -2442,3 +2442,12 @@ enum _ecore_status_t ecore_mcp_get_resc_info(struct ecore_hwfn *p_hwfn,
 
 	return ECORE_SUCCESS;
 }
+
+enum _ecore_status_t ecore_mcp_initiate_pf_flr(struct ecore_hwfn *p_hwfn,
+					       struct ecore_ptt *p_ptt)
+{
+	u32 mcp_resp, mcp_param;
+
+	return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR,
+			     0, &mcp_resp, &mcp_param);
+}
diff --git a/drivers/net/qede/base/ecore_mcp.h b/drivers/net/qede/base/ecore_mcp.h
index 2fc503a..1f84355 100644
--- a/drivers/net/qede/base/ecore_mcp.h
+++ b/drivers/net/qede/base/ecore_mcp.h
@@ -358,4 +358,15 @@ enum _ecore_status_t ecore_mcp_get_resc_info(struct ecore_hwfn *p_hwfn,
 					     struct resource_info *p_resc_info,
 					     u32 *p_mcp_resp, u32 *p_mcp_param);
 
+/**
+ * @brief - Initiates PF FLR
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ *
+ * @param return ECORE_SUCCESS upon success.
+ */
+enum _ecore_status_t ecore_mcp_initiate_pf_flr(struct ecore_hwfn *p_hwfn,
+					       struct ecore_ptt *p_ptt);
+
 #endif /* __ECORE_MCP_H__ */
-- 
1.8.3.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox