DPDK patches and discussions
 help / color / mirror / Atom feed
From: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
To: dev@dpdk.org
Cc: Thomas Monjalon <thomas@monjalon.net>,
	Ferruh Yigit <ferruh.yigit@intel.com>,
	Andy Moreton <amoreton@xilinx.com>
Subject: [PATCH v2 1/2] common/sfc_efx/base: support NIC DMA memory regions API
Date: Wed, 17 Nov 2021 10:05:44 +0300	[thread overview]
Message-ID: <20211117070545.4004374-2-andrew.rybchenko@oktetlabs.ru> (raw)
In-Reply-To: <20211117070545.4004374-1-andrew.rybchenko@oktetlabs.ru>

NIC DMA memory regions API allows to establish mapping of DMA addresses
used by NIC to host IOVA understood by the host when IOMMU is absent
and NIC cannot address entire host IOVA space because of too small
DMA mask.

The API does not allow to address entire host IOVA space, but allows
arbitrary regions of the space really used for the NIC DMA.

A DMA region needs to be mapped in order to perform MCDI initialization.
Since the NIC has not been probed at that point, its configuration cannot
be accessed and there an UNKNOWN mapping type is assumed.

Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/common/sfc_efx/base/ef10_nic.c  |  51 +++
 drivers/common/sfc_efx/base/efx.h       |  46 +++
 drivers/common/sfc_efx/base/efx_impl.h  |  20 ++
 drivers/common/sfc_efx/base/efx_mcdi.c  | 204 +++++++++++
 drivers/common/sfc_efx/base/efx_mcdi.h  |  31 ++
 drivers/common/sfc_efx/base/efx_nic.c   | 460 ++++++++++++++++++++++++
 drivers/common/sfc_efx/base/siena_nic.c |   2 +
 drivers/common/sfc_efx/version.map      |   3 +
 8 files changed, 817 insertions(+)

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;
-- 
2.30.2


  reply	other threads:[~2021-11-17  7:06 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-05  8:33 [dpdk-dev] [PATCH 0/4] net/sfc: support SN1022 SoC Andrew Rybchenko
2021-11-05  8:33 ` [dpdk-dev] [PATCH 1/4] common/sfc_efx: use correct define to control debug Andrew Rybchenko
2021-11-05 21:07   ` Ferruh Yigit
2021-11-05  8:33 ` [dpdk-dev] [PATCH 2/4] common/sfc_efx/base: support NIC DMA memory regions API Andrew Rybchenko
2021-11-05  8:33 ` [dpdk-dev] [PATCH 3/4] net/sfc: make adapter lock recursive Andrew Rybchenko
2021-11-05  8:33 ` [dpdk-dev] [PATCH 4/4] net/sfc: support regioned NIC DMA memory mapping type Andrew Rybchenko
2021-11-05 19:05   ` Ferruh Yigit
2021-11-05 20:14     ` Thomas Monjalon
2021-11-06  8:39       ` Andrew Rybchenko
2021-11-06  8:48         ` Thomas Monjalon
2021-11-17  7:05 ` [PATCH v2 0/2] net/sfc: support SN1022 SoC Andrew Rybchenko
2021-11-17  7:05   ` Andrew Rybchenko [this message]
2021-11-17  7:05   ` [PATCH v2 2/2] net/sfc: support regioned NIC DMA memory mapping type Andrew Rybchenko
2021-11-17 11:44   ` [PATCH v2 0/2] net/sfc: support SN1022 SoC Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211117070545.4004374-2-andrew.rybchenko@oktetlabs.ru \
    --to=andrew.rybchenko@oktetlabs.ru \
    --cc=amoreton@xilinx.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@intel.com \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).