diff --git a/drivers/common/sfc_efx/base/ef10_nic.c b/drivers/common/sfc_efx/base/ef10_nic.c
index 72d2caadb8..355d274470 100644
--- a/drivers/common/sfc_efx/base/ef10_nic.c
+++ b/drivers/common/sfc_efx/base/ef10_nic.c
@@ -1854,6 +1854,51 @@ ef10_external_port_mapping(
 	return (rc);
 }
 
+static __checkReturn	efx_rc_t
+efx_mcdi_get_nic_addr_caps(
+	__in		efx_nic_t *enp)
+{
+	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
+	uint32_t mapping_type;
+	efx_rc_t rc;
+
+	rc = efx_mcdi_get_nic_addr_info(enp, &mapping_type);
+	if (rc != 0) {
+		if (rc == ENOTSUP) {
+			encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+			goto out;
+		}
+		goto fail1;
+	}
+
+	switch (mapping_type) {
+	case MC_CMD_GET_DESC_ADDR_INFO_OUT_MAPPING_FLAT:
+		encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+		break;
+	case MC_CMD_GET_DESC_ADDR_INFO_OUT_MAPPING_REGIONED:
+		encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_REGIONED;
+		rc = efx_mcdi_get_nic_addr_regions(enp,
+		    &enp->en_dma.end_u.endu_region_info);
+		if (rc != 0)
+			goto fail2;
+		break;
+	default:
+		goto fail3;
+	}
+
+out:
+	return (0);
+
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
 	__checkReturn	efx_rc_t
 efx_mcdi_nic_board_cfg(
 	__in		efx_nic_t *enp)
@@ -1994,8 +2039,14 @@ efx_mcdi_nic_board_cfg(
 	encp->enc_intr_vec_base = base;
 	encp->enc_intr_limit = nvec;
 
+	rc = efx_mcdi_get_nic_addr_caps(enp);
+	if (rc != 0)
+		goto fail12;
+
 	return (0);
 
+fail12:
+	EFSYS_PROBE(fail12);
 fail11:
 	EFSYS_PROBE(fail11);
 fail10:
diff --git a/drivers/common/sfc_efx/base/efx.h b/drivers/common/sfc_efx/base/efx.h
index f08a004536..4d3210f6b6 100644
--- a/drivers/common/sfc_efx/base/efx.h
+++ b/drivers/common/sfc_efx/base/efx.h
@@ -1444,6 +1444,14 @@ typedef enum efx_vi_window_shift_e {
 	EFX_VI_WINDOW_SHIFT_64K = 16,
 } efx_vi_window_shift_t;
 
+typedef enum efx_nic_dma_mapping_e {
+	EFX_NIC_DMA_MAPPING_UNKNOWN = 0,
+	EFX_NIC_DMA_MAPPING_FLAT,
+	EFX_NIC_DMA_MAPPING_REGIONED,
+
+	EFX_NIC_DMA_MAPPING_NTYPES
+} efx_nic_dma_mapping_t;
+
 typedef struct efx_nic_cfg_s {
 	uint32_t		enc_board_type;
 	uint32_t		enc_phy_type;
@@ -1633,6 +1641,8 @@ typedef struct efx_nic_cfg_s {
 	uint32_t		enc_filter_action_mark_max;
 	/* Port assigned to this PCI function */
 	uint32_t		enc_assigned_port;
+	/* NIC DMA mapping type */
+	efx_nic_dma_mapping_t	enc_dma_mapping;
 } efx_nic_cfg_t;
 
 #define	EFX_PCI_VF_INVALID 0xffff
@@ -4897,6 +4907,42 @@ efx_virtio_verify_features(
 
 #endif /* EFSYS_OPT_VIRTIO */
 
+LIBEFX_API
+extern	 __checkReturn	efx_rc_t
+efx_nic_dma_config_add(
+	__in		efx_nic_t *enp,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out_opt	efsys_dma_addr_t *nic_basep,
+	__out_opt	efsys_dma_addr_t *trgt_basep,
+	__out_opt	size_t *map_lenp);
+
+LIBEFX_API
+extern	 __checkReturn	efx_rc_t
+efx_nic_dma_reconfigure(
+	__in		efx_nic_t *enp);
+
+typedef enum efx_nic_dma_addr_type_e {
+	EFX_NIC_DMA_ADDR_MCDI_BUF,
+	EFX_NIC_DMA_ADDR_MAC_STATS_BUF,
+	EFX_NIC_DMA_ADDR_EVENT_RING,
+	EFX_NIC_DMA_ADDR_RX_RING,
+	EFX_NIC_DMA_ADDR_TX_RING,
+	EFX_NIC_DMA_ADDR_RX_BUF,
+	EFX_NIC_DMA_ADDR_TX_BUF,
+
+	EFX_NIC_DMA_ADDR_NTYPES
+} efx_nic_dma_addr_type_t;
+
+LIBEFX_API
+extern	__checkReturn	efx_rc_t
+efx_nic_dma_map(
+	__in		efx_nic_t *enp,
+	__in		efx_nic_dma_addr_type_t addr_type,
+	__in		efsys_dma_addr_t tgt_addr,
+	__in		size_t len,
+	__out		efsys_dma_addr_t *nic_addrp);
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h
index eda41b4be0..71c83515f7 100644
--- a/drivers/common/sfc_efx/base/efx_impl.h
+++ b/drivers/common/sfc_efx/base/efx_impl.h
@@ -428,6 +428,25 @@ typedef struct efx_nic_ops_s {
 #define	EFX_RXQ_LIMIT_TARGET 512
 #endif
 
+typedef struct efx_nic_dma_region_s {
+	efsys_dma_addr_t	endr_nic_base;
+	efsys_dma_addr_t	endr_trgt_base;
+	unsigned int		endr_window_log2;
+	unsigned int		endr_align_log2;
+	boolean_t		endr_inuse;
+} efx_nic_dma_region_t;
+
+typedef struct efx_nic_dma_region_info_s {
+	unsigned int		endri_count;
+	efx_nic_dma_region_t	*endri_regions;
+} efx_nic_dma_region_info_t;
+
+typedef struct efx_nic_dma_s {
+	union {
+		/* No configuration in the case flat mapping type */
+		efx_nic_dma_region_info_t	endu_region_info;
+	} end_u;
+} efx_nic_dma_t;
 
 #if EFSYS_OPT_FILTER
 
@@ -859,6 +878,7 @@ struct efx_nic_s {
 	const efx_rx_ops_t	*en_erxop;
 	efx_fw_variant_t	efv;
 	char			en_drv_version[EFX_DRV_VER_MAX];
+	efx_nic_dma_t		en_dma;
 #if EFSYS_OPT_FILTER
 	efx_filter_t		en_filter;
 	const efx_filter_ops_t	*en_efop;
diff --git a/drivers/common/sfc_efx/base/efx_mcdi.c b/drivers/common/sfc_efx/base/efx_mcdi.c
index cdf7181e0d..9189a7a8b3 100644
--- a/drivers/common/sfc_efx/base/efx_mcdi.c
+++ b/drivers/common/sfc_efx/base/efx_mcdi.c
@@ -3236,4 +3236,208 @@ efx_mcdi_fini_txq(
 
 #endif	/* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
 
+	__checkReturn	efx_rc_t
+efx_mcdi_get_nic_addr_info(
+	__in		efx_nic_t *enp,
+	__out		uint32_t *mapping_typep)
+{
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_INFO_IN_LEN,
+		MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN);
+	efx_mcdi_req_t req;
+	efx_rc_t rc;
+
+	req.emr_cmd = MC_CMD_GET_DESC_ADDR_INFO;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_GET_DESC_ADDR_INFO_IN_LEN;
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN;
+
+	efx_mcdi_execute_quiet(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail1;
+	}
+
+	if (req.emr_out_length_used < MC_CMD_GET_DESC_ADDR_INFO_OUT_LEN) {
+		rc = EMSGSIZE;
+		goto fail2;
+	}
+
+	*mapping_typep =
+	    MCDI_OUT_DWORD(req, GET_DESC_ADDR_INFO_OUT_MAPPING_TYPE);
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+	__checkReturn	efx_rc_t
+efx_mcdi_get_nic_addr_regions(
+	__in		efx_nic_t *enp,
+	__out		efx_nic_dma_region_info_t *endrip)
+{
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN,
+		MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2);
+	efx_xword_t *regions;
+	efx_mcdi_req_t req;
+	efx_rc_t rc;
+	size_t alloc_size;
+	unsigned int nregions;
+	unsigned int i;
+
+	req.emr_cmd = MC_CMD_GET_DESC_ADDR_REGIONS;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_GET_DESC_ADDR_REGIONS_IN_LEN;
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMAX_MCDI2;
+
+	efx_mcdi_execute_quiet(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail1;
+	}
+
+	if (req.emr_out_length_used <
+	    MC_CMD_GET_DESC_ADDR_REGIONS_OUT_LENMIN) {
+		rc = EMSGSIZE;
+		goto fail2;
+	}
+
+	nregions = MC_CMD_GET_DESC_ADDR_REGIONS_OUT_REGIONS_NUM(
+	    req.emr_out_length_used);
+
+	EFX_STATIC_ASSERT(sizeof (*regions) == DESC_ADDR_REGION_LEN);
+	regions = MCDI_OUT2(req, efx_xword_t,
+	    GET_DESC_ADDR_REGIONS_OUT_REGIONS);
+
+	alloc_size = nregions * sizeof(endrip->endri_regions[0]);
+	if (alloc_size / sizeof (endrip->endri_regions[0]) != nregions) {
+		rc = ENOMEM;
+		goto fail3;
+	}
+
+	EFSYS_KMEM_ALLOC(enp->en_esip,
+	    alloc_size,
+	    endrip->endri_regions);
+	if (endrip->endri_regions == NULL) {
+		rc = ENOMEM;
+		goto fail4;
+	}
+
+	endrip->endri_count = nregions;
+	for (i = 0; i < nregions; ++i) {
+		efx_nic_dma_region_t *region_info;
+
+		region_info = &endrip->endri_regions[i];
+
+		region_info->endr_inuse = B_FALSE;
+
+		region_info->endr_nic_base =
+		    MCDI_OUT_INDEXED_MEMBER_QWORD(req,
+		        GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+		        DESC_ADDR_REGION_DESC_ADDR_BASE);
+
+		region_info->endr_trgt_base =
+		    MCDI_OUT_INDEXED_MEMBER_QWORD(req,
+		        GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+		        DESC_ADDR_REGION_TRGT_ADDR_BASE);
+
+		region_info->endr_window_log2 =
+		    MCDI_OUT_INDEXED_MEMBER_DWORD(req,
+		        GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+		        DESC_ADDR_REGION_WINDOW_SIZE_LOG2);
+
+		region_info->endr_align_log2 =
+		    MCDI_OUT_INDEXED_MEMBER_DWORD(req,
+		        GET_DESC_ADDR_REGIONS_OUT_REGIONS, i,
+		        DESC_ADDR_REGION_TRGT_ADDR_ALIGN_LOG2);
+	}
+
+	return (0);
+
+fail4:
+	EFSYS_PROBE(fail4);
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+	__checkReturn	efx_rc_t
+efx_mcdi_set_nic_addr_regions(
+	__in		efx_nic_t *enp,
+	__in		const efx_nic_dma_region_info_t *endrip)
+{
+	EFX_MCDI_DECLARE_BUF(payload,
+		MC_CMD_SET_DESC_ADDR_REGIONS_IN_LENMAX_MCDI2,
+		MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN);
+	efx_qword_t *trgt_addr_base;
+	efx_mcdi_req_t req;
+	unsigned int i;
+	efx_rc_t rc;
+
+	if (endrip->endri_count >
+	    MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	req.emr_cmd = MC_CMD_SET_DESC_ADDR_REGIONS;
+	req.emr_in_buf = payload;
+	req.emr_in_length =
+	    MC_CMD_SET_DESC_ADDR_REGIONS_IN_LEN(endrip->endri_count);
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_SET_DESC_ADDR_REGIONS_OUT_LEN;
+
+	EFX_STATIC_ASSERT(sizeof (*trgt_addr_base) ==
+	    MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_LEN);
+	trgt_addr_base = MCDI_OUT2(req, efx_qword_t,
+	    SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE);
+
+	for (i = 0; i < endrip->endri_count; ++i) {
+		const efx_nic_dma_region_t *region_info;
+
+		region_info = &endrip->endri_regions[i];
+
+		if (region_info->endr_inuse != B_TRUE)
+			continue;
+
+		EFX_STATIC_ASSERT(sizeof (1U) * 8 >=
+		    MC_CMD_SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE_MAXNUM);
+		MCDI_IN_SET_DWORD(req,
+		    SET_DESC_ADDR_REGIONS_IN_SET_REGION_MASK, 1U << i);
+
+		MCDI_IN_SET_INDEXED_QWORD(req,
+		    SET_DESC_ADDR_REGIONS_IN_TRGT_ADDR_BASE, i,
+		    region_info->endr_trgt_base);
+	}
+
+	efx_mcdi_execute_quiet(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
 #endif	/* EFSYS_OPT_MCDI */
diff --git a/drivers/common/sfc_efx/base/efx_mcdi.h b/drivers/common/sfc_efx/base/efx_mcdi.h
index 96f237b1b0..c91ea41911 100644
--- a/drivers/common/sfc_efx/base/efx_mcdi.h
+++ b/drivers/common/sfc_efx/base/efx_mcdi.h
@@ -289,6 +289,26 @@ efx_mcdi_phy_module_get_info(
 	__in			size_t len,
 	__out_bcount(len)	uint8_t *data);
 
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+efx_mcdi_get_nic_addr_info(
+	__in		efx_nic_t *enp,
+	__out		uint32_t *mapping_typep);
+
+struct efx_nic_dma_region_info_s;
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+efx_mcdi_get_nic_addr_regions(
+	__in		efx_nic_t *enp,
+	__out		struct efx_nic_dma_region_info_s *endrip);
+
+LIBEFX_INTERNAL
+extern	__checkReturn	efx_rc_t
+efx_mcdi_set_nic_addr_regions(
+	__in		efx_nic_t *enp,
+	__in		const struct efx_nic_dma_region_info_s *endrip);
+
 #define	MCDI_IN(_emr, _type, _ofst)					\
 	((_type *)((_emr).emr_in_buf + (_ofst)))
 
@@ -315,6 +335,17 @@ efx_mcdi_phy_module_get_info(
 	EFX_POPULATE_DWORD_1(*(MCDI_IN2(_emr, efx_dword_t, _ofst) +	\
 			     (_idx)), EFX_DWORD_0, _value)		\
 
+#define	MCDI_IN_SET_QWORD(_emr, _ofst, _value)				\
+	EFX_POPULATE_QWORD_2(*MCDI_IN2(_emr, efx_qword_t, _ofst),	\
+		EFX_DWORD_0, ((_value) & 0xffffffff),			\
+		EFX_DWORD_1, ((_value) >> 32))
+
+#define	MCDI_IN_SET_INDEXED_QWORD(_emr, _ofst, _idx, _value)		\
+	EFX_POPULATE_QWORD_2(*(MCDI_IN2(_emr, efx_qword_t, _ofst) +	\
+			(_idx)),					\
+		EFX_DWORD_0, ((_value) & 0xffffffff),	\
+		EFX_DWORD_1, ((_value) >> 32))
+
 #define	MCDI_IN_POPULATE_DWORD_1(_emr, _ofst, _field1, _value1)		\
 	EFX_POPULATE_DWORD_1(*MCDI_IN2(_emr, efx_dword_t, _ofst),	\
 		MC_CMD_ ## _field1, _value1)
diff --git a/drivers/common/sfc_efx/base/efx_nic.c b/drivers/common/sfc_efx/base/efx_nic.c
index 9fe0933772..172488e083 100644
--- a/drivers/common/sfc_efx/base/efx_nic.c
+++ b/drivers/common/sfc_efx/base/efx_nic.c
@@ -1300,3 +1300,463 @@ efx_nic_check_pcie_link_speed(
 
 	return (rc);
 }
+
+/* Required en_eslp lock held */
+static __checkReturn	efx_rc_t
+efx_nic_dma_config_regioned_find_region(
+	__in		const efx_nic_t *enp,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		const efx_nic_dma_region_t **regionp)
+{
+	const efx_nic_dma_region_info_t *region_info;
+	const efx_nic_dma_region_t *region;
+	unsigned int i;
+	efx_rc_t rc;
+
+	if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+	    EFX_NIC_DMA_MAPPING_REGIONED) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	region_info = &enp->en_dma.end_u.endu_region_info;
+
+	for (i = 0; i < region_info->endri_count; ++i) {
+		efsys_dma_addr_t offset;
+
+		region = &region_info->endri_regions[i];
+		if (region->endr_inuse == B_FALSE)
+			continue;
+
+		if (trgt_addr < region->endr_trgt_base)
+			continue;
+
+		EFSYS_ASSERT3U(region->endr_window_log2, <, 64);
+		offset = trgt_addr - region->endr_trgt_base;
+		if (offset + len > (1ULL << region->endr_window_log2))
+			continue;
+
+		*regionp = region;
+		return (0);
+	}
+
+	rc = ENOENT;
+	goto fail2;
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static __checkReturn	efx_rc_t
+efx_nic_dma_config_regioned_add_region(
+	__in		efx_nic_t *enp,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		const efx_nic_dma_region_t **regionp)
+{
+	efx_nic_dma_region_info_t *region_info;
+	efx_nic_dma_region_t *region;
+	unsigned int i;
+	efx_rc_t rc;
+
+	if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+	    EFX_NIC_DMA_MAPPING_REGIONED) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	region_info = &enp->en_dma.end_u.endu_region_info;
+
+	for (i = 0; i < region_info->endri_count; ++i) {
+		efsys_dma_addr_t trgt_base;
+		efsys_dma_addr_t offset;
+
+		region = &region_info->endri_regions[i];
+		if (region->endr_inuse == B_TRUE)
+			continue;
+
+		/*
+		 * Align target address base in accordance with
+		 * the region requirements.
+		 */
+		EFSYS_ASSERT3U(region->endr_align_log2, <, 64);
+		trgt_base = EFX_P2ALIGN(efsys_dma_addr_t, trgt_addr,
+		    (1ULL << region->endr_align_log2));
+
+		offset = trgt_addr - trgt_base;
+
+		/* Check if region window is sufficient */
+		EFSYS_ASSERT3U(region->endr_window_log2, <, 64);
+		if (offset + len > (1ULL << region->endr_window_log2))
+			continue;
+
+		region->endr_trgt_base = trgt_base;
+		region->endr_inuse = B_TRUE;
+
+		*regionp = region;
+		return (0);
+	}
+
+	/* No suitable free region found */
+	rc = ENOMEM;
+	goto fail2;
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static	__checkReturn	efx_rc_t
+efx_nic_dma_config_regioned_add(
+	__in		efx_nic_t *enp,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out_opt	efsys_dma_addr_t *nic_basep,
+	__out_opt	efsys_dma_addr_t *trgt_basep,
+	__out_opt	size_t *map_lenp)
+{
+	const efx_nic_dma_region_t *region;
+	efsys_lock_state_t state;
+	efx_rc_t rc;
+
+	EFSYS_LOCK(enp->en_eslp, state);
+
+	rc = efx_nic_dma_config_regioned_find_region(enp, trgt_addr, len,
+	    &region);
+	switch (rc) {
+	case 0:
+		/* Already covered by existing mapping */
+		break;
+	case ENOENT:
+		/* No existing mapping found */
+		rc = efx_nic_dma_config_regioned_add_region(enp,
+		    trgt_addr, len, &region);
+		if (rc != 0)
+			goto fail1;
+		break;
+	default:
+		goto fail2;
+	}
+
+	if (nic_basep != NULL)
+		*nic_basep = region->endr_nic_base;
+	if (trgt_basep != NULL)
+		*trgt_basep = region->endr_trgt_base;
+	if (map_lenp != NULL)
+		*map_lenp = 1ULL << region->endr_window_log2;
+
+	EFSYS_UNLOCK(enp->en_eslp, state);
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	EFSYS_UNLOCK(enp->en_eslp, state);
+
+	return (rc);
+}
+
+	 __checkReturn	efx_rc_t
+efx_nic_dma_config_add(
+	__in		efx_nic_t *enp,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out_opt	efsys_dma_addr_t *nic_basep,
+	__out_opt	efsys_dma_addr_t *trgt_basep,
+	__out_opt	size_t *map_lenp)
+{
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+	efx_rc_t rc;
+
+	switch (encp->enc_dma_mapping) {
+	case EFX_NIC_DMA_MAPPING_FLAT:
+		/* No mapping is required */
+		if (nic_basep != NULL)
+			*nic_basep = 0;
+		if (trgt_basep != NULL)
+			*trgt_basep = 0;
+		if (map_lenp != NULL)
+			*map_lenp = 0;
+		break;
+	case EFX_NIC_DMA_MAPPING_REGIONED:
+		rc = efx_nic_dma_config_regioned_add(enp, trgt_addr, len,
+		    nic_basep, trgt_basep, map_lenp);
+		if (rc != 0)
+			goto fail1;
+		break;
+	case EFX_NIC_DMA_MAPPING_UNKNOWN:
+	default:
+		rc = ENOTSUP;
+		goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static	 __checkReturn	efx_rc_t
+efx_nic_dma_reconfigure_regioned(
+	__in		efx_nic_t *enp)
+{
+	efx_rc_t rc;
+
+	rc = efx_mcdi_set_nic_addr_regions(enp,
+	    &enp->en_dma.end_u.endu_region_info);
+	if (rc != 0)
+		goto fail1;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+
+}
+
+	 __checkReturn	efx_rc_t
+efx_nic_dma_reconfigure(
+	__in		efx_nic_t *enp)
+{
+	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+	efx_rc_t rc;
+
+	switch (encp->enc_dma_mapping) {
+	case EFX_NIC_DMA_MAPPING_UNKNOWN:
+	case EFX_NIC_DMA_MAPPING_FLAT:
+		/* Nothing to do */
+		break;
+	case EFX_NIC_DMA_MAPPING_REGIONED:
+		rc = efx_nic_dma_reconfigure_regioned(enp);
+		if (rc != 0)
+			goto fail1;
+		break;
+	default:
+		rc = ENOTSUP;
+		goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static __checkReturn	efx_rc_t
+efx_nic_dma_unknown_map(
+	__in		efx_nic_t *enp,
+	__in		efx_nic_dma_addr_type_t addr_type,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		efsys_dma_addr_t *nic_addrp)
+{
+	efx_rc_t rc;
+
+	/* This function may be called before the NIC has been probed. */
+	if (enp->en_mod_flags & EFX_MOD_PROBE) {
+		EFSYS_ASSERT3U(efx_nic_cfg_get(enp)->enc_dma_mapping, ==,
+		    EFX_NIC_DMA_MAPPING_UNKNOWN);
+	}
+
+	switch (addr_type) {
+	case EFX_NIC_DMA_ADDR_MCDI_BUF:
+		/*
+		 * MC cares about MCDI buffer mapping itself since it cannot
+		 * be really mapped using MCDI because mapped MCDI
+		 * buffer is required to execute MCDI commands.
+		 */
+		*nic_addrp = trgt_addr;
+		break;
+
+	case EFX_NIC_DMA_ADDR_MAC_STATS_BUF:
+	case EFX_NIC_DMA_ADDR_EVENT_RING:
+	case EFX_NIC_DMA_ADDR_RX_RING:
+	case EFX_NIC_DMA_ADDR_TX_RING:
+	case EFX_NIC_DMA_ADDR_RX_BUF:
+	case EFX_NIC_DMA_ADDR_TX_BUF:
+		/* Mapping type must be discovered first */
+		rc = EFAULT;
+		goto fail1;
+
+	default:
+		rc = EINVAL;
+		goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static __checkReturn	efx_rc_t
+efx_nic_dma_flat_map(
+	__in		efx_nic_t *enp,
+	__in		efx_nic_dma_addr_type_t addr_type,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		efsys_dma_addr_t *nic_addrp)
+{
+	_NOTE(ARGUNUSED(addr_type, len))
+
+	EFSYS_ASSERT3U(efx_nic_cfg_get(enp)->enc_dma_mapping, ==,
+	    EFX_NIC_DMA_MAPPING_FLAT);
+
+	/* No re-mapping is required */
+	*nic_addrp = trgt_addr;
+
+	return (0);
+}
+
+static __checkReturn	efx_rc_t
+efx_nic_dma_regioned_map(
+	__in		efx_nic_t *enp,
+	__in		efx_nic_dma_addr_type_t addr_type,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		efsys_dma_addr_t *nic_addrp)
+{
+	const efx_nic_dma_region_t *region;
+	efsys_lock_state_t state;
+	efx_rc_t rc;
+
+	if (efx_nic_cfg_get(enp)->enc_dma_mapping !=
+	    EFX_NIC_DMA_MAPPING_REGIONED) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	switch (addr_type) {
+	case EFX_NIC_DMA_ADDR_MCDI_BUF:
+	case EFX_NIC_DMA_ADDR_MAC_STATS_BUF:
+		/*
+		 * MC cares about MCDI buffer mapping itself since it cannot
+		 * be really mapped using MCDI because mapped MCDI buffer is
+		 * required to execute MCDI commands. It is not a problem
+		 * for MAC stats buffer, but since MC can care about mapping
+		 * itself, it may be done for MAC stats buffer as well.
+		 */
+		*nic_addrp = trgt_addr;
+		goto out;
+
+	case EFX_NIC_DMA_ADDR_EVENT_RING:
+	case EFX_NIC_DMA_ADDR_RX_RING:
+	case EFX_NIC_DMA_ADDR_TX_RING:
+	case EFX_NIC_DMA_ADDR_RX_BUF:
+	case EFX_NIC_DMA_ADDR_TX_BUF:
+		/* Rings and buffer addresses should be mapped */
+		break;
+
+	default:
+		rc = EINVAL;
+		goto fail2;
+	}
+
+	EFSYS_LOCK(enp->en_eslp, state);
+
+	rc = efx_nic_dma_config_regioned_find_region(enp, trgt_addr, len,
+	    &region);
+	if (rc != 0)
+		goto fail3;
+
+	*nic_addrp = region->endr_nic_base +
+		(trgt_addr - region->endr_trgt_base);
+
+	EFSYS_UNLOCK(enp->en_eslp, state);
+
+out:
+	return (0);
+
+fail3:
+	EFSYS_PROBE(fail3);
+	EFSYS_UNLOCK(enp->en_eslp, state);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+	__checkReturn	efx_rc_t
+efx_nic_dma_map(
+	__in		efx_nic_t *enp,
+	__in		efx_nic_dma_addr_type_t addr_type,
+	__in		efsys_dma_addr_t trgt_addr,
+	__in		size_t len,
+	__out		efsys_dma_addr_t *nic_addrp)
+{
+	efx_nic_dma_mapping_t mapping;
+	efx_rc_t rc;
+
+	/*
+	 * We cannot check configuration of a NIC that hasn't been probed.
+	 * Use EFX_NIC_DMA_MAPPING_UNKNOWN by default.
+	 */
+	if ((enp->en_mod_flags & EFX_MOD_PROBE) == 0)
+		mapping = EFX_NIC_DMA_MAPPING_UNKNOWN;
+	else
+		mapping = efx_nic_cfg_get(enp)->enc_dma_mapping;
+
+	switch (mapping) {
+	case EFX_NIC_DMA_MAPPING_UNKNOWN:
+		rc = efx_nic_dma_unknown_map(enp, addr_type, trgt_addr,
+		    len, nic_addrp);
+		if (rc != 0)
+			goto fail1;
+		break;
+	case EFX_NIC_DMA_MAPPING_FLAT:
+		rc = efx_nic_dma_flat_map(enp, addr_type, trgt_addr,
+		    len, nic_addrp);
+		if (rc != 0)
+			goto fail2;
+		break;
+	case EFX_NIC_DMA_MAPPING_REGIONED:
+		rc = efx_nic_dma_regioned_map(enp, addr_type, trgt_addr,
+		    len, nic_addrp);
+		if (rc != 0)
+			goto fail3;
+		break;
+	default:
+		rc = ENOTSUP;
+		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);
+}
diff --git a/drivers/common/sfc_efx/base/siena_nic.c b/drivers/common/sfc_efx/base/siena_nic.c
index 8b810d3ae3..e42599131a 100644
--- a/drivers/common/sfc_efx/base/siena_nic.c
+++ b/drivers/common/sfc_efx/base/siena_nic.c
@@ -199,6 +199,8 @@ siena_board_cfg(
 	encp->enc_mae_supported = B_FALSE;
 	encp->enc_mae_admin = B_FALSE;
 
+	encp->enc_dma_mapping = EFX_NIC_DMA_MAPPING_FLAT;
+
 	return (0);
 
 fail2:
diff --git a/drivers/common/sfc_efx/version.map b/drivers/common/sfc_efx/version.map
index 765ca39332..3e57791c99 100644
--- a/drivers/common/sfc_efx/version.map
+++ b/drivers/common/sfc_efx/version.map
@@ -160,6 +160,9 @@ INTERNAL {
 	efx_nic_check_pcie_link_speed;
 	efx_nic_create;
 	efx_nic_destroy;
+	efx_nic_dma_config_add;
+	efx_nic_dma_map;
+	efx_nic_dma_reconfigure;
 	efx_nic_fini;
 	efx_nic_get_bar_region;
 	efx_nic_get_board_info;
