diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h
index fac2815f25..d7e11c6323 100644
--- a/drivers/common/sfc_efx/base/efx_impl.h
+++ b/drivers/common/sfc_efx/base/efx_impl.h
@@ -1452,10 +1452,6 @@ efx_mcdi_fini_rxq(
 	__in		efx_nic_t *enp,
 	__in		uint32_t instance);
 
-#endif	/* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
-
-#if EFX_OPTS_EF10()
-
 LIBEFX_INTERNAL
 extern	__checkReturn	efx_rc_t
 efx_mcdi_init_txq(
@@ -1473,7 +1469,7 @@ efx_mcdi_fini_txq(
 	__in		efx_nic_t *enp,
 	__in		uint32_t instance);
 
-#endif	/* EFX_OPTS_EF10() */
+#endif	/* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
 
 #endif /* EFSYS_OPT_MCDI */
 
diff --git a/drivers/common/sfc_efx/base/efx_mcdi.c b/drivers/common/sfc_efx/base/efx_mcdi.c
index 6a227858e6..278c5e2a64 100644
--- a/drivers/common/sfc_efx/base/efx_mcdi.c
+++ b/drivers/common/sfc_efx/base/efx_mcdi.c
@@ -2863,10 +2863,6 @@ efx_mcdi_fini_rxq(
 	return (rc);
 }
 
-#endif	/* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
-
-#if EFX_OPTS_EF10()
-
 	__checkReturn	efx_rc_t
 efx_mcdi_init_txq(
 	__in		efx_nic_t *enp,
@@ -2999,6 +2995,6 @@ efx_mcdi_fini_txq(
 	return (rc);
 }
 
-#endif	/* EFX_OPTS_EF10() */
+#endif	/* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
 
 #endif	/* EFSYS_OPT_MCDI */
diff --git a/drivers/common/sfc_efx/base/efx_tx.c b/drivers/common/sfc_efx/base/efx_tx.c
index 38c64e028b..d7f31fd46d 100644
--- a/drivers/common/sfc_efx/base/efx_tx.c
+++ b/drivers/common/sfc_efx/base/efx_tx.c
@@ -205,6 +205,33 @@ static const efx_tx_ops_t	__efx_tx_medford2_ops = {
 };
 #endif /* EFSYS_OPT_MEDFORD2 */
 
+#if EFSYS_OPT_RIVERHEAD
+static const efx_tx_ops_t	__efx_tx_rhead_ops = {
+	rhead_tx_init,				/* etxo_init */
+	rhead_tx_fini,				/* etxo_fini */
+	rhead_tx_qcreate,			/* etxo_qcreate */
+	rhead_tx_qdestroy,			/* etxo_qdestroy */
+	rhead_tx_qpost,				/* etxo_qpost */
+	rhead_tx_qpush,				/* etxo_qpush */
+	rhead_tx_qpace,				/* etxo_qpace */
+	rhead_tx_qflush,			/* etxo_qflush */
+	rhead_tx_qenable,			/* etxo_qenable */
+	NULL,					/* etxo_qpio_enable */
+	NULL,					/* etxo_qpio_disable */
+	NULL,					/* etxo_qpio_write */
+	NULL,					/* etxo_qpio_post */
+	rhead_tx_qdesc_post,			/* etxo_qdesc_post */
+	NULL,					/* etxo_qdesc_dma_create */
+	NULL,					/* etxo_qdesc_tso_create */
+	NULL,					/* etxo_qdesc_tso2_create */
+	NULL,					/* etxo_qdesc_vlantci_create */
+	NULL,					/* etxo_qdesc_checksum_create */
+#if EFSYS_OPT_QSTATS
+	rhead_tx_qstats_update,			/* etxo_qstats_update */
+#endif
+};
+#endif /* EFSYS_OPT_RIVERHEAD */
+
 
 	__checkReturn	efx_rc_t
 efx_tx_init(
@@ -251,6 +278,12 @@ efx_tx_init(
 		break;
 #endif /* EFSYS_OPT_MEDFORD2 */
 
+#if EFSYS_OPT_RIVERHEAD
+	case EFX_FAMILY_RIVERHEAD:
+		etxop = &__efx_tx_rhead_ops;
+		break;
+#endif /* EFSYS_OPT_RIVERHEAD */
+
 	default:
 		EFSYS_ASSERT(0);
 		rc = ENOTSUP;
diff --git a/drivers/common/sfc_efx/base/meson.build b/drivers/common/sfc_efx/base/meson.build
index aff5017cff..8f944bb45b 100644
--- a/drivers/common/sfc_efx/base/meson.build
+++ b/drivers/common/sfc_efx/base/meson.build
@@ -56,6 +56,7 @@ sources = [
 	'rhead_intr.c',
 	'rhead_nic.c',
 	'rhead_rx.c',
+	'rhead_tx.c',
 ]
 
 extra_flags = [
diff --git a/drivers/common/sfc_efx/base/rhead_impl.h b/drivers/common/sfc_efx/base/rhead_impl.h
index 0ba663653b..c3ffad7208 100644
--- a/drivers/common/sfc_efx/base/rhead_impl.h
+++ b/drivers/common/sfc_efx/base/rhead_impl.h
@@ -355,6 +355,89 @@ rhead_rx_qdestroy(
 	__in		efx_rxq_t *erp);
 
 
+/* TX */
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+rhead_tx_init(
+	__in		efx_nic_t *enp);
+
+LIBEFX_INTERNAL
+extern			void
+rhead_tx_fini(
+	__in		efx_nic_t *enp);
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+rhead_tx_qcreate(
+	__in		efx_nic_t *enp,
+	__in		unsigned int index,
+	__in		unsigned int label,
+	__in		efsys_mem_t *esmp,
+	__in		size_t ndescs,
+	__in		uint32_t id,
+	__in		uint16_t flags,
+	__in		efx_evq_t *eep,
+	__in		efx_txq_t *etp,
+	__out		unsigned int *addedp);
+
+LIBEFX_INTERNAL
+extern		void
+rhead_tx_qdestroy(
+	__in		efx_txq_t *etp);
+
+LIBEFX_INTERNAL
+extern	__checkReturn		efx_rc_t
+rhead_tx_qpost(
+	__in			efx_txq_t *etp,
+	__in_ecount(ndescs)	efx_buffer_t *ebp,
+	__in			unsigned int ndescs,
+	__in			unsigned int completed,
+	__inout			unsigned int *addedp);
+
+LIBEFX_INTERNAL
+extern			void
+rhead_tx_qpush(
+	__in		efx_txq_t *etp,
+	__in		unsigned int added,
+	__in		unsigned int pushed);
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+rhead_tx_qpace(
+	__in		efx_txq_t *etp,
+	__in		unsigned int ns);
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+rhead_tx_qflush(
+	__in		efx_txq_t *etp);
+
+LIBEFX_INTERNAL
+extern			void
+rhead_tx_qenable(
+	__in		efx_txq_t *etp);
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+rhead_tx_qdesc_post(
+	__in		efx_txq_t *etp,
+	__in_ecount(n)	efx_desc_t *ed,
+	__in		unsigned int n,
+	__in		unsigned int completed,
+	__inout		unsigned int *addedp);
+
+#if EFSYS_OPT_QSTATS
+
+LIBEFX_INTERNAL
+extern			void
+rhead_tx_qstats_update(
+	__in				efx_txq_t *etp,
+	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat);
+
+#endif /* EFSYS_OPT_QSTATS */
+
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/drivers/common/sfc_efx/base/rhead_tx.c b/drivers/common/sfc_efx/base/rhead_tx.c
new file mode 100644
index 0000000000..4c60f329d1
--- /dev/null
+++ b/drivers/common/sfc_efx/base/rhead_tx.c
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright(c) 2019-2020 Xilinx, Inc.
+ * Copyright(c) 2018-2019 Solarflare Communications Inc.
+ */
+
+#include "efx.h"
+#include "efx_impl.h"
+
+
+#if EFSYS_OPT_RIVERHEAD
+
+	__checkReturn	efx_rc_t
+rhead_tx_init(
+	__in		efx_nic_t *enp)
+{
+	_NOTE(ARGUNUSED(enp))
+	/* Nothing to do here */
+	return (0);
+}
+
+			void
+rhead_tx_fini(
+	__in		efx_nic_t *enp)
+{
+	_NOTE(ARGUNUSED(enp))
+	/* Nothing to do here */
+}
+
+	__checkReturn	efx_rc_t
+rhead_tx_qcreate(
+	__in		efx_nic_t *enp,
+	__in		unsigned int index,
+	__in		unsigned int label,
+	__in		efsys_mem_t *esmp,
+	__in		size_t ndescs,
+	__in		uint32_t id,
+	__in		uint16_t flags,
+	__in		efx_evq_t *eep,
+	__in		efx_txq_t *etp,
+	__out		unsigned int *addedp)
+{
+	efx_rc_t rc;
+
+	/*
+	 * NMC manages the NMMU entries, and so buffer table IDs are
+	 * ignored here
+	 */
+	_NOTE(ARGUNUSED(id))
+
+	if ((rc = efx_mcdi_init_txq(enp, ndescs, eep->ee_index, label, index,
+	    flags, esmp)) != 0)
+		goto fail1;
+
+	/*
+	 * Return the initial queue index which is zero since no option
+	 * descriptors are sent at start of day.
+	 */
+	*addedp = 0;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+		void
+rhead_tx_qdestroy(
+	__in	efx_txq_t *etp)
+{
+	_NOTE(ARGUNUSED(etp))
+	/* Nothing to do here */
+}
+
+	__checkReturn		efx_rc_t
+rhead_tx_qpost(
+	__in			efx_txq_t *etp,
+	__in_ecount(ndescs)	efx_buffer_t *eb,
+	__in			unsigned int ndescs,
+	__in			unsigned int completed,
+	__inout			unsigned int *addedp)
+{
+	_NOTE(ARGUNUSED(etp))
+	_NOTE(ARGUNUSED(eb))
+	_NOTE(ARGUNUSED(ndescs))
+	_NOTE(ARGUNUSED(completed))
+	_NOTE(ARGUNUSED(addedp))
+
+	/* FIXME Implement the method for Riverhead */
+
+	return (ENOTSUP);
+}
+
+			void
+rhead_tx_qpush(
+	__in		efx_txq_t *etp,
+	__in		unsigned int added,
+	__in		unsigned int pushed)
+{
+	_NOTE(ARGUNUSED(etp, added, pushed))
+
+	/* FIXME Implement the method for Riverhead */
+	EFSYS_ASSERT(B_FALSE);
+}
+
+	__checkReturn	efx_rc_t
+rhead_tx_qpace(
+	__in		efx_txq_t *etp,
+	__in		unsigned int ns)
+{
+	_NOTE(ARGUNUSED(etp))
+	_NOTE(ARGUNUSED(ns))
+
+	/* FIXME Implement the method for Riverhead */
+
+	return (ENOTSUP);
+}
+
+	__checkReturn	efx_rc_t
+rhead_tx_qflush(
+	__in		efx_txq_t *etp)
+{
+	efx_nic_t *enp = etp->et_enp;
+	efx_rc_t rc;
+
+	if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0)
+		goto fail1;
+
+	return (0);
+
+fail1:
+	/*
+	 * EALREADY is not an error, but indicates that the MC has rebooted and
+	 * that the TXQ has already been destroyed. Callers need to know that
+	 * the TXQ flush has completed to avoid waiting until timeout for a
+	 * flush done event that will not be delivered.
+	 */
+	if (rc != EALREADY)
+		EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+			void
+rhead_tx_qenable(
+	__in		efx_txq_t *etp)
+{
+	_NOTE(ARGUNUSED(etp))
+	/* Nothing to do here */
+}
+
+	__checkReturn		efx_rc_t
+rhead_tx_qdesc_post(
+	__in			efx_txq_t *etp,
+	__in_ecount(ndescs)	efx_desc_t *ed,
+	__in			unsigned int ndescs,
+	__in			unsigned int completed,
+	__inout			unsigned int *addedp)
+{
+	_NOTE(ARGUNUSED(etp))
+	_NOTE(ARGUNUSED(ed))
+	_NOTE(ARGUNUSED(ndescs))
+	_NOTE(ARGUNUSED(completed))
+	_NOTE(ARGUNUSED(addedp))
+
+	/* FIXME Implement the method for Riverhead */
+
+	return (ENOTSUP);
+}
+
+#if EFSYS_OPT_QSTATS
+
+			void
+rhead_tx_qstats_update(
+	__in				efx_txq_t *etp,
+	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
+{
+	unsigned int id;
+
+	for (id = 0; id < TX_NQSTATS; id++) {
+		efsys_stat_t *essp = &stat[id];
+
+		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
+		etp->et_stat[id] = 0;
+	}
+}
+
+#endif /* EFSYS_OPT_QSTATS */
+
+#endif /* EFSYS_OPT_RIVERHEAD */
