[dpdk-dev,v3,2/9] cxgbe: add cxgbe poll mode driver.

Message ID 033bfa619a1d67e4d0e353bc66f553464328423d.1434628361.git.rahul.lakkireddy@chelsio.com (mailing list archive)
State Changes Requested, archived
Headers

Commit Message

Rahul Lakkireddy June 18, 2015, 12:17 p.m. UTC
  Adds cxgbe poll mode driver for DPDK under drivers/net/cxgbe directory. This
patch:

1. Adds the Makefile to compile cxgbe pmd.
2. Registers and initializes the cxgbe pmd driver.

Enable cxgbe PMD for compilation and linking with changes to:
1. config/common_linuxapp to add macros for cxgbe pmd.
2. drivers/net/Makefile to add cxgbe pmd to the compile list.
3. mk/rte.app.mk to add cxgbe pmd to link.

Update MAINTAINERS file to claim responsibility for the cxgbe PMD.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
---
v3:
- Merge patches 10 and 11 with this patch to enable compilation and update
  MAINTAINERS.  Also, update commit log.
- Add rte_pmd_cxgbe_version.map and add EXPORT_MAP and LIBABIVER to cxgbe
  Makefile.
- Use RTE_DIM macro for calculating ARRAY_SIZE.

v2:
- Move files to new directory under drivers/net/cxgbe and update commit log.
- Move eth_dev_ops to separate patches.
- Update cxgbe Makefile to use relative rather than absolute path of pmd.
- Replace bitwise operations in fls() with gcc's __builtin_clz().
- Fix an issue in adap_init0_tweaks() related to rx_dma_offset.

 MAINTAINERS                                 |   5 +
 config/common_linuxapp                      |  10 +
 drivers/net/Makefile                        |   1 +
 drivers/net/cxgbe/Makefile                  |  78 +++
 drivers/net/cxgbe/cxgbe.h                   |  48 ++
 drivers/net/cxgbe/cxgbe_compat.h            | 266 +++++++++++
 drivers/net/cxgbe/cxgbe_ethdev.c            | 169 +++++++
 drivers/net/cxgbe/cxgbe_main.c              | 706 ++++++++++++++++++++++++++++
 drivers/net/cxgbe/rte_pmd_cxgbe_version.map |   4 +
 drivers/net/cxgbe/sge.c                     | 311 ++++++++++++
 mk/rte.app.mk                               |   1 +
 11 files changed, 1599 insertions(+)
 create mode 100644 drivers/net/cxgbe/Makefile
 create mode 100644 drivers/net/cxgbe/cxgbe.h
 create mode 100644 drivers/net/cxgbe/cxgbe_compat.h
 create mode 100644 drivers/net/cxgbe/cxgbe_ethdev.c
 create mode 100644 drivers/net/cxgbe/cxgbe_main.c
 create mode 100644 drivers/net/cxgbe/rte_pmd_cxgbe_version.map
 create mode 100644 drivers/net/cxgbe/sge.c
  

Comments

Thomas Monjalon June 28, 2015, 7:32 p.m. UTC | #1
2015-06-18 17:47, Rahul Lakkireddy:
> +Chelsio cxgbe
> +M: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
> +F: drivers/net/cxgbe/
> +F: doc/guides/nics/cxgbe.rst

Just a detail: the doc file is added in a later patch.
For consistency, this line should be added later.

[...]
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -208,6 +208,16 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
>  CONFIG_RTE_LIBRTE_MLX4_SOFT_COUNTERS=1
>  
>  #
> +# Compile burst-oriented Chelsio Terminator 10GbE/40GbE (CXGBE) PMD
> +#
> +CONFIG_RTE_LIBRTE_CXGBE_PMD=y
> +CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
> +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
> +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
> +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
> +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n

What is the status of the driver with FreeBSD?
Could we, at least, add the options in common_bsdapp even disabled?
  
Rahul Lakkireddy June 29, 2015, 11:23 p.m. UTC | #2
Hi Thomas,

On Sun, Jun 28, 2015 at 21:32:32 +0200, Thomas Monjalon wrote:
> 2015-06-18 17:47, Rahul Lakkireddy:
> > +Chelsio cxgbe
> > +M: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
> > +F: drivers/net/cxgbe/
> > +F: doc/guides/nics/cxgbe.rst
> 
> Just a detail: the doc file is added in a later patch.
> For consistency, this line should be added later.

I have fixed it in v4. Will post it soon.

> 
> [...]
> > --- a/config/common_linuxapp
> > +++ b/config/common_linuxapp
> > @@ -208,6 +208,16 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
> >  CONFIG_RTE_LIBRTE_MLX4_SOFT_COUNTERS=1
> >  
> >  #
> > +# Compile burst-oriented Chelsio Terminator 10GbE/40GbE (CXGBE) PMD
> > +#
> > +CONFIG_RTE_LIBRTE_CXGBE_PMD=y
> > +CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
> > +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
> > +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
> > +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
> > +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n
> 
> What is the status of the driver with FreeBSD?

We have compilation fixes in pipeline waiting for internal QA.
We are currently mid-way in testing linux vfio after which we will pick
up FBSD support.

> Could we, at least, add the options in common_bsdapp even disabled?

We tried compilation by keeping it disabled in common_bsdapp and the
compilation goes fine.

However, if its ok with you, we would like to carry out some basic testing
once our QA picks it up before adding this to common_bsdapp.

Thanks,
Rahul
  

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 9362c19..1ec5117 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -210,6 +210,11 @@  Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
 F: drivers/net/af_packet/
 
+Chelsio cxgbe
+M: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
+F: drivers/net/cxgbe/
+F: doc/guides/nics/cxgbe.rst
+
 Cisco enic
 F: drivers/net/enic/
 
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 5deb55a..22a6d4e 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -208,6 +208,16 @@  CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8
 CONFIG_RTE_LIBRTE_MLX4_SOFT_COUNTERS=1
 
 #
+# Compile burst-oriented Chelsio Terminator 10GbE/40GbE (CXGBE) PMD
+#
+CONFIG_RTE_LIBRTE_CXGBE_PMD=y
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n
+
+#
 # Compile burst-oriented Cisco ENIC PMD driver
 #
 CONFIG_RTE_LIBRTE_ENIC_PMD=y
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1e6648a..644cacb 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -33,6 +33,7 @@  include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET) += af_packet
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += bonding
+DIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe
 DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += e1000
 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
 DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
diff --git a/drivers/net/cxgbe/Makefile b/drivers/net/cxgbe/Makefile
new file mode 100644
index 0000000..4dfc6b0
--- /dev/null
+++ b/drivers/net/cxgbe/Makefile
@@ -0,0 +1,78 @@ 
+#   BSD LICENSE
+#
+#   Copyright(c) 2014-2015 Chelsio Communications.
+#   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 Chelsio Communications 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.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_cxgbe.a
+
+CFLAGS += -I$(SRCDIR)/base/
+CFLAGS += -I$(SRCDIR)
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_cxgbe_version.map
+
+LIBABIVER := 1
+
+ifeq ($(CC), icc)
+#
+# CFLAGS for icc
+#
+CFLAGS_BASE_DRIVER = -wd174 -wd593 -wd869 -wd981 -wd2259
+else
+#
+# CFLAGS for gcc
+#
+ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1)
+CFLAGS     += -Wno-deprecated
+endif
+CFLAGS_BASE_DRIVER = -Wno-unused-parameter -Wno-unused-value
+CFLAGS_BASE_DRIVER += -Wno-strict-aliasing -Wno-format-extra-args
+
+endif
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_main.c
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += sge.c
+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += base/t4_hw.c
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += lib/librte_eal lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += lib/librte_mempool lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += lib/librte_net lib/librte_malloc
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/cxgbe/cxgbe.h b/drivers/net/cxgbe/cxgbe.h
new file mode 100644
index 0000000..44d48dc
--- /dev/null
+++ b/drivers/net/cxgbe/cxgbe.h
@@ -0,0 +1,48 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2014-2015 Chelsio Communications.
+ *   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 Chelsio Communications 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 _CXGBE_H_
+#define _CXGBE_H_
+
+#include "common.h"
+#include "t4_regs.h"
+
+#define CXGBE_MIN_RING_DESC_SIZE      1024 /* Min TX/RX descriptor ring size */
+#define CXGBE_MAX_RING_DESC_SIZE      4096 /* Max TX/RX descriptor ring size */
+
+#define CXGBE_DEFAULT_TX_DESC_SIZE    1024 /* Default TX ring size */
+#define CXGBE_DEFAULT_RX_DESC_SIZE    1024 /* Default RX ring size */
+
+int cxgbe_probe(struct adapter *adapter);
+
+#endif /* _CXGBE_H_ */
diff --git a/drivers/net/cxgbe/cxgbe_compat.h b/drivers/net/cxgbe/cxgbe_compat.h
new file mode 100644
index 0000000..3b871ee
--- /dev/null
+++ b/drivers/net/cxgbe/cxgbe_compat.h
@@ -0,0 +1,266 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2014-2015 Chelsio Communications.
+ *   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 Chelsio Communications 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 _CXGBE_COMPAT_H_
+#define _CXGBE_COMPAT_H_
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rte_common.h>
+#include <rte_memcpy.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
+#include <rte_spinlock.h>
+#include <rte_log.h>
+
+#define dev_printf(level, fmt, args...) \
+	RTE_LOG(level, PMD, "rte_cxgbe_pmd: " fmt, ## args)
+
+#define dev_err(x, args...) dev_printf(ERR, args)
+#define dev_info(x, args...) dev_printf(INFO, args)
+#define dev_warn(x, args...) dev_printf(WARNING, args)
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG
+#define dev_debug(x, args...) dev_printf(DEBUG, args)
+#else
+#define dev_debug(x, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG_REG
+#define CXGBE_DEBUG_REG(x, args...) dev_printf(DEBUG, "REG:" args)
+#else
+#define CXGBE_DEBUG_REG(x, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG_MBOX
+#define CXGBE_DEBUG_MBOX(x, args...) dev_printf(DEBUG, "MBOX:" args)
+#else
+#define CXGBE_DEBUG_MBOX(x, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG_TX
+#define CXGBE_DEBUG_TX(x, args...) dev_printf(DEBUG, "TX:" args)
+#else
+#define CXGBE_DEBUG_TX(x, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG_RX
+#define CXGBE_DEBUG_RX(x, args...) dev_printf(DEBUG, "RX:" args)
+#else
+#define CXGBE_DEBUG_RX(x, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_CXGBE_DEBUG
+#define CXGBE_FUNC_TRACE() \
+	RTE_LOG(DEBUG, PMD, "CXGBE trace: %s\n", __func__)
+#else
+#define CXGBE_FUNC_TRACE() do { } while (0)
+#endif
+
+#define pr_err(y, args...) dev_err(0, y, ##args)
+#define pr_warn(y, args...) dev_warn(0, y, ##args)
+#define pr_info(y, args...) dev_info(0, y, ##args)
+#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__)
+
+#define ASSERT(x) do {\
+	if (!(x)) \
+		rte_panic("CXGBE: x"); \
+} while (0)
+#define BUG_ON(x) ASSERT(!(x))
+
+#ifndef WARN_ON
+#define WARN_ON(x) do { \
+	int ret = !!(x); \
+	if (unlikely(ret)) \
+		pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \
+} while (0)
+#endif
+
+#define __iomem
+
+#ifndef BIT
+#define BIT(n) (1 << (n))
+#endif
+
+#define L1_CACHE_SHIFT  6
+#define L1_CACHE_BYTES  BIT(L1_CACHE_SHIFT)
+
+#define PAGE_SHIFT  12
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+
+#define VLAN_HLEN 4
+
+#define rmb()     rte_rmb() /* dpdk rte provided rmb */
+#define wmb()     rte_wmb() /* dpdk rte provided wmb */
+
+typedef uint8_t   u8;
+typedef int8_t    s8;
+typedef uint16_t  u16;
+typedef uint32_t  u32;
+typedef int32_t   s32;
+typedef uint64_t  u64;
+typedef int       bool;
+typedef uint64_t  dma_addr_t;
+
+#ifndef __le16
+#define __le16	uint16_t
+#endif
+#ifndef __le32
+#define __le32	uint32_t
+#endif
+#ifndef __le64
+#define __le64	uint64_t
+#endif
+#ifndef __be16
+#define __be16	uint16_t
+#endif
+#ifndef __be32
+#define __be32	uint32_t
+#endif
+#ifndef __be64
+#define __be64	uint64_t
+#endif
+#ifndef __u8
+#define __u8	uint8_t
+#endif
+#ifndef __u16
+#define __u16	uint16_t
+#endif
+#ifndef __u32
+#define __u32	uint32_t
+#endif
+#ifndef __u64
+#define __u64	uint64_t
+#endif
+
+#define FALSE	0
+#define TRUE	1
+#define false	0
+#define true	1
+
+#define min(a, b) RTE_MIN(a, b)
+#define max(a, b) RTE_MAX(a, b)
+
+/*
+ * round up val _p to a power of 2 size _s
+ */
+#define roundup(_p, _s) (((unsigned long)(_p) + (_s - 1)) & ~(_s - 1))
+
+#undef container_of
+#define container_of(ptr, type, member) ({ \
+		typeof(((type *)0)->member)(*__mptr) = (ptr); \
+		(type *)((char *)__mptr - offsetof(type, member)); })
+
+#define ARRAY_SIZE(arr) RTE_DIM(arr)
+
+#define cpu_to_be16(o) rte_cpu_to_be_16(o)
+#define cpu_to_be32(o) rte_cpu_to_be_32(o)
+#define cpu_to_be64(o) rte_cpu_to_be_64(o)
+#define cpu_to_le32(o) rte_cpu_to_le_32(o)
+#define be16_to_cpu(o) rte_be_to_cpu_16(o)
+#define be32_to_cpu(o) rte_be_to_cpu_32(o)
+#define be64_to_cpu(o) rte_be_to_cpu_64(o)
+#define le32_to_cpu(o) rte_le_to_cpu_32(o)
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define DELAY(x) rte_delay_us(x)
+#define udelay(x) DELAY(x)
+#define msleep(x) DELAY(1000 * (x))
+#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
+
+static inline uint8_t hweight32(uint32_t word32)
+{
+	uint32_t res = word32 - ((word32 >> 1) & 0x55555555);
+
+	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+	res = (res + (res >> 4)) & 0x0F0F0F0F;
+	res = res + (res >> 8);
+	return (res + (res >> 16)) & 0x000000FF;
+
+} /* weight32 */
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static inline int fls(int x)
+{
+	return x ? sizeof(x) * 8 - __builtin_clz(x) : 0;
+}
+
+static inline unsigned long ilog2(unsigned long n)
+{
+	unsigned int e = 0;
+
+	while (n) {
+		if (n & ~((1 << 8) - 1)) {
+			e += 8;
+			n >>= 8;
+			continue;
+		}
+
+		if (n & ~((1 << 4) - 1)) {
+			e += 4;
+			n >>= 4;
+		}
+
+		for (;;) {
+			n >>= 1;
+			if (n == 0)
+				break;
+			e++;
+		}
+	}
+
+	return e;
+}
+
+static inline void writel(unsigned int val, volatile void __iomem *addr)
+{
+	*(volatile unsigned int *)addr = val;
+}
+
+static inline void writeq(u64 val, volatile void __iomem *addr)
+{
+	writel(val, addr);
+	writel(val >> 32, (void *)((uintptr_t)addr + 4));
+}
+
+#endif /* _CXGBE_COMPAT_H_ */
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
new file mode 100644
index 0000000..30d39b4
--- /dev/null
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -0,0 +1,169 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2014-2015 Chelsio Communications.
+ *   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 Chelsio Communications 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.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_interrupts.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_atomic.h>
+#include <rte_malloc.h>
+#include <rte_random.h>
+#include <rte_dev.h>
+
+#include "cxgbe.h"
+
+/*
+ * Macros needed to support the PCI Device ID Table ...
+ */
+#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \
+	static struct rte_pci_id cxgb4_pci_tbl[] = {
+#define CH_PCI_DEVICE_ID_FUNCTION 0x4
+
+#define PCI_VENDOR_ID_CHELSIO 0x1425
+
+#define CH_PCI_ID_TABLE_ENTRY(devid) \
+		{ RTE_PCI_DEVICE(PCI_VENDOR_ID_CHELSIO, (devid)) }
+
+#define CH_PCI_DEVICE_ID_TABLE_DEFINE_END \
+		{ .vendor_id = 0, } \
+	}
+
+/*
+ *... and the PCI ID Table itself ...
+ */
+#include "t4_pci_id_tbl.h"
+
+static struct eth_dev_ops cxgbe_eth_dev_ops = {
+};
+
+/*
+ * Initialize driver
+ * It returns 0 on success.
+ */
+static int eth_cxgbe_dev_init(struct rte_eth_dev *eth_dev)
+{
+	struct rte_pci_device *pci_dev;
+	struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
+	struct adapter *adapter = NULL;
+	char name[RTE_ETH_NAME_MAX_LEN];
+	int err = 0;
+
+	CXGBE_FUNC_TRACE();
+
+	eth_dev->dev_ops = &cxgbe_eth_dev_ops;
+
+	/* for secondary processes, we don't initialise any further as primary
+	 * has already done this work.
+	 */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	pci_dev = eth_dev->pci_dev;
+	snprintf(name, sizeof(name), "cxgbeadapter%d", eth_dev->data->port_id);
+	adapter = rte_zmalloc(name, sizeof(*adapter), 0);
+	if (!adapter)
+		return -1;
+
+	adapter->use_unpacked_mode = 1;
+	adapter->regs = (void *)pci_dev->mem_resource[0].addr;
+	if (!adapter->regs) {
+		dev_err(adapter, "%s: cannot map device registers\n", __func__);
+		err = -ENOMEM;
+		goto out_free_adapter;
+	}
+	adapter->pdev = pci_dev;
+	adapter->eth_dev = eth_dev;
+	pi->adapter = adapter;
+
+	err = cxgbe_probe(adapter);
+	if (err)
+		dev_err(adapter, "%s: cxgbe probe failed with err %d\n",
+			__func__, err);
+
+out_free_adapter:
+	return err;
+}
+
+static struct eth_driver rte_cxgbe_pmd = {
+	{
+		.name = "rte_cxgbe_pmd",
+		.id_table = cxgb4_pci_tbl,
+		.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+	},
+	.eth_dev_init = eth_cxgbe_dev_init,
+	.dev_private_size = sizeof(struct port_info),
+};
+
+/*
+ * Driver initialization routine.
+ * Invoked once at EAL init time.
+ * Register itself as the [Poll Mode] Driver of PCI CXGBE devices.
+ */
+static int rte_cxgbe_pmd_init(const char *name __rte_unused,
+			      const char *params __rte_unused)
+{
+	CXGBE_FUNC_TRACE();
+
+	rte_eth_driver_register(&rte_cxgbe_pmd);
+	return 0;
+}
+
+static struct rte_driver rte_cxgbe_driver = {
+	.name = "cxgbe_driver",
+	.type = PMD_PDEV,
+	.init = rte_cxgbe_pmd_init,
+};
+
+PMD_REGISTER_DRIVER(rte_cxgbe_driver);
diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c
new file mode 100644
index 0000000..6f3a6db
--- /dev/null
+++ b/drivers/net/cxgbe/cxgbe_main.c
@@ -0,0 +1,706 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2014-2015 Chelsio Communications.
+ *   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 Chelsio Communications 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.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_interrupts.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_atomic.h>
+#include <rte_malloc.h>
+#include <rte_random.h>
+#include <rte_dev.h>
+
+#include "common.h"
+#include "t4_regs.h"
+#include "t4_msg.h"
+#include "cxgbe.h"
+
+static void setup_memwin(struct adapter *adap)
+{
+	u32 mem_win0_base;
+
+	/* For T5, only relative offset inside the PCIe BAR is passed */
+	mem_win0_base = MEMWIN0_BASE;
+
+	/*
+	 * Set up memory window for accessing adapter memory ranges.  (Read
+	 * back MA register to ensure that changes propagate before we attempt
+	 * to use the new values.)
+	 */
+	t4_write_reg(adap,
+		     PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN,
+					 MEMWIN_NIC),
+		     mem_win0_base | V_BIR(0) |
+		     V_WINDOW(ilog2(MEMWIN0_APERTURE) - X_WINDOW_SHIFT));
+	t4_read_reg(adap,
+		    PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN,
+					MEMWIN_NIC));
+}
+
+static void print_port_info(struct adapter *adap)
+{
+	int i;
+	char buf[80];
+	struct rte_pci_addr *loc = &adap->pdev->addr;
+
+	for_each_port(adap, i) {
+		const struct port_info *pi = &adap->port[i];
+		char *bufp = buf;
+
+		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
+			bufp += sprintf(bufp, "100/");
+		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
+			bufp += sprintf(bufp, "1000/");
+		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
+			bufp += sprintf(bufp, "10G/");
+		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G)
+			bufp += sprintf(bufp, "40G/");
+		if (bufp != buf)
+			--bufp;
+		sprintf(bufp, "BASE-%s",
+			t4_get_port_type_description(pi->port_type));
+
+		dev_info(adap,
+			 " " PCI_PRI_FMT " Chelsio rev %d %s %s\n",
+			 loc->domain, loc->bus, loc->devid, loc->function,
+			 CHELSIO_CHIP_RELEASE(adap->params.chip), buf,
+			 (adap->flags & USING_MSIX) ? " MSI-X" :
+			 (adap->flags & USING_MSI) ? " MSI" : "");
+	}
+}
+
+/*
+ * Tweak configuration based on system architecture, etc.  Most of these have
+ * defaults assigned to them by Firmware Configuration Files (if we're using
+ * them) but need to be explicitly set if we're using hard-coded
+ * initialization. So these are essentially common tweaks/settings for
+ * Configuration Files and hard-coded initialization ...
+ */
+static int adap_init0_tweaks(struct adapter *adapter)
+{
+	u8 rx_dma_offset;
+
+	/*
+	 * Fix up various Host-Dependent Parameters like Page Size, Cache
+	 * Line Size, etc.  The firmware default is for a 4KB Page Size and
+	 * 64B Cache Line Size ...
+	 */
+	t4_fixup_host_params_compat(adapter, PAGE_SIZE, L1_CACHE_BYTES,
+				    T5_LAST_REV);
+
+	/*
+	 * Keep the chip default offset to deliver Ingress packets into our
+	 * DMA buffers to zero
+	 */
+	rx_dma_offset = 0;
+	t4_set_reg_field(adapter, A_SGE_CONTROL, V_PKTSHIFT(M_PKTSHIFT),
+			 V_PKTSHIFT(rx_dma_offset));
+
+	/*
+	 * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux
+	 * adds the pseudo header itself.
+	 */
+	t4_tp_wr_bits_indirect(adapter, A_TP_INGRESS_CONFIG,
+			       F_CSUM_HAS_PSEUDO_HDR, 0);
+
+	return 0;
+}
+
+/*
+ * Attempt to initialize the adapter via a Firmware Configuration File.
+ */
+static int adap_init0_config(struct adapter *adapter, int reset)
+{
+	struct fw_caps_config_cmd caps_cmd;
+	unsigned long mtype = 0, maddr = 0;
+	u32 finiver, finicsum, cfcsum;
+	int ret;
+	int config_issued = 0;
+	int cfg_addr;
+	char config_name[20];
+
+	/*
+	 * Reset device if necessary.
+	 */
+	if (reset) {
+		ret = t4_fw_reset(adapter, adapter->mbox,
+				  F_PIORSTMODE | F_PIORST);
+		if (ret < 0) {
+			dev_warn(adapter, "Firmware reset failed, error %d\n",
+				 -ret);
+			goto bye;
+		}
+	}
+
+	cfg_addr = t4_flash_cfg_addr(adapter);
+	if (cfg_addr < 0) {
+		ret = cfg_addr;
+		dev_warn(adapter, "Finding address for firmware config file in flash failed, error %d\n",
+			 -ret);
+		goto bye;
+	}
+
+	strcpy(config_name, "On Flash");
+	mtype = FW_MEMTYPE_CF_FLASH;
+	maddr = cfg_addr;
+
+	/*
+	 * Issue a Capability Configuration command to the firmware to get it
+	 * to parse the Configuration File.  We don't use t4_fw_config_file()
+	 * because we want the ability to modify various features after we've
+	 * processed the configuration file ...
+	 */
+	memset(&caps_cmd, 0, sizeof(caps_cmd));
+	caps_cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+					   F_FW_CMD_REQUEST | F_FW_CMD_READ);
+	caps_cmd.cfvalid_to_len16 =
+		cpu_to_be32(F_FW_CAPS_CONFIG_CMD_CFVALID |
+			    V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
+			    V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
+			    FW_LEN16(caps_cmd));
+	ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
+			 &caps_cmd);
+	/*
+	 * If the CAPS_CONFIG failed with an ENOENT (for a Firmware
+	 * Configuration File in FLASH), our last gasp effort is to use the
+	 * Firmware Configuration File which is embedded in the firmware.  A
+	 * very few early versions of the firmware didn't have one embedded
+	 * but we can ignore those.
+	 */
+	if (ret == -ENOENT) {
+		dev_info(adapter, "%s: Going for embedded config in firmware..\n",
+			 __func__);
+
+		memset(&caps_cmd, 0, sizeof(caps_cmd));
+		caps_cmd.op_to_write =
+			cpu_to_be32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+				    F_FW_CMD_REQUEST | F_FW_CMD_READ);
+		caps_cmd.cfvalid_to_len16 = cpu_to_be32(FW_LEN16(caps_cmd));
+		ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd,
+				 sizeof(caps_cmd), &caps_cmd);
+		strcpy(config_name, "Firmware Default");
+	}
+
+	config_issued = 1;
+	if (ret < 0)
+		goto bye;
+
+	finiver = be32_to_cpu(caps_cmd.finiver);
+	finicsum = be32_to_cpu(caps_cmd.finicsum);
+	cfcsum = be32_to_cpu(caps_cmd.cfcsum);
+	if (finicsum != cfcsum)
+		dev_warn(adapter, "Configuration File checksum mismatch: [fini] csum=%#x, computed csum=%#x\n",
+			 finicsum, cfcsum);
+
+	/*
+	 * If we're a pure NIC driver then disable all offloading facilities.
+	 * This will allow the firmware to optimize aspects of the hardware
+	 * configuration which will result in improved performance.
+	 */
+	caps_cmd.niccaps &= cpu_to_be16(~(FW_CAPS_CONFIG_NIC_HASHFILTER |
+					  FW_CAPS_CONFIG_NIC_ETHOFLD));
+	caps_cmd.toecaps = 0;
+	caps_cmd.iscsicaps = 0;
+	caps_cmd.rdmacaps = 0;
+	caps_cmd.fcoecaps = 0;
+
+	/*
+	 * And now tell the firmware to use the configuration we just loaded.
+	 */
+	caps_cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+					   F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
+	caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
+	ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
+			 NULL);
+	if (ret < 0) {
+		dev_warn(adapter, "Unable to finalize Firmware Capabilities %d\n",
+			 -ret);
+		goto bye;
+	}
+
+	/*
+	 * Tweak configuration based on system architecture, etc.
+	 */
+	ret = adap_init0_tweaks(adapter);
+	if (ret < 0) {
+		dev_warn(adapter, "Unable to do init0-tweaks %d\n", -ret);
+		goto bye;
+	}
+
+	/*
+	 * And finally tell the firmware to initialize itself using the
+	 * parameters from the Configuration File.
+	 */
+	ret = t4_fw_initialize(adapter, adapter->mbox);
+	if (ret < 0) {
+		dev_warn(adapter, "Initializing Firmware failed, error %d\n",
+			 -ret);
+		goto bye;
+	}
+
+	/*
+	 * Return successfully and note that we're operating with parameters
+	 * not supplied by the driver, rather than from hard-wired
+	 * initialization constants burried in the driver.
+	 */
+	dev_info(adapter,
+		 "Successfully configured using Firmware Configuration File \"%s\", version %#x, computed checksum %#x\n",
+		 config_name, finiver, cfcsum);
+
+	return 0;
+
+	/*
+	 * Something bad happened.  Return the error ...  (If the "error"
+	 * is that there's no Configuration File on the adapter we don't
+	 * want to issue a warning since this is fairly common.)
+	 */
+bye:
+	if (config_issued && ret != -ENOENT)
+		dev_warn(adapter, "\"%s\" configuration file error %d\n",
+			 config_name, -ret);
+
+	dev_debug(adapter, "%s: returning ret = %d ..\n", __func__, ret);
+	return ret;
+}
+
+static int adap_init0(struct adapter *adap)
+{
+	int ret = 0;
+	u32 v, port_vec;
+	enum dev_state state;
+	u32 params[7], val[7];
+	int reset = 1;
+	int mbox = adap->mbox;
+
+	/*
+	 * Contact FW, advertising Master capability.
+	 */
+	ret = t4_fw_hello(adap, adap->mbox, adap->mbox, MASTER_MAY, &state);
+	if (ret < 0) {
+		dev_err(adap, "%s: could not connect to FW, error %d\n",
+			__func__, -ret);
+		goto bye;
+	}
+
+	CXGBE_DEBUG_MBOX(adap, "%s: adap->mbox = %d; ret = %d\n", __func__,
+			 adap->mbox, ret);
+
+	if (ret == mbox)
+		adap->flags |= MASTER_PF;
+
+	if (state == DEV_STATE_INIT) {
+		/*
+		 * Force halt and reset FW because a previous instance may have
+		 * exited abnormally without properly shutting down
+		 */
+		ret = t4_fw_halt(adap, adap->mbox, reset);
+		if (ret < 0) {
+			dev_err(adap, "Failed to halt. Exit.\n");
+			goto bye;
+		}
+
+		ret = t4_fw_restart(adap, adap->mbox, reset);
+		if (ret < 0) {
+			dev_err(adap, "Failed to restart. Exit.\n");
+			goto bye;
+		}
+		state &= ~DEV_STATE_INIT;
+	}
+
+	t4_get_fw_version(adap, &adap->params.fw_vers);
+	t4_get_tp_version(adap, &adap->params.tp_vers);
+
+	dev_info(adap, "fw: %u.%u.%u.%u, TP: %u.%u.%u.%u\n",
+		 G_FW_HDR_FW_VER_MAJOR(adap->params.fw_vers),
+		 G_FW_HDR_FW_VER_MINOR(adap->params.fw_vers),
+		 G_FW_HDR_FW_VER_MICRO(adap->params.fw_vers),
+		 G_FW_HDR_FW_VER_BUILD(adap->params.fw_vers),
+		 G_FW_HDR_FW_VER_MAJOR(adap->params.tp_vers),
+		 G_FW_HDR_FW_VER_MINOR(adap->params.tp_vers),
+		 G_FW_HDR_FW_VER_MICRO(adap->params.tp_vers),
+		 G_FW_HDR_FW_VER_BUILD(adap->params.tp_vers));
+
+	ret = t4_get_core_clock(adap, &adap->params.vpd);
+	if (ret < 0) {
+		dev_err(adap, "%s: could not get core clock, error %d\n",
+			__func__, -ret);
+		goto bye;
+	}
+
+	/*
+	 * Find out what ports are available to us.  Note that we need to do
+	 * this before calling adap_init0_no_config() since it needs nports
+	 * and portvec ...
+	 */
+	v = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
+	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_PORTVEC);
+	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &v, &port_vec);
+	if (ret < 0) {
+		dev_err(adap, "%s: failure in t4_queury_params; error = %d\n",
+			__func__, ret);
+		goto bye;
+	}
+
+	adap->params.nports = hweight32(port_vec);
+	adap->params.portvec = port_vec;
+
+	dev_debug(adap, "%s: adap->params.nports = %u\n", __func__,
+		  adap->params.nports);
+
+	/*
+	 * If the firmware is initialized already (and we're not forcing a
+	 * master initialization), note that we're living with existing
+	 * adapter parameters.  Otherwise, it's time to try initializing the
+	 * adapter ...
+	 */
+	if (state == DEV_STATE_INIT) {
+		dev_info(adap, "Coming up as %s: Adapter already initialized\n",
+			 adap->flags & MASTER_PF ? "MASTER" : "SLAVE");
+	} else {
+		dev_info(adap, "Coming up as MASTER: Initializing adapter\n");
+
+		ret = adap_init0_config(adap, reset);
+		if (ret == -ENOENT) {
+			dev_err(adap,
+				"No Configuration File present on adapter. Using hard-wired configuration parameters.\n");
+			goto bye;
+		}
+	}
+	if (ret < 0) {
+		dev_err(adap, "could not initialize adapter, error %d\n", -ret);
+		goto bye;
+	}
+
+	/*
+	 * Give the SGE code a chance to pull in anything that it needs ...
+	 * Note that this must be called after we retrieve our VPD parameters
+	 * in order to know how to convert core ticks to seconds, etc.
+	 */
+	ret = t4_sge_init(adap);
+	if (ret < 0) {
+		dev_err(adap, "t4_sge_init failed with error %d\n",
+			-ret);
+		goto bye;
+	}
+
+	/*
+	 * Grab some of our basic fundamental operating parameters.
+	 */
+#define FW_PARAM_DEV(param) \
+	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
+	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
+
+#define FW_PARAM_PFVF(param) \
+	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
+	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) |  \
+	 V_FW_PARAMS_PARAM_Y(0) | \
+	 V_FW_PARAMS_PARAM_Z(0))
+
+	/* If we're running on newer firmware, let it know that we're
+	 * prepared to deal with encapsulated CPL messages.  Older
+	 * firmware won't understand this and we'll just get
+	 * unencapsulated messages ...
+	 */
+	params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
+	val[0] = 1;
+	(void)t4_set_params(adap, adap->mbox, adap->pf, 0, 1, params, val);
+
+	/*
+	 * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL
+	 * capability.  Earlier versions of the firmware didn't have the
+	 * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no
+	 * permission to use ULPTX MEMWRITE DSGL.
+	 */
+	if (is_t4(adap->params.chip)) {
+		adap->params.ulptx_memwrite_dsgl = false;
+	} else {
+		params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL);
+		ret = t4_query_params(adap, adap->mbox, adap->pf, 0,
+				      1, params, val);
+		adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
+	}
+
+	/*
+	 * The MTU/MSS Table is initialized by now, so load their values.  If
+	 * we're initializing the adapter, then we'll make any modifications
+	 * we want to the MTU/MSS Table and also initialize the congestion
+	 * parameters.
+	 */
+	t4_read_mtu_tbl(adap, adap->params.mtus, NULL);
+	if (state != DEV_STATE_INIT) {
+		int i;
+
+		/*
+		 * The default MTU Table contains values 1492 and 1500.
+		 * However, for TCP, it's better to have two values which are
+		 * a multiple of 8 +/- 4 bytes apart near this popular MTU.
+		 * This allows us to have a TCP Data Payload which is a
+		 * multiple of 8 regardless of what combination of TCP Options
+		 * are in use (always a multiple of 4 bytes) which is
+		 * important for performance reasons.  For instance, if no
+		 * options are in use, then we have a 20-byte IP header and a
+		 * 20-byte TCP header.  In this case, a 1500-byte MSS would
+		 * result in a TCP Data Payload of 1500 - 40 == 1460 bytes
+		 * which is not a multiple of 8.  So using an MSS of 1488 in
+		 * this case results in a TCP Data Payload of 1448 bytes which
+		 * is a multiple of 8.  On the other hand, if 12-byte TCP Time
+		 * Stamps have been negotiated, then an MTU of 1500 bytes
+		 * results in a TCP Data Payload of 1448 bytes which, as
+		 * above, is a multiple of 8 bytes ...
+		 */
+		for (i = 0; i < NMTUS; i++)
+			if (adap->params.mtus[i] == 1492) {
+				adap->params.mtus[i] = 1488;
+				break;
+			}
+
+		t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
+			     adap->params.b_wnd);
+	}
+	t4_init_sge_params(adap);
+	t4_init_tp_params(adap);
+
+	adap->params.drv_memwin = MEMWIN_NIC;
+	adap->flags |= FW_OK;
+	dev_debug(adap, "%s: returning zero..\n", __func__);
+	return 0;
+
+	/*
+	 * Something bad happened.  If a command timed out or failed with EIO
+	 * FW does not operate within its spec or something catastrophic
+	 * happened to HW/FW, stop issuing commands.
+	 */
+bye:
+	if (ret != -ETIMEDOUT && ret != -EIO)
+		t4_fw_bye(adap, adap->mbox);
+	return ret;
+}
+
+/**
+ * t4_os_portmod_changed - handle port module changes
+ * @adap: the adapter associated with the module change
+ * @port_id: the port index whose module status has changed
+ *
+ * This is the OS-dependent handler for port module changes.  It is
+ * invoked when a port module is removed or inserted for any OS-specific
+ * processing.
+ */
+void t4_os_portmod_changed(const struct adapter *adap, int port_id)
+{
+	static const char * const mod_str[] = {
+		NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM"
+	};
+
+	const struct port_info *pi = &adap->port[port_id];
+
+	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
+		dev_info(adap, "Port%d: port module unplugged\n", pi->port_id);
+	else if (pi->mod_type < ARRAY_SIZE(mod_str))
+		dev_info(adap, "Port%d: %s port module inserted\n", pi->port_id,
+			 mod_str[pi->mod_type]);
+	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
+		dev_info(adap, "Port%d: unsupported optical port module inserted\n",
+			 pi->port_id);
+	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
+		dev_info(adap, "Port%d: unknown port module inserted, forcing TWINAX\n",
+			 pi->port_id);
+	else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR)
+		dev_info(adap, "Port%d: transceiver module error\n",
+			 pi->port_id);
+	else
+		dev_info(adap, "Port%d: unknown module type %d inserted\n",
+			 pi->port_id, pi->mod_type);
+}
+
+int cxgbe_probe(struct adapter *adapter)
+{
+	struct port_info *pi;
+	int func, i;
+	int err = 0;
+
+	func = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI));
+	adapter->mbox = func;
+	adapter->pf = func;
+
+	t4_os_lock_init(&adapter->mbox_lock);
+	TAILQ_INIT(&adapter->mbox_list);
+
+	err = t4_prep_adapter(adapter);
+	if (err)
+		return err;
+
+	setup_memwin(adapter);
+	err = adap_init0(adapter);
+	if (err) {
+		dev_err(adapter, "%s: Adapter initialization failed, error %d\n",
+			__func__, err);
+		goto out_free;
+	}
+
+	if (!is_t4(adapter->params.chip)) {
+		/*
+		 * The userspace doorbell BAR is split evenly into doorbell
+		 * regions, each associated with an egress queue.  If this
+		 * per-queue region is large enough (at least UDBS_SEG_SIZE)
+		 * then it can be used to submit a tx work request with an
+		 * implied doorbell.  Enable write combining on the BAR if
+		 * there is room for such work requests.
+		 */
+		int s_qpp, qpp, num_seg;
+
+		s_qpp = (S_QUEUESPERPAGEPF0 +
+			(S_QUEUESPERPAGEPF1 - S_QUEUESPERPAGEPF0) *
+			adapter->pf);
+		qpp = 1 << ((t4_read_reg(adapter,
+				A_SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp)
+				& M_QUEUESPERPAGEPF0);
+		num_seg = PAGE_SIZE / UDBS_SEG_SIZE;
+		if (qpp > num_seg)
+			dev_warn(adapter, "Incorrect SGE EGRESS QUEUES_PER_PAGE configuration, continuing in debug mode\n");
+
+		adapter->bar2 = (void *)adapter->pdev->mem_resource[2].addr;
+		if (!adapter->bar2) {
+			dev_err(adapter, "cannot map device bar2 region\n");
+			err = -ENOMEM;
+			goto out_free;
+		}
+		t4_write_reg(adapter, A_SGE_STAT_CFG, V_STATSOURCE_T5(7) |
+			     V_STATMODE(0));
+	}
+
+	for_each_port(adapter, i) {
+		char name[RTE_ETH_NAME_MAX_LEN];
+		struct rte_eth_dev_data *data = NULL;
+		const unsigned int numa_node = rte_socket_id();
+
+		pi = &adapter->port[i];
+		pi->adapter = adapter;
+		pi->xact_addr_filt = -1;
+		pi->port_id = i;
+
+		snprintf(name, sizeof(name), "cxgbe%d",
+			 adapter->eth_dev->data->port_id + i);
+
+		if (i == 0) {
+			/* First port is already allocated by DPDK */
+			pi->eth_dev = adapter->eth_dev;
+			goto allocate_mac;
+		}
+
+		/*
+		 * now do all data allocation - for eth_dev structure,
+		 * and internal (private) data for the remaining ports
+		 */
+
+		/* reserve an ethdev entry */
+		pi->eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_PCI);
+		if (!pi->eth_dev)
+			goto out_free;
+
+		data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+		if (!data)
+			goto out_free;
+
+		data->port_id = adapter->eth_dev->data->port_id + i;
+
+		pi->eth_dev->data = data;
+
+allocate_mac:
+		pi->eth_dev->pci_dev = adapter->pdev;
+		pi->eth_dev->data->dev_private = pi;
+		pi->eth_dev->driver = adapter->eth_dev->driver;
+		pi->eth_dev->dev_ops = adapter->eth_dev->dev_ops;
+		TAILQ_INIT(&pi->eth_dev->link_intr_cbs);
+
+		pi->eth_dev->data->mac_addrs = rte_zmalloc(name,
+							   ETHER_ADDR_LEN, 0);
+		if (!pi->eth_dev->data->mac_addrs) {
+			dev_err(adapter, "%s: Mem allocation failed for storing mac addr, aborting\n",
+				__func__);
+			err = -1;
+			goto out_free;
+		}
+	}
+
+	if (adapter->flags & FW_OK) {
+		err = t4_port_init(adapter, adapter->mbox, adapter->pf, 0);
+		if (err) {
+			dev_err(adapter, "%s: t4_port_init failed with err %d\n",
+				__func__, err);
+			goto out_free;
+		}
+	}
+
+	print_port_info(adapter);
+
+	return 0;
+
+out_free:
+	for_each_port(adapter, i) {
+		pi = adap2pinfo(adapter, i);
+		if (pi->viid != 0)
+			t4_free_vi(adapter, adapter->mbox, adapter->pf,
+				   0, pi->viid);
+		/* Skip first port since it'll be de-allocated by DPDK */
+		if (i == 0)
+			continue;
+		if (pi->eth_dev->data)
+			rte_free(pi->eth_dev->data);
+	}
+
+	if (adapter->flags & FW_OK)
+		t4_fw_bye(adapter, adapter->mbox);
+	return -err;
+}
diff --git a/drivers/net/cxgbe/rte_pmd_cxgbe_version.map b/drivers/net/cxgbe/rte_pmd_cxgbe_version.map
new file mode 100644
index 0000000..bd8138a
--- /dev/null
+++ b/drivers/net/cxgbe/rte_pmd_cxgbe_version.map
@@ -0,0 +1,4 @@ 
+DPDK_2.1 {
+
+	local: *;
+};
diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c
new file mode 100644
index 0000000..20da0fd
--- /dev/null
+++ b/drivers/net/cxgbe/sge.c
@@ -0,0 +1,311 @@ 
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2014-2015 Chelsio Communications.
+ *   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 Chelsio Communications 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.
+ */
+
+#include <linux/if_ether.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_interrupts.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_atomic.h>
+#include <rte_malloc.h>
+#include <rte_random.h>
+#include <rte_dev.h>
+
+#include "common.h"
+#include "t4_regs.h"
+#include "t4_msg.h"
+#include "cxgbe.h"
+
+/*
+ * Rx buffer sizes for "usembufs" Free List buffers (one ingress packet
+ * per mbuf buffer).  We currently only support two sizes for 1500- and
+ * 9000-byte MTUs. We could easily support more but there doesn't seem to be
+ * much need for that ...
+ */
+#define FL_MTU_SMALL 1500
+#define FL_MTU_LARGE 9000
+
+static inline unsigned int fl_mtu_bufsize(struct adapter *adapter,
+					  unsigned int mtu)
+{
+	struct sge *s = &adapter->sge;
+
+	return ALIGN(s->pktshift + ETH_HLEN + VLAN_HLEN + mtu, s->fl_align);
+}
+
+#define FL_MTU_SMALL_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_SMALL)
+#define FL_MTU_LARGE_BUFSIZE(adapter) fl_mtu_bufsize(adapter, FL_MTU_LARGE)
+
+/*
+ * Bits 0..3 of rx_sw_desc.dma_addr have special meaning.  The hardware uses
+ * these to specify the buffer size as an index into the SGE Free List Buffer
+ * Size register array.  We also use bit 4, when the buffer has been unmapped
+ * for DMA, but this is of course never sent to the hardware and is only used
+ * to prevent double unmappings.  All of the above requires that the Free List
+ * Buffers which we allocate have the bottom 5 bits free (0) -- i.e. are
+ * 32-byte or or a power of 2 greater in alignment.  Since the SGE's minimal
+ * Free List Buffer alignment is 32 bytes, this works out for us ...
+ */
+enum {
+	RX_BUF_FLAGS     = 0x1f,   /* bottom five bits are special */
+	RX_BUF_SIZE      = 0x0f,   /* bottom three bits are for buf sizes */
+	RX_UNMAPPED_BUF  = 0x10,   /* buffer is not mapped */
+
+	/*
+	 * XXX We shouldn't depend on being able to use these indices.
+	 * XXX Especially when some other Master PF has initialized the
+	 * XXX adapter or we use the Firmware Configuration File.  We
+	 * XXX should really search through the Host Buffer Size register
+	 * XXX array for the appropriately sized buffer indices.
+	 */
+	RX_SMALL_PG_BUF  = 0x0,   /* small (PAGE_SIZE) page buffer */
+	RX_LARGE_PG_BUF  = 0x1,   /* buffer large page buffer */
+
+	RX_SMALL_MTU_BUF = 0x2,   /* small MTU buffer */
+	RX_LARGE_MTU_BUF = 0x3,   /* large MTU buffer */
+};
+
+/**
+ * t4_sge_init - initialize SGE
+ * @adap: the adapter
+ *
+ * Performs SGE initialization needed every time after a chip reset.
+ * We do not initialize any of the queues here, instead the driver
+ * top-level must request those individually.
+ *
+ * Called in two different modes:
+ *
+ *  1. Perform actual hardware initialization and record hard-coded
+ *     parameters which were used.  This gets used when we're the
+ *     Master PF and the Firmware Configuration File support didn't
+ *     work for some reason.
+ *
+ *  2. We're not the Master PF or initialization was performed with
+ *     a Firmware Configuration File.  In this case we need to grab
+ *     any of the SGE operating parameters that we need to have in
+ *     order to do our job and make sure we can live with them ...
+ */
+static int t4_sge_init_soft(struct adapter *adap)
+{
+	struct sge *s = &adap->sge;
+	u32 fl_small_pg, fl_large_pg, fl_small_mtu, fl_large_mtu;
+	u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5;
+	u32 ingress_rx_threshold;
+
+	/*
+	 * Verify that CPL messages are going to the Ingress Queue for
+	 * process_responses() and that only packet data is going to the
+	 * Free Lists.
+	 */
+	if ((t4_read_reg(adap, A_SGE_CONTROL) & F_RXPKTCPLMODE) !=
+	    V_RXPKTCPLMODE(X_RXPKTCPLMODE_SPLIT)) {
+		dev_err(adap, "bad SGE CPL MODE\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Validate the Host Buffer Register Array indices that we want to
+	 * use ...
+	 *
+	 * XXX Note that we should really read through the Host Buffer Size
+	 * XXX register array and find the indices of the Buffer Sizes which
+	 * XXX meet our needs!
+	 */
+#define READ_FL_BUF(x) \
+	t4_read_reg(adap, A_SGE_FL_BUFFER_SIZE0 + (x) * sizeof(u32))
+
+	fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF);
+	fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF);
+	fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF);
+	fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF);
+
+	/*
+	 * We only bother using the Large Page logic if the Large Page Buffer
+	 * is larger than our Page Size Buffer.
+	 */
+	if (fl_large_pg <= fl_small_pg)
+		fl_large_pg = 0;
+
+#undef READ_FL_BUF
+
+	/*
+	 * The Page Size Buffer must be exactly equal to our Page Size and the
+	 * Large Page Size Buffer should be 0 (per above) or a power of 2.
+	 */
+	if (fl_small_pg != PAGE_SIZE ||
+	    (fl_large_pg & (fl_large_pg - 1)) != 0) {
+		dev_err(adap, "bad SGE FL page buffer sizes [%d, %d]\n",
+			fl_small_pg, fl_large_pg);
+		return -EINVAL;
+	}
+	if (fl_large_pg)
+		s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT;
+
+	if (adap->use_unpacked_mode) {
+		int err = 0;
+
+		if (fl_small_mtu < FL_MTU_SMALL_BUFSIZE(adap)) {
+			dev_err(adap, "bad SGE FL small MTU %d\n",
+				fl_small_mtu);
+			err = -EINVAL;
+		}
+		if (fl_large_mtu < FL_MTU_LARGE_BUFSIZE(adap)) {
+			dev_err(adap, "bad SGE FL large MTU %d\n",
+				fl_large_mtu);
+			err = -EINVAL;
+		}
+		if (err)
+			return err;
+	}
+
+	/*
+	 * Retrieve our RX interrupt holdoff timer values and counter
+	 * threshold values from the SGE parameters.
+	 */
+	timer_value_0_and_1 = t4_read_reg(adap, A_SGE_TIMER_VALUE_0_AND_1);
+	timer_value_2_and_3 = t4_read_reg(adap, A_SGE_TIMER_VALUE_2_AND_3);
+	timer_value_4_and_5 = t4_read_reg(adap, A_SGE_TIMER_VALUE_4_AND_5);
+	s->timer_val[0] = core_ticks_to_us(adap,
+					   G_TIMERVALUE0(timer_value_0_and_1));
+	s->timer_val[1] = core_ticks_to_us(adap,
+					   G_TIMERVALUE1(timer_value_0_and_1));
+	s->timer_val[2] = core_ticks_to_us(adap,
+					   G_TIMERVALUE2(timer_value_2_and_3));
+	s->timer_val[3] = core_ticks_to_us(adap,
+					   G_TIMERVALUE3(timer_value_2_and_3));
+	s->timer_val[4] = core_ticks_to_us(adap,
+					   G_TIMERVALUE4(timer_value_4_and_5));
+	s->timer_val[5] = core_ticks_to_us(adap,
+					   G_TIMERVALUE5(timer_value_4_and_5));
+
+	ingress_rx_threshold = t4_read_reg(adap, A_SGE_INGRESS_RX_THRESHOLD);
+	s->counter_val[0] = G_THRESHOLD_0(ingress_rx_threshold);
+	s->counter_val[1] = G_THRESHOLD_1(ingress_rx_threshold);
+	s->counter_val[2] = G_THRESHOLD_2(ingress_rx_threshold);
+	s->counter_val[3] = G_THRESHOLD_3(ingress_rx_threshold);
+
+	return 0;
+}
+
+int t4_sge_init(struct adapter *adap)
+{
+	struct sge *s = &adap->sge;
+	u32 sge_control, sge_control2, sge_conm_ctrl;
+	unsigned int ingpadboundary, ingpackboundary;
+	int ret, egress_threshold;
+
+	/*
+	 * Ingress Padding Boundary and Egress Status Page Size are set up by
+	 * t4_fixup_host_params().
+	 */
+	sge_control = t4_read_reg(adap, A_SGE_CONTROL);
+	s->pktshift = G_PKTSHIFT(sge_control);
+	s->stat_len = (sge_control & F_EGRSTATUSPAGESIZE) ? 128 : 64;
+
+	/*
+	 * T4 uses a single control field to specify both the PCIe Padding and
+	 * Packing Boundary.  T5 introduced the ability to specify these
+	 * separately.  The actual Ingress Packet Data alignment boundary
+	 * within Packed Buffer Mode is the maximum of these two
+	 * specifications.
+	 */
+	ingpadboundary = 1 << (G_INGPADBOUNDARY(sge_control) +
+			 X_INGPADBOUNDARY_SHIFT);
+	s->fl_align = ingpadboundary;
+
+	if (!is_t4(adap->params.chip) && !adap->use_unpacked_mode) {
+		/*
+		 * T5 has a weird interpretation of one of the PCIe Packing
+		 * Boundary values.  No idea why ...
+		 */
+		sge_control2 = t4_read_reg(adap, A_SGE_CONTROL2);
+		ingpackboundary = G_INGPACKBOUNDARY(sge_control2);
+		if (ingpackboundary == X_INGPACKBOUNDARY_16B)
+			ingpackboundary = 16;
+		else
+			ingpackboundary = 1 << (ingpackboundary +
+					  X_INGPACKBOUNDARY_SHIFT);
+
+		s->fl_align = max(ingpadboundary, ingpackboundary);
+	}
+
+	ret = t4_sge_init_soft(adap);
+	if (ret < 0) {
+		dev_err(adap, "%s: t4_sge_init_soft failed, error %d\n",
+			__func__, -ret);
+		return ret;
+	}
+
+	/*
+	 * A FL with <= fl_starve_thres buffers is starving and a periodic
+	 * timer will attempt to refill it.  This needs to be larger than the
+	 * SGE's Egress Congestion Threshold.  If it isn't, then we can get
+	 * stuck waiting for new packets while the SGE is waiting for us to
+	 * give it more Free List entries.  (Note that the SGE's Egress
+	 * Congestion Threshold is in units of 2 Free List pointers.)  For T4,
+	 * there was only a single field to control this.  For T5 there's the
+	 * original field which now only applies to Unpacked Mode Free List
+	 * buffers and a new field which only applies to Packed Mode Free List
+	 * buffers.
+	 */
+	sge_conm_ctrl = t4_read_reg(adap, A_SGE_CONM_CTRL);
+	if (is_t4(adap->params.chip) || adap->use_unpacked_mode)
+		egress_threshold = G_EGRTHRESHOLD(sge_conm_ctrl);
+	else
+		egress_threshold = G_EGRTHRESHOLDPACKING(sge_conm_ctrl);
+	s->fl_starve_thres = 2 * egress_threshold + 1;
+
+	return 0;
+}
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 1a2043a..bba6ddc 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -122,6 +122,7 @@  ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),n)
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD)    += -lrte_pmd_vmxnet3_uio
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD)     += -lrte_pmd_virtio
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD)      += -lrte_pmd_cxgbe
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k