e1000: get queue info and descriptor limits
[dpdk.git] / drivers / net / e1000 / igb_rxtx.c
index 43d6703..384e4f1 100644 (file)
@@ -76,7 +76,8 @@
 #define IGB_TX_OFFLOAD_MASK (                   \
                PKT_TX_VLAN_PKT |                \
                PKT_TX_IP_CKSUM |                \
-               PKT_TX_L4_MASK)
+               PKT_TX_L4_MASK |                 \
+               PKT_TX_TCP_SEG)
 
 static inline struct rte_mbuf *
 rte_rxmbuf_alloc(struct rte_mempool *mp)
@@ -146,32 +147,40 @@ enum igb_advctx_num {
 };
 
 /** Offload features */
-union igb_vlan_macip {
-       uint32_t data;
+union igb_tx_offload {
+       uint64_t data;
        struct {
-               uint16_t l2_l3_len; /**< 7bit L2 and 9b L3 lengths combined */
-               uint16_t vlan_tci;
-               /**< VLAN Tag Control Identifier (CPU order). */
-       } f;
+               uint64_t l3_len:9; /**< L3 (IP) Header Length. */
+               uint64_t l2_len:7; /**< L2 (MAC) Header Length. */
+               uint64_t vlan_tci:16;  /**< VLAN Tag Control Identifier(CPU order). */
+               uint64_t l4_len:8; /**< L4 (TCP/UDP) Header Length. */
+               uint64_t tso_segsz:16; /**< TCP TSO segment size. */
+
+               /* uint64_t unused:8; */
+       };
 };
 
 /*
- * Compare mask for vlan_macip_len.data,
- * should be in sync with igb_vlan_macip.f layout.
+ * Compare mask for igb_tx_offload.data,
+ * should be in sync with igb_tx_offload layout.
  * */
-#define TX_VLAN_CMP_MASK        0xFFFF0000  /**< VLAN length - 16-bits. */
-#define TX_MAC_LEN_CMP_MASK     0x0000FE00  /**< MAC length - 7-bits. */
-#define TX_IP_LEN_CMP_MASK      0x000001FF  /**< IP  length - 9-bits. */
-/** MAC+IP  length. */
-#define TX_MACIP_LEN_CMP_MASK   (TX_MAC_LEN_CMP_MASK | TX_IP_LEN_CMP_MASK)
+#define TX_MACIP_LEN_CMP_MASK  0x000000000000FFFFULL /**< L2L3 header mask. */
+#define TX_VLAN_CMP_MASK               0x00000000FFFF0000ULL /**< Vlan mask. */
+#define TX_TCP_LEN_CMP_MASK            0x000000FF00000000ULL /**< TCP header mask. */
+#define TX_TSO_MSS_CMP_MASK            0x00FFFF0000000000ULL /**< TSO segsz mask. */
+/** Mac + IP + TCP + Mss mask. */
+#define TX_TSO_CMP_MASK        \
+       (TX_MACIP_LEN_CMP_MASK | TX_TCP_LEN_CMP_MASK | TX_TSO_MSS_CMP_MASK)
 
 /**
  * Strucutre to check if new context need be built
  */
 struct igb_advctx_info {
        uint64_t flags;           /**< ol_flags related to context build. */
-       uint32_t cmp_mask;        /**< compare mask for vlan_macip_lens */
-       union igb_vlan_macip vlan_macip_lens; /**< vlan, mac & ip length. */
+       /** tx offload: vlan, tso, l2-l3-l4 lengths. */
+       union igb_tx_offload tx_offload;
+       /** compare mask for tx offload. */
+       union igb_tx_offload tx_offload_mask;
 };
 
 /**
@@ -221,6 +230,8 @@ struct igb_tx_queue {
  * Macro for VMDq feature for 1 GbE NIC.
  */
 #define E1000_VMOLR_SIZE                       (8)
+#define IGB_TSO_MAX_HDRLEN                     (512)
+#define IGB_TSO_MAX_MSS                                (9216)
 
 /*********************************************************************
  *
@@ -228,6 +239,23 @@ struct igb_tx_queue {
  *
  **********************************************************************/
 
+/*
+ *There're some limitations in hardware for TCP segmentation offload. We
+ *should check whether the parameters are valid.
+ */
+static inline uint64_t
+check_tso_para(uint64_t ol_req, union igb_tx_offload ol_para)
+{
+       if (!(ol_req & PKT_TX_TCP_SEG))
+               return ol_req;
+       if ((ol_para.tso_segsz > IGB_TSO_MAX_MSS) || (ol_para.l2_len +
+                       ol_para.l3_len + ol_para.l4_len > IGB_TSO_MAX_HDRLEN)) {
+               ol_req &= ~PKT_TX_TCP_SEG;
+               ol_req |= PKT_TX_TCP_CKSUM;
+       }
+       return ol_req;
+}
+
 /*
  * Advanced context descriptor are almost same between igb/ixgbe
  * This is a separate function, looking for optimization opportunity here
@@ -237,64 +265,81 @@ struct igb_tx_queue {
 static inline void
 igbe_set_xmit_ctx(struct igb_tx_queue* txq,
                volatile struct e1000_adv_tx_context_desc *ctx_txd,
-               uint64_t ol_flags, uint32_t vlan_macip_lens)
+               uint64_t ol_flags, union igb_tx_offload tx_offload)
 {
        uint32_t type_tucmd_mlhl;
        uint32_t mss_l4len_idx;
        uint32_t ctx_idx, ctx_curr;
-       uint32_t cmp_mask;
+       uint32_t vlan_macip_lens;
+       union igb_tx_offload tx_offload_mask;
 
        ctx_curr = txq->ctx_curr;
        ctx_idx = ctx_curr + txq->ctx_start;
 
-       cmp_mask = 0;
+       tx_offload_mask.data = 0;
        type_tucmd_mlhl = 0;
 
-       if (ol_flags & PKT_TX_VLAN_PKT) {
-               cmp_mask |= TX_VLAN_CMP_MASK;
-       }
-
-       if (ol_flags & PKT_TX_IP_CKSUM) {
-               type_tucmd_mlhl = E1000_ADVTXD_TUCMD_IPV4;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-       }
-
        /* Specify which HW CTX to upload. */
        mss_l4len_idx = (ctx_idx << E1000_ADVTXD_IDX_SHIFT);
-       switch (ol_flags & PKT_TX_L4_MASK) {
-       case PKT_TX_UDP_CKSUM:
-               type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP |
+
+       if (ol_flags & PKT_TX_VLAN_PKT)
+               tx_offload_mask.data |= TX_VLAN_CMP_MASK;
+
+       /* check if TCP segmentation required for this packet */
+       if (ol_flags & PKT_TX_TCP_SEG) {
+               /* implies IP cksum in IPv4 */
+               if (ol_flags & PKT_TX_IP_CKSUM)
+                       type_tucmd_mlhl = E1000_ADVTXD_TUCMD_IPV4 |
+                               E1000_ADVTXD_TUCMD_L4T_TCP |
                                E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct udp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       case PKT_TX_TCP_CKSUM:
-               type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP |
+               else
+                       type_tucmd_mlhl = E1000_ADVTXD_TUCMD_IPV6 |
+                               E1000_ADVTXD_TUCMD_L4T_TCP |
                                E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct tcp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       case PKT_TX_SCTP_CKSUM:
-               type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP |
+
+               tx_offload_mask.data |= TX_TSO_CMP_MASK;
+               mss_l4len_idx |= tx_offload.tso_segsz << E1000_ADVTXD_MSS_SHIFT;
+               mss_l4len_idx |= tx_offload.l4_len << E1000_ADVTXD_L4LEN_SHIFT;
+       } else { /* no TSO, check if hardware checksum is needed */
+               if (ol_flags & (PKT_TX_IP_CKSUM | PKT_TX_L4_MASK))
+                       tx_offload_mask.data |= TX_MACIP_LEN_CMP_MASK;
+
+               if (ol_flags & PKT_TX_IP_CKSUM)
+                       type_tucmd_mlhl = E1000_ADVTXD_TUCMD_IPV4;
+
+               switch (ol_flags & PKT_TX_L4_MASK) {
+               case PKT_TX_UDP_CKSUM:
+                       type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP |
                                E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct sctp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       default:
-               type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_RSV |
+                       mss_l4len_idx |= sizeof(struct udp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
+                       break;
+               case PKT_TX_TCP_CKSUM:
+                       type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP |
                                E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
-               break;
+                       mss_l4len_idx |= sizeof(struct tcp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
+                       break;
+               case PKT_TX_SCTP_CKSUM:
+                       type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP |
+                               E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
+                       mss_l4len_idx |= sizeof(struct sctp_hdr) << E1000_ADVTXD_L4LEN_SHIFT;
+                       break;
+               default:
+                       type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_RSV |
+                               E1000_ADVTXD_DTYP_CTXT | E1000_ADVTXD_DCMD_DEXT;
+                       break;
+               }
        }
 
-       txq->ctx_cache[ctx_curr].flags           = ol_flags;
-       txq->ctx_cache[ctx_curr].cmp_mask        = cmp_mask;
-       txq->ctx_cache[ctx_curr].vlan_macip_lens.data =
-               vlan_macip_lens & cmp_mask;
+       txq->ctx_cache[ctx_curr].flags = ol_flags;
+       txq->ctx_cache[ctx_idx].tx_offload.data =
+               tx_offload_mask.data & tx_offload.data;
+       txq->ctx_cache[ctx_idx].tx_offload_mask = tx_offload_mask;
 
        ctx_txd->type_tucmd_mlhl = rte_cpu_to_le_32(type_tucmd_mlhl);
+       vlan_macip_lens = (uint32_t)tx_offload.data;
        ctx_txd->vlan_macip_lens = rte_cpu_to_le_32(vlan_macip_lens);
-       ctx_txd->mss_l4len_idx   = rte_cpu_to_le_32(mss_l4len_idx);
-       ctx_txd->seqnum_seed     = 0;
+       ctx_txd->mss_l4len_idx = rte_cpu_to_le_32(mss_l4len_idx);
+       ctx_txd->seqnum_seed = 0;
 }
 
 /*
@@ -303,20 +348,20 @@ igbe_set_xmit_ctx(struct igb_tx_queue* txq,
  */
 static inline uint32_t
 what_advctx_update(struct igb_tx_queue *txq, uint64_t flags,
-               uint32_t vlan_macip_lens)
+               union igb_tx_offload tx_offload)
 {
        /* If match with the current context */
        if (likely((txq->ctx_cache[txq->ctx_curr].flags == flags) &&
-               (txq->ctx_cache[txq->ctx_curr].vlan_macip_lens.data ==
-               (txq->ctx_cache[txq->ctx_curr].cmp_mask & vlan_macip_lens)))) {
+               (txq->ctx_cache[txq->ctx_curr].tx_offload.data ==
+               (txq->ctx_cache[txq->ctx_curr].tx_offload_mask.data & tx_offload.data)))) {
                        return txq->ctx_curr;
        }
 
        /* If match with the second context */
        txq->ctx_curr ^= 1;
        if (likely((txq->ctx_cache[txq->ctx_curr].flags == flags) &&
-               (txq->ctx_cache[txq->ctx_curr].vlan_macip_lens.data ==
-               (txq->ctx_cache[txq->ctx_curr].cmp_mask & vlan_macip_lens)))) {
+               (txq->ctx_cache[txq->ctx_curr].tx_offload.data ==
+               (txq->ctx_cache[txq->ctx_curr].tx_offload_mask.data & tx_offload.data)))) {
                        return txq->ctx_curr;
        }
 
@@ -333,14 +378,19 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
 
        tmp  = l4_olinfo[(ol_flags & PKT_TX_L4_MASK)  != PKT_TX_L4_NO_CKSUM];
        tmp |= l3_olinfo[(ol_flags & PKT_TX_IP_CKSUM) != 0];
+       tmp |= l4_olinfo[(ol_flags & PKT_TX_TCP_SEG) != 0];
        return tmp;
 }
 
 static inline uint32_t
 tx_desc_vlan_flags_to_cmdtype(uint64_t ol_flags)
 {
+       uint32_t cmdtype;
        static uint32_t vlan_cmd[2] = {0, E1000_ADVTXD_DCMD_VLE};
-       return vlan_cmd[(ol_flags & PKT_TX_VLAN_PKT) != 0];
+       static uint32_t tso_cmd[2] = {0, E1000_ADVTXD_DCMD_TSE};
+       cmdtype = vlan_cmd[(ol_flags & PKT_TX_VLAN_PKT) != 0];
+       cmdtype |= tso_cmd[(ol_flags & PKT_TX_TCP_SEG) != 0];
+       return cmdtype;
 }
 
 uint16_t
@@ -354,14 +404,6 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        volatile union e1000_adv_tx_desc *txd;
        struct rte_mbuf     *tx_pkt;
        struct rte_mbuf     *m_seg;
-       union igb_vlan_macip vlan_macip_lens;
-       union {
-               uint16_t u16;
-               struct {
-                       uint16_t l3_len:9;
-                       uint16_t l2_len:7;
-               };
-       } l2_l3_len;
        uint64_t buf_dma_addr;
        uint32_t olinfo_status;
        uint32_t cmd_type_len;
@@ -375,6 +417,7 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        uint64_t tx_ol_req;
        uint32_t new_ctx = 0;
        uint32_t ctx = 0;
+       union igb_tx_offload tx_offload = {0};
 
        txq = tx_queue;
        sw_ring = txq->sw_ring;
@@ -399,16 +442,18 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                tx_last = (uint16_t) (tx_id + tx_pkt->nb_segs - 1);
 
                ol_flags = tx_pkt->ol_flags;
-               l2_l3_len.l2_len = tx_pkt->l2_len;
-               l2_l3_len.l3_len = tx_pkt->l3_len;
-               vlan_macip_lens.f.vlan_tci = tx_pkt->vlan_tci;
-               vlan_macip_lens.f.l2_l3_len = l2_l3_len.u16;
                tx_ol_req = ol_flags & IGB_TX_OFFLOAD_MASK;
 
                /* If a Context Descriptor need be built . */
                if (tx_ol_req) {
-                       ctx = what_advctx_update(txq, tx_ol_req,
-                               vlan_macip_lens.data);
+                       tx_offload.l2_len = tx_pkt->l2_len;
+                       tx_offload.l3_len = tx_pkt->l3_len;
+                       tx_offload.l4_len = tx_pkt->l4_len;
+                       tx_offload.vlan_tci = tx_pkt->vlan_tci;
+                       tx_offload.tso_segsz = tx_pkt->tso_segsz;
+                       tx_ol_req = check_tso_para(tx_ol_req, tx_offload);
+
+                       ctx = what_advctx_update(txq, tx_ol_req, tx_offload);
                        /* Only allocate context descriptor if required*/
                        new_ctx = (ctx == IGB_CTX_NUM);
                        ctx = txq->ctx_curr;
@@ -500,6 +545,8 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                 */
                cmd_type_len = txq->txd_type |
                        E1000_ADVTXD_DCMD_IFCS | E1000_ADVTXD_DCMD_DEXT;
+               if (tx_ol_req & PKT_TX_TCP_SEG)
+                       pkt_len -= (tx_pkt->l2_len + tx_pkt->l3_len + tx_pkt->l4_len);
                olinfo_status = (pkt_len << E1000_ADVTXD_PAYLEN_SHIFT);
 #if defined(RTE_LIBRTE_IEEE1588)
                if (ol_flags & PKT_TX_IEEE1588_TMST)
@@ -523,8 +570,7 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                                        txe->mbuf = NULL;
                                }
 
-                               igbe_set_xmit_ctx(txq, ctx_txd, tx_ol_req,
-                                   vlan_macip_lens.data);
+                               igbe_set_xmit_ctx(txq, ctx_txd, tx_ol_req, tx_offload);
 
                                txe->last_id = tx_last;
                                tx_id = txe->next_id;
@@ -532,8 +578,8 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                        }
 
                        /* Setup the TX Advanced Data Descriptor */
-                       cmd_type_len  |= tx_desc_vlan_flags_to_cmdtype(ol_flags);
-                       olinfo_status |= tx_desc_cksum_flags_to_olinfo(ol_flags);
+                       cmd_type_len  |= tx_desc_vlan_flags_to_cmdtype(tx_ol_req);
+                       olinfo_status |= tx_desc_cksum_flags_to_olinfo(tx_ol_req);
                        olinfo_status |= (ctx << E1000_ADVTXD_IDX_SHIFT);
                }
 
@@ -590,17 +636,87 @@ eth_igb_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
  *  RX functions
  *
  **********************************************************************/
-static inline uint64_t
-rx_desc_hlen_type_rss_to_pkt_flags(uint32_t hl_tp_rs)
+#define IGB_PACKET_TYPE_IPV4              0X01
+#define IGB_PACKET_TYPE_IPV4_TCP          0X11
+#define IGB_PACKET_TYPE_IPV4_UDP          0X21
+#define IGB_PACKET_TYPE_IPV4_SCTP         0X41
+#define IGB_PACKET_TYPE_IPV4_EXT          0X03
+#define IGB_PACKET_TYPE_IPV4_EXT_SCTP     0X43
+#define IGB_PACKET_TYPE_IPV6              0X04
+#define IGB_PACKET_TYPE_IPV6_TCP          0X14
+#define IGB_PACKET_TYPE_IPV6_UDP          0X24
+#define IGB_PACKET_TYPE_IPV6_EXT          0X0C
+#define IGB_PACKET_TYPE_IPV6_EXT_TCP      0X1C
+#define IGB_PACKET_TYPE_IPV6_EXT_UDP      0X2C
+#define IGB_PACKET_TYPE_IPV4_IPV6         0X05
+#define IGB_PACKET_TYPE_IPV4_IPV6_TCP     0X15
+#define IGB_PACKET_TYPE_IPV4_IPV6_UDP     0X25
+#define IGB_PACKET_TYPE_IPV4_IPV6_EXT     0X0D
+#define IGB_PACKET_TYPE_IPV4_IPV6_EXT_TCP 0X1D
+#define IGB_PACKET_TYPE_IPV4_IPV6_EXT_UDP 0X2D
+#define IGB_PACKET_TYPE_MAX               0X80
+#define IGB_PACKET_TYPE_MASK              0X7F
+#define IGB_PACKET_TYPE_SHIFT             0X04
+static inline uint32_t
+igb_rxd_pkt_info_to_pkt_type(uint16_t pkt_info)
 {
-       uint64_t pkt_flags;
-
-       static uint64_t ip_pkt_types_map[16] = {
-               0, PKT_RX_IPV4_HDR, PKT_RX_IPV4_HDR_EXT, PKT_RX_IPV4_HDR_EXT,
-               PKT_RX_IPV6_HDR, 0, 0, 0,
-               PKT_RX_IPV6_HDR_EXT, 0, 0, 0,
-               PKT_RX_IPV6_HDR_EXT, 0, 0, 0,
+       static const uint32_t
+               ptype_table[IGB_PACKET_TYPE_MAX] __rte_cache_aligned = {
+               [IGB_PACKET_TYPE_IPV4] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4,
+               [IGB_PACKET_TYPE_IPV4_EXT] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4_EXT,
+               [IGB_PACKET_TYPE_IPV6] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6,
+               [IGB_PACKET_TYPE_IPV4_IPV6] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6,
+               [IGB_PACKET_TYPE_IPV6_EXT] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6_EXT,
+               [IGB_PACKET_TYPE_IPV4_IPV6_EXT] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6_EXT,
+               [IGB_PACKET_TYPE_IPV4_TCP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+               [IGB_PACKET_TYPE_IPV6_TCP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP,
+               [IGB_PACKET_TYPE_IPV4_IPV6_TCP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6 | RTE_PTYPE_INNER_L4_TCP,
+               [IGB_PACKET_TYPE_IPV6_EXT_TCP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L4_TCP,
+               [IGB_PACKET_TYPE_IPV4_IPV6_EXT_TCP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6_EXT | RTE_PTYPE_INNER_L4_TCP,
+               [IGB_PACKET_TYPE_IPV4_UDP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_UDP,
+               [IGB_PACKET_TYPE_IPV6_UDP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP,
+               [IGB_PACKET_TYPE_IPV4_IPV6_UDP] =  RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6 | RTE_PTYPE_INNER_L4_UDP,
+               [IGB_PACKET_TYPE_IPV6_EXT_UDP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L4_UDP,
+               [IGB_PACKET_TYPE_IPV4_IPV6_EXT_UDP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_TUNNEL_IP |
+                       RTE_PTYPE_INNER_L3_IPV6_EXT | RTE_PTYPE_INNER_L4_UDP,
+               [IGB_PACKET_TYPE_IPV4_SCTP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_SCTP,
+               [IGB_PACKET_TYPE_IPV4_EXT_SCTP] = RTE_PTYPE_L2_ETHER |
+                       RTE_PTYPE_L3_IPV4_EXT | RTE_PTYPE_L4_SCTP,
        };
+       if (unlikely(pkt_info & E1000_RXDADV_PKTTYPE_ETQF))
+               return RTE_PTYPE_UNKNOWN;
+
+       pkt_info = (pkt_info >> IGB_PACKET_TYPE_SHIFT) & IGB_PACKET_TYPE_MASK;
+
+       return ptype_table[pkt_info];
+}
+
+static inline uint64_t
+rx_desc_hlen_type_rss_to_pkt_flags(struct igb_rx_queue *rxq, uint32_t hl_tp_rs)
+{
+       uint64_t pkt_flags = ((hl_tp_rs & 0x0F) == 0) ?  0 : PKT_RX_RSS_HASH;
 
 #if defined(RTE_LIBRTE_IEEE1588)
        static uint32_t ip_pkt_etqf_map[8] = {
@@ -608,14 +724,19 @@ rx_desc_hlen_type_rss_to_pkt_flags(uint32_t hl_tp_rs)
                0, 0, 0, 0,
        };
 
-       pkt_flags = (hl_tp_rs & E1000_RXDADV_PKTTYPE_ETQF) ?
-                               ip_pkt_etqf_map[(hl_tp_rs >> 4) & 0x07] :
-                               ip_pkt_types_map[(hl_tp_rs >> 4) & 0x0F];
+       struct rte_eth_dev dev = rte_eth_devices[rxq->port_id];
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev.data->dev_private);
+
+       /* EtherType is in bits 8:10 in Packet Type, and not in the default 0:2 */
+       if (hw->mac.type == e1000_i210)
+               pkt_flags |= ip_pkt_etqf_map[(hl_tp_rs >> 12) & 0x07];
+       else
+               pkt_flags |= ip_pkt_etqf_map[(hl_tp_rs >> 4) & 0x07];
 #else
-       pkt_flags = (hl_tp_rs & E1000_RXDADV_PKTTYPE_ETQF) ? 0 :
-                               ip_pkt_types_map[(hl_tp_rs >> 4) & 0x0F];
+       RTE_SET_USED(rxq);
 #endif
-       return pkt_flags | (((hl_tp_rs & 0x0F) == 0) ?  0 : PKT_RX_RSS_HASH);
+
+       return pkt_flags;
 }
 
 static inline uint64_t
@@ -755,7 +876,7 @@ eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                rxe->mbuf = nmb;
                dma_addr =
                        rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(nmb));
-               rxdp->read.hdr_addr = dma_addr;
+               rxdp->read.hdr_addr = 0;
                rxdp->read.pkt_addr = dma_addr;
 
                /*
@@ -786,10 +907,12 @@ eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                /* Only valid if PKT_RX_VLAN_PKT set in pkt_flags */
                rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);
 
-               pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(hlen_type_rss);
+               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);
                rxm->ol_flags = pkt_flags;
+               rxm->packet_type = igb_rxd_pkt_info_to_pkt_type(rxd.wb.lower.
+                                               lo_dword.hs_rss.pkt_info);
 
                /*
                 * Store the mbuf address into the next entry of the array
@@ -940,7 +1063,7 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                rxe->mbuf = nmb;
                dma = rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(nmb));
                rxdp->read.pkt_addr = dma;
-               rxdp->read.hdr_addr = dma;
+               rxdp->read.hdr_addr = 0;
 
                /*
                 * Set data length & data buffer address of mbuf.
@@ -1020,10 +1143,12 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                 */
                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(hlen_type_rss);
+               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);
                first_seg->ol_flags = pkt_flags;
+               first_seg->packet_type = igb_rxd_pkt_info_to_pkt_type(rxd.wb.
+                                       lower.lo_dword.hs_rss.pkt_info);
 
                /* Prefetch data of first segment, if configured to do so. */
                rte_packet_prefetch((char *)first_seg->buf_addr +
@@ -1077,16 +1202,6 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
        return (nb_rx);
 }
 
-/*
- * Rings setup and release.
- *
- * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
- * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary.
- * This will also optimize cache line size effect.
- * H/W supports up to cache line size 128.
- */
-#define IGB_ALIGN 128
-
 /*
  * Maximum number of Ring Descriptors.
  *
@@ -1094,9 +1209,6 @@ eth_igb_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
  * desscriptors should meet the following condition:
  *      (num_ring_desc * sizeof(struct e1000_rx/tx_desc)) % 128 == 0
  */
-#define IGB_MIN_RING_DESC 32
-#define IGB_MAX_RING_DESC 4096
-
 static const struct rte_memzone *
 ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,
                      uint16_t queue_id, uint32_t ring_size, int socket_id)
@@ -1113,10 +1225,10 @@ ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,
 
 #ifdef RTE_LIBRTE_XEN_DOM0
        return rte_memzone_reserve_bounded(z_name, ring_size,
-                       socket_id, 0, IGB_ALIGN, RTE_PGSIZE_2M);
+                       socket_id, 0, E1000_ALIGN, RTE_PGSIZE_2M);
 #else
        return rte_memzone_reserve_aligned(z_name, ring_size,
-                       socket_id, 0, IGB_ALIGN);
+                       socket_id, 0, E1000_ALIGN);
 #endif
 }
 
@@ -1212,10 +1324,11 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
        /*
         * Validate number of transmit descriptors.
         * It must not exceed hardware maximum, and must be multiple
-        * of IGB_ALIGN.
+        * of E1000_ALIGN.
         */
-       if (((nb_desc * sizeof(union e1000_adv_tx_desc)) % IGB_ALIGN) != 0 ||
-           (nb_desc > IGB_MAX_RING_DESC) || (nb_desc < IGB_MIN_RING_DESC)) {
+       if (nb_desc % IGB_TXD_ALIGN != 0 ||
+                       (nb_desc > E1000_MAX_RING_DESC) ||
+                       (nb_desc < E1000_MIN_RING_DESC)) {
                return -EINVAL;
        }
 
@@ -1251,7 +1364,7 @@ eth_igb_tx_queue_setup(struct rte_eth_dev *dev,
         * handle the maximum ring size is allocated in order to allow for
         * resizing in later calls to the queue setup function.
         */
-       size = sizeof(union e1000_adv_tx_desc) * IGB_MAX_RING_DESC;
+       size = sizeof(union e1000_adv_tx_desc) * E1000_MAX_RING_DESC;
        tz = ring_dma_zone_reserve(dev, "tx_ring", queue_idx,
                                        size, socket_id);
        if (tz == NULL) {
@@ -1360,10 +1473,11 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
        /*
         * Validate number of receive descriptors.
         * It must not exceed hardware maximum, and must be multiple
-        * of IGB_ALIGN.
+        * of E1000_ALIGN.
         */
-       if (((nb_desc * sizeof(union e1000_adv_rx_desc)) % IGB_ALIGN) != 0 ||
-           (nb_desc > IGB_MAX_RING_DESC) || (nb_desc < IGB_MIN_RING_DESC)) {
+       if (nb_desc % IGB_RXD_ALIGN != 0 ||
+                       (nb_desc > E1000_MAX_RING_DESC) ||
+                       (nb_desc < E1000_MIN_RING_DESC)) {
                return (-EINVAL);
        }
 
@@ -1399,7 +1513,7 @@ eth_igb_rx_queue_setup(struct rte_eth_dev *dev,
         *  handle the maximum ring size is allocated in order to allow for
         *  resizing in later calls to the queue setup function.
         */
-       size = sizeof(union e1000_adv_rx_desc) * IGB_MAX_RING_DESC;
+       size = sizeof(union e1000_adv_rx_desc) * E1000_MAX_RING_DESC;
        rz = ring_dma_zone_reserve(dev, "rx_ring", queue_idx, size, socket_id);
        if (rz == NULL) {
                igb_rx_queue_release(rxq);
@@ -1500,6 +1614,24 @@ igb_dev_clear_queues(struct rte_eth_dev *dev)
        }
 }
 
+void
+igb_dev_free_queues(struct rte_eth_dev *dev)
+{
+       uint16_t i;
+
+       for (i = 0; i < dev->data->nb_rx_queues; i++) {
+               eth_igb_rx_queue_release(dev->data->rx_queues[i]);
+               dev->data->rx_queues[i] = NULL;
+       }
+       dev->data->nb_rx_queues = 0;
+
+       for (i = 0; i < dev->data->nb_tx_queues; i++) {
+               eth_igb_tx_queue_release(dev->data->tx_queues[i]);
+               dev->data->tx_queues[i] = NULL;
+       }
+       dev->data->nb_tx_queues = 0;
+}
+
 /**
  * Receive Side Scaling (RSS).
  * See section 7.1.1.7 in the following document:
@@ -1868,7 +2000,7 @@ igb_alloc_rx_queue_mbufs(struct igb_rx_queue *rxq)
                dma_addr =
                        rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(mbuf));
                rxd = &rxq->rx_ring[i];
-               rxd->read.hdr_addr = dma_addr;
+               rxd->read.hdr_addr = 0;
                rxd->read.pkt_addr = dma_addr;
                rxe[i].mbuf = mbuf;
        }
@@ -2394,3 +2526,34 @@ eth_igbvf_tx_init(struct rte_eth_dev *dev)
        }
 
 }
+
+void
+igb_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+       struct rte_eth_rxq_info *qinfo)
+{
+       struct igb_rx_queue *rxq;
+
+       rxq = dev->data->rx_queues[queue_id];
+
+       qinfo->mp = rxq->mb_pool;
+       qinfo->scattered_rx = dev->data->scattered_rx;
+       qinfo->nb_desc = rxq->nb_rx_desc;
+
+       qinfo->conf.rx_free_thresh = rxq->rx_free_thresh;
+       qinfo->conf.rx_drop_en = rxq->drop_en;
+}
+
+void
+igb_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+       struct rte_eth_txq_info *qinfo)
+{
+       struct igb_tx_queue *txq;
+
+       txq = dev->data->tx_queues[queue_id];
+
+       qinfo->nb_desc = txq->nb_tx_desc;
+
+       qinfo->conf.tx_thresh.pthresh = txq->pthresh;
+       qinfo->conf.tx_thresh.hthresh = txq->hthresh;
+       qinfo->conf.tx_thresh.wthresh = txq->wthresh;
+}