ixgbe: fix Tx hang when RS distance exceeds HW limit
[dpdk.git] / drivers / net / ixgbe / ixgbe_rxtx.c
index ad66b09..ca6fb69 100644 (file)
@@ -415,7 +415,6 @@ ixgbe_set_xmit_ctx(struct ixgbe_tx_queue *txq,
                        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 |
@@ -573,7 +572,7 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        struct ixgbe_tx_entry *sw_ring;
        struct ixgbe_tx_entry *txe, *txn;
        volatile union ixgbe_adv_tx_desc *txr;
-       volatile union ixgbe_adv_tx_desc *txd;
+       volatile union ixgbe_adv_tx_desc *txd, *txp;
        struct rte_mbuf     *tx_pkt;
        struct rte_mbuf     *m_seg;
        uint64_t buf_dma_addr;
@@ -596,6 +595,7 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
        txr     = txq->tx_ring;
        tx_id   = txq->tx_tail;
        txe = &sw_ring[tx_id];
+       txp = NULL;
 
        /* Determine if the descriptor ring needs to be cleaned. */
        if (txq->nb_tx_free < txq->tx_free_thresh)
@@ -639,6 +639,12 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                 */
                nb_used = (uint16_t)(tx_pkt->nb_segs + new_ctx);
 
+               if (txp != NULL &&
+                               nb_used + txq->nb_tx_used >= txq->tx_rs_thresh)
+                       /* set RS on the previous packet in the burst */
+                       txp->read.cmd_type_len |=
+                               rte_cpu_to_le_32(IXGBE_TXD_CMD_RS);
+
                /*
                 * The number of descriptors that must be allocated for a
                 * packet is the number of segments of that packet, plus 1
@@ -841,10 +847,18 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
                        /* Update txq RS bit counters */
                        txq->nb_tx_used = 0;
-               }
+                       txp = NULL;
+               } else
+                       txp = txd;
+
                txd->read.cmd_type_len |= rte_cpu_to_le_32(cmd_type_len);
        }
+
 end_of_tx:
+       /* set RS on last packet in the burst */
+       if (txp != NULL)
+               txp->read.cmd_type_len |= rte_cpu_to_le_32(IXGBE_TXD_CMD_RS);
+
        rte_wmb();
 
        /*
@@ -1820,25 +1834,6 @@ ixgbe_recv_pkts_lro_bulk_alloc(void *rx_queue, struct rte_mbuf **rx_pkts,
  *
  **********************************************************************/
 
-/*
- * 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 IXGBE_ALIGN 128
-
-/*
- * Maximum number of Ring Descriptors.
- *
- * Since RDLEN/TDLEN should be multiple of 128 bytes, the number of ring
- * descriptors should meet the following condition:
- *      (num_ring_desc * sizeof(rx/tx descriptor)) % 128 == 0
- */
-#define IXGBE_MIN_RING_DESC 32
-#define IXGBE_MAX_RING_DESC 4096
-
 /*
  * Create memzone for HW rings. malloc can't be used as the physical address is
  * needed. If the memzone is already created, then this function returns a ptr
@@ -2007,9 +2002,9 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
         * It must not exceed hardware maximum, and must be multiple
         * of IXGBE_ALIGN.
         */
-       if (((nb_desc * sizeof(union ixgbe_adv_tx_desc)) % IXGBE_ALIGN) != 0 ||
-           (nb_desc > IXGBE_MAX_RING_DESC) ||
-           (nb_desc < IXGBE_MIN_RING_DESC)) {
+       if (nb_desc % IXGBE_TXD_ALIGN != 0 ||
+                       (nb_desc > IXGBE_MAX_RING_DESC) ||
+                       (nb_desc < IXGBE_MIN_RING_DESC)) {
                return -EINVAL;
        }
 
@@ -2039,9 +2034,16 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
                        tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH);
        if (tx_rs_thresh >= (nb_desc - 2)) {
                PMD_INIT_LOG(ERR, "tx_rs_thresh must be less than the number "
-                            "of TX descriptors minus 2. (tx_rs_thresh=%u "
-                            "port=%d queue=%d)", (unsigned int)tx_rs_thresh,
-                            (int)dev->data->port_id, (int)queue_idx);
+                       "of TX descriptors minus 2. (tx_rs_thresh=%u "
+                       "port=%d queue=%d)", (unsigned int)tx_rs_thresh,
+                       (int)dev->data->port_id, (int)queue_idx);
+               return -(EINVAL);
+       }
+       if (tx_rs_thresh > DEFAULT_TX_RS_THRESH) {
+               PMD_INIT_LOG(ERR, "tx_rs_thresh must be less or equal than %u. "
+                       "(tx_rs_thresh=%u port=%d queue=%d)",
+                       DEFAULT_TX_RS_THRESH, (unsigned int)tx_rs_thresh,
+                       (int)dev->data->port_id, (int)queue_idx);
                return -(EINVAL);
        }
        if (tx_free_thresh >= (nb_desc - 3)) {
@@ -2374,9 +2376,9 @@ ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,
         * It must not exceed hardware maximum, and must be multiple
         * of IXGBE_ALIGN.
         */
-       if (((nb_desc * sizeof(union ixgbe_adv_rx_desc)) % IXGBE_ALIGN) != 0 ||
-           (nb_desc > IXGBE_MAX_RING_DESC) ||
-           (nb_desc < IXGBE_MIN_RING_DESC)) {
+       if (nb_desc % IXGBE_RXD_ALIGN != 0 ||
+                       (nb_desc > IXGBE_MAX_RING_DESC) ||
+                       (nb_desc < IXGBE_MIN_RING_DESC)) {
                return (-EINVAL);
        }
 
@@ -4533,6 +4535,7 @@ ixgbe_dev_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
                rte_wmb();
                IXGBE_WRITE_REG(hw, IXGBE_RDH(rxq->reg_idx), 0);
                IXGBE_WRITE_REG(hw, IXGBE_RDT(rxq->reg_idx), rxq->nb_rx_desc - 1);
+               dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
        } else
                return -1;
 
@@ -4576,6 +4579,7 @@ ixgbe_dev_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
 
                ixgbe_rx_queue_release_mbufs(rxq);
                ixgbe_reset_rx_queue(adapter, rxq);
+               dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
        } else
                return -1;
 
@@ -4618,6 +4622,7 @@ ixgbe_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
                rte_wmb();
                IXGBE_WRITE_REG(hw, IXGBE_TDH(txq->reg_idx), 0);
                IXGBE_WRITE_REG(hw, IXGBE_TDT(txq->reg_idx), 0);
+               dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
        } else
                return -1;
 
@@ -4678,12 +4683,50 @@ ixgbe_dev_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
                        txq->ops->release_mbufs(txq);
                        txq->ops->reset(txq);
                }
+               dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
        } else
                return -1;
 
        return 0;
 }
 
+void
+ixgbe_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+       struct rte_eth_rxq_info *qinfo)
+{
+       struct ixgbe_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;
+       qinfo->conf.rx_deferred_start = rxq->rx_deferred_start;
+}
+
+void
+ixgbe_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+       struct rte_eth_txq_info *qinfo)
+{
+       struct ixgbe_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;
+
+       qinfo->conf.tx_free_thresh = txq->tx_free_thresh;
+       qinfo->conf.tx_rs_thresh = txq->tx_rs_thresh;
+       qinfo->conf.txq_flags = txq->txq_flags;
+       qinfo->conf.tx_deferred_start = txq->tx_deferred_start;
+}
+
 /*
  * [VF] Initializes Receive Unit.
  */