[v3,42/60] common/sfc_efx/base: choose smallest Rx prefix on Riverhead
diff mbox series

Message ID 1600949555-28043-43-git-send-email-arybchenko@solarflare.com
State Accepted
Delegated to: Ferruh Yigit
Headers show
Series
  • common/sfc_efx: support Riverhead NIC family
Related show

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Andrew Rybchenko Sept. 24, 2020, 12:12 p.m. UTC
Riverhead supports many Rx prefixes. The Rx prefix may be chosen
based on which information is required.

To have better performance choose the smallest Rx prefix which
meets our requirements.

Right now there is no way to specify requirements on Rx queue
creation, but it could be added in the future.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/common/sfc_efx/base/efx_impl.h |   1 +
 drivers/common/sfc_efx/base/efx_mcdi.c |  10 +-
 drivers/common/sfc_efx/base/rhead_rx.c | 333 ++++++++++++++++++++++++-
 3 files changed, 338 insertions(+), 6 deletions(-)

Patch
diff mbox series

diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h
index c373192554..fc0a654f80 100644
--- a/drivers/common/sfc_efx/base/efx_impl.h
+++ b/drivers/common/sfc_efx/base/efx_impl.h
@@ -1439,6 +1439,7 @@  typedef struct efx_mcdi_init_rxq_params_s {
 	uint32_t	es_max_dma_len;
 	uint32_t	es_buf_stride;
 	uint32_t	hol_block_timeout;
+	uint32_t	prefix_id;
 } efx_mcdi_init_rxq_params_t;
 
 LIBEFX_INTERNAL
diff --git a/drivers/common/sfc_efx/base/efx_mcdi.c b/drivers/common/sfc_efx/base/efx_mcdi.c
index aa19c7c759..b8e45b458d 100644
--- a/drivers/common/sfc_efx/base/efx_mcdi.c
+++ b/drivers/common/sfc_efx/base/efx_mcdi.c
@@ -2692,8 +2692,8 @@  efx_mcdi_init_rxq(
 {
 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 	efx_mcdi_req_t req;
-	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V4_IN_LEN,
-		MC_CMD_INIT_RXQ_V4_OUT_LEN);
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V5_IN_LEN,
+		MC_CMD_INIT_RXQ_V5_OUT_LEN);
 	int npages = efx_rxq_nbufs(enp, ndescs);
 	int i;
 	efx_qword_t *dma_addr;
@@ -2747,9 +2747,9 @@  efx_mcdi_init_rxq(
 
 	req.emr_cmd = MC_CMD_INIT_RXQ;
 	req.emr_in_buf = payload;
-	req.emr_in_length = MC_CMD_INIT_RXQ_V4_IN_LEN;
+	req.emr_in_length = MC_CMD_INIT_RXQ_V5_IN_LEN;
 	req.emr_out_buf = payload;
-	req.emr_out_length = MC_CMD_INIT_RXQ_V4_OUT_LEN;
+	req.emr_out_length = MC_CMD_INIT_RXQ_V5_OUT_LEN;
 
 	MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs);
 	MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, eep->ee_index);
@@ -2787,6 +2787,8 @@  efx_mcdi_init_rxq(
 		MCDI_IN_SET_DWORD(req, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES,
 		    params->buf_size);
 
+	MCDI_IN_SET_DWORD(req, INIT_RXQ_V5_IN_RX_PREFIX_ID, params->prefix_id);
+
 	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
 	addr = EFSYS_MEM_ADDR(esmp);
 
diff --git a/drivers/common/sfc_efx/base/rhead_rx.c b/drivers/common/sfc_efx/base/rhead_rx.c
index 38c905444a..d683f280ce 100644
--- a/drivers/common/sfc_efx/base/rhead_rx.c
+++ b/drivers/common/sfc_efx/base/rhead_rx.c
@@ -10,6 +10,12 @@ 
 
 #if EFSYS_OPT_RIVERHEAD
 
+/*
+ * Maximum number of Rx prefixes supported by Rx prefix choice to be
+ * returned from firmware.
+ */
+#define	RHEAD_RX_PREFIX_IDS_MAX		16
+
 /*
  * Default Rx prefix layout on Riverhead if FW does not support Rx
  * prefix choice using MC_CMD_GET_RX_PREFIX_ID and query its layout
@@ -265,6 +271,312 @@  rhead_rx_qenable(
 	_NOTE(ARGUNUSED(erp))
 }
 
+static	__checkReturn	efx_rc_t
+efx_mcdi_get_rx_prefix_ids(
+	__in					efx_nic_t *enp,
+	__in					uint32_t mcdi_fields_mask,
+	__in					unsigned int max_ids,
+	__out					unsigned int *nids,
+	__out_ecount_part(max_ids, *nids)	uint32_t *idsp)
+{
+	efx_mcdi_req_t req;
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RX_PREFIX_ID_IN_LEN,
+		MC_CMD_GET_RX_PREFIX_ID_OUT_LENMAX);
+	efx_rc_t rc;
+	uint32_t num;
+
+	req.emr_cmd = MC_CMD_GET_RX_PREFIX_ID;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_GET_RX_PREFIX_ID_IN_LEN;
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_GET_RX_PREFIX_ID_OUT_LENMAX;
+
+	MCDI_IN_SET_DWORD(req, GET_RX_PREFIX_ID_IN_FIELDS, mcdi_fields_mask);
+
+	efx_mcdi_execute(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail1;
+	}
+
+	if (req.emr_out_length_used < MC_CMD_GET_RX_PREFIX_ID_OUT_LENMIN) {
+		rc = EMSGSIZE;
+		goto fail2;
+	}
+
+	num = MCDI_OUT_DWORD(req, GET_RX_PREFIX_ID_OUT_NUM_RX_PREFIX_IDS);
+
+	if (req.emr_out_length_used != MC_CMD_GET_RX_PREFIX_ID_OUT_LEN(num)) {
+		rc = EMSGSIZE;
+		goto fail3;
+	}
+
+	*nids = MIN(num, max_ids);
+
+	EFX_STATIC_ASSERT(sizeof (idsp[0]) ==
+	    MC_CMD_GET_RX_PREFIX_ID_OUT_RX_PREFIX_ID_LEN);
+	memcpy(idsp,
+	    MCDI_OUT2(req, uint32_t, GET_RX_PREFIX_ID_OUT_RX_PREFIX_ID),
+	    *nids * sizeof (idsp[0]));
+
+	return (0);
+
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static	__checkReturn	efx_rx_prefix_field_t
+efx_mcdi_rx_prefix_field_map(unsigned int mcdi_idx)
+{
+	static const efx_rx_prefix_field_t efx_mcdi_to_rx_prefix_field[] = {
+#define	EFX_MCDI_TO_RX_PREFIX_FIELD(_field) \
+	[RX_PREFIX_FIELD_INFO_ ## _field] = EFX_RX_PREFIX_FIELD_ ## _field
+
+		EFX_MCDI_TO_RX_PREFIX_FIELD(LENGTH),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(RSS_HASH_VALID),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(USER_FLAG),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(CLASS),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(PARTIAL_TSTAMP),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(RSS_HASH),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(USER_MARK),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(INGRESS_VPORT),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(CSUM_FRAME),
+		EFX_MCDI_TO_RX_PREFIX_FIELD(VLAN_STRIP_TCI),
+
+#undef	EFX_MCDI_TO_RX_PREFIX_FIELD
+	};
+
+	if (mcdi_idx >= EFX_ARRAY_SIZE(efx_mcdi_to_rx_prefix_field))
+		return (EFX_RX_PREFIX_NFIELDS);
+
+	return (efx_mcdi_to_rx_prefix_field[mcdi_idx]);
+}
+
+static	__checkReturn	int
+efx_rx_prefix_field_map_to_mcdi(
+	__in		efx_rx_prefix_field_t field)
+{
+	static const int efx_rx_prefix_field_to_mcdi[] = {
+		[EFX_RX_PREFIX_FIELD_LENGTH] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_LENGTH),
+		[EFX_RX_PREFIX_FIELD_ORIG_LENGTH] = -1,
+		[EFX_RX_PREFIX_FIELD_CLASS] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_CLASS),
+		[EFX_RX_PREFIX_FIELD_RSS_HASH] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_RSS_HASH),
+		[EFX_RX_PREFIX_FIELD_RSS_HASH_VALID] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_RSS_HASH_VALID),
+		[EFX_RX_PREFIX_FIELD_PARTIAL_TSTAMP] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_PARTIAL_TSTAMP),
+		[EFX_RX_PREFIX_FIELD_VLAN_STRIP_TCI] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_VLAN_STRIP_TCI),
+		[EFX_RX_PREFIX_FIELD_INNER_VLAN_STRIP_TCI] = -1,
+		[EFX_RX_PREFIX_FIELD_USER_FLAG] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_USER_FLAG),
+		[EFX_RX_PREFIX_FIELD_USER_MARK] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_USER_MARK),
+		[EFX_RX_PREFIX_FIELD_USER_MARK_VALID] = -1,
+		[EFX_RX_PREFIX_FIELD_CSUM_FRAME] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_CSUM_FRAME),
+		[EFX_RX_PREFIX_FIELD_INGRESS_VPORT] =
+			EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_INGRESS_VPORT),
+	};
+
+	if (field >= EFX_ARRAY_SIZE(efx_rx_prefix_field_to_mcdi))
+		return (-1);
+
+	return (efx_rx_prefix_field_to_mcdi[field]);
+}
+
+static	__checkReturn	efx_rc_t
+efx_rx_prefix_fields_mask_to_mcdi(
+	__in		uint32_t fields_mask,
+	__out		uint32_t *mcdi_fields_maskp)
+{
+	uint32_t mcdi_fields_mask = 0;
+	unsigned int i;
+
+	for (i = 0; i < EFX_RX_PREFIX_NFIELDS; ++i) {
+		if (fields_mask & (1U << i)) {
+			int mcdi_field = efx_rx_prefix_field_map_to_mcdi(i);
+
+			if (mcdi_field < 0)
+				return (EINVAL);
+
+			mcdi_fields_mask |= (1U << mcdi_field);
+		}
+	}
+
+	*mcdi_fields_maskp = mcdi_fields_mask;
+	return (0);
+}
+
+static	__checkReturn	efx_rc_t
+efx_mcdi_query_rx_prefix_id(
+	__in		efx_nic_t *enp,
+	__in		uint32_t prefix_id,
+	__out		efx_rx_prefix_layout_t *erplp)
+{
+	efx_mcdi_req_t req;
+	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_QUERY_RX_PREFIX_ID_IN_LEN,
+		MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMAX);
+	efx_rc_t rc;
+	size_t response_len;
+	const efx_dword_t *resp;
+	const efx_dword_t *finfo;
+	unsigned int num_fields;
+	unsigned int mcdi_field;
+	efx_rx_prefix_field_t field;
+	unsigned int i;
+
+	req.emr_cmd = MC_CMD_QUERY_RX_PREFIX_ID;
+	req.emr_in_buf = payload;
+	req.emr_in_length = MC_CMD_QUERY_RX_PREFIX_ID_IN_LEN;
+	req.emr_out_buf = payload;
+	req.emr_out_length = MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMAX;
+
+	MCDI_IN_SET_DWORD(req, QUERY_RX_PREFIX_ID_IN_RX_PREFIX_ID, prefix_id);
+
+	efx_mcdi_execute(enp, &req);
+
+	if (req.emr_rc != 0) {
+		rc = req.emr_rc;
+		goto fail1;
+	}
+
+	if (req.emr_out_length_used < MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMIN) {
+		rc = EMSGSIZE;
+		goto fail2;
+	}
+
+	if (MCDI_OUT_BYTE(req, QUERY_RX_PREFIX_ID_OUT_RESPONSE_TYPE) !=
+	    MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_TYPE_FIXED) {
+		rc = ENOTSUP;
+		goto fail3;
+	}
+
+	EFX_STATIC_ASSERT(MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMIN >=
+	    MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_OFST);
+	response_len = req.emr_out_length_used -
+	    MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_OFST;
+
+	if (response_len < RX_PREFIX_FIXED_RESPONSE_LENMIN) {
+		rc = EMSGSIZE;
+		goto fail4;
+	}
+
+	resp = MCDI_OUT2(req, efx_dword_t, QUERY_RX_PREFIX_ID_OUT_RESPONSE);
+
+	memset(erplp, 0, sizeof (*erplp));
+	erplp->erpl_id = prefix_id;
+	erplp->erpl_length =
+	    EFX_DWORD_FIELD(*resp, RX_PREFIX_FIXED_RESPONSE_PREFIX_LENGTH_BYTES);
+	num_fields =
+	    EFX_DWORD_FIELD(*resp, RX_PREFIX_FIXED_RESPONSE_FIELD_COUNT);
+
+	if (response_len < RX_PREFIX_FIXED_RESPONSE_LEN(num_fields)) {
+		rc = EMSGSIZE;
+		goto fail5;
+	}
+
+	finfo = (const efx_dword_t *)((const uint8_t *)resp +
+	     RX_PREFIX_FIXED_RESPONSE_FIELDS_OFST);
+
+	for (i = 0; i < num_fields; ++i, ++finfo) {
+		mcdi_field = EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_TYPE);
+
+		field = efx_mcdi_rx_prefix_field_map(mcdi_field);
+		if (field >= EFX_RX_PREFIX_NFIELDS)
+			continue;
+
+		erplp->erpl_fields[field].erpfi_offset_bits =
+		    EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_OFFSET_BITS);
+		erplp->erpl_fields[field].erpfi_width_bits =
+		    EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_WIDTH_BITS);
+	}
+
+	return (0);
+
+fail5:
+	EFSYS_PROBE(fail5);
+fail4:
+	EFSYS_PROBE(fail4);
+fail3:
+	EFSYS_PROBE(fail3);
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+	return (rc);
+}
+
+static	__checkReturn	efx_rc_t
+rhead_rx_choose_prefix_id(
+	__in		efx_nic_t *enp,
+	__in		uint32_t fields_mask,
+	__out		efx_rx_prefix_layout_t *erplp)
+{
+	efx_rx_prefix_layout_t erpl;
+	uint32_t prefix_ids[RHEAD_RX_PREFIX_IDS_MAX];
+	uint32_t mcdi_fields_mask;
+	unsigned int num = 0;
+	unsigned int i;
+	efx_rc_t rc;
+
+	rc = efx_rx_prefix_fields_mask_to_mcdi(fields_mask, &mcdi_fields_mask);
+	if (rc != 0)
+		goto fail1;
+
+	memset(erplp, 0, sizeof (*erplp));
+
+	rc = efx_mcdi_get_rx_prefix_ids(enp, mcdi_fields_mask,
+	    EFX_ARRAY_SIZE(prefix_ids), &num, prefix_ids);
+	if (rc == ENOTSUP) {
+		/* Not supported MCDI, use default prefix ID */
+		*erplp = rhead_default_rx_prefix_layout;
+		goto done;
+	}
+	if (rc != 0)
+		goto fail2;
+
+	if (num == 0) {
+		rc = ENOTSUP;
+		goto fail3;
+	}
+
+	for (i = 0; i < num; ++i) {
+		rc = efx_mcdi_query_rx_prefix_id(enp, prefix_ids[i], &erpl);
+		if (rc != 0)
+			goto fail4;
+
+		/* Choose the smallest prefix which meets our requirements */
+		if (i == 0 || erpl.erpl_length < erplp->erpl_length)
+			*erplp = erpl;
+	}
+
+done:
+	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
 rhead_rx_qcreate(
 	__in		efx_nic_t *enp,
@@ -281,6 +593,7 @@  rhead_rx_qcreate(
 {
 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 	efx_mcdi_init_rxq_params_t params;
+	efx_rx_prefix_layout_t erpl;
 	efx_rc_t rc;
 
 	_NOTE(ARGUNUSED(id))
@@ -310,6 +623,20 @@  rhead_rx_qcreate(
 	else
 		params.disable_scatter = encp->enc_rx_disable_scatter_supported;
 
+	/*
+	 * LENGTH is required in EF100 host interface, as receive events
+	 * do not include the packet length.
+	 * NOTE: Required fields are hard-wired now. Future designs will
+	 * want to allow the client (driver) code to have control over
+	 * which fields are required or may be allow to request so-called
+	 * default Rx prefix (which ID is equal to 0).
+	 */
+	if ((rc = rhead_rx_choose_prefix_id(enp,
+	    (1U << EFX_RX_PREFIX_FIELD_LENGTH), &erpl)) != 0)
+		goto fail3;
+
+	params.prefix_id = erpl.erpl_id;
+
 	/*
 	 * Ignore EFX_RXQ_FLAG_INNER_CLASSES since in accordance with
 	 * EF100 host interface both inner and outer classes are provided
@@ -318,15 +645,17 @@  rhead_rx_qcreate(
 
 	if ((rc = efx_mcdi_init_rxq(enp, ndescs, eep, label, index,
 		    esmp, &params)) != 0)
-		goto fail3;
+		goto fail4;
 
 	erp->er_eep = eep;
 	erp->er_label = label;
 	erp->er_buf_size = params.buf_size;
-	erp->er_prefix_layout = rhead_default_rx_prefix_layout;
+	erp->er_prefix_layout = erpl;
 
 	return (0);
 
+fail4:
+	EFSYS_PROBE(fail4);
 fail3:
 	EFSYS_PROBE(fail3);
 fail2: