diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 30679014e3..30bd109e8b 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -236,6 +236,9 @@ struct sfc_sw_stats {
 	unsigned int			cache_count;
 
 	uint64_t			*reset_vals;
+	/* Location of per-queue reset values for packets/bytes in reset_vals */
+	uint64_t			*reset_rx_pkts;
+	uint64_t			*reset_rx_bytes;
 
 	rte_spinlock_t			queues_bitmap_lock;
 	void				*queues_bitmap_mem;
diff --git a/drivers/net/sfc/sfc_dp.h b/drivers/net/sfc/sfc_dp.h
index 7fd8f34b0f..2edde61a68 100644
--- a/drivers/net/sfc/sfc_dp.h
+++ b/drivers/net/sfc/sfc_dp.h
@@ -16,6 +16,7 @@
 #include <rte_pci.h>
 
 #include "sfc_log.h"
+#include "sfc_stats.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -49,6 +50,7 @@ struct sfc_dp_queue {
 	 * put stats at top of the structure to be closer to fields
 	 * used on datapath or reap to have more chances to be cache-hot.
 	 */
+	union sfc_pkts_bytes		stats;
 	uint32_t			rx_dbells;
 	uint32_t			tx_dbells;
 
diff --git a/drivers/net/sfc/sfc_dp_rx.h b/drivers/net/sfc/sfc_dp_rx.h
index b6c44085ce..d037acaa56 100644
--- a/drivers/net/sfc/sfc_dp_rx.h
+++ b/drivers/net/sfc/sfc_dp_rx.h
@@ -216,6 +216,7 @@ struct sfc_dp_rx {
 #define SFC_DP_RX_FEAT_FLOW_FLAG		0x2
 #define SFC_DP_RX_FEAT_FLOW_MARK		0x4
 #define SFC_DP_RX_FEAT_INTR			0x8
+#define SFC_DP_RX_FEAT_STATS			0x10
 	/**
 	 * Rx offload capabilities supported by the datapath on device
 	 * level only if HW/FW supports it.
diff --git a/drivers/net/sfc/sfc_ef100_rx.c b/drivers/net/sfc/sfc_ef100_rx.c
index 1bf04f565a..391c52487d 100644
--- a/drivers/net/sfc/sfc_ef100_rx.c
+++ b/drivers/net/sfc/sfc_ef100_rx.c
@@ -525,10 +525,13 @@ sfc_ef100_rx_process_ready_pkts(struct sfc_ef100_rxq *rxq,
 			lastseg = seg;
 		}
 
-		if (likely(deliver))
+		if (likely(deliver)) {
 			*rx_pkts++ = pkt;
-		else
+			sfc_pkts_bytes_add(&rxq->dp.dpq.stats, 1,
+					   rte_pktmbuf_pkt_len(pkt));
+		} else {
 			rte_pktmbuf_free(pkt);
+		}
 	}
 
 	return rx_pkts;
@@ -914,7 +917,8 @@ struct sfc_dp_rx sfc_ef100_rx = {
 		.hw_fw_caps	= SFC_DP_HW_FW_CAP_EF100,
 	},
 	.features		= SFC_DP_RX_FEAT_MULTI_PROCESS |
-				  SFC_DP_RX_FEAT_INTR,
+				  SFC_DP_RX_FEAT_INTR |
+				  SFC_DP_RX_FEAT_STATS,
 	.dev_offload_capa	= 0,
 	.queue_offload_capa	= DEV_RX_OFFLOAD_CHECKSUM |
 				  DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 2db0d000c3..20d808d15c 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -586,6 +586,33 @@ sfc_tx_queue_release(void *queue)
 	sfc_adapter_unlock(sa);
 }
 
+static void
+sfc_stats_get_dp_rx(struct sfc_adapter *sa, uint64_t *pkts, uint64_t *bytes)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	uint64_t pkts_sum = 0;
+	uint64_t bytes_sum = 0;
+	unsigned int i;
+
+	for (i = 0; i < sas->ethdev_rxq_count; ++i) {
+		struct sfc_rxq_info *rxq_info;
+
+		rxq_info = sfc_rxq_info_by_ethdev_qid(sas, i);
+		if (rxq_info->state & SFC_RXQ_INITIALIZED) {
+			union sfc_pkts_bytes qstats;
+
+			sfc_pkts_bytes_get(&rxq_info->dp->dpq.stats, &qstats);
+			pkts_sum += qstats.pkts -
+					sa->sw_stats.reset_rx_pkts[i];
+			bytes_sum += qstats.bytes -
+					sa->sw_stats.reset_rx_bytes[i];
+		}
+	}
+
+	*pkts = pkts_sum;
+	*bytes = bytes_sum;
+}
+
 /*
  * Some statistics are computed as A - B where A and B each increase
  * monotonically with some hardware counter(s) and the counters are read
@@ -612,6 +639,8 @@ sfc_update_diff_stat(uint64_t *stat, uint64_t newval)
 static int
 sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
+	const struct sfc_adapter_priv *sap = sfc_adapter_priv_by_eth_dev(dev);
+	bool have_dp_rx_stats = sap->dp_rx->features & SFC_DP_RX_FEAT_STATS;
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
 	uint64_t *mac_stats;
@@ -619,6 +648,9 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	sfc_adapter_lock(sa);
 
+	if (have_dp_rx_stats)
+		sfc_stats_get_dp_rx(sa, &stats->ipackets, &stats->ibytes);
+
 	ret = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (ret != 0)
 		goto unlock;
@@ -627,18 +659,23 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask,
 				   EFX_MAC_VADAPTER_RX_UNICAST_PACKETS)) {
-		stats->ipackets =
-			mac_stats[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS] +
-			mac_stats[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS] +
-			mac_stats[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS];
+		if (!have_dp_rx_stats) {
+			stats->ipackets =
+				mac_stats[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS] +
+				mac_stats[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS] +
+				mac_stats[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS];
+			stats->ibytes =
+				mac_stats[EFX_MAC_VADAPTER_RX_UNICAST_BYTES] +
+				mac_stats[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES] +
+				mac_stats[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES];
+
+			/* CRC is included in these stats, but shouldn't be */
+			stats->ibytes -= stats->ipackets * RTE_ETHER_CRC_LEN;
+		}
 		stats->opackets =
 			mac_stats[EFX_MAC_VADAPTER_TX_UNICAST_PACKETS] +
 			mac_stats[EFX_MAC_VADAPTER_TX_MULTICAST_PACKETS] +
 			mac_stats[EFX_MAC_VADAPTER_TX_BROADCAST_PACKETS];
-		stats->ibytes =
-			mac_stats[EFX_MAC_VADAPTER_RX_UNICAST_BYTES] +
-			mac_stats[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES] +
-			mac_stats[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES];
 		stats->obytes =
 			mac_stats[EFX_MAC_VADAPTER_TX_UNICAST_BYTES] +
 			mac_stats[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES] +
@@ -647,15 +684,12 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 		stats->oerrors = mac_stats[EFX_MAC_VADAPTER_TX_BAD_PACKETS];
 
 		/* CRC is included in these stats, but shouldn't be */
-		stats->ibytes -= stats->ipackets * RTE_ETHER_CRC_LEN;
 		stats->obytes -= stats->opackets * RTE_ETHER_CRC_LEN;
 	} else {
 		stats->opackets = mac_stats[EFX_MAC_TX_PKTS];
-		stats->ibytes = mac_stats[EFX_MAC_RX_OCTETS];
 		stats->obytes = mac_stats[EFX_MAC_TX_OCTETS];
 
 		/* CRC is included in these stats, but shouldn't be */
-		stats->ibytes -= mac_stats[EFX_MAC_RX_PKTS] * RTE_ETHER_CRC_LEN;
 		stats->obytes -= mac_stats[EFX_MAC_TX_PKTS] * RTE_ETHER_CRC_LEN;
 
 		/*
@@ -681,12 +715,16 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 			mac_stats[EFX_MAC_RX_JABBER_PKTS];
 		/* no oerrors counters supported on EF10 */
 
-		/* Exclude missed, errors and pauses from Rx packets */
-		sfc_update_diff_stat(&port->ipackets,
-			mac_stats[EFX_MAC_RX_PKTS] -
-			mac_stats[EFX_MAC_RX_PAUSE_PKTS] -
-			stats->imissed - stats->ierrors);
-		stats->ipackets = port->ipackets;
+		if (!have_dp_rx_stats) {
+			/* Exclude missed, errors and pauses from Rx packets */
+			sfc_update_diff_stat(&port->ipackets,
+				mac_stats[EFX_MAC_RX_PKTS] -
+				mac_stats[EFX_MAC_RX_PAUSE_PKTS] -
+				stats->imissed - stats->ierrors);
+			stats->ipackets = port->ipackets;
+			stats->ibytes = mac_stats[EFX_MAC_RX_OCTETS] -
+				mac_stats[EFX_MAC_RX_PKTS] * RTE_ETHER_CRC_LEN;
+		}
 	}
 
 unlock:
diff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c
index 81bd531a17..8ffa923215 100644
--- a/drivers/net/sfc/sfc_sw_stats.c
+++ b/drivers/net/sfc/sfc_sw_stats.c
@@ -12,13 +12,21 @@
 
 #define SFC_SW_STAT_INVALID		UINT64_MAX
 
-#define SFC_SW_STATS_GROUP_SIZE_MAX	1U
+#define SFC_SW_STATS_GROUP_SIZE_MAX	2U
+#define SFC_SW_STAT_GOOD_PACKETS	"packets"
+#define SFC_SW_STAT_GOOD_BYTES		"bytes"
 
 enum sfc_sw_stats_type {
 	SFC_SW_STATS_RX,
 	SFC_SW_STATS_TX,
 };
 
+enum sfc_sw_stats_group_basic {
+	SFC_SW_STATS_GROUP_BASIC_PKTS = 0,
+	SFC_SW_STATS_GROUP_BASIC_BYTES,
+	SFX_SW_STATS_GROUP_BASIC_MAX
+};
+
 typedef void sfc_get_sw_stat_val_t(struct sfc_adapter *sa, uint16_t qid,
 				   uint64_t *values, unsigned int values_count);
 
@@ -29,6 +37,29 @@ struct sfc_sw_stat_descr {
 	bool provide_total;
 };
 
+static sfc_get_sw_stat_val_t sfc_sw_stat_get_rx_good_pkts_bytes;
+static void
+sfc_sw_stat_get_rx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid,
+				   uint64_t *values,
+				   unsigned int values_count)
+{
+	struct sfc_adapter_shared *sas = sfc_sa2shared(sa);
+	struct sfc_rxq_info *rxq_info;
+	union sfc_pkts_bytes qstats;
+
+	RTE_SET_USED(values_count);
+	SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX);
+	rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid);
+	if (rxq_info->state & SFC_RXQ_INITIALIZED) {
+		sfc_pkts_bytes_get(&rxq_info->dp->dpq.stats, &qstats);
+		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = qstats.pkts;
+		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = qstats.bytes;
+	} else {
+		values[SFC_SW_STATS_GROUP_BASIC_PKTS] = 0;
+		values[SFC_SW_STATS_GROUP_BASIC_BYTES] = 0;
+	}
+}
+
 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_rx_dbells;
 static void
 sfc_get_sw_stat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid,
@@ -66,6 +97,20 @@ sfc_get_sw_stat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid,
  * The start of the group is denoted by stat implementing get value callback.
  */
 const struct sfc_sw_stat_descr sfc_sw_stats_descr[] = {
+	/* Group of Rx packets/bytes stats */
+	{
+		.name = SFC_SW_STAT_GOOD_PACKETS,
+		.type = SFC_SW_STATS_RX,
+		.get_val  = sfc_sw_stat_get_rx_good_pkts_bytes,
+		.provide_total = false,
+	},
+	{
+		.name = SFC_SW_STAT_GOOD_BYTES,
+		.type = SFC_SW_STATS_RX,
+		.get_val  = NULL,
+		.provide_total = false,
+	},
+	/* End of basic stats */
 	{
 		.name = "dbells",
 		.type = SFC_SW_STATS_RX,
@@ -584,6 +629,66 @@ sfc_sw_xstats_reset(struct sfc_adapter *sa)
 	}
 }
 
+static bool
+sfc_sw_stats_is_packets_or_bytes(const char *xstat_name)
+{
+	return strcmp(xstat_name, SFC_SW_STAT_GOOD_PACKETS) == 0 ||
+	       strcmp(xstat_name, SFC_SW_STAT_GOOD_BYTES) == 0;
+}
+
+static void
+sfc_sw_stats_fill_available_descr(struct sfc_adapter *sa)
+{
+	const struct sfc_adapter_priv *sap = &sa->priv;
+	bool have_dp_rx_stats = sap->dp_rx->features & SFC_DP_RX_FEAT_STATS;
+	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
+	const struct sfc_sw_stat_descr *sw_stat_descr;
+	unsigned int i;
+
+	sw_stats->supp_count = 0;
+	for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) {
+		sw_stat_descr = &sfc_sw_stats_descr[i];
+		if (!have_dp_rx_stats &&
+		    sw_stat_descr->type == SFC_SW_STATS_RX &&
+		    sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name))
+			continue;
+		sw_stats->supp[sw_stats->supp_count].descr = sw_stat_descr;
+		sw_stats->supp_count++;
+	}
+}
+
+static int
+sfc_sw_stats_set_reset_basic_stats(struct sfc_adapter *sa)
+{
+	uint64_t *reset_vals = sa->sw_stats.reset_vals;
+	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
+	const struct sfc_sw_stat_descr *sw_stat;
+	unsigned int i;
+
+	for (i = 0; i < sw_stats->supp_count; i++) {
+		sw_stat = sw_stats->supp[i].descr;
+
+		switch (sw_stat->type) {
+		case SFC_SW_STATS_RX:
+			if (strcmp(sw_stat->name,
+				   SFC_SW_STAT_GOOD_PACKETS) == 0)
+				sa->sw_stats.reset_rx_pkts = reset_vals;
+			else if (strcmp(sw_stat->name,
+					SFC_SW_STAT_GOOD_BYTES) == 0)
+				sa->sw_stats.reset_rx_bytes = reset_vals;
+			break;
+		case SFC_SW_STATS_TX:
+		default:
+			SFC_GENERIC_LOG(ERR, "Unknown SW stat type");
+			return -EINVAL;
+		}
+
+		reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_stat);
+	}
+
+	return 0;
+}
+
 int
 sfc_sw_xstats_configure(struct sfc_adapter *sa)
 {
@@ -605,6 +710,7 @@ sfc_sw_xstats_configure(struct sfc_adapter *sa)
 	}
 	for (i = 0; i < sw_stats->supp_count; i++)
 		sw_stats->supp[i].descr = &sfc_sw_stats_descr[i];
+	sfc_sw_stats_fill_available_descr(sa);
 
 	for (i = 0; i < sw_stats->supp_count; i++) {
 		nb_supported += sfc_sw_xstat_get_nb_supported(sa,
@@ -630,6 +736,9 @@ sfc_sw_xstats_configure(struct sfc_adapter *sa)
 	}
 	sa->sw_stats.cache_count = cache_count;
 	stat_cache = *cache;
+	rc = sfc_sw_stats_set_reset_basic_stats(sa);
+	if (rc != 0)
+		goto fail_reset_basic_stats;
 
 	for (i = 0; i < sw_stats->supp_count; i++) {
 		sw_stats->supp[i].cache = stat_cache;
@@ -639,6 +748,10 @@ sfc_sw_xstats_configure(struct sfc_adapter *sa)
 
 	return 0;
 
+fail_reset_basic_stats:
+	rte_free(*cache);
+	*cache = NULL;
+	sa->sw_stats.cache_count = 0;
 fail_cache:
 	rte_free(*reset_vals);
 	*reset_vals = NULL;
