net/sfc: support deferred start of receive queues
[dpdk.git] / drivers / net / sfc / sfc_rx.c
index be8fa23..3bfce1c 100644 (file)
@@ -87,6 +87,10 @@ sfc_rx_qrefill(struct sfc_rxq *rxq)
 
        free_space = EFX_RXQ_LIMIT(rxq->ptr_mask + 1) -
                (added - rxq->completed);
+
+       if (free_space < rxq->refill_threshold)
+               return;
+
        bulks = free_space / RTE_DIM(objs);
 
        id = added & rxq->ptr_mask;
@@ -189,6 +193,7 @@ sfc_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
        unsigned int prefix_size = rxq->prefix_size;
        unsigned int done_pkts = 0;
        boolean_t discard_next = B_FALSE;
+       struct rte_mbuf *scatter_pkt = NULL;
 
        if (unlikely((rxq->state & SFC_RXQ_RUNNING) == 0))
                return 0;
@@ -214,9 +219,6 @@ sfc_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                if (desc_flags & (EFX_ADDR_MISMATCH | EFX_DISCARD))
                        goto discard;
 
-               if (desc_flags & EFX_PKT_CONT)
-                       goto discard;
-
                if (desc_flags & EFX_PKT_PREFIX_LEN) {
                        uint16_t tmp_size;
                        int rc __rte_unused;
@@ -233,6 +235,29 @@ sfc_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
                rte_pktmbuf_data_len(m) = seg_len;
                rte_pktmbuf_pkt_len(m) = seg_len;
 
+               if (scatter_pkt != NULL) {
+                       if (rte_pktmbuf_chain(scatter_pkt, m) != 0) {
+                               rte_mempool_put(rxq->refill_mb_pool,
+                                               scatter_pkt);
+                               goto discard;
+                       }
+                       /* The packet to deliver */
+                       m = scatter_pkt;
+               }
+
+               if (desc_flags & EFX_PKT_CONT) {
+                       /* The packet is scattered, more fragments to come */
+                       scatter_pkt = m;
+                       /* Futher fragments have no prefix */
+                       prefix_size = 0;
+                       continue;
+               }
+
+               /* Scattered packet is done */
+               scatter_pkt = NULL;
+               /* The first fragment of the packet has prefix */
+               prefix_size = rxq->prefix_size;
+
                m->ol_flags = sfc_rx_desc_flags_to_offload_flags(desc_flags);
                m->packet_type = sfc_rx_desc_flags_to_packet_type(desc_flags);
 
@@ -246,6 +271,9 @@ discard:
                rxd->mbuf = NULL;
        }
 
+       /* pending is only moved when entire packet is received */
+       SFC_ASSERT(scatter_pkt == NULL);
+
        rxq->completed = completed;
 
        sfc_rx_qrefill(rxq);
@@ -253,6 +281,33 @@ discard:
        return done_pkts;
 }
 
+unsigned int
+sfc_rx_qdesc_npending(struct sfc_adapter *sa, unsigned int sw_index)
+{
+       struct sfc_rxq *rxq;
+
+       SFC_ASSERT(sw_index < sa->rxq_count);
+       rxq = sa->rxq_info[sw_index].rxq;
+
+       if (rxq == NULL || (rxq->state & SFC_RXQ_RUNNING) == 0)
+               return 0;
+
+       sfc_ev_qpoll(rxq->evq);
+
+       return rxq->pending - rxq->completed;
+}
+
+int
+sfc_rx_qdesc_done(struct sfc_rxq *rxq, unsigned int offset)
+{
+       if ((rxq->state & SFC_RXQ_RUNNING) == 0)
+               return 0;
+
+       sfc_ev_qpoll(rxq->evq);
+
+       return offset < (rxq->pending - rxq->completed);
+}
+
 static void
 sfc_rx_qpurge(struct sfc_rxq *rxq)
 {
@@ -389,6 +444,9 @@ sfc_rx_qstop(struct sfc_adapter *sa, unsigned int sw_index)
 
        rxq_info = &sa->rxq_info[sw_index];
        rxq = rxq_info->rxq;
+
+       if (rxq->state == SFC_RXQ_INITIALIZED)
+               return;
        SFC_ASSERT(rxq->state & SFC_RXQ_STARTED);
 
        /* It seems to be used by DPDK for debug purposes only ('rte_ether') */
@@ -410,9 +468,10 @@ sfc_rx_qstop(struct sfc_adapter *sa, unsigned int sw_index)
 }
 
 static int
-sfc_rx_qcheck_conf(struct sfc_adapter *sa,
+sfc_rx_qcheck_conf(struct sfc_adapter *sa, uint16_t nb_rx_desc,
                   const struct rte_eth_rxconf *rx_conf)
 {
+       const uint16_t rx_free_thresh_max = EFX_RXQ_LIMIT(nb_rx_desc);
        int rc = 0;
 
        if (rx_conf->rx_thresh.pthresh != 0 ||
@@ -423,8 +482,10 @@ sfc_rx_qcheck_conf(struct sfc_adapter *sa,
                rc = EINVAL;
        }
 
-       if (rx_conf->rx_free_thresh != 0) {
-               sfc_err(sa, "RxQ free threshold is not supported");
+       if (rx_conf->rx_free_thresh > rx_free_thresh_max) {
+               sfc_err(sa,
+                       "RxQ free threshold too large: %u vs maximum %u",
+                       rx_conf->rx_free_thresh, rx_free_thresh_max);
                rc = EINVAL;
        }
 
@@ -433,11 +494,6 @@ sfc_rx_qcheck_conf(struct sfc_adapter *sa,
                rc = EINVAL;
        }
 
-       if (rx_conf->rx_deferred_start != 0) {
-               sfc_err(sa, "RxQ deferred start is not supported");
-               rc = EINVAL;
-       }
-
        return rc;
 }
 
@@ -555,7 +611,7 @@ sfc_rx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
        struct sfc_evq *evq;
        struct sfc_rxq *rxq;
 
-       rc = sfc_rx_qcheck_conf(sa, rx_conf);
+       rc = sfc_rx_qcheck_conf(sa, nb_rx_desc, rx_conf);
        if (rc != 0)
                goto fail_bad_conf;
 
@@ -584,7 +640,9 @@ sfc_rx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
 
        SFC_ASSERT(nb_rx_desc <= rxq_info->max_entries);
        rxq_info->entries = nb_rx_desc;
-       rxq_info->type = EFX_RXQ_TYPE_DEFAULT;
+       rxq_info->type =
+               sa->eth_dev->data->dev_conf.rxmode.enable_scatter ?
+               EFX_RXQ_TYPE_SCATTER : EFX_RXQ_TYPE_DEFAULT;
 
        evq_index = sfc_evq_index_by_rxq_sw_index(sa, sw_index);
 
@@ -615,6 +673,7 @@ sfc_rx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
        evq->rxq = rxq;
        rxq->evq = evq;
        rxq->ptr_mask = rxq_info->entries - 1;
+       rxq->refill_threshold = rx_conf->rx_free_thresh;
        rxq->refill_mb_pool = mb_pool;
        rxq->buf_size = buf_size;
        rxq->hw_index = sw_index;
@@ -627,6 +686,7 @@ sfc_rx_qinit(struct sfc_adapter *sa, unsigned int sw_index,
        rxq->state = SFC_RXQ_INITIALIZED;
 
        rxq_info->rxq = rxq;
+       rxq_info->deferred_start = (rx_conf->rx_deferred_start != 0);
 
        return 0;
 
@@ -681,9 +741,12 @@ sfc_rx_start(struct sfc_adapter *sa)
                goto fail_rx_init;
 
        for (sw_index = 0; sw_index < sa->rxq_count; ++sw_index) {
-               rc = sfc_rx_qstart(sa, sw_index);
-               if (rc != 0)
-                       goto fail_rx_qstart;
+               if ((!sa->rxq_info[sw_index].deferred_start ||
+                    sa->rxq_info[sw_index].deferred_started)) {
+                       rc = sfc_rx_qstart(sa, sw_index);
+                       if (rc != 0)
+                               goto fail_rx_qstart;
+               }
        }
 
        return 0;
@@ -771,11 +834,6 @@ sfc_rx_check_mode(struct sfc_adapter *sa, struct rte_eth_rxmode *rxmode)
                rxmode->hw_strip_crc = 1;
        }
 
-       if (rxmode->enable_scatter) {
-               sfc_err(sa, "Scatter on Rx not supported");
-               rc = EINVAL;
-       }
-
        if (rxmode->enable_lro) {
                sfc_err(sa, "LRO not supported");
                rc = EINVAL;