net: add rte prefix to ether defines
[dpdk.git] / drivers / net / e1000 / igb_rxtx.c
index a47c640..01f5e73 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2015 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.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation
  */
 
 #include <sys/queue.h>
 #include <rte_malloc.h>
 #include <rte_mbuf.h>
 #include <rte_ether.h>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_prefetch.h>
 #include <rte_udp.h>
 #include <rte_tcp.h>
 #include <rte_sctp.h>
+#include <rte_net.h>
 #include <rte_string_fns.h>
 
 #include "e1000_logs.h"
 #include "base/e1000_api.h"
 #include "e1000_ethdev.h"
 
+#ifdef RTE_LIBRTE_IEEE1588
+#define IGB_TX_IEEE1588_TMST PKT_TX_IEEE1588_TMST
+#else
+#define IGB_TX_IEEE1588_TMST 0
+#endif
 /* Bit Mask to indicate what bits required for building TX context */
 #define IGB_TX_OFFLOAD_MASK (                   \
+               PKT_TX_OUTER_IPV6 |      \
+               PKT_TX_OUTER_IPV4 |      \
+               PKT_TX_IPV6 |            \
+               PKT_TX_IPV4 |            \
                PKT_TX_VLAN_PKT |                \
                PKT_TX_IP_CKSUM |                \
                PKT_TX_L4_MASK |                 \
-               PKT_TX_TCP_SEG)
+               PKT_TX_TCP_SEG |                 \
+               IGB_TX_IEEE1588_TMST)
+
+#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.
@@ -94,6 +79,13 @@ struct igb_tx_entry {
        uint16_t last_id; /**< Index of last scattered descriptor. */
 };
 
+/**
+ * rx queue flags
+ */
+enum igb_rxq_flags {
+       IGB_RXQ_FLAG_LB_BSWAP_VLAN = 0x01,
+};
+
 /**
  * Structure associated with each RX queue.
  */
@@ -112,12 +104,14 @@ struct igb_rx_queue {
        uint16_t            rx_free_thresh; /**< max free RX desc to hold. */
        uint16_t            queue_id;   /**< RX queue index. */
        uint16_t            reg_idx;    /**< RX queue register index. */
-       uint8_t             port_id;    /**< Device port identifier. */
+       uint16_t            port_id;    /**< Device port identifier. */
        uint8_t             pthresh;    /**< Prefetch threshold register. */
        uint8_t             hthresh;    /**< Host threshold register. */
        uint8_t             wthresh;    /**< Write-back threshold register. */
        uint8_t             crc_len;    /**< 0 if CRC stripped, 4 otherwise. */
        uint8_t             drop_en;  /**< If not 0, set SRRCTL.Drop_En. */
+       uint32_t            flags;      /**< RX flags. */
+       uint64_t            offloads;   /**< offloads of DEV_RX_OFFLOAD_* */
 };
 
 /**
@@ -181,7 +175,7 @@ struct igb_tx_queue {
        /**< Index of first used TX descriptor. */
        uint16_t               queue_id; /**< TX queue index. */
        uint16_t               reg_idx;  /**< TX queue register index. */
-       uint8_t                port_id;  /**< Device port identifier. */
+       uint16_t               port_id;  /**< Device port identifier. */
        uint8_t                pthresh;  /**< Prefetch threshold register. */
        uint8_t                hthresh;  /**< Host threshold register. */
        uint8_t                wthresh;  /**< Write-back threshold register. */
@@ -191,6 +185,7 @@ struct igb_tx_queue {
        /**< Start context position for transmit queue. */
        struct igb_advctx_info ctx_cache[IGB_CTX_NUM];
        /**< Hardware context history.*/
+       uint64_t               offloads; /**< offloads of DEV_TX_OFFLOAD_* */
 };
 
 #if 1
@@ -579,7 +574,7 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                         * Set up transmit descriptor.
                         */
                        slen = (uint16_t) m_seg->data_len;
-                       buf_dma_addr = rte_mbuf_data_dma_addr(m_seg);
+                       buf_dma_addr = rte_mbuf_data_iova(m_seg);
                        txd->read.buffer_addr =
                                rte_cpu_to_le_64(buf_dma_addr);
                        txd->read.cmd_type_len =
@@ -605,7 +600,7 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        /*
         * Set the Transmit Descriptor Tail (TDT).
         */
-       E1000_PCI_REG_WRITE(txq->tdt_reg_addr, tx_id);
+       E1000_PCI_REG_WRITE_RELAXED(txq->tdt_reg_addr, tx_id);
        PMD_TX_LOG(DEBUG, "port_id=%u queue_id=%u tx_tail=%u nb_tx=%u",
                   (unsigned) txq->port_id, (unsigned) txq->queue_id,
                   (unsigned) tx_id, (unsigned) nb_tx);
@@ -614,6 +609,52 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        return nb_tx;
 }
 
+/*********************************************************************
+ *
+ *  TX prep functions
+ *
+ **********************************************************************/
+uint16_t
+eth_igb_prep_pkts(__rte_unused void *tx_queue, 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 = -ENOTSUP;
+                       return i;
+               }
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+               ret = rte_validate_tx_offload(m);
+               if (ret != 0) {
+                       rte_errno = ret;
+                       return i;
+               }
+#endif
+               ret = rte_net_intel_cksum_prepare(m);
+               if (ret != 0) {
+                       rte_errno = ret;
+                       return i;
+               }
+       }
+
+       return i;
+}
+
 /*********************************************************************
  *
  *  RX functions
@@ -729,7 +770,7 @@ rx_desc_status_to_pkt_flags(uint32_t rx_status)
 
        /* Check if VLAN present */
        pkt_flags = ((rx_status & E1000_RXD_STAT_VP) ?
-               PKT_RX_VLAN_PKT | PKT_RX_VLAN_STRIPPED : 0);
+               PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED : 0);
 
 #if defined(RTE_LIBRTE_IEEE1588)
        if (rx_status & E1000_RXD_STAT_TMST)
@@ -747,7 +788,9 @@ rx_desc_error_to_pkt_flags(uint32_t rx_status)
         */
 
        static uint64_t error_to_pkt_flags_map[4] = {
-               0,  PKT_RX_L4_CKSUM_BAD, PKT_RX_IP_CKSUM_BAD,
+               PKT_RX_IP_CKSUM_GOOD | PKT_RX_L4_CKSUM_GOOD,
+               PKT_RX_IP_CKSUM_GOOD | PKT_RX_L4_CKSUM_BAD,
+               PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_GOOD,
                PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD
        };
        return error_to_pkt_flags_map[(rx_status >>
@@ -859,7 +902,7 @@ eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                rxm = rxe->mbuf;
                rxe->mbuf = nmb;
                dma_addr =
-                       rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(nmb));
+                       rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
                rxdp->read.hdr_addr = 0;
                rxdp->read.pkt_addr = dma_addr;
 
@@ -888,9 +931,17 @@ eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 
                rxm->hash.rss = rxd.wb.lower.hi_dword.rss;
                hlen_type_rss = rte_le_to_cpu_32(rxd.wb.lower.lo_dword.data);
-               /* Only valid if PKT_RX_VLAN_PKT set in pkt_flags */
-               rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);
 
+               /*
+                * The vlan_tci field is only valid when PKT_RX_VLAN is
+                * set in the pkt_flags field and must be in CPU byte order.
+                */
+               if ((staterr & rte_cpu_to_le_32(E1000_RXDEXT_STATERR_LB)) &&
+                               (rxq->flags & IGB_RXQ_FLAG_LB_BSWAP_VLAN)) {
+                       rxm->vlan_tci = rte_be_to_cpu_16(rxd.wb.upper.vlan);
+               } else {
+                       rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);
+               }
                pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(rxq, hlen_type_rss);
                pkt_flags = pkt_flags | rx_desc_status_to_pkt_flags(staterr);
                pkt_flags = pkt_flags | rx_desc_error_to_pkt_flags(staterr);
@@ -1045,7 +1096,7 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                 */
                rxm = rxe->mbuf;
                rxe->mbuf = nmb;
-               dma = rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(nmb));
+               dma = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
                rxdp->read.pkt_addr = dma;
                rxdp->read.hdr_addr = 0;
 
@@ -1096,17 +1147,17 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                 */
                rxm->next = NULL;
                if (unlikely(rxq->crc_len > 0)) {
-                       first_seg->pkt_len -= ETHER_CRC_LEN;
-                       if (data_len <= ETHER_CRC_LEN) {
+                       first_seg->pkt_len -= RTE_ETHER_CRC_LEN;
+                       if (data_len <= RTE_ETHER_CRC_LEN) {
                                rte_pktmbuf_free_seg(rxm);
                                first_seg->nb_segs--;
                                last_seg->data_len = (uint16_t)
                                        (last_seg->data_len -
-                                        (ETHER_CRC_LEN - data_len));
+                                        (RTE_ETHER_CRC_LEN - data_len));
                                last_seg->next = NULL;
                        } else
-                               rxm->data_len =
-                                       (uint16_t) (data_len - ETHER_CRC_LEN);
+                               rxm->data_len = (uint16_t)
+                                       (data_len - RTE_ETHER_CRC_LEN);
                }
 
                /*
@@ -1122,10 +1173,17 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                first_seg->hash.rss = rxd.wb.lower.hi_dword.rss;
 
                /*
-                * The vlan_tci field is only valid when PKT_RX_VLAN_PKT is
-                * set in the pkt_flags field.
+                * The vlan_tci field is only valid when PKT_RX_VLAN is
+                * set in the pkt_flags field and must be in CPU byte order.
                 */
-               first_seg->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);
+               if ((staterr & rte_cpu_to_le_32(E1000_RXDEXT_STATERR_LB)) &&
+                               (rxq->flags & IGB_RXQ_FLAG_LB_BSWAP_VLAN)) {
+                       first_seg->vlan_tci =
+                               rte_be_to_cpu_16(rxd.wb.upper.vlan);
+               } else {
+                       first_seg->vlan_tci =
+                               rte_le_to_cpu_16(rxd.wb.upper.vlan);
+               }
                hlen_type_rss = rte_le_to_cpu_32(rxd.wb.lower.lo_dword.data);
                pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(rxq, hlen_type_rss);
                pkt_flags = pkt_flags | rx_desc_status_to_pkt_flags(staterr);
@@ -1225,6 +1283,132 @@ eth_igb_tx_queue_release(void *txq)
        igb_tx_queue_release(txq);
 }
 
+static int
+igb_tx_done_cleanup(struct igb_tx_queue *txq, uint32_t free_cnt)
+{
+       struct igb_tx_entry *sw_ring;
+       volatile union e1000_adv_tx_desc *txr;
+       uint16_t tx_first; /* First segment analyzed. */
+       uint16_t tx_id;    /* Current segment being processed. */
+       uint16_t tx_last;  /* Last segment in the current packet. */
+       uint16_t tx_next;  /* First segment of the next packet. */
+       int count;
+
+       if (txq != NULL) {
+               count = 0;
+               sw_ring = txq->sw_ring;
+               txr = txq->tx_ring;
+
+               /*
+                * tx_tail is the last sent packet on the sw_ring. Goto the end
+                * of that packet (the last segment in the packet chain) and
+                * then the next segment will be the start of the oldest segment
+                * in the sw_ring. This is the first packet that will be
+                * attempted to be freed.
+                */
+
+               /* Get last segment in most recently added packet. */
+               tx_first = sw_ring[txq->tx_tail].last_id;
+
+               /* Get the next segment, which is the oldest segment in ring. */
+               tx_first = sw_ring[tx_first].next_id;
+
+               /* Set the current index to the first. */
+               tx_id = tx_first;
+
+               /*
+                * Loop through each packet. For each packet, verify that an
+                * mbuf exists and that the last segment is free. If so, free
+                * it and move on.
+                */
+               while (1) {
+                       tx_last = sw_ring[tx_id].last_id;
+
+                       if (sw_ring[tx_last].mbuf) {
+                               if (txr[tx_last].wb.status &
+                                               E1000_TXD_STAT_DD) {
+                                       /*
+                                        * Increment the number of packets
+                                        * freed.
+                                        */
+                                       count++;
+
+                                       /* Get the start of the next packet. */
+                                       tx_next = sw_ring[tx_last].next_id;
+
+                                       /*
+                                        * Loop through all segments in a
+                                        * packet.
+                                        */
+                                       do {
+                                               rte_pktmbuf_free_seg(sw_ring[tx_id].mbuf);
+                                               sw_ring[tx_id].mbuf = NULL;
+                                               sw_ring[tx_id].last_id = tx_id;
+
+                                               /* Move to next segemnt. */
+                                               tx_id = sw_ring[tx_id].next_id;
+
+                                       } while (tx_id != tx_next);
+
+                                       if (unlikely(count == (int)free_cnt))
+                                               break;
+                               } else
+                                       /*
+                                        * mbuf still in use, nothing left to
+                                        * free.
+                                        */
+                                       break;
+                       } else {
+                               /*
+                                * There are multiple reasons to be here:
+                                * 1) All the packets on the ring have been
+                                *    freed - tx_id is equal to tx_first
+                                *    and some packets have been freed.
+                                *    - Done, exit
+                                * 2) Interfaces has not sent a rings worth of
+                                *    packets yet, so the segment after tail is
+                                *    still empty. Or a previous call to this
+                                *    function freed some of the segments but
+                                *    not all so there is a hole in the list.
+                                *    Hopefully this is a rare case.
+                                *    - Walk the list and find the next mbuf. If
+                                *      there isn't one, then done.
+                                */
+                               if (likely((tx_id == tx_first) && (count != 0)))
+                                       break;
+
+                               /*
+                                * Walk the list and find the next mbuf, if any.
+                                */
+                               do {
+                                       /* Move to next segemnt. */
+                                       tx_id = sw_ring[tx_id].next_id;
+
+                                       if (sw_ring[tx_id].mbuf)
+                                               break;
+
+                               } while (tx_id != tx_first);
+
+                               /*
+                                * Determine why previous loop bailed. If there
+                                * is not an mbuf, done.
+                                */
+                               if (sw_ring[tx_id].mbuf == NULL)
+                                       break;
+                       }
+               }
+       } else
+               count = -ENODEV;
+
+       return count;
+}
+
+int
+eth_igb_tx_done_cleanup(void *txq, uint32_t free_cnt)
+{
+       return igb_tx_done_cleanup(txq, free_cnt);
+}
+
 static void
 igb_reset_tx_queue_stat(struct igb_tx_queue *txq)
 {
@@ -1269,6 +1453,33 @@ igb_reset_tx_queue(struct igb_tx_queue *txq, struct rte_eth_dev *dev)
        igb_reset_tx_queue_stat(txq);
 }
 
+uint64_t
+igb_get_tx_port_offloads_capa(struct rte_eth_dev *dev)
+{
+       uint64_t tx_offload_capa;
+
+       RTE_SET_USED(dev);
+       tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT |
+                         DEV_TX_OFFLOAD_IPV4_CKSUM  |
+                         DEV_TX_OFFLOAD_UDP_CKSUM   |
+                         DEV_TX_OFFLOAD_TCP_CKSUM   |
+                         DEV_TX_OFFLOAD_SCTP_CKSUM  |
+                         DEV_TX_OFFLOAD_TCP_TSO     |
+                         DEV_TX_OFFLOAD_MULTI_SEGS;
+
+       return tx_offload_capa;
+}
+
+uint64_t
+igb_get_tx_queue_offloads_capa(struct rte_eth_dev *dev)
+{
+       uint64_t tx_queue_offload_capa;
+
+       tx_queue_offload_capa = igb_get_tx_port_offloads_capa(dev);
+
+       return tx_queue_offload_capa;
+}
+
 int
 eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
                         uint16_t queue_idx,
@@ -1280,6 +1491,9 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
        struct igb_tx_queue *txq;
        struct e1000_hw     *hw;
        uint32_t size;
+       uint64_t offloads;
+
+       offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
 
        hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -1346,7 +1560,7 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
        txq->port_id = dev->data->port_id;
 
        txq->tdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_TDT(txq->reg_idx));
-       txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+       txq->tx_ring_phys_addr = tz->iova;
 
        txq->tx_ring = (union e1000_adv_tx_desc *) tz->addr;
        /* Allocate software ring */
@@ -1362,7 +1576,9 @@ 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_prepare = &eth_igb_prep_pkts;
        dev->data->tx_queues[queue_idx] = txq;
+       txq->offloads = offloads;
 
        return 0;
 }
@@ -1414,6 +1630,45 @@ igb_reset_rx_queue(struct igb_rx_queue *rxq)
        rxq->pkt_last_seg = NULL;
 }
 
+uint64_t
+igb_get_rx_port_offloads_capa(struct rte_eth_dev *dev)
+{
+       uint64_t rx_offload_capa;
+
+       RTE_SET_USED(dev);
+       rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP  |
+                         DEV_RX_OFFLOAD_VLAN_FILTER |
+                         DEV_RX_OFFLOAD_IPV4_CKSUM  |
+                         DEV_RX_OFFLOAD_UDP_CKSUM   |
+                         DEV_RX_OFFLOAD_TCP_CKSUM   |
+                         DEV_RX_OFFLOAD_JUMBO_FRAME |
+                         DEV_RX_OFFLOAD_KEEP_CRC    |
+                         DEV_RX_OFFLOAD_SCATTER;
+
+       return rx_offload_capa;
+}
+
+uint64_t
+igb_get_rx_queue_offloads_capa(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint64_t rx_queue_offload_capa;
+
+       switch (hw->mac.type) {
+       case e1000_vfadapt_i350:
+               /*
+                * As only one Rx queue can be used, let per queue offloading
+                * capability be same to per port queue offloading capability
+                * for better convenience.
+                */
+               rx_queue_offload_capa = igb_get_rx_port_offloads_capa(dev);
+               break;
+       default:
+               rx_queue_offload_capa = 0;
+       }
+       return rx_queue_offload_capa;
+}
+
 int
 eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
                         uint16_t queue_idx,
@@ -1426,6 +1681,9 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
        struct igb_rx_queue *rxq;
        struct e1000_hw     *hw;
        unsigned int size;
+       uint64_t offloads;
+
+       offloads = rx_conf->offloads | dev->data->dev_conf.rxmode.offloads;
 
        hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -1451,6 +1709,7 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
                          RTE_CACHE_LINE_SIZE);
        if (rxq == NULL)
                return -ENOMEM;
+       rxq->offloads = offloads;
        rxq->mb_pool = mp;
        rxq->nb_rx_desc = nb_desc;
        rxq->pthresh = rx_conf->rx_thresh.pthresh;
@@ -1465,8 +1724,10 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
        rxq->reg_idx = (uint16_t)((RTE_ETH_DEV_SRIOV(dev).active == 0) ?
                queue_idx : RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx + queue_idx);
        rxq->port_id = dev->data->port_id;
-       rxq->crc_len = (uint8_t) ((dev->data->dev_conf.rxmode.hw_strip_crc) ? 0 :
-                                 ETHER_CRC_LEN);
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC)
+               rxq->crc_len = RTE_ETHER_CRC_LEN;
+       else
+               rxq->crc_len = 0;
 
        /*
         *  Allocate RX ring hardware descriptors. A memzone large enough to
@@ -1482,7 +1743,7 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
        }
        rxq->rdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDT(rxq->reg_idx));
        rxq->rdh_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_RDH(rxq->reg_idx));
-       rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+       rxq->rx_ring_phys_addr = rz->iova;
        rxq->rx_ring = (union e1000_adv_rx_desc *) rz->addr;
 
        /* Allocate software ring. */
@@ -1510,11 +1771,6 @@ eth_igb_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
        struct igb_rx_queue *rxq;
        uint32_t desc = 0;
 
-       if (rx_queue_id >= dev->data->nb_rx_queues) {
-               PMD_RX_LOG(ERR, "Invalid RX queue id=%d", rx_queue_id);
-               return 0;
-       }
-
        rxq = dev->data->rx_queues[rx_queue_id];
        rxdp = &(rxq->rx_ring[rxq->rx_tail]);
 
@@ -1527,7 +1783,7 @@ eth_igb_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
                                desc - rxq->nb_rx_desc]);
        }
 
-       return 0;
+       return desc;
 }
 
 int
@@ -1547,6 +1803,51 @@ eth_igb_rx_descriptor_done(void *rx_queue, uint16_t offset)
        return !!(rxdp->wb.upper.status_error & E1000_RXD_STAT_DD);
 }
 
+int
+eth_igb_rx_descriptor_status(void *rx_queue, uint16_t offset)
+{
+       struct igb_rx_queue *rxq = rx_queue;
+       volatile uint32_t *status;
+       uint32_t desc;
+
+       if (unlikely(offset >= rxq->nb_rx_desc))
+               return -EINVAL;
+
+       if (offset >= rxq->nb_rx_desc - rxq->nb_rx_hold)
+               return RTE_ETH_RX_DESC_UNAVAIL;
+
+       desc = rxq->rx_tail + offset;
+       if (desc >= rxq->nb_rx_desc)
+               desc -= rxq->nb_rx_desc;
+
+       status = &rxq->rx_ring[desc].wb.upper.status_error;
+       if (*status & rte_cpu_to_le_32(E1000_RXD_STAT_DD))
+               return RTE_ETH_RX_DESC_DONE;
+
+       return RTE_ETH_RX_DESC_AVAIL;
+}
+
+int
+eth_igb_tx_descriptor_status(void *tx_queue, uint16_t offset)
+{
+       struct igb_tx_queue *txq = tx_queue;
+       volatile uint32_t *status;
+       uint32_t desc;
+
+       if (unlikely(offset >= txq->nb_tx_desc))
+               return -EINVAL;
+
+       desc = txq->tx_tail + offset;
+       if (desc >= txq->nb_tx_desc)
+               desc -= txq->nb_tx_desc;
+
+       status = &txq->tx_ring[desc].wb.status;
+       if (*status & rte_cpu_to_le_32(E1000_TXD_STAT_DD))
+               return RTE_ETH_TX_DESC_DONE;
+
+       return RTE_ETH_TX_DESC_FULL;
+}
+
 void
 igb_dev_clear_queues(struct rte_eth_dev *dev)
 {
@@ -1955,7 +2256,7 @@ igb_alloc_rx_queue_mbufs(struct igb_rx_queue *rxq)
                        return -ENOMEM;
                }
                dma_addr =
-                       rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(mbuf));
+                       rte_cpu_to_le_64(rte_mbuf_data_iova_default(mbuf));
                rxd = &rxq->rx_ring[i];
                rxd->read.hdr_addr = 0;
                rxd->read.pkt_addr = dma_addr;
@@ -2008,6 +2309,7 @@ igb_dev_mq_rx_configure(struct rte_eth_dev *dev)
 int
 eth_igb_rx_init(struct rte_eth_dev *dev)
 {
+       struct rte_eth_rxmode *rxmode;
        struct e1000_hw     *hw;
        struct igb_rx_queue *rxq;
        uint32_t rctl;
@@ -2028,10 +2330,12 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
        rctl = E1000_READ_REG(hw, E1000_RCTL);
        E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);
 
+       rxmode = &dev->data->dev_conf.rxmode;
+
        /*
         * Configure support of jumbo frames, if any.
         */
-       if (dev->data->dev_conf.rxmode.jumbo_frame == 1) {
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
                rctl |= E1000_RCTL_LPE;
 
                /*
@@ -2053,6 +2357,17 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
 
                rxq = dev->data->rx_queues[i];
 
+               rxq->flags = 0;
+               /*
+                * i350 and i354 vlan packets have vlan tags byte swapped.
+                */
+               if (hw->mac.type == e1000_i350 || hw->mac.type == e1000_i354) {
+                       rxq->flags |= IGB_RXQ_FLAG_LB_BSWAP_VLAN;
+                       PMD_INIT_LOG(DEBUG, "IGB rx vlan bswap required");
+               } else {
+                       PMD_INIT_LOG(DEBUG, "IGB rx vlan bswap not required");
+               }
+
                /* Allocate buffers for descriptor rings and set up queue */
                ret = igb_alloc_rx_queue_mbufs(rxq);
                if (ret)
@@ -2062,9 +2377,10 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
                 * Reset crc_len in case it was changed after queue setup by a
                 *  call to configure
                 */
-               rxq->crc_len =
-                       (uint8_t)(dev->data->dev_conf.rxmode.hw_strip_crc ?
-                                                       0 : ETHER_CRC_LEN);
+               if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC)
+                       rxq->crc_len = RTE_ETHER_CRC_LEN;
+               else
+                       rxq->crc_len = 0;
 
                bus_addr = rxq->rx_ring_phys_addr;
                E1000_WRITE_REG(hw, E1000_RDLEN(rxq->reg_idx),
@@ -2132,7 +2448,7 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
                E1000_WRITE_REG(hw, E1000_RXDCTL(rxq->reg_idx), rxdctl);
        }
 
-       if (dev->data->dev_conf.rxmode.enable_scatter) {
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_SCATTER) {
                if (!dev->data->scattered_rx)
                        PMD_INIT_LOG(DEBUG, "forcing scatter mode");
                dev->rx_pkt_burst = eth_igb_recv_scattered_pkts;
@@ -2176,17 +2492,27 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
        rxcsum |= E1000_RXCSUM_PCSD;
 
        /* Enable both L3/L4 rx checksum offload */
-       if (dev->data->dev_conf.rxmode.hw_ip_checksum)
-               rxcsum |= (E1000_RXCSUM_IPOFL  | E1000_RXCSUM_TUOFL);
+       if (rxmode->offloads & DEV_RX_OFFLOAD_IPV4_CKSUM)
+               rxcsum |= E1000_RXCSUM_IPOFL;
+       else
+               rxcsum &= ~E1000_RXCSUM_IPOFL;
+       if (rxmode->offloads &
+               (DEV_RX_OFFLOAD_TCP_CKSUM | DEV_RX_OFFLOAD_UDP_CKSUM))
+               rxcsum |= E1000_RXCSUM_TUOFL;
        else
-               rxcsum &= ~(E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
+               rxcsum &= ~E1000_RXCSUM_TUOFL;
+       if (rxmode->offloads & DEV_RX_OFFLOAD_CHECKSUM)
+               rxcsum |= E1000_RXCSUM_CRCOFL;
+       else
+               rxcsum &= ~E1000_RXCSUM_CRCOFL;
+
        E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
 
        /* Setup the Receive Control Register. */
-       if (dev->data->dev_conf.rxmode.hw_strip_crc) {
-               rctl |= E1000_RCTL_SECRC; /* Strip Ethernet CRC. */
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC) {
+               rctl &= ~E1000_RCTL_SECRC; /* Do not Strip Ethernet CRC. */
 
-               /* set STRCRC bit in all queues */
+               /* clear STRCRC bit in all queues */
                if (hw->mac.type == e1000_i350 ||
                    hw->mac.type == e1000_i210 ||
                    hw->mac.type == e1000_i211 ||
@@ -2195,14 +2521,14 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
                                rxq = dev->data->rx_queues[i];
                                uint32_t dvmolr = E1000_READ_REG(hw,
                                        E1000_DVMOLR(rxq->reg_idx));
-                               dvmolr |= E1000_DVMOLR_STRCRC;
+                               dvmolr &= ~E1000_DVMOLR_STRCRC;
                                E1000_WRITE_REG(hw, E1000_DVMOLR(rxq->reg_idx), dvmolr);
                        }
                }
        } else {
-               rctl &= ~E1000_RCTL_SECRC; /* Do not Strip Ethernet CRC. */
+               rctl |= E1000_RCTL_SECRC; /* Strip Ethernet CRC. */
 
-               /* clear STRCRC bit in all queues */
+               /* set STRCRC bit in all queues */
                if (hw->mac.type == e1000_i350 ||
                    hw->mac.type == e1000_i210 ||
                    hw->mac.type == e1000_i211 ||
@@ -2211,7 +2537,7 @@ eth_igb_rx_init(struct rte_eth_dev *dev)
                                rxq = dev->data->rx_queues[i];
                                uint32_t dvmolr = E1000_READ_REG(hw,
                                        E1000_DVMOLR(rxq->reg_idx));
-                               dvmolr &= ~E1000_DVMOLR_STRCRC;
+                               dvmolr |= E1000_DVMOLR_STRCRC;
                                E1000_WRITE_REG(hw, E1000_DVMOLR(rxq->reg_idx), dvmolr);
                        }
                }
@@ -2330,6 +2656,17 @@ eth_igbvf_rx_init(struct rte_eth_dev *dev)
 
                rxq = dev->data->rx_queues[i];
 
+               rxq->flags = 0;
+               /*
+                * i350VF LB vlan packets have vlan tags byte swapped.
+                */
+               if (hw->mac.type == e1000_vfadapt_i350) {
+                       rxq->flags |= IGB_RXQ_FLAG_LB_BSWAP_VLAN;
+                       PMD_INIT_LOG(DEBUG, "IGB rx vlan bswap required");
+               } else {
+                       PMD_INIT_LOG(DEBUG, "IGB rx vlan bswap not required");
+               }
+
                /* Allocate buffers for descriptor rings and set up queue */
                ret = igb_alloc_rx_queue_mbufs(rxq);
                if (ret)
@@ -2411,7 +2748,7 @@ eth_igbvf_rx_init(struct rte_eth_dev *dev)
                E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
        }
 
-       if (dev->data->dev_conf.rxmode.enable_scatter) {
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_SCATTER) {
                if (!dev->data->scattered_rx)
                        PMD_INIT_LOG(DEBUG, "forcing scatter mode");
                dev->rx_pkt_burst = eth_igb_recv_scattered_pkts;
@@ -2498,6 +2835,7 @@ igb_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 
        qinfo->conf.rx_free_thresh = rxq->rx_free_thresh;
        qinfo->conf.rx_drop_en = rxq->drop_en;
+       qinfo->conf.offloads = rxq->offloads;
 }
 
 void
@@ -2513,4 +2851,111 @@ igb_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
        qinfo->conf.tx_thresh.pthresh = txq->pthresh;
        qinfo->conf.tx_thresh.hthresh = txq->hthresh;
        qinfo->conf.tx_thresh.wthresh = txq->wthresh;
+       qinfo->conf.offloads = txq->offloads;
+}
+
+int
+igb_rss_conf_init(struct rte_eth_dev *dev,
+                 struct igb_rte_flow_rss_conf *out,
+                 const struct rte_flow_action_rss *in)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       if (in->key_len > RTE_DIM(out->key) ||
+           ((hw->mac.type == e1000_82576) &&
+            (in->queue_num > IGB_MAX_RX_QUEUE_NUM_82576)) ||
+           ((hw->mac.type != e1000_82576) &&
+            (in->queue_num > IGB_MAX_RX_QUEUE_NUM)))
+               return -EINVAL;
+       out->conf = (struct rte_flow_action_rss){
+               .func = in->func,
+               .level = in->level,
+               .types = in->types,
+               .key_len = in->key_len,
+               .queue_num = in->queue_num,
+               .key = memcpy(out->key, in->key, in->key_len),
+               .queue = memcpy(out->queue, in->queue,
+                               sizeof(*in->queue) * in->queue_num),
+       };
+       return 0;
+}
+
+int
+igb_action_rss_same(const struct rte_flow_action_rss *comp,
+                   const struct rte_flow_action_rss *with)
+{
+       return (comp->func == with->func &&
+               comp->level == with->level &&
+               comp->types == with->types &&
+               comp->key_len == with->key_len &&
+               comp->queue_num == with->queue_num &&
+               !memcmp(comp->key, with->key, with->key_len) &&
+               !memcmp(comp->queue, with->queue,
+                       sizeof(*with->queue) * with->queue_num));
+}
+
+int
+igb_config_rss_filter(struct rte_eth_dev *dev,
+               struct igb_rte_flow_rss_conf *conf, bool add)
+{
+       uint32_t shift;
+       uint16_t i, j;
+       struct rte_eth_rss_conf rss_conf = {
+               .rss_key = conf->conf.key_len ?
+                       (void *)(uintptr_t)conf->conf.key : NULL,
+               .rss_key_len = conf->conf.key_len,
+               .rss_hf = conf->conf.types,
+       };
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       if (!add) {
+               if (igb_action_rss_same(&filter_info->rss_info.conf,
+                                       &conf->conf)) {
+                       igb_rss_disable(dev);
+                       memset(&filter_info->rss_info, 0,
+                               sizeof(struct igb_rte_flow_rss_conf));
+                       return 0;
+               }
+               return -EINVAL;
+       }
+
+       if (filter_info->rss_info.conf.queue_num)
+               return -EINVAL;
+
+       /* Fill in redirection table. */
+       shift = (hw->mac.type == e1000_82575) ? 6 : 0;
+       for (i = 0, j = 0; i < 128; i++, j++) {
+               union e1000_reta {
+                       uint32_t dword;
+                       uint8_t  bytes[4];
+               } reta;
+               uint8_t q_idx;
+
+               if (j == conf->conf.queue_num)
+                       j = 0;
+               q_idx = conf->conf.queue[j];
+               reta.bytes[i & 3] = (uint8_t)(q_idx << shift);
+               if ((i & 3) == 3)
+                       E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta.dword);
+       }
+
+       /* Configure the RSS key and the RSS protocols used to compute
+        * the RSS hash of input packets.
+        */
+       if ((rss_conf.rss_hf & IGB_RSS_OFFLOAD_ALL) == 0) {
+               igb_rss_disable(dev);
+               return 0;
+       }
+       if (rss_conf.rss_key == NULL)
+               rss_conf.rss_key = rss_intel_key; /* Default hash key */
+       igb_hw_rss_hash_set(hw, &rss_conf);
+
+       if (igb_rss_conf_init(dev, &filter_info->rss_info, &conf->conf))
+               return -EINVAL;
+
+       return 0;
 }