/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2019 Cesnet * Copyright(c) 2019 Netcope Technologies, a.s. * All rights reserved. */ #ifndef _NFB_RX_H_ #define _NFB_RX_H_ #include #include #include #include #define NFB_TIMESTAMP_FLAG (1 << 0) struct ndp_rx_queue { struct nfb_device *nfb; /* nfb dev structure */ struct ndp_queue *queue; /* rx queue */ uint16_t rx_queue_id; /* index */ uint8_t in_port; /* port */ uint8_t flags; /* setup flags */ struct rte_mempool *mb_pool; /* memory pool to allocate packets */ uint16_t buf_size; /* mbuf size */ volatile uint64_t rx_pkts; /* packets read */ volatile uint64_t rx_bytes; /* bytes read */ volatile uint64_t err_pkts; /* erroneous packets */ }; /** * Initialize ndp_rx_queue structure * * @param nfb * Pointer to nfb device structure. * @param rx_queue_id * RX queue index. * @param port_id * Device [external] port identifier. * @param mb_pool * Memory pool for buffer allocations. * @param[out] rxq * Pointer to ndp_rx_queue output structure * @return * 0 on success, a negative errno value otherwise. */ int nfb_eth_rx_queue_init(struct nfb_device *nfb, uint16_t rx_queue_id, uint16_t port_id, struct rte_mempool *mb_pool, struct ndp_rx_queue *rxq); /** * DPDK callback to setup a RX queue for use. * * @param dev * Pointer to Ethernet device structure. * @param idx * RX queue index. * @param desc * Number of descriptors to configure in queue. * @param socket * NUMA socket on which memory must be allocated. * @param[in] conf * Thresholds parameters. * @param mb_pool * Memory pool for buffer allocations. * * @return * 0 on success, a negative errno value otherwise. */ int nfb_eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id, uint16_t nb_rx_desc __rte_unused, unsigned int socket_id, const struct rte_eth_rxconf *rx_conf __rte_unused, struct rte_mempool *mb_pool); /** * DPDK callback to release a RX queue. * * @param dpdk_rxq * Generic RX queue pointer. */ void nfb_eth_rx_queue_release(void *q); /** * Start traffic on Rx queue. * * @param dev * Pointer to Ethernet device structure. * @param txq_id * RX queue index. * @return * 0 on success, a negative errno value otherwise. */ int nfb_eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rxq_id); /** * Stop traffic on Rx queue. * * @param dev * Pointer to Ethernet device structure. * @param txq_id * RX queue index. */ int nfb_eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rxq_id); /** * DPDK callback for RX. * * @param dpdk_rxq * Generic pointer to RX queue structure. * @param[out] bufs * Array to store received packets. * @param nb_pkts * Maximum number of packets in array. * * @return * Number of packets successfully received (<= nb_pkts). */ static __rte_always_inline uint16_t nfb_eth_ndp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { struct ndp_rx_queue *ndp = queue; uint8_t timestamping_enabled; uint16_t packet_size; uint64_t num_bytes = 0; uint16_t num_rx; unsigned int i; const uint16_t buf_size = ndp->buf_size; struct rte_mbuf *mbuf; struct ndp_packet packets[nb_pkts]; struct rte_mbuf *mbufs[nb_pkts]; if (unlikely(ndp->queue == NULL || nb_pkts == 0)) { RTE_LOG(ERR, PMD, "RX invalid arguments!\n"); return 0; } timestamping_enabled = ndp->flags & NFB_TIMESTAMP_FLAG; /* returns either all or nothing */ i = rte_pktmbuf_alloc_bulk(ndp->mb_pool, mbufs, nb_pkts); if (unlikely(i != 0)) return 0; num_rx = ndp_rx_burst_get(ndp->queue, packets, nb_pkts); if (unlikely(num_rx != nb_pkts)) { for (i = num_rx; i < nb_pkts; i++) rte_pktmbuf_free(mbufs[i]); } nb_pkts = num_rx; num_rx = 0; /* * Reads the given number of packets from NDP queue given * by queue and copies the packet data into a newly allocated mbuf * to return. */ for (i = 0; i < nb_pkts; ++i) { mbuf = mbufs[i]; /* get the space available for data in the mbuf */ packet_size = packets[i].data_length; if (likely(packet_size <= buf_size)) { /* NDP packet will fit in one mbuf, go ahead and copy */ rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packets[i].data, packet_size); mbuf->data_len = (uint16_t)packet_size; mbuf->pkt_len = packet_size; mbuf->port = ndp->in_port; mbuf->ol_flags = 0; if (timestamping_enabled) { /* nanoseconds */ mbuf->timestamp = rte_le_to_cpu_32(*((uint32_t *) (packets[i].header + 4))); mbuf->timestamp <<= 32; /* seconds */ mbuf->timestamp |= rte_le_to_cpu_32(*((uint32_t *) (packets[i].header + 8))); mbuf->ol_flags |= PKT_RX_TIMESTAMP; } bufs[num_rx++] = mbuf; num_bytes += packet_size; } else { /* * NDP packet will not fit in one mbuf, * scattered mode is not enabled, drop packet */ rte_pktmbuf_free(mbuf); } } ndp_rx_burst_put(ndp->queue); ndp->rx_pkts += num_rx; ndp->rx_bytes += num_bytes; return num_rx; } #endif /* _NFB_RX_H_ */