src/dpdk/drivers/net/nfp/nfp_net.c
static uint16_t
nfp_net_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
{
	struct nfp_net_rxq *rxq;
	struct nfp_net_rx_desc *rxds;
	struct nfp_net_rx_buff *rxb;
	struct nfp_net_hw *hw;
	struct rte_mbuf *mb;
	struct rte_mbuf *new_mb;
	uint16_t nb_hold;
	uint64_t dma_addr;
	int avail;

	rxq = rx_queue;
	if (unlikely(rxq == NULL)) {
		/*
		 * DPDK just checks the queue is lower than max queues
		 * enabled. But the queue needs to be configured
		 */
		RTE_LOG_DP(ERR, PMD, "RX Bad queue\n");
		return -EINVAL;
	}

	hw = rxq->hw;
	avail = 0;
	nb_hold = 0;

	while (avail < nb_pkts) {
		rxb = &rxq->rxbufs[rxq->rd_p];
		if (unlikely(rxb == NULL)) {
			RTE_LOG_DP(ERR, PMD, "rxb does not exist!\n");
			break;
		}

		rxds = &rxq->rxds[rxq->rd_p];
		if ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)
			break;

		/*
		 * Memory barrier to ensure that we won't do other
		 * reads before the DD bit.
		 */
		rte_rmb();

		/*
		 * We got a packet. Let's alloc a new mbuf for refilling the
		 * free descriptor ring as soon as possible
		 */
		new_mb = rte_pktmbuf_alloc(rxq->mem_pool);
		if (unlikely(new_mb == NULL)) {
			RTE_LOG_DP(DEBUG, PMD,
			"RX mbuf alloc failed port_id=%u queue_id=%u\n",
				rxq->port_id, (unsigned int)rxq->qidx);
			nfp_net_mbuf_alloc_failed(rxq);
			break;
		}

		nb_hold++;

		/*
		 * Grab the mbuf and refill the descriptor with the
		 * previously allocated mbuf
		 */
		mb = rxb->mbuf;
		rxb->mbuf = new_mb;

		PMD_RX_LOG(DEBUG, "Packet len: %u, mbuf_size: %u",
			   rxds->rxd.data_len, rxq->mbuf_size);

		/* Size of this segment */
		mb->data_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);
		/* Size of the whole packet. We just support 1 segment */
		mb->pkt_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);

		if (unlikely((mb->data_len + hw->rx_offset) >
			     rxq->mbuf_size)) {
			/*
			 * This should not happen and the user has the
			 * responsibility of avoiding it. But we have
			 * to give some info about the error
			 */
			RTE_LOG_DP(ERR, PMD,
				"mbuf overflow likely due to the RX offset.\n"
				"\t\tYour mbuf size should have extra space for"
				" RX offset=%u bytes.\n"
				"\t\tCurrently you just have %u bytes available"
				" but the received packet is %u bytes long",
				hw->rx_offset,
				rxq->mbuf_size - hw->rx_offset,
				mb->data_len);
			return -EINVAL;
		}

		/* Filling the received mbuf with packet info */
		if (hw->rx_offset)
			mb->data_off = RTE_PKTMBUF_HEADROOM + hw->rx_offset;
		else
			mb->data_off = RTE_PKTMBUF_HEADROOM +
				       NFP_DESC_META_LEN(rxds);

		/* No scatter mode supported */
		mb->nb_segs = 1;
		mb->next = NULL;

		mb->port = rxq->port_id;

		/* Checking the RSS flag */
		nfp_net_set_hash(rxq, rxds, mb);

		/* Checking the checksum flag */
		nfp_net_rx_cksum(rxq, rxds, mb);

		if ((rxds->rxd.flags & PCIE_DESC_RX_VLAN) &&
		    (hw->ctrl & NFP_NET_CFG_CTRL_RXVLAN)) {
			mb->vlan_tci = rte_cpu_to_le_32(rxds->rxd.vlan);
			mb->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
		}

		/* Adding the mbuf to the mbuf array passed by the app */
		rx_pkts[avail++] = mb;

		/* Now resetting and updating the descriptor */
		rxds->vals[0] = 0;
		rxds->vals[1] = 0;
		dma_addr = rte_cpu_to_le_64(RTE_MBUF_DMA_ADDR_DEFAULT(new_mb));
		rxds->fld.dd = 0;
		rxds->fld.dma_addr_hi = (dma_addr >> 32) & 0xff;
		rxds->fld.dma_addr_lo = dma_addr & 0xffffffff;

		rxq->rd_p++;
		if (unlikely(rxq->rd_p == rxq->rx_count)) /* wrapping?*/
			rxq->rd_p = 0;
	}

	if (nb_hold == 0)
		return nb_hold;

	PMD_RX_LOG(DEBUG, "RX  port_id=%u queue_id=%u, %d packets received",
		   rxq->port_id, (unsigned int)rxq->qidx, nb_hold);

	nb_hold += rxq->nb_rx_hold;

	/*
	 * FL descriptors needs to be written before incrementing the
	 * FL queue WR pointer
	 */
	rte_wmb();
	if (nb_hold > rxq->rx_free_thresh) {
		PMD_RX_LOG(DEBUG, "port=%u queue=%u nb_hold=%u avail=%u",
			   rxq->port_id, (unsigned int)rxq->qidx,
			   (unsigned)nb_hold, (unsigned)avail);
		nfp_qcp_ptr_add(rxq->qcp_fl, NFP_QCP_WRITE_PTR, nb_hold);
		nb_hold = 0;
	}
	rxq->nb_rx_hold = nb_hold;

	return avail;
}
/*
 * RX path design:
 *
 * There are some decisions to take:
 * 1) How to check DD RX descriptors bit
 * 2) How and when to allocate new mbufs
 *
 * Current implementation checks just one single DD bit each loop. As each
 * descriptor is 8 bytes, it is likely a good idea to check descriptors in
 * a single cache line instead. Tests with this change have not shown any
 * performance improvement but it requires further investigation. For example,
 * depending on which descriptor is next, the number of descriptors could be
 * less than 8 for just checking those in the same cache line. This implies
 * extra work which could be counterproductive by itself. Indeed, last firmware
 * changes are just doing this: writing several descriptors with the DD bit
 * for saving PCIe bandwidth and DMA operations from the NFP.
 *
 * Mbuf allocation is done when a new packet is received. Then the descriptor
 * is automatically linked with the new mbuf and the old one is given to the
 * user. The main drawback with this design is mbuf allocation is heavier than
 * using bulk allocations allowed by DPDK with rte_mempool_get_bulk. From the
 * cache point of view it does not seem allocating the mbuf early on as we are
 * doing now have any benefit at all. Again, tests with this change have not
 * shown any improvement. Also, rte_mempool_get_bulk returns all or nothing
 * so looking at the implications of this type of allocation should be studied
 * deeply
 */
RX path design:
There are some decisions to take:
1) How to check DD RX descriptors bit
2) How and when to allocate new mbufs

Current implementation checks just one single DD bit each loop. As each
descriptor is 8 bytes, it is likely a good idea to check descriptors in
a single cache line instead. Tests with this change have not shown any
performance improvement but it requires further investigation. For example,
depending on which descriptor is next, the number of descriptors could be
less than 8 for just checking those in the same cache line. This implies
extra work which could be counterproductive by itself. Indeed, last firmware
changes are just doing this: writing several descriptors with the DD bit
for saving PCIe bandwidth and DMA operations from the NFP.

Mbuf allocation is done when a new packet is received. Then the descriptor
is automatically linked with the new mbuf and the old one is given to the
user. The main drawback with this design is mbuf allocation is heavier than
using bulk allocations allowed by DPDK with rte_mempool_get_bulk. From the
cache point of view it does not seem allocating the mbuf early on as we are
doing now have any benefit at all. Again, tests with this change have not
shown any improvement. Also, rte_mempool_get_bulk returns all or nothing
so looking at the implications of this type of allocation should be studied
deeply
RX path design : There are some decisions to take : 1 ) How to check DD RX descriptors bit 2 ) How and when to allocate new mbufs Current implementation checks just one single DD bit each loop . As each descriptor is 8 bytes it is likely a good idea to check descriptors in a single cache line instead . Tests with this change have not shown any performance improvement but it requires further investigation . For example depending on which descriptor is next the number of descriptors could be less than 8 for just checking those in the same cache line . This implies extra work which could be counterproductive by itself . Indeed last firmware changes are just doing this : writing several descriptors with the DD bit for saving PCIe bandwidth and DMA operations from the NFP . Mbuf allocation is done when a new packet is received . Then the descriptor is automatically linked with the new mbuf and the old one is given to the user . The main drawback with this design is mbuf allocation is heavier than using bulk allocations allowed by DPDK with rte_mempool_get_bulk . From the cache point of view it does not seem allocating the mbuf early on as we are doing now have any benefit at all . Again tests with this change have not shown any improvement . Also rte_mempool_get_bulk returns all or nothing so looking at the implications of this type of allocation should be studied deeply
static uint16_t
nfp_net_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
{
	struct nfp_net_rxq *rxq;
	struct nfp_net_rx_desc *rxds;
	struct nfp_net_rx_buff *rxb;
	struct nfp_net_hw *hw;
	struct rte_mbuf *mb;
	struct rte_mbuf *new_mb;
	uint16_t nb_hold;
	uint64_t dma_addr;
	int avail;
	rxq = rx_queue;
	if (unlikely(rxq == NULL)) {
		RTE_LOG_DP(ERR, PMD, "RX Bad queue\n");
		return -EINVAL;
	}
	hw = rxq->hw;
	avail = 0;
	nb_hold = 0;
	while (avail < nb_pkts) {
		rxb = &rxq->rxbufs[rxq->rd_p];
		if (unlikely(rxb == NULL)) {
			RTE_LOG_DP(ERR, PMD, "rxb does not exist!\n");
			break;
		}
		rxds = &rxq->rxds[rxq->rd_p];
		if ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)
			break;
		rte_rmb();
		new_mb = rte_pktmbuf_alloc(rxq->mem_pool);
		if (unlikely(new_mb == NULL)) {
			RTE_LOG_DP(DEBUG, PMD,
			"RX mbuf alloc failed port_id=%u queue_id=%u\n",
				rxq->port_id, (unsigned int)rxq->qidx);
			nfp_net_mbuf_alloc_failed(rxq);
			break;
		}
		nb_hold++;
		mb = rxb->mbuf;
		rxb->mbuf = new_mb;
		PMD_RX_LOG(DEBUG, "Packet len: %u, mbuf_size: %u",
			   rxds->rxd.data_len, rxq->mbuf_size);
		mb->data_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);
		mb->pkt_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);
		if (unlikely((mb->data_len + hw->rx_offset) >
			     rxq->mbuf_size)) {
			RTE_LOG_DP(ERR, PMD,
				"mbuf overflow likely due to the RX offset.\n"
				"\t\tYour mbuf size should have extra space for"
				" RX offset=%u bytes.\n"
				"\t\tCurrently you just have %u bytes available"
				" but the received packet is %u bytes long",
				hw->rx_offset,
				rxq->mbuf_size - hw->rx_offset,
				mb->data_len);
			return -EINVAL;
		}
		if (hw->rx_offset)
			mb->data_off = RTE_PKTMBUF_HEADROOM + hw->rx_offset;
		else
			mb->data_off = RTE_PKTMBUF_HEADROOM +
				       NFP_DESC_META_LEN(rxds);
		mb->nb_segs = 1;
		mb->next = NULL;
		mb->port = rxq->port_id;
		nfp_net_set_hash(rxq, rxds, mb);
		nfp_net_rx_cksum(rxq, rxds, mb);
		if ((rxds->rxd.flags & PCIE_DESC_RX_VLAN) &&
		    (hw->ctrl & NFP_NET_CFG_CTRL_RXVLAN)) {
			mb->vlan_tci = rte_cpu_to_le_32(rxds->rxd.vlan);
			mb->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
		}
		rx_pkts[avail++] = mb;
		rxds->vals[0] = 0;
		rxds->vals[1] = 0;
		dma_addr = rte_cpu_to_le_64(RTE_MBUF_DMA_ADDR_DEFAULT(new_mb));
		rxds->fld.dd = 0;
		rxds->fld.dma_addr_hi = (dma_addr >> 32) & 0xff;
		rxds->fld.dma_addr_lo = dma_addr & 0xffffffff;
		rxq->rd_p++;
		if (unlikely(rxq->rd_p == rxq->rx_count)) 
			rxq->rd_p = 0;
	}
	if (nb_hold == 0)
		return nb_hold;
	PMD_RX_LOG(DEBUG, "RX  port_id=%u queue_id=%u, %d packets received",
		   rxq->port_id, (unsigned int)rxq->qidx, nb_hold);
	nb_hold += rxq->nb_rx_hold;
	rte_wmb();
	if (nb_hold > rxq->rx_free_thresh) {
		PMD_RX_LOG(DEBUG, "port=%u queue=%u nb_hold=%u avail=%u",
			   rxq->port_id, (unsigned int)rxq->qidx,
			   (unsigned)nb_hold, (unsigned)avail);
		nfp_qcp_ptr_add(rxq->qcp_fl, NFP_QCP_WRITE_PTR, nb_hold);
		nb_hold = 0;
	}
	rxq->nb_rx_hold = nb_hold;
	return avail;
}
static uint16_t nfp_net_recv_pkts ( void * rx_queue , struct rte_mbuf * * rx_pkts , uint16_t nb_pkts ) { struct nfp_net_rxq * rxq ; struct nfp_net_rx_desc * rxds ; struct nfp_net_rx_buff * rxb ; struct nfp_net_hw * hw ; struct rte_mbuf * mb ; struct rte_mbuf * new_mb ; uint16_t nb_hold ; uint64_t dma_addr ; int avail ; rxq = rx_queue ; if ( unlikely ( rxq == NULL ) ) { RTE_LOG_DP ( ERR , PMD , " \n " ) ; return - EINVAL ; } hw = rxq -> hw ; avail = 0 ; nb_hold = 0 ; while ( avail < nb_pkts ) { rxb = & rxq -> rxbufs [ rxq -> rd_p ] ; if ( unlikely ( rxb == NULL ) ) { RTE_LOG_DP ( ERR , PMD , " \n " ) ; break ; } rxds = & rxq -> rxds [ rxq -> rd_p ] ; if ( ( rxds -> rxd . meta_len_dd & PCIE_DESC_RX_DD ) == 0 ) break ; rte_rmb ( ) ; new_mb = rte_pktmbuf_alloc ( rxq -> mem_pool ) ; if ( unlikely ( new_mb == NULL ) ) { RTE_LOG_DP ( DEBUG , PMD , " \n " , rxq -> port_id , ( unsigned int ) rxq -> qidx ) ; nfp_net_mbuf_alloc_failed ( rxq ) ; break ; } nb_hold ++ ; mb = rxb -> mbuf ; rxb -> mbuf = new_mb ; PMD_RX_LOG ( DEBUG , " " , rxds -> rxd . data_len , rxq -> mbuf_size ) ; mb -> data_len = rxds -> rxd . data_len - NFP_DESC_META_LEN ( rxds ) ; mb -> pkt_len = rxds -> rxd . data_len - NFP_DESC_META_LEN ( rxds ) ; if ( unlikely ( ( mb -> data_len + hw -> rx_offset ) > rxq -> mbuf_size ) ) { RTE_LOG_DP ( ERR , PMD , " \n " " \t \t " " \n " " \t \t " " " , hw -> rx_offset , rxq -> mbuf_size - hw -> rx_offset , mb -> data_len ) ; return - EINVAL ; } if ( hw -> rx_offset ) mb -> data_off = RTE_PKTMBUF_HEADROOM + hw -> rx_offset ; else mb -> data_off = RTE_PKTMBUF_HEADROOM + NFP_DESC_META_LEN ( rxds ) ; mb -> nb_segs = 1 ; mb -> next = NULL ; mb -> port = rxq -> port_id ; nfp_net_set_hash ( rxq , rxds , mb ) ; nfp_net_rx_cksum ( rxq , rxds , mb ) ; if ( ( rxds -> rxd . flags & PCIE_DESC_RX_VLAN ) && ( hw -> ctrl & NFP_NET_CFG_CTRL_RXVLAN ) ) { mb -> vlan_tci = rte_cpu_to_le_32 ( rxds -> rxd . vlan ) ; mb -> ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED ; } rx_pkts [ avail ++ ] = mb ; rxds -> vals [ 0 ] = 0 ; rxds -> vals [ 1 ] = 0 ; dma_addr = rte_cpu_to_le_64 ( RTE_MBUF_DMA_ADDR_DEFAULT ( new_mb ) ) ; rxds -> fld . dd = 0 ; rxds -> fld . dma_addr_hi = ( dma_addr >> 32 ) & 0xff ; rxds -> fld . dma_addr_lo = dma_addr & 0xffffffff ; rxq -> rd_p ++ ; if ( unlikely ( rxq -> rd_p == rxq -> rx_count ) ) rxq -> rd_p = 0 ; } if ( nb_hold == 0 ) return nb_hold ; PMD_RX_LOG ( DEBUG , " " , rxq -> port_id , ( unsigned int ) rxq -> qidx , nb_hold ) ; nb_hold += rxq -> nb_rx_hold ; rte_wmb ( ) ; if ( nb_hold > rxq -> rx_free_thresh ) { PMD_RX_LOG ( DEBUG , " " , rxq -> port_id , ( unsigned int ) rxq -> qidx , ( unsigned ) nb_hold , ( unsigned ) avail ) ; nfp_qcp_ptr_add ( rxq -> qcp_fl , NFP_QCP_WRITE_PTR , nb_hold ) ; nb_hold = 0 ; } rxq -> nb_rx_hold = nb_hold ; return avail ; }
RX path design:
 There are some decisions to take:
 1) How to check DD RX descriptors bit
 2) How and when to allocate new mbufs
RX path design : There are some decisions to take : 1 ) How to check DD RX descriptors bit 2 ) How and when to allocate new mbufs
/*
		 * DPDK just checks the queue is lower than max queues
		 * enabled. But the queue needs to be configured
		 */ /*
		 * Memory barrier to ensure that we won't do other
		 * reads before the DD bit.
		 */ /*
		 * We got a packet. Let's alloc a new mbuf for refilling the
		 * free descriptor ring as soon as possible
		 */ /*
		 * Grab the mbuf and refill the descriptor with the
		 * previously allocated mbuf
		 */ /* Size of this segment */ /* Size of the whole packet. We just support 1 segment */ /*
			 * This should not happen and the user has the
			 * responsibility of avoiding it. But we have
			 * to give some info about the error
			 */ /* Filling the received mbuf with packet info */ /* No scatter mode supported */ /* Checking the RSS flag */ /* Checking the checksum flag */ /* Adding the mbuf to the mbuf array passed by the app */ /* Now resetting and updating the descriptor */ /* wrapping?*/ /*
	 * FL descriptors needs to be written before incrementing the
	 * FL queue WR pointer
	 */