[dpdk-dev] [PATCH v4 30/52] common/cnxk: add nix flow control support

Nithin Dabilpuram ndabilpuram at marvell.com
Tue Apr 6 13:41:09 CEST 2021


From: Sunil Kumar Kori <skori at marvell.com>

Add support to enable/disable Rx/Tx flow control and pause
frame configuration on NIX.

Signed-off-by: Sunil Kumar Kori <skori at marvell.com>
---
 drivers/common/cnxk/meson.build  |   1 +
 drivers/common/cnxk/roc_nix.h    |  34 ++++++
 drivers/common/cnxk/roc_nix_fc.c | 251 +++++++++++++++++++++++++++++++++++++++
 drivers/common/cnxk/version.map  |   4 +
 4 files changed, 290 insertions(+)
 create mode 100644 drivers/common/cnxk/roc_nix_fc.c

diff --git a/drivers/common/cnxk/meson.build b/drivers/common/cnxk/meson.build
index f975681..33eeb8c 100644
--- a/drivers/common/cnxk/meson.build
+++ b/drivers/common/cnxk/meson.build
@@ -17,6 +17,7 @@ sources = files('roc_dev.c',
 		'roc_model.c',
 		'roc_nix.c',
 		'roc_nix_debug.c',
+		'roc_nix_fc.c',
 		'roc_nix_irq.c',
 		'roc_nix_mac.c',
 		'roc_nix_mcast.c',
diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h
index ba3575b..2158f8c 100644
--- a/drivers/common/cnxk/roc_nix.h
+++ b/drivers/common/cnxk/roc_nix.h
@@ -17,6 +17,13 @@ enum roc_nix_sq_max_sqe_sz {
 	roc_nix_maxsqesz_w8 = NIX_MAXSQESZ_W8,
 };
 
+enum roc_nix_fc_mode {
+	ROC_NIX_FC_NONE = 0,
+	ROC_NIX_FC_RX,
+	ROC_NIX_FC_TX,
+	ROC_NIX_FC_FULL
+};
+
 enum roc_nix_vlan_type {
 	ROC_NIX_VLAN_TYPE_INNER = 0x01,
 	ROC_NIX_VLAN_TYPE_OUTER = 0x02,
@@ -37,6 +44,21 @@ struct roc_nix_vlan_config {
 	};
 };
 
+struct roc_nix_fc_cfg {
+	bool cq_cfg_valid;
+	union {
+		struct {
+			bool enable;
+		} rxchan_cfg;
+
+		struct {
+			uint32_t rq;
+			uint16_t cq_drop;
+			bool enable;
+		} cq_cfg;
+	};
+};
+
 /* Range to adjust PTP frequency. Valid range is
  * (-ROC_NIX_PTP_FREQ_ADJUST, ROC_NIX_PTP_FREQ_ADJUST)
  */
@@ -293,6 +315,18 @@ int __roc_api roc_nix_mac_link_cb_register(struct roc_nix *roc_nix,
 					   link_status_t link_update);
 void __roc_api roc_nix_mac_link_cb_unregister(struct roc_nix *roc_nix);
 
+/* Flow control */
+int __roc_api roc_nix_fc_config_set(struct roc_nix *roc_nix,
+				    struct roc_nix_fc_cfg *fc_cfg);
+
+int __roc_api roc_nix_fc_config_get(struct roc_nix *roc_nix,
+				    struct roc_nix_fc_cfg *fc_cfg);
+
+int __roc_api roc_nix_fc_mode_set(struct roc_nix *roc_nix,
+				  enum roc_nix_fc_mode mode);
+
+enum roc_nix_fc_mode __roc_api roc_nix_fc_mode_get(struct roc_nix *roc_nix);
+
 /* NPC */
 int __roc_api roc_nix_npc_promisc_ena_dis(struct roc_nix *roc_nix, int enable);
 
diff --git a/drivers/common/cnxk/roc_nix_fc.c b/drivers/common/cnxk/roc_nix_fc.c
new file mode 100644
index 0000000..47be8aa
--- /dev/null
+++ b/drivers/common/cnxk/roc_nix_fc.c
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+static inline struct mbox *
+get_mbox(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct dev *dev = &nix->dev;
+
+	return dev->mbox;
+}
+
+static int
+nix_fc_rxchan_bpid_get(struct roc_nix *roc_nix, struct roc_nix_fc_cfg *fc_cfg)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+
+	if (nix->chan_cnt != 0)
+		fc_cfg->rxchan_cfg.enable = true;
+	else
+		fc_cfg->rxchan_cfg.enable = false;
+
+	fc_cfg->cq_cfg_valid = false;
+
+	return 0;
+}
+
+static int
+nix_fc_rxchan_bpid_set(struct roc_nix *roc_nix, bool enable)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct mbox *mbox = get_mbox(roc_nix);
+	struct nix_bp_cfg_req *req;
+	struct nix_bp_cfg_rsp *rsp;
+	int rc = -ENOSPC;
+
+	if (roc_nix_is_sdp(roc_nix))
+		return 0;
+
+	if (enable) {
+		req = mbox_alloc_msg_nix_bp_enable(mbox);
+		if (req == NULL)
+			return rc;
+		req->chan_base = 0;
+		req->chan_cnt = 1;
+		req->bpid_per_chan = 0;
+
+		rc = mbox_process_msg(mbox, (void *)&rsp);
+		if (rc || (req->chan_cnt != rsp->chan_cnt))
+			goto exit;
+
+		nix->bpid[0] = rsp->chan_bpid[0];
+		nix->chan_cnt = rsp->chan_cnt;
+	} else {
+		req = mbox_alloc_msg_nix_bp_disable(mbox);
+		if (req == NULL)
+			return rc;
+		req->chan_base = 0;
+		req->chan_cnt = 1;
+
+		rc = mbox_process(mbox);
+		if (rc)
+			goto exit;
+
+		memset(nix->bpid, 0, sizeof(uint16_t) * NIX_MAX_CHAN);
+		nix->chan_cnt = 0;
+	}
+
+exit:
+	return rc;
+}
+
+static int
+nix_fc_cq_config_get(struct roc_nix *roc_nix, struct roc_nix_fc_cfg *fc_cfg)
+{
+	struct mbox *mbox = get_mbox(roc_nix);
+	struct nix_aq_enq_rsp *rsp;
+	int rc;
+
+	if (roc_model_is_cn9k()) {
+		struct nix_aq_enq_req *aq;
+
+		aq = mbox_alloc_msg_nix_aq_enq(mbox);
+		aq->qidx = fc_cfg->cq_cfg.rq;
+		aq->ctype = NIX_AQ_CTYPE_CQ;
+		aq->op = NIX_AQ_INSTOP_READ;
+	} else {
+		struct nix_cn10k_aq_enq_req *aq;
+
+		aq = mbox_alloc_msg_nix_cn10k_aq_enq(mbox);
+		aq->qidx = fc_cfg->cq_cfg.rq;
+		aq->ctype = NIX_AQ_CTYPE_CQ;
+		aq->op = NIX_AQ_INSTOP_READ;
+	}
+
+	rc = mbox_process_msg(mbox, (void *)&rsp);
+	if (rc)
+		goto exit;
+
+	fc_cfg->cq_cfg.cq_drop = rsp->cq.bp;
+	fc_cfg->cq_cfg.enable = rsp->cq.bp_ena;
+	fc_cfg->cq_cfg_valid = true;
+
+exit:
+	return rc;
+}
+
+static int
+nix_fc_cq_config_set(struct roc_nix *roc_nix, struct roc_nix_fc_cfg *fc_cfg)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct mbox *mbox = get_mbox(roc_nix);
+
+	if (roc_model_is_cn9k()) {
+		struct nix_aq_enq_req *aq;
+
+		aq = mbox_alloc_msg_nix_aq_enq(mbox);
+		aq->qidx = fc_cfg->cq_cfg.rq;
+		aq->ctype = NIX_AQ_CTYPE_CQ;
+		aq->op = NIX_AQ_INSTOP_WRITE;
+
+		if (fc_cfg->cq_cfg.enable) {
+			aq->cq.bpid = nix->bpid[0];
+			aq->cq_mask.bpid = ~(aq->cq_mask.bpid);
+			aq->cq.bp = fc_cfg->cq_cfg.cq_drop;
+			aq->cq_mask.bp = ~(aq->cq_mask.bp);
+		}
+
+		aq->cq.bp_ena = !!(fc_cfg->cq_cfg.enable);
+		aq->cq_mask.bp_ena = ~(aq->cq_mask.bp_ena);
+	} else {
+		struct nix_cn10k_aq_enq_req *aq;
+
+		aq = mbox_alloc_msg_nix_cn10k_aq_enq(mbox);
+		aq->qidx = fc_cfg->cq_cfg.rq;
+		aq->ctype = NIX_AQ_CTYPE_CQ;
+		aq->op = NIX_AQ_INSTOP_WRITE;
+
+		if (fc_cfg->cq_cfg.enable) {
+			aq->cq.bpid = nix->bpid[0];
+			aq->cq_mask.bpid = ~(aq->cq_mask.bpid);
+			aq->cq.bp = fc_cfg->cq_cfg.cq_drop;
+			aq->cq_mask.bp = ~(aq->cq_mask.bp);
+		}
+
+		aq->cq.bp_ena = !!(fc_cfg->cq_cfg.enable);
+		aq->cq_mask.bp_ena = ~(aq->cq_mask.bp_ena);
+	}
+
+	return mbox_process(mbox);
+}
+
+int
+roc_nix_fc_config_get(struct roc_nix *roc_nix, struct roc_nix_fc_cfg *fc_cfg)
+{
+	if (roc_nix_is_vf_or_sdp(roc_nix))
+		return 0;
+
+	if (fc_cfg->cq_cfg_valid)
+		return nix_fc_cq_config_get(roc_nix, fc_cfg);
+	else
+		return nix_fc_rxchan_bpid_get(roc_nix, fc_cfg);
+}
+
+int
+roc_nix_fc_config_set(struct roc_nix *roc_nix, struct roc_nix_fc_cfg *fc_cfg)
+{
+	if (roc_nix_is_vf_or_sdp(roc_nix))
+		return 0;
+
+	if (fc_cfg->cq_cfg_valid)
+		return nix_fc_cq_config_set(roc_nix, fc_cfg);
+	else
+		return nix_fc_rxchan_bpid_set(roc_nix,
+					      fc_cfg->rxchan_cfg.enable);
+}
+
+enum roc_nix_fc_mode
+roc_nix_fc_mode_get(struct roc_nix *roc_nix)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct mbox *mbox = get_mbox(roc_nix);
+	struct cgx_pause_frm_cfg *req, *rsp;
+	enum roc_nix_fc_mode mode;
+	int rc = -ENOSPC;
+
+	if (roc_nix_is_lbk(roc_nix))
+		return ROC_NIX_FC_NONE;
+
+	req = mbox_alloc_msg_cgx_cfg_pause_frm(mbox);
+	if (req == NULL)
+		return rc;
+	req->set = 0;
+
+	rc = mbox_process_msg(mbox, (void *)&rsp);
+	if (rc)
+		goto exit;
+
+	if (rsp->rx_pause && rsp->tx_pause)
+		mode = ROC_NIX_FC_FULL;
+	else if (rsp->rx_pause)
+		mode = ROC_NIX_FC_RX;
+	else if (rsp->tx_pause)
+		mode = ROC_NIX_FC_TX;
+	else
+		mode = ROC_NIX_FC_NONE;
+
+	nix->rx_pause = rsp->rx_pause;
+	nix->tx_pause = rsp->tx_pause;
+	return mode;
+
+exit:
+	return ROC_NIX_FC_NONE;
+}
+
+int
+roc_nix_fc_mode_set(struct roc_nix *roc_nix, enum roc_nix_fc_mode mode)
+{
+	struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+	struct mbox *mbox = get_mbox(roc_nix);
+	struct cgx_pause_frm_cfg *req;
+	uint8_t tx_pause, rx_pause;
+	int rc = -ENOSPC;
+
+	if (roc_nix_is_lbk(roc_nix))
+		return NIX_ERR_OP_NOTSUP;
+
+	rx_pause = (mode == ROC_NIX_FC_FULL) || (mode == ROC_NIX_FC_RX);
+	tx_pause = (mode == ROC_NIX_FC_FULL) || (mode == ROC_NIX_FC_TX);
+
+	req = mbox_alloc_msg_cgx_cfg_pause_frm(mbox);
+	if (req == NULL)
+		return rc;
+	req->set = 1;
+	req->rx_pause = rx_pause;
+	req->tx_pause = tx_pause;
+
+	rc = mbox_process(mbox);
+	if (rc)
+		goto exit;
+
+	nix->rx_pause = rx_pause;
+	nix->tx_pause = tx_pause;
+
+exit:
+	return rc;
+}
diff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map
index 5e90129..48182a0 100644
--- a/drivers/common/cnxk/version.map
+++ b/drivers/common/cnxk/version.map
@@ -21,6 +21,10 @@ INTERNAL {
 	roc_nix_dev_init;
 	roc_nix_dump;
 	roc_nix_err_intr_ena_dis;
+	roc_nix_fc_config_get;
+	roc_nix_fc_config_set;
+	roc_nix_fc_mode_set;
+	roc_nix_fc_mode_get;
 	roc_nix_get_base_chan;
 	roc_nix_get_pf;
 	roc_nix_get_pf_func;
-- 
2.8.4



More information about the dev mailing list