ixgbe: code cleanup
[dpdk.git] / lib / librte_pmd_ixgbe / ixgbe_rxtx.c
index ca35db2..61ffc4f 100644 (file)
@@ -2,6 +2,7 @@
  *   BSD LICENSE
  *
  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright 2014 6WIND S.A.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -94,7 +95,8 @@
 #define IXGBE_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)
@@ -363,59 +365,84 @@ ixgbe_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
 static inline void
 ixgbe_set_xmit_ctx(struct igb_tx_queue* txq,
                volatile struct ixgbe_adv_tx_context_desc *ctx_txd,
-               uint64_t ol_flags, uint32_t vlan_macip_lens)
+               uint64_t ol_flags, union ixgbe_tx_offload tx_offload)
 {
        uint32_t type_tucmd_mlhl;
-       uint32_t mss_l4len_idx;
+       uint32_t mss_l4len_idx = 0;
        uint32_t ctx_idx;
-       uint32_t cmp_mask;
+       uint32_t vlan_macip_lens;
+       union ixgbe_tx_offload tx_offload_mask;
 
        ctx_idx = txq->ctx_curr;
-       cmp_mask = 0;
+       tx_offload_mask.data = 0;
        type_tucmd_mlhl = 0;
 
+       /* Specify which HW CTX to upload. */
+       mss_l4len_idx |= (ctx_idx << IXGBE_ADVTXD_IDX_SHIFT);
+
        if (ol_flags & PKT_TX_VLAN_PKT) {
-               cmp_mask |= TX_VLAN_CMP_MASK;
+               tx_offload_mask.vlan_tci |= ~0;
        }
 
-       if (ol_flags & PKT_TX_IP_CKSUM) {
-               type_tucmd_mlhl = IXGBE_ADVTXD_TUCMD_IPV4;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-       }
+       /* check if TCP segmentation required for this packet */
+       if (ol_flags & PKT_TX_TCP_SEG) {
+               /* implies IP cksum and TCP cksum */
+               type_tucmd_mlhl = IXGBE_ADVTXD_TUCMD_IPV4 |
+                       IXGBE_ADVTXD_TUCMD_L4T_TCP |
+                       IXGBE_ADVTXD_DTYP_CTXT | IXGBE_ADVTXD_DCMD_DEXT;
+
+               tx_offload_mask.l2_len |= ~0;
+               tx_offload_mask.l3_len |= ~0;
+               tx_offload_mask.l4_len |= ~0;
+               tx_offload_mask.tso_segsz |= ~0;
+               mss_l4len_idx |= tx_offload.tso_segsz << IXGBE_ADVTXD_MSS_SHIFT;
+               mss_l4len_idx |= tx_offload.l4_len << IXGBE_ADVTXD_L4LEN_SHIFT;
+       } else { /* no TSO, check if hardware checksum is needed */
+               if (ol_flags & PKT_TX_IP_CKSUM) {
+                       type_tucmd_mlhl = IXGBE_ADVTXD_TUCMD_IPV4;
+                       tx_offload_mask.l2_len |= ~0;
+                       tx_offload_mask.l3_len |= ~0;
+               }
 
-       /* Specify which HW CTX to upload. */
-       mss_l4len_idx = (ctx_idx << IXGBE_ADVTXD_IDX_SHIFT);
-       switch (ol_flags & PKT_TX_L4_MASK) {
-       case PKT_TX_UDP_CKSUM:
-               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP |
+               switch (ol_flags & PKT_TX_L4_MASK) {
+               case PKT_TX_UDP_CKSUM:
+                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP |
                                IXGBE_ADVTXD_DTYP_CTXT | IXGBE_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct udp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       case PKT_TX_TCP_CKSUM:
-               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP |
+                       mss_l4len_idx |= sizeof(struct udp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
+                       tx_offload_mask.l2_len |= ~0;
+                       tx_offload_mask.l3_len |= ~0;
+                       break;
+               case PKT_TX_TCP_CKSUM:
+                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP |
                                IXGBE_ADVTXD_DTYP_CTXT | IXGBE_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct tcp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       case PKT_TX_SCTP_CKSUM:
-               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_SCTP |
+                       mss_l4len_idx |= sizeof(struct tcp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
+                       tx_offload_mask.l2_len |= ~0;
+                       tx_offload_mask.l3_len |= ~0;
+                       tx_offload_mask.l4_len |= ~0;
+                       break;
+               case PKT_TX_SCTP_CKSUM:
+                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_SCTP |
                                IXGBE_ADVTXD_DTYP_CTXT | IXGBE_ADVTXD_DCMD_DEXT;
-               mss_l4len_idx |= sizeof(struct sctp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
-               cmp_mask |= TX_MACIP_LEN_CMP_MASK;
-               break;
-       default:
-               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_RSV |
+                       mss_l4len_idx |= sizeof(struct sctp_hdr) << IXGBE_ADVTXD_L4LEN_SHIFT;
+                       tx_offload_mask.l2_len |= ~0;
+                       tx_offload_mask.l3_len |= ~0;
+                       break;
+               default:
+                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_RSV |
                                IXGBE_ADVTXD_DTYP_CTXT | IXGBE_ADVTXD_DCMD_DEXT;
-               break;
+                       break;
+               }
        }
 
        txq->ctx_cache[ctx_idx].flags = ol_flags;
-       txq->ctx_cache[ctx_idx].cmp_mask = cmp_mask;
-       txq->ctx_cache[ctx_idx].vlan_macip_lens.data =
-               vlan_macip_lens & cmp_mask;
+       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 = tx_offload.l3_len;
+       vlan_macip_lens |= (tx_offload.l2_len << IXGBE_ADVTXD_MACLEN_SHIFT);
+       vlan_macip_lens |= ((uint32_t)tx_offload.vlan_tci << IXGBE_ADVTXD_VLAN_SHIFT);
        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;
@@ -427,20 +454,20 @@ ixgbe_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 ixgbe_tx_offload tx_offload)
 {
        /* If match with the current used 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;
        }
 
        /* What if match with the next 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;
        }
 
@@ -451,20 +478,25 @@ what_advctx_update(struct igb_tx_queue *txq, uint64_t flags,
 static inline uint32_t
 tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
 {
-       static const uint32_t l4_olinfo[2] = {0, IXGBE_ADVTXD_POPTS_TXSM};
-       static const uint32_t l3_olinfo[2] = {0, IXGBE_ADVTXD_POPTS_IXSM};
-       uint32_t tmp;
-
-       tmp  = l4_olinfo[(ol_flags & PKT_TX_L4_MASK)  != PKT_TX_L4_NO_CKSUM];
-       tmp |= l3_olinfo[(ol_flags & PKT_TX_IP_CKSUM) != 0];
+       uint32_t tmp = 0;
+       if ((ol_flags & PKT_TX_L4_MASK) != PKT_TX_L4_NO_CKSUM)
+               tmp |= IXGBE_ADVTXD_POPTS_TXSM;
+       if (ol_flags & PKT_TX_IP_CKSUM)
+               tmp |= IXGBE_ADVTXD_POPTS_IXSM;
+       if (ol_flags & PKT_TX_TCP_SEG)
+               tmp |= IXGBE_ADVTXD_POPTS_TXSM;
        return tmp;
 }
 
 static inline uint32_t
-tx_desc_vlan_flags_to_cmdtype(uint64_t ol_flags)
+tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
 {
-       static const uint32_t vlan_cmd[2] = {0, IXGBE_ADVTXD_DCMD_VLE};
-       return vlan_cmd[(ol_flags & PKT_TX_VLAN_PKT) != 0];
+       uint32_t cmdtype = 0;
+       if (ol_flags & PKT_TX_VLAN_PKT)
+               cmdtype |= IXGBE_ADVTXD_DCMD_VLE;
+       if (ol_flags & PKT_TX_TCP_SEG)
+               cmdtype |= IXGBE_ADVTXD_DCMD_TSE;
+       return cmdtype;
 }
 
 /* Default RS bit threshold values */
@@ -545,7 +577,6 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        volatile union ixgbe_adv_tx_desc *txd;
        struct rte_mbuf     *tx_pkt;
        struct rte_mbuf     *m_seg;
-       union ixgbe_vlan_macip vlan_macip_lens;
        uint64_t buf_dma_addr;
        uint32_t olinfo_status;
        uint32_t cmd_type_len;
@@ -559,6 +590,7 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        uint64_t tx_ol_req;
        uint32_t ctx = 0;
        uint32_t new_ctx;
+       union ixgbe_tx_offload tx_offload = { .data = 0 };
 
        txq = tx_queue;
        sw_ring = txq->sw_ring;
@@ -588,12 +620,15 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                /* If hardware offload required */
                tx_ol_req = ol_flags & IXGBE_TX_OFFLOAD_MASK;
                if (tx_ol_req) {
-                       vlan_macip_lens.f.vlan_tci = tx_pkt->vlan_tci;
-                       vlan_macip_lens.f.l2_l3_len = tx_pkt->l2_l3_len;
+                       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;
 
                        /* If new context need be built or reuse the exist ctx. */
                        ctx = what_advctx_update(txq, tx_ol_req,
-                               vlan_macip_lens.data);
+                               tx_offload);
                        /* Only allocate context descriptor if required*/
                        new_ctx = (ctx == IXGBE_CTX_NUM);
                        ctx = txq->ctx_curr;
@@ -708,13 +743,22 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                 */
                cmd_type_len = IXGBE_ADVTXD_DTYP_DATA |
                        IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
-               olinfo_status = (pkt_len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
 #ifdef RTE_LIBRTE_IEEE1588
                if (ol_flags & PKT_TX_IEEE1588_TMST)
                        cmd_type_len |= IXGBE_ADVTXD_MAC_1588;
 #endif
 
+               olinfo_status = 0;
                if (tx_ol_req) {
+
+                       if (ol_flags & PKT_TX_TCP_SEG) {
+                               /* when TSO is on, paylen in descriptor is the
+                                * not the packet len but the tcp payload len */
+                               pkt_len -= (tx_offload.l2_len +
+                                       tx_offload.l3_len + tx_offload.l4_len);
+                       }
+
                        /*
                         * Setup the TX Advanced Context Descriptor if required
                         */
@@ -735,7 +779,7 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                                }
 
                                ixgbe_set_xmit_ctx(txq, ctx_txd, tx_ol_req,
-                                   vlan_macip_lens.data);
+                                       tx_offload);
 
                                txe->last_id = tx_last;
                                tx_id = txe->next_id;
@@ -747,11 +791,13 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                         * This path will go through
                         * whatever new/reuse the context descriptor
                         */
-                       cmd_type_len  |= tx_desc_vlan_flags_to_cmdtype(ol_flags);
+                       cmd_type_len  |= tx_desc_ol_flags_to_cmdtype(ol_flags);
                        olinfo_status |= tx_desc_cksum_flags_to_olinfo(ol_flags);
                        olinfo_status |= ctx << IXGBE_ADVTXD_IDX_SHIFT;
                }
 
+               olinfo_status |= (pkt_len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
                m_seg = tx_pkt;
                do {
                        txd = &txr[tx_id];
@@ -1725,6 +1771,40 @@ static struct ixgbe_txq_ops def_txq_ops = {
        .reset = ixgbe_reset_tx_queue,
 };
 
+/* Takes an ethdev and a queue and sets up the tx function to be used based on
+ * the queue parameters. Used in tx_queue_setup by primary process and then
+ * in dev_init by secondary process when attaching to an existing ethdev.
+ */
+void
+set_tx_function(struct rte_eth_dev *dev, struct igb_tx_queue *txq)
+{
+       /* Use a simple Tx queue (no offloads, no multi segs) if possible */
+       if (((txq->txq_flags & IXGBE_SIMPLE_FLAGS) == IXGBE_SIMPLE_FLAGS)
+                       && (txq->tx_rs_thresh >= RTE_PMD_IXGBE_TX_MAX_BURST)) {
+               PMD_INIT_LOG(INFO, "Using simple tx code path");
+#ifdef RTE_IXGBE_INC_VECTOR
+               if (txq->tx_rs_thresh <= RTE_IXGBE_TX_MAX_FREE_BUF_SZ &&
+                               (rte_eal_process_type() != RTE_PROC_PRIMARY ||
+                                       ixgbe_txq_vec_setup(txq) == 0)) {
+                       PMD_INIT_LOG(INFO, "Vector tx enabled.");
+                       dev->tx_pkt_burst = ixgbe_xmit_pkts_vec;
+               } else
+#endif
+               dev->tx_pkt_burst = ixgbe_xmit_pkts_simple;
+       } else {
+               PMD_INIT_LOG(INFO, "Using full-featured tx code path");
+               PMD_INIT_LOG(INFO,
+                               " - txq_flags = %lx " "[IXGBE_SIMPLE_FLAGS=%lx]",
+                               (unsigned long)txq->txq_flags,
+                               (unsigned long)IXGBE_SIMPLE_FLAGS);
+               PMD_INIT_LOG(INFO,
+                               " - tx_rs_thresh = %lu " "[RTE_PMD_IXGBE_TX_MAX_BURST=%lu]",
+                               (unsigned long)txq->tx_rs_thresh,
+                               (unsigned long)RTE_PMD_IXGBE_TX_MAX_BURST);
+               dev->tx_pkt_burst = ixgbe_xmit_pkts;
+       }
+}
+
 int
 ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
                         uint16_t queue_idx,
@@ -1831,7 +1911,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
 
        /* First allocate the tx queue data structure */
        txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct igb_tx_queue),
-                                CACHE_LINE_SIZE, socket_id);
+                                RTE_CACHE_LINE_SIZE, socket_id);
        if (txq == NULL)
                return (-ENOMEM);
 
@@ -1865,7 +1945,8 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
        /*
         * Modification to set VFTDT for virtual function if vf is detected
         */
-       if (hw->mac.type == ixgbe_mac_82599_vf)
+       if (hw->mac.type == ixgbe_mac_82599_vf ||
+           hw->mac.type == ixgbe_mac_X540_vf)
                txq->tdt_reg_addr = IXGBE_PCI_REG_ADDR(hw, IXGBE_VFTDT(queue_idx));
        else
                txq->tdt_reg_addr = IXGBE_PCI_REG_ADDR(hw, IXGBE_TDT(txq->reg_idx));
@@ -1879,7 +1960,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
        /* Allocate software ring */
        txq->sw_ring = rte_zmalloc_socket("txq->sw_ring",
                                sizeof(struct igb_tx_entry) * nb_desc,
-                               CACHE_LINE_SIZE, socket_id);
+                               RTE_CACHE_LINE_SIZE, socket_id);
        if (txq->sw_ring == NULL) {
                ixgbe_tx_queue_release(txq);
                return (-ENOMEM);
@@ -1887,31 +1968,8 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
        PMD_INIT_LOG(DEBUG, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
                     txq->sw_ring, txq->tx_ring, txq->tx_ring_phys_addr);
 
-       /* Use a simple Tx queue (no offloads, no multi segs) if possible */
-       if (((txq->txq_flags & IXGBE_SIMPLE_FLAGS) == IXGBE_SIMPLE_FLAGS) &&
-           (txq->tx_rs_thresh >= RTE_PMD_IXGBE_TX_MAX_BURST)) {
-               PMD_INIT_LOG(INFO, "Using simple tx code path");
-#ifdef RTE_IXGBE_INC_VECTOR
-               if (txq->tx_rs_thresh <= RTE_IXGBE_TX_MAX_FREE_BUF_SZ &&
-                   ixgbe_txq_vec_setup(txq) == 0) {
-                       PMD_INIT_LOG(INFO, "Vector tx enabled.");
-                       dev->tx_pkt_burst = ixgbe_xmit_pkts_vec;
-               }
-               else
-#endif
-                       dev->tx_pkt_burst = ixgbe_xmit_pkts_simple;
-       } else {
-               PMD_INIT_LOG(INFO, "Using full-featured tx code path");
-               PMD_INIT_LOG(INFO, " - txq_flags = %lx "
-                            "[IXGBE_SIMPLE_FLAGS=%lx]",
-                            (long unsigned)txq->txq_flags,
-                            (long unsigned)IXGBE_SIMPLE_FLAGS);
-               PMD_INIT_LOG(INFO, " - tx_rs_thresh = %lu "
-                            "[RTE_PMD_IXGBE_TX_MAX_BURST=%lu]",
-                            (long unsigned)txq->tx_rs_thresh,
-                            (long unsigned)RTE_PMD_IXGBE_TX_MAX_BURST);
-               dev->tx_pkt_burst = ixgbe_xmit_pkts;
-       }
+       /* set up vector or scalar TX function as appropriate */
+       set_tx_function(dev, txq);
 
        txq->ops->reset(txq);
 
@@ -2117,7 +2175,7 @@ ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
 
        /* First allocate the rx queue data structure */
        rxq = rte_zmalloc_socket("ethdev RX queue", sizeof(struct igb_rx_queue),
-                                CACHE_LINE_SIZE, socket_id);
+                                RTE_CACHE_LINE_SIZE, socket_id);
        if (rxq == NULL)
                return (-ENOMEM);
        rxq->mb_pool = mp;
@@ -2152,7 +2210,8 @@ ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
        /*
         * Modified to setup VFRDT for Virtual Function
         */
-       if (hw->mac.type == ixgbe_mac_82599_vf) {
+       if (hw->mac.type == ixgbe_mac_82599_vf ||
+           hw->mac.type == ixgbe_mac_X540_vf) {
                rxq->rdt_reg_addr =
                        IXGBE_PCI_REG_ADDR(hw, IXGBE_VFRDT(queue_idx));
                rxq->rdh_reg_addr =
@@ -2183,7 +2242,7 @@ ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
 #endif
        rxq->sw_ring = rte_zmalloc_socket("rxq->sw_ring",
                                          sizeof(struct igb_rx_entry) * len,
-                                         CACHE_LINE_SIZE, socket_id);
+                                         RTE_CACHE_LINE_SIZE, socket_id);
        if (rxq->sw_ring == NULL) {
                ixgbe_rx_queue_release(rxq);
                return (-ENOMEM);
@@ -3502,9 +3561,9 @@ ixgbe_dev_rx_init(struct rte_eth_dev *dev)
                                IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(rxq->reg_idx), psrtype);
                        }
                        srrctl = ((dev->data->dev_conf.rxmode.split_hdr_size <<
-                                  IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
-                                 IXGBE_SRRCTL_BSIZEHDR_MASK);
-                       srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+                               IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+                               IXGBE_SRRCTL_BSIZEHDR_MASK);
+                       srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
                } else
 #endif
                        srrctl = IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
@@ -3602,9 +3661,10 @@ ixgbe_dev_tx_init(struct rte_eth_dev *dev)
        PMD_INIT_FUNC_TRACE();
        hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       /* Enable TX CRC (checksum offload requirement) */
+       /* Enable TX CRC (checksum offload requirement) and hw padding
+        * (TSO requirement) */
        hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
-       hlreg0 |= IXGBE_HLREG0_TXCRCEN;
+       hlreg0 |= (IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN);
        IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
 
        /* Setup the Base and Length of the Tx Descriptor Rings */
@@ -3938,7 +3998,7 @@ ixgbevf_dev_rx_init(struct rte_eth_dev *dev)
        struct igb_rx_queue *rxq;
        struct rte_pktmbuf_pool_private *mbp_priv;
        uint64_t bus_addr;
-       uint32_t srrctl;
+       uint32_t srrctl, psrtype = 0;
        uint16_t buf_size;
        uint16_t i;
        int ret;
@@ -3992,20 +4052,10 @@ ixgbevf_dev_rx_init(struct rte_eth_dev *dev)
                 * Configure Header Split
                 */
                if (dev->data->dev_conf.rxmode.header_split) {
-
-                       /* Must setup the PSRTYPE register */
-                       uint32_t psrtype;
-                       psrtype = IXGBE_PSRTYPE_TCPHDR |
-                               IXGBE_PSRTYPE_UDPHDR   |
-                               IXGBE_PSRTYPE_IPV4HDR  |
-                               IXGBE_PSRTYPE_IPV6HDR;
-
-                       IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE(i), psrtype);
-
                        srrctl = ((dev->data->dev_conf.rxmode.split_hdr_size <<
-                                  IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
-                                 IXGBE_SRRCTL_BSIZEHDR_MASK);
-                       srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+                               IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+                               IXGBE_SRRCTL_BSIZEHDR_MASK);
+                       srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
                } else
 #endif
                        srrctl = IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
@@ -4048,6 +4098,17 @@ ixgbevf_dev_rx_init(struct rte_eth_dev *dev)
                }
        }
 
+#ifdef RTE_HEADER_SPLIT_ENABLE
+       if (dev->data->dev_conf.rxmode.header_split)
+               /* Must setup the PSRTYPE register */
+               psrtype = IXGBE_PSRTYPE_TCPHDR |
+                       IXGBE_PSRTYPE_UDPHDR   |
+                       IXGBE_PSRTYPE_IPV4HDR  |
+                       IXGBE_PSRTYPE_IPV6HDR;
+#endif
+
+       IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype);
+
        if (dev->data->dev_conf.rxmode.enable_scatter) {
                if (!dev->data->scattered_rx)
                        PMD_INIT_LOG(DEBUG, "forcing scatter mode");