[dpdk-dev] [PATCH 7/8] net/octeontx: add flow control support

Harman Kalra hkalra at marvell.com
Mon Mar 16 10:33:43 CET 2020


From: Vamsi Attunuru <vattunuru at marvell.com>

Patch adds ethdev flow control set/get callback ops,
pmd enables modifying flow control attributes like
rx_pause, tx_pause, high & low water mark.

Signed-off-by: Vamsi Attunuru <vattunuru at marvell.com>
---
 doc/guides/nics/features/octeontx.ini      |   1 +
 drivers/net/octeontx/base/octeontx_bgx.c   |  50 ++++++++
 drivers/net/octeontx/base/octeontx_bgx.h   |  28 +++++
 drivers/net/octeontx/octeontx_ethdev.c     |  20 ++++
 drivers/net/octeontx/octeontx_ethdev.h     |  19 +++
 drivers/net/octeontx/octeontx_ethdev_ops.c | 128 +++++++++++++++++++++
 6 files changed, 246 insertions(+)

diff --git a/doc/guides/nics/features/octeontx.ini b/doc/guides/nics/features/octeontx.ini
index 377bb4d30..6049c1c43 100644
--- a/doc/guides/nics/features/octeontx.ini
+++ b/doc/guides/nics/features/octeontx.ini
@@ -18,6 +18,7 @@ VLAN filter          = Y
 VLAN offload         = P
 CRC offload          = Y
 Packet type parsing  = Y
+Flow control         = Y
 Basic stats          = Y
 Linux VFIO           = Y
 ARMv8                = Y
diff --git a/drivers/net/octeontx/base/octeontx_bgx.c b/drivers/net/octeontx/base/octeontx_bgx.c
index d8611cb77..ac856ff86 100644
--- a/drivers/net/octeontx/base/octeontx_bgx.c
+++ b/drivers/net/octeontx/base/octeontx_bgx.c
@@ -326,3 +326,53 @@ octeontx_bgx_port_mac_entries_get(int port)
 
 	return resp;
 }
+
+int octeontx_bgx_port_get_fifo_cfg(int port,
+				   octeontx_mbox_bgx_port_fifo_cfg_t *cfg)
+{
+	int len = sizeof(octeontx_mbox_bgx_port_fifo_cfg_t);
+	octeontx_mbox_bgx_port_fifo_cfg_t conf;
+	struct octeontx_mbox_hdr hdr;
+
+	hdr.coproc = OCTEONTX_BGX_COPROC;
+	hdr.msg = MBOX_BGX_PORT_GET_FIFO_CFG;
+	hdr.vfid = port;
+
+	if (octeontx_mbox_send(&hdr, NULL, 0, &conf, len) < 0)
+		return -EACCES;
+
+	cfg->rx_fifosz = conf.rx_fifosz;
+
+	return 0;
+}
+
+int octeontx_bgx_port_flow_ctrl_cfg(int port,
+				    octeontx_mbox_bgx_port_fc_cfg_t *cfg)
+{
+	int len = sizeof(octeontx_mbox_bgx_port_fc_cfg_t);
+	octeontx_mbox_bgx_port_fc_cfg_t conf;
+	struct octeontx_mbox_hdr hdr;
+
+	hdr.coproc = OCTEONTX_BGX_COPROC;
+	hdr.msg = MBOX_BGX_PORT_FLOW_CTRL_CFG;
+	hdr.vfid = port;
+
+	if (cfg->fc_cfg == BGX_PORT_FC_CFG_SET)
+		memcpy(&conf, cfg, len);
+	else
+		memset(&conf, 0, len);
+
+	if (octeontx_mbox_send(&hdr, &conf, len, &conf, len) < 0)
+		return -EACCES;
+
+	if (cfg->fc_cfg == BGX_PORT_FC_CFG_SET)
+		goto done;
+
+	cfg->rx_pause = conf.rx_pause;
+	cfg->tx_pause = conf.tx_pause;
+	cfg->low_water = conf.low_water;
+	cfg->high_water = conf.high_water;
+
+done:
+	return 0;
+}
diff --git a/drivers/net/octeontx/base/octeontx_bgx.h b/drivers/net/octeontx/base/octeontx_bgx.h
index 6b7476510..d126a0b7f 100644
--- a/drivers/net/octeontx/base/octeontx_bgx.h
+++ b/drivers/net/octeontx/base/octeontx_bgx.h
@@ -11,6 +11,8 @@
 
 #include <octeontx_mbox.h>
 
+#define OCTEONTX_BGX_RSVD_RX_FIFOBYTES	0x40
+
 #define OCTEONTX_BGX_COPROC	        6
 
 /* BGX messages */
@@ -32,6 +34,8 @@
 #define MBOX_BGX_PORT_ADD_MACADDR	15
 #define MBOX_BGX_PORT_DEL_MACADDR	16
 #define MBOX_BGX_PORT_GET_MACADDR_ENTRIES 17
+#define MBOX_BGX_PORT_GET_FIFO_CFG	18
+#define MBOX_BGX_PORT_FLOW_CTRL_CFG	19
 #define MBOX_BGX_PORT_SET_LINK_STATE	20
 
 /* BGX port configuration parameters: */
@@ -119,6 +123,26 @@ struct octeontx_mbox_bgx_port_mac_filter {
 	int index;
 };
 
+/* BGX port fifo config: */
+typedef struct octeontx_mbox_bgx_port_fifo_cfg {
+	uint32_t rx_fifosz; /* in Bytes */
+} octeontx_mbox_bgx_port_fifo_cfg_t;
+
+typedef enum {
+	BGX_PORT_FC_CFG_GET = 0,
+	BGX_PORT_FC_CFG_SET = 1
+} bgx_port_fc_t;
+
+/* BGX port flow control config: */
+typedef struct octeontx_mbox_bgx_port_fc_cfg {
+	/* BP on/off threshold levels in Bytes, must be a multiple of 16 */
+	uint16_t high_water;
+	uint16_t low_water;
+	uint8_t rx_pause; /* rx_pause = 1/0 to enable/disable fc on Tx */
+	uint8_t tx_pause; /* tx_pause = 1/0 to enable/disable fc on Rx */
+	bgx_port_fc_t fc_cfg;
+} octeontx_mbox_bgx_port_fc_cfg_t;
+
 int octeontx_bgx_port_open(int port, octeontx_mbox_bgx_port_conf_t *conf);
 int octeontx_bgx_port_close(int port);
 int octeontx_bgx_port_start(int port);
@@ -135,6 +159,10 @@ int octeontx_bgx_port_mac_del(int port, uint32_t index);
 int octeontx_bgx_port_mac_entries_get(int port);
 int octeontx_bgx_port_mtu_set(int port, int mtu);
 int octeontx_bgx_port_set_link_state(int port, bool en);
+int octeontx_bgx_port_get_fifo_cfg(int port,
+				   octeontx_mbox_bgx_port_fifo_cfg_t *cfg);
+int octeontx_bgx_port_flow_ctrl_cfg(int port,
+				    octeontx_mbox_bgx_port_fc_cfg_t *cfg);
 
 #endif	/* __OCTEONTX_BGX_H__ */
 
diff --git a/drivers/net/octeontx/octeontx_ethdev.c b/drivers/net/octeontx/octeontx_ethdev.c
index 08c621b4b..191869683 100644
--- a/drivers/net/octeontx/octeontx_ethdev.c
+++ b/drivers/net/octeontx/octeontx_ethdev.c
@@ -122,6 +122,7 @@ static int
 octeontx_port_open(struct octeontx_nic *nic)
 {
 	octeontx_mbox_bgx_port_conf_t bgx_port_conf;
+	octeontx_mbox_bgx_port_fifo_cfg_t fifo_cfg;
 	int res;
 
 	res = 0;
@@ -147,6 +148,16 @@ octeontx_port_open(struct octeontx_nic *nic)
 	nic->mcast_mode = bgx_port_conf.mcast_mode;
 	nic->speed	= bgx_port_conf.mode;
 
+	memset(&fifo_cfg, 0x0, sizeof(fifo_cfg));
+
+	res = octeontx_bgx_port_get_fifo_cfg(nic->port_id, &fifo_cfg);
+	if (res < 0) {
+		octeontx_log_err("failed to get port %d fifo cfg", res);
+		return res;
+	}
+
+	nic->fc.rx_fifosz = fifo_cfg.rx_fifosz;
+
 	memcpy(&nic->mac_addr[0], &bgx_port_conf.macaddr[0],
 		RTE_ETHER_ADDR_LEN);
 
@@ -482,6 +493,8 @@ octeontx_dev_close(struct rte_eth_dev *dev)
 
 	rte_event_dev_close(nic->evdev);
 
+	octeontx_dev_flow_ctrl_fini(dev);
+
 	octeontx_dev_vlan_offload_fini(dev);
 
 	ret = octeontx_pko_channel_close(nic->base_ochan);
@@ -1208,6 +1221,7 @@ octeontx_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qidx,
 	octeontx_recheck_rx_offloads(rxq);
 	dev->data->rx_queues[qidx] = rxq;
 	dev->data->rx_queue_state[qidx] = RTE_ETH_QUEUE_STATE_STOPPED;
+
 	return 0;
 }
 
@@ -1276,6 +1290,8 @@ static const struct eth_dev_ops octeontx_dev_ops = {
 	.dev_supported_ptypes_get = octeontx_dev_supported_ptypes_get,
 	.mtu_set                 = octeontx_dev_mtu_set,
 	.pool_ops_supported      = octeontx_pool_ops,
+	.flow_ctrl_get           = octeontx_dev_flow_ctrl_get,
+	.flow_ctrl_set           = octeontx_dev_flow_ctrl_set,
 };
 
 /* Create Ethdev interface per BGX LMAC ports */
@@ -1407,6 +1423,10 @@ octeontx_create(struct rte_vdev_device *dev, int port, uint8_t evdev,
 	/* Update same mac address to BGX CAM table at index 0 */
 	octeontx_bgx_port_mac_add(nic->port_id, nic->mac_addr, 0);
 
+	res = octeontx_dev_flow_ctrl_init(eth_dev);
+	if (res < 0)
+		goto err;
+
 	PMD_INIT_LOG(DEBUG, "ethdev info: ");
 	PMD_INIT_LOG(DEBUG, "port %d, port_ena %d ochan %d num_ochan %d tx_q %d",
 				nic->port_id, nic->port_ena,
diff --git a/drivers/net/octeontx/octeontx_ethdev.h b/drivers/net/octeontx/octeontx_ethdev.h
index 186a044f7..dc53b53be 100644
--- a/drivers/net/octeontx/octeontx_ethdev.h
+++ b/drivers/net/octeontx/octeontx_ethdev.h
@@ -83,6 +83,16 @@ struct octeontx_vlan_info {
 	uint8_t filter_on;
 };
 
+struct octeontx_fc_info {
+	enum rte_eth_fc_mode mode;  /**< Link flow control mode */
+	enum rte_eth_fc_mode def_mode;
+	uint16_t high_water;
+	uint16_t low_water;
+	uint16_t def_highmark;
+	uint16_t def_lowmark;
+	uint32_t rx_fifosz;
+};
+
 /* Octeontx ethdev nic */
 struct octeontx_nic {
 	struct rte_eth_dev *dev;
@@ -122,6 +132,7 @@ struct octeontx_nic {
 	uint16_t tx_offload_flags;
 	struct octeontx_vlan_info vlan_info;
 	int print_flag;
+	struct octeontx_fc_info fc;
 } __rte_cache_aligned;
 
 struct octeontx_txq {
@@ -154,4 +165,12 @@ int octeontx_dev_vlan_filter_set(struct rte_eth_dev *dev,
 int octeontx_dev_set_link_up(struct rte_eth_dev *eth_dev);
 int octeontx_dev_set_link_down(struct rte_eth_dev *eth_dev);
 
+/* Flow control */
+int octeontx_dev_flow_ctrl_init(struct rte_eth_dev *dev);
+int octeontx_dev_flow_ctrl_fini(struct rte_eth_dev *dev);
+int octeontx_dev_flow_ctrl_get(struct rte_eth_dev *dev,
+			       struct rte_eth_fc_conf *fc_conf);
+int octeontx_dev_flow_ctrl_set(struct rte_eth_dev *dev,
+			       struct rte_eth_fc_conf *fc_conf);
+
 #endif /* __OCTEONTX_ETHDEV_H__ */
diff --git a/drivers/net/octeontx/octeontx_ethdev_ops.c b/drivers/net/octeontx/octeontx_ethdev_ops.c
index b5f0bfe8a..ff627a68e 100644
--- a/drivers/net/octeontx/octeontx_ethdev_ops.c
+++ b/drivers/net/octeontx/octeontx_ethdev_ops.c
@@ -213,3 +213,131 @@ octeontx_dev_set_link_down(struct rte_eth_dev *eth_dev)
 
 	return octeontx_bgx_port_set_link_state(nic->port_id, false);
 }
+
+int
+octeontx_dev_flow_ctrl_get(struct rte_eth_dev *dev,
+			   struct rte_eth_fc_conf *fc_conf)
+{
+	struct octeontx_nic *nic = octeontx_pmd_priv(dev);
+	octeontx_mbox_bgx_port_fc_cfg_t conf;
+	int rc;
+
+	memset(&conf, 0, sizeof(octeontx_mbox_bgx_port_fc_cfg_t));
+
+	rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
+	if (rc)
+		return rc;
+
+	if (conf.rx_pause && conf.tx_pause)
+		fc_conf->mode = RTE_FC_FULL;
+	else if (conf.rx_pause)
+		fc_conf->mode = RTE_FC_RX_PAUSE;
+	else if (conf.tx_pause)
+		fc_conf->mode = RTE_FC_TX_PAUSE;
+	else
+		fc_conf->mode = RTE_FC_NONE;
+
+	/* low_water & high_water values are in Bytes */
+	fc_conf->low_water = conf.low_water;
+	fc_conf->high_water = conf.high_water;
+
+	return rc;
+}
+
+int
+octeontx_dev_flow_ctrl_set(struct rte_eth_dev *dev,
+			   struct rte_eth_fc_conf *fc_conf)
+{
+	struct octeontx_nic *nic = octeontx_pmd_priv(dev);
+	struct octeontx_fc_info *fc = &nic->fc;
+	octeontx_mbox_bgx_port_fc_cfg_t conf;
+	uint8_t tx_pause, rx_pause;
+	uint16_t max_high_water;
+	int rc;
+
+	if (fc_conf->pause_time || fc_conf->mac_ctrl_frame_fwd ||
+	    fc_conf->autoneg) {
+		octeontx_log_err("Below flowctrl parameters are not supported "
+				 "pause_time, mac_ctrl_frame_fwd and autoneg");
+		return -EINVAL;
+	}
+
+	if (fc_conf->high_water == fc->high_water &&
+	    fc_conf->low_water == fc->low_water &&
+	    fc_conf->mode == fc->mode)
+		return 0;
+
+	max_high_water = fc->rx_fifosz - OCTEONTX_BGX_RSVD_RX_FIFOBYTES;
+
+	if (fc_conf->high_water > max_high_water ||
+	    fc_conf->high_water < fc_conf->low_water) {
+		octeontx_log_err("Invalid high/low water values "
+				 "High_water(in Bytes) must <= 0x%x ",
+				 max_high_water);
+		return -EINVAL;
+	}
+
+	if (fc_conf->high_water % BIT(4) || fc_conf->low_water % BIT(4)) {
+		octeontx_log_err("High/low water value must be multiple of 16");
+		return -EINVAL;
+	}
+
+	rx_pause = (fc_conf->mode == RTE_FC_FULL) ||
+			(fc_conf->mode == RTE_FC_RX_PAUSE);
+	tx_pause = (fc_conf->mode == RTE_FC_FULL) ||
+			(fc_conf->mode == RTE_FC_TX_PAUSE);
+
+	conf.high_water = fc_conf->high_water;
+	conf.low_water = fc_conf->low_water;
+	conf.fc_cfg = BGX_PORT_FC_CFG_SET;
+	conf.rx_pause = rx_pause;
+	conf.tx_pause = tx_pause;
+
+	rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
+	if (rc)
+		return rc;
+
+	fc->high_water = fc_conf->high_water;
+	fc->low_water = fc_conf->low_water;
+	fc->mode = fc_conf->mode;
+
+	return rc;
+}
+
+int
+octeontx_dev_flow_ctrl_init(struct rte_eth_dev *dev)
+{
+	struct octeontx_nic *nic = octeontx_pmd_priv(dev);
+	struct octeontx_fc_info *fc = &nic->fc;
+	struct rte_eth_fc_conf fc_conf;
+	int rc;
+
+	rc = octeontx_dev_flow_ctrl_get(dev, &fc_conf);
+	if (rc) {
+		octeontx_log_err("Failed to get flow control info");
+		return rc;
+	}
+
+	fc->def_highmark = fc_conf.high_water;
+	fc->def_lowmark = fc_conf.low_water;
+	fc->def_mode = fc_conf.mode;
+
+	return rc;
+}
+
+int
+octeontx_dev_flow_ctrl_fini(struct rte_eth_dev *dev)
+{
+	struct octeontx_nic *nic = octeontx_pmd_priv(dev);
+	struct octeontx_fc_info *fc = &nic->fc;
+	struct rte_eth_fc_conf fc_conf;
+
+	memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf));
+
+	/* Restore flow control parameters with default values */
+	fc_conf.high_water = fc->def_highmark;
+	fc_conf.low_water = fc->def_lowmark;
+	fc_conf.mode = fc->def_mode;
+
+	return octeontx_dev_flow_ctrl_set(dev, &fc_conf);
+}
-- 
2.18.0



More information about the dev mailing list