diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 30bd109e8b..ace66d435c 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -239,6 +239,8 @@ struct sfc_sw_stats {
 	/* Location of per-queue reset values for packets/bytes in reset_vals */
 	uint64_t			*reset_rx_pkts;
 	uint64_t			*reset_rx_bytes;
+	uint64_t			*reset_tx_pkts;
+	uint64_t			*reset_tx_bytes;
 
 	rte_spinlock_t			queues_bitmap_lock;
 	void				*queues_bitmap_mem;
diff --git a/drivers/net/sfc/sfc_dp_tx.h b/drivers/net/sfc/sfc_dp_tx.h
index 777807985b..184711b887 100644
--- a/drivers/net/sfc/sfc_dp_tx.h
+++ b/drivers/net/sfc/sfc_dp_tx.h
@@ -168,6 +168,7 @@ struct sfc_dp_tx {
 
 	unsigned int			features;
 #define SFC_DP_TX_FEAT_MULTI_PROCESS	0x1
+#define SFC_DP_TX_FEAT_STATS		0x2
 	/**
 	 * Tx offload capabilities supported by the datapath on device
 	 * level only if HW/FW supports it.
diff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c
index 522e9a0d34..fce82795cc 100644
--- a/drivers/net/sfc/sfc_ef100_tx.c
+++ b/drivers/net/sfc/sfc_ef100_tx.c
@@ -710,6 +710,9 @@ sfc_ef100_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 		}
 
 		dma_desc_space -= (added - pkt_start);
+
+		sfc_pkts_bytes_add(&txq->dp.dpq.stats, 1,
+				   rte_pktmbuf_pkt_len(*pktp));
 	}
 
 	if (likely(added != txq->added)) {
@@ -940,7 +943,8 @@ struct sfc_dp_tx sfc_ef100_tx = {
 		.type		= SFC_DP_TX,
 		.hw_fw_caps	= SFC_DP_HW_FW_CAP_EF100,
 	},
-	.features		= SFC_DP_TX_FEAT_MULTI_PROCESS,
+	.features		= SFC_DP_TX_FEAT_MULTI_PROCESS |
+				  SFC_DP_TX_FEAT_STATS,
 	.dev_offload_capa	= 0,
 	.queue_offload_capa	= DEV_TX_OFFLOAD_VLAN_INSERT |
 				  DEV_TX_OFFLOAD_IPV4_CKSUM |
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index 20d808d15c..fac9b27974 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -613,6 +613,33 @@ sfc_stats_get_dp_rx(struct sfc_adapter *sa, uint64_t *pkts, uint64_t *bytes)
 	*bytes = bytes_sum;
 }
 
+static void
+sfc_stats_get_dp_tx(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_txq_count; ++i) {
+		struct sfc_txq_info *txq_info;
+
+		txq_info = sfc_txq_info_by_ethdev_qid(sas, i);
+		if (txq_info->state & SFC_TXQ_INITIALIZED) {
+			union sfc_pkts_bytes qstats;
+
+			sfc_pkts_bytes_get(&txq_info->dp->dpq.stats, &qstats);
+			pkts_sum += qstats.pkts -
+					sa->sw_stats.reset_tx_pkts[i];
+			bytes_sum += qstats.bytes -
+					sa->sw_stats.reset_tx_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
@@ -641,6 +668,7 @@ 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;
+	bool have_dp_tx_stats = sap->dp_tx->features & SFC_DP_TX_FEAT_STATS;
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
 	struct sfc_port *port = &sa->port;
 	uint64_t *mac_stats;
@@ -650,6 +678,8 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 
 	if (have_dp_rx_stats)
 		sfc_stats_get_dp_rx(sa, &stats->ipackets, &stats->ibytes);
+	if (have_dp_tx_stats)
+		sfc_stats_get_dp_tx(sa, &stats->opackets, &stats->obytes);
 
 	ret = sfc_port_update_mac_stats(sa, B_FALSE);
 	if (ret != 0)
@@ -672,25 +702,27 @@ sfc_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 			/* 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->obytes =
-			mac_stats[EFX_MAC_VADAPTER_TX_UNICAST_BYTES] +
-			mac_stats[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES] +
-			mac_stats[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES];
+		if (!have_dp_tx_stats) {
+			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->obytes =
+				mac_stats[EFX_MAC_VADAPTER_TX_UNICAST_BYTES] +
+				mac_stats[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES] +
+				mac_stats[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES];
+
+			/* CRC is included in these stats, but shouldn't be */
+			stats->obytes -= stats->opackets * RTE_ETHER_CRC_LEN;
+		}
 		stats->imissed = mac_stats[EFX_MAC_VADAPTER_RX_BAD_PACKETS];
 		stats->oerrors = mac_stats[EFX_MAC_VADAPTER_TX_BAD_PACKETS];
-
-		/* CRC is included in these stats, but shouldn't be */
-		stats->obytes -= stats->opackets * RTE_ETHER_CRC_LEN;
 	} else {
-		stats->opackets = mac_stats[EFX_MAC_TX_PKTS];
-		stats->obytes = mac_stats[EFX_MAC_TX_OCTETS];
-
-		/* CRC is included in these stats, but shouldn't be */
-		stats->obytes -= mac_stats[EFX_MAC_TX_PKTS] * RTE_ETHER_CRC_LEN;
+		if (!have_dp_tx_stats) {
+			stats->opackets = mac_stats[EFX_MAC_TX_PKTS];
+			stats->obytes = mac_stats[EFX_MAC_TX_OCTETS] -
+				mac_stats[EFX_MAC_TX_PKTS] * RTE_ETHER_CRC_LEN;
+		}
 
 		/*
 		 * Take into account stats which are whenever supported
diff --git a/drivers/net/sfc/sfc_sw_stats.c b/drivers/net/sfc/sfc_sw_stats.c
index 8ffa923215..6b3a01b3c6 100644
--- a/drivers/net/sfc/sfc_sw_stats.c
+++ b/drivers/net/sfc/sfc_sw_stats.c
@@ -60,6 +60,29 @@ sfc_sw_stat_get_rx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid,
 	}
 }
 
+static sfc_get_sw_stat_val_t sfc_sw_stat_get_tx_good_pkts_bytes;
+static void
+sfc_sw_stat_get_tx_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_txq_info *txq_info;
+	union sfc_pkts_bytes qstats;
+
+	RTE_SET_USED(values_count);
+	SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX);
+	txq_info = sfc_txq_info_by_ethdev_qid(sas, qid);
+	if (txq_info->state & SFC_TXQ_INITIALIZED) {
+		sfc_pkts_bytes_get(&txq_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,
@@ -110,6 +133,19 @@ const struct sfc_sw_stat_descr sfc_sw_stats_descr[] = {
 		.get_val  = NULL,
 		.provide_total = false,
 	},
+	/* Group of Tx packets/bytes stats */
+	{
+		.name = SFC_SW_STAT_GOOD_PACKETS,
+		.type = SFC_SW_STATS_TX,
+		.get_val  = sfc_sw_stat_get_tx_good_pkts_bytes,
+		.provide_total = false,
+	},
+	{
+		.name = SFC_SW_STAT_GOOD_BYTES,
+		.type = SFC_SW_STATS_TX,
+		.get_val  = NULL,
+		.provide_total = false,
+	},
 	/* End of basic stats */
 	{
 		.name = "dbells",
@@ -641,6 +677,7 @@ 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;
+	bool have_dp_tx_stats = sap->dp_tx->features & SFC_DP_TX_FEAT_STATS;
 	struct sfc_sw_stats *sw_stats = &sa->sw_stats;
 	const struct sfc_sw_stat_descr *sw_stat_descr;
 	unsigned int i;
@@ -652,6 +689,10 @@ sfc_sw_stats_fill_available_descr(struct sfc_adapter *sa)
 		    sw_stat_descr->type == SFC_SW_STATS_RX &&
 		    sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name))
 			continue;
+		if (!have_dp_tx_stats &&
+		    sw_stat_descr->type == SFC_SW_STATS_TX &&
+		    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++;
 	}
@@ -678,6 +719,13 @@ sfc_sw_stats_set_reset_basic_stats(struct sfc_adapter *sa)
 				sa->sw_stats.reset_rx_bytes = reset_vals;
 			break;
 		case SFC_SW_STATS_TX:
+			if (strcmp(sw_stat->name,
+				   SFC_SW_STAT_GOOD_PACKETS) == 0)
+				sa->sw_stats.reset_tx_pkts = reset_vals;
+			else if (strcmp(sw_stat->name,
+					SFC_SW_STAT_GOOD_BYTES) == 0)
+				sa->sw_stats.reset_tx_bytes = reset_vals;
+			break;
 		default:
 			SFC_GENERIC_LOG(ERR, "Unknown SW stat type");
 			return -EINVAL;
