diff --git a/drivers/common/sfc_efx/base/ef10_impl.h b/drivers/common/sfc_efx/base/ef10_impl.h
index 597dd24909..342a9a2006 100644
--- a/drivers/common/sfc_efx/base/ef10_impl.h
+++ b/drivers/common/sfc_efx/base/ef10_impl.h
@@ -1137,6 +1137,7 @@ ef10_rx_scale_context_alloc(
 	__in		efx_nic_t *enp,
 	__in		efx_rx_scale_context_type_t type,
 	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
 	__out		uint32_t *rss_contextp);
 
 LIBEFX_INTERNAL
diff --git a/drivers/common/sfc_efx/base/ef10_nic.c b/drivers/common/sfc_efx/base/ef10_nic.c
index d9f7c0f362..cca31bc725 100644
--- a/drivers/common/sfc_efx/base/ef10_nic.c
+++ b/drivers/common/sfc_efx/base/ef10_nic.c
@@ -1409,6 +1409,11 @@ ef10_get_datapath_caps(
 		 */
 		encp->enc_rx_scale_l4_hash_supported = B_TRUE;
 	}
+
+	if (CAP_FLAGS3(req, RSS_SELECTABLE_TABLE_SIZE))
+		encp->enc_rx_scale_tbl_entry_count_is_selectable = B_TRUE;
+	else
+		encp->enc_rx_scale_tbl_entry_count_is_selectable = B_FALSE;
 #endif /* EFSYS_OPT_RX_SCALE */
 
 	/* Check if the firmware supports "FLAG" and "MARK" filter actions */
@@ -1471,8 +1476,16 @@ ef10_get_datapath_caps(
 		encp->enc_rx_scale_indirection_max_nqueues =
 		    MCDI_OUT_DWORD(req,
 			GET_CAPABILITIES_V9_OUT_RSS_MAX_INDIRECTION_QUEUES);
+		encp->enc_rx_scale_tbl_min_nentries =
+		    MCDI_OUT_DWORD(req,
+			GET_CAPABILITIES_V9_OUT_RSS_MIN_INDIRECTION_TABLE_SIZE);
+		encp->enc_rx_scale_tbl_max_nentries =
+		    MCDI_OUT_DWORD(req,
+			GET_CAPABILITIES_V9_OUT_RSS_MAX_INDIRECTION_TABLE_SIZE);
 	} else {
 		encp->enc_rx_scale_indirection_max_nqueues = EFX_MAXRSS;
+		encp->enc_rx_scale_tbl_min_nentries = EFX_RSS_TBL_SIZE;
+		encp->enc_rx_scale_tbl_max_nentries = EFX_RSS_TBL_SIZE;
 	}
 #endif /* EFSYS_OPT_RX_SCALE */
 
diff --git a/drivers/common/sfc_efx/base/ef10_rx.c b/drivers/common/sfc_efx/base/ef10_rx.c
index 5008139a3f..78af7300a0 100644
--- a/drivers/common/sfc_efx/base/ef10_rx.c
+++ b/drivers/common/sfc_efx/base/ef10_rx.c
@@ -16,11 +16,12 @@ efx_mcdi_rss_context_alloc(
 	__in		efx_nic_t *enp,
 	__in		efx_rx_scale_context_type_t type,
 	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
 	__out		uint32_t *rss_contextp)
 {
 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 	efx_mcdi_req_t req;
-	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_RSS_CONTEXT_ALLOC_V2_IN_LEN,
 		MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN);
 	uint32_t rss_context;
 	uint32_t context_type;
@@ -31,6 +32,13 @@ efx_mcdi_rss_context_alloc(
 		goto fail1;
 	}
 
+	if (table_nentries < encp->enc_rx_scale_tbl_min_nentries ||
+	    table_nentries > encp->enc_rx_scale_tbl_max_nentries ||
+	    !ISP2(table_nentries)) {
+		rc = EINVAL;
+		goto fail2;
+	}
+
 	switch (type) {
 	case EFX_RX_SCALE_EXCLUSIVE:
 		context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
@@ -40,12 +48,15 @@ efx_mcdi_rss_context_alloc(
 		break;
 	default:
 		rc = EINVAL;
-		goto fail2;
+		goto fail3;
 	}
 
 	req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
 	req.emr_in_buf = payload;
-	req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
+	req.emr_in_length =
+	    (encp->enc_rx_scale_tbl_entry_count_is_selectable != B_FALSE) ?
+	    MC_CMD_RSS_CONTEXT_ALLOC_V2_IN_LEN :
+	    MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
 	req.emr_out_buf = payload;
 	req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
 
@@ -61,28 +72,36 @@ efx_mcdi_rss_context_alloc(
 	 */
 	MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);
 
+	if (encp->enc_rx_scale_tbl_entry_count_is_selectable != B_FALSE) {
+		MCDI_IN_SET_DWORD(req,
+		    RSS_CONTEXT_ALLOC_V2_IN_INDIRECTION_TABLE_SIZE,
+		    table_nentries);
+	}
+
 	efx_mcdi_execute(enp, &req);
 
 	if (req.emr_rc != 0) {
 		rc = req.emr_rc;
-		goto fail3;
+		goto fail4;
 	}
 
 	if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
 		rc = EMSGSIZE;
-		goto fail4;
+		goto fail5;
 	}
 
 	rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
 	if (rss_context == EF10_RSS_CONTEXT_INVALID) {
 		rc = ENOENT;
-		goto fail5;
+		goto fail6;
 	}
 
 	*rss_contextp = rss_context;
 
 	return (0);
 
+fail6:
+	EFSYS_PROBE(fail6);
 fail5:
 	EFSYS_PROBE(fail5);
 fail4:
@@ -347,6 +366,76 @@ efx_mcdi_rss_context_set_table(
 }
 #endif /* EFSYS_OPT_RX_SCALE */
 
+#if EFSYS_OPT_RX_SCALE
+static	__checkReturn		efx_rc_t
+efx_mcdi_rss_context_write_table(
+	__in			efx_nic_t *enp,
+	__in			uint32_t context,
+	__in			unsigned int start_idx,
+	__in_ecount(nentries)	unsigned int *table,
+	__in			unsigned int nentries)
+{
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+	efx_mcdi_req_t req;
+	EFX_MCDI_DECLARE_BUF(payload,
+	     MC_CMD_RSS_CONTEXT_WRITE_TABLE_IN_LENMAX_MCDI2,
+	     MC_CMD_RSS_CONTEXT_WRITE_TABLE_OUT_LEN);
+	unsigned int i;
+	int rc;
+
+	if (nentries >
+	    MC_CMD_RSS_CONTEXT_WRITE_TABLE_IN_ENTRIES_MAXNUM_MCDI2) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	if (start_idx + nentries >
+	    encp->enc_rx_scale_tbl_max_nentries) {
+		rc = EINVAL;
+		goto fail2;
+	}
+
+	req.emr_cmd = MC_CMD_RSS_CONTEXT_WRITE_TABLE;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_RSS_CONTEXT_WRITE_TABLE_IN_LEN(nentries);
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_RSS_CONTEXT_WRITE_TABLE_OUT_LEN;
+
+	MCDI_IN_SET_DWORD(req,
+	    RSS_CONTEXT_WRITE_TABLE_IN_RSS_CONTEXT_ID, context);
+
+	for (i = 0; i < nentries; ++i) {
+		if (table[i] >= encp->enc_rx_scale_indirection_max_nqueues) {
+			rc = EINVAL;
+			goto fail3;
+		}
+
+		MCDI_IN_POPULATE_INDEXED_DWORD_2(req,
+		    RSS_CONTEXT_WRITE_TABLE_IN_ENTRIES, i,
+		    RSS_CONTEXT_WRITE_TABLE_ENTRY_INDEX, start_idx + i,
+		    RSS_CONTEXT_WRITE_TABLE_ENTRY_VALUE, table[i]);
+	}
+
+	efx_mcdi_execute(enp, &req);
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail4;
+	}
+
+	return (0);
+
+fail4:
+	EFSYS_PROBE(fail4);
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+	return (rc);
+}
+#endif /* EFSYS_OPT_RX_SCALE */
+
 
 	__checkReturn	efx_rc_t
 ef10_rx_init(
@@ -355,7 +444,7 @@ ef10_rx_init(
 #if EFSYS_OPT_RX_SCALE
 
 	if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS,
-		&enp->en_rss_context) == 0) {
+		EFX_RSS_TBL_SIZE, &enp->en_rss_context) == 0) {
 		/*
 		 * Allocated an exclusive RSS context, which allows both the
 		 * indirection table and key to be modified.
@@ -398,11 +487,13 @@ ef10_rx_scale_context_alloc(
 	__in		efx_nic_t *enp,
 	__in		efx_rx_scale_context_type_t type,
 	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
 	__out		uint32_t *rss_contextp)
 {
 	efx_rc_t rc;
 
-	rc = efx_mcdi_rss_context_alloc(enp, type, num_queues, rss_contextp);
+	rc = efx_mcdi_rss_context_alloc(enp, type, num_queues, table_nentries,
+					rss_contextp);
 	if (rc != 0)
 		goto fail1;
 
@@ -522,6 +613,7 @@ ef10_rx_scale_tbl_set(
 	__in_ecount(nentries)	unsigned int *table,
 	__in			size_t nentries)
 {
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 	efx_rc_t rc;
 
 
@@ -533,12 +625,34 @@ ef10_rx_scale_tbl_set(
 		rss_context = enp->en_rss_context;
 	}
 
-	if ((rc = efx_mcdi_rss_context_set_table(enp,
-		    rss_context, table, nentries)) != 0)
-		goto fail2;
+	if (encp->enc_rx_scale_tbl_entry_count_is_selectable != B_FALSE) {
+		uint32_t index, remain, batch;
+
+		batch = MC_CMD_RSS_CONTEXT_WRITE_TABLE_IN_ENTRIES_MAXNUM_MCDI2;
+		index = 0;
+
+		for (remain = nentries; remain > 0; remain -= batch) {
+			if (batch > remain)
+				batch = remain;
+
+			rc = efx_mcdi_rss_context_write_table(enp, rss_context,
+				    index, &table[index], batch);
+			if (rc != 0)
+				goto fail2;
+
+			index += batch;
+		}
+	} else {
+		rc = efx_mcdi_rss_context_set_table(enp, rss_context, table,
+			    nentries);
+		if (rc != 0)
+			goto fail3;
+	}
 
 	return (0);
 
+fail3:
+	EFSYS_PROBE(fail3);
 fail2:
 	EFSYS_PROBE(fail2);
 fail1:
diff --git a/drivers/common/sfc_efx/base/efx.h b/drivers/common/sfc_efx/base/efx.h
index a35e29ebcf..4523829eb2 100644
--- a/drivers/common/sfc_efx/base/efx.h
+++ b/drivers/common/sfc_efx/base/efx.h
@@ -1502,6 +1502,10 @@ typedef struct efx_nic_cfg_s {
 	 * This means that the maximum offset has to be less than this value.
 	 */
 	uint32_t		enc_rx_scale_indirection_max_nqueues;
+	/* Minimum number of entries an RSS indirection table can contain. */
+	uint32_t		enc_rx_scale_tbl_min_nentries;
+	/* Maximum number of entries an RSS indirection table can contain. */
+	uint32_t		enc_rx_scale_tbl_max_nentries;
 	uint32_t		enc_rx_scale_max_exclusive_contexts;
 	/*
 	 * Mask of supported hash algorithms.
@@ -1514,6 +1518,11 @@ typedef struct efx_nic_cfg_s {
 	 */
 	boolean_t		enc_rx_scale_l4_hash_supported;
 	boolean_t		enc_rx_scale_additional_modes_supported;
+	/*
+	 * Indicates whether the user can decide how many entries to
+	 * have in the indirection table of an exclusive RSS context.
+	 */
+	boolean_t		enc_rx_scale_tbl_entry_count_is_selectable;
 #endif /* EFSYS_OPT_RX_SCALE */
 #if EFSYS_OPT_LOOPBACK
 	efx_qword_t		enc_loopback_types[EFX_LINK_NMODES];
@@ -2887,6 +2896,15 @@ efx_rx_scale_context_alloc(
 	__in		uint32_t num_queues,
 	__out		uint32_t *rss_contextp);
 
+LIBEFX_API
+extern	__checkReturn	efx_rc_t
+efx_rx_scale_context_alloc_v2(
+	__in		efx_nic_t *enp,
+	__in		efx_rx_scale_context_type_t type,
+	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
+	__out		uint32_t *rss_contextp);
+
 LIBEFX_API
 extern	__checkReturn	efx_rc_t
 efx_rx_scale_context_free(
diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h
index e2802e6672..7dfe30b695 100644
--- a/drivers/common/sfc_efx/base/efx_impl.h
+++ b/drivers/common/sfc_efx/base/efx_impl.h
@@ -173,7 +173,8 @@ typedef struct efx_rx_ops_s {
 #if EFSYS_OPT_RX_SCALE
 	efx_rc_t	(*erxo_scale_context_alloc)(efx_nic_t *,
 						    efx_rx_scale_context_type_t,
-						    uint32_t, uint32_t *);
+						    uint32_t, uint32_t,
+						    uint32_t *);
 	efx_rc_t	(*erxo_scale_context_free)(efx_nic_t *, uint32_t);
 	efx_rc_t	(*erxo_scale_mode_set)(efx_nic_t *, uint32_t,
 					       efx_rx_hash_alg_t,
diff --git a/drivers/common/sfc_efx/base/efx_mcdi.h b/drivers/common/sfc_efx/base/efx_mcdi.h
index c91ea41911..14a3833567 100644
--- a/drivers/common/sfc_efx/base/efx_mcdi.h
+++ b/drivers/common/sfc_efx/base/efx_mcdi.h
@@ -315,6 +315,10 @@ efx_mcdi_set_nic_addr_regions(
 #define	MCDI_IN2(_emr, _type, _ofst)					\
 	MCDI_IN(_emr, _type, MC_CMD_ ## _ofst ## _OFST)
 
+#define	MCDI_INDEXED_IN2(_emr, _type, _ofst, _idx)			\
+	MCDI_IN(_emr, _type, MC_CMD_ ## _ofst ## _OFST +		\
+		_idx * MC_CMD_ ## _ofst ## _LEN)
+
 #define	MCDI_IN_SET_BYTE(_emr, _ofst, _value)				\
 	EFX_POPULATE_BYTE_1(*MCDI_IN2(_emr, efx_byte_t, _ofst),		\
 		EFX_BYTE_0, _value)
@@ -356,6 +360,13 @@ efx_mcdi_set_nic_addr_regions(
 		MC_CMD_ ## _field1, _value1,				\
 		MC_CMD_ ## _field2, _value2)
 
+#define	MCDI_IN_POPULATE_INDEXED_DWORD_2(_emr, _ofst, _idx,		\
+		_field1, _value1, _field2, _value2)			\
+	EFX_POPULATE_DWORD_2(						\
+		*MCDI_INDEXED_IN2(_emr, efx_dword_t, _ofst, _idx),	\
+		MC_CMD_ ## _field1, _value1,				\
+		MC_CMD_ ## _field2, _value2)
+
 #define	MCDI_IN_POPULATE_DWORD_3(_emr, _ofst, _field1, _value1,		\
 		_field2, _value2, _field3, _value3)			\
 	EFX_POPULATE_DWORD_3(*MCDI_IN2(_emr, efx_dword_t, _ofst),	\
diff --git a/drivers/common/sfc_efx/base/efx_rx.c b/drivers/common/sfc_efx/base/efx_rx.c
index eb3f736f63..d10b990259 100644
--- a/drivers/common/sfc_efx/base/efx_rx.c
+++ b/drivers/common/sfc_efx/base/efx_rx.c
@@ -514,8 +514,44 @@ efx_rx_scale_context_alloc(
 		rc = ENOTSUP;
 		goto fail1;
 	}
+
+	if ((rc = erxop->erxo_scale_context_alloc(enp, type, num_queues,
+			    EFX_RSS_TBL_SIZE, rss_contextp)) != 0) {
+		goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+	return (rc);
+}
+#endif	/* EFSYS_OPT_RX_SCALE */
+
+#if EFSYS_OPT_RX_SCALE
+	__checkReturn	efx_rc_t
+efx_rx_scale_context_alloc_v2(
+	__in		efx_nic_t *enp,
+	__in		efx_rx_scale_context_type_t type,
+	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
+	__out		uint32_t *rss_contextp)
+{
+	const efx_rx_ops_t *erxop = enp->en_erxop;
+	efx_rc_t rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
+
+	if (erxop->erxo_scale_context_alloc == NULL) {
+		rc = ENOTSUP;
+		goto fail1;
+	}
+
 	if ((rc = erxop->erxo_scale_context_alloc(enp, type,
-			    num_queues, rss_contextp)) != 0) {
+			    num_queues, table_nentries, rss_contextp)) != 0) {
 		goto fail2;
 	}
 
diff --git a/drivers/common/sfc_efx/base/rhead_impl.h b/drivers/common/sfc_efx/base/rhead_impl.h
index e0d95ba2aa..fb0ecca79d 100644
--- a/drivers/common/sfc_efx/base/rhead_impl.h
+++ b/drivers/common/sfc_efx/base/rhead_impl.h
@@ -261,6 +261,7 @@ rhead_rx_scale_context_alloc(
 	__in		efx_nic_t *enp,
 	__in		efx_rx_scale_context_type_t type,
 	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
 	__out		uint32_t *rss_contextp);
 
 LIBEFX_INTERNAL
diff --git a/drivers/common/sfc_efx/base/rhead_rx.c b/drivers/common/sfc_efx/base/rhead_rx.c
index d28f936ab7..d0ac5c02f8 100644
--- a/drivers/common/sfc_efx/base/rhead_rx.c
+++ b/drivers/common/sfc_efx/base/rhead_rx.c
@@ -88,11 +88,13 @@ rhead_rx_scale_context_alloc(
 	__in		efx_nic_t *enp,
 	__in		efx_rx_scale_context_type_t type,
 	__in		uint32_t num_queues,
+	__in		uint32_t table_nentries,
 	__out		uint32_t *rss_contextp)
 {
 	efx_rc_t rc;
 
-	rc = ef10_rx_scale_context_alloc(enp, type, num_queues, rss_contextp);
+	rc = ef10_rx_scale_context_alloc(enp, type, num_queues, table_nentries,
+		    rss_contextp);
 	if (rc != 0)
 		goto fail1;
 
diff --git a/drivers/common/sfc_efx/version.map b/drivers/common/sfc_efx/version.map
index 97dd943ec4..9510897b83 100644
--- a/drivers/common/sfc_efx/version.map
+++ b/drivers/common/sfc_efx/version.map
@@ -216,6 +216,7 @@ INTERNAL {
 	efx_rx_qpost;
 	efx_rx_qpush;
 	efx_rx_scale_context_alloc;
+	efx_rx_scale_context_alloc_v2;
 	efx_rx_scale_context_free;
 	efx_rx_scale_default_support_get;
 	efx_rx_scale_hash_flags_get;
