[7/8] net/octeontx: add flow control support
Checks
Commit Message
From: Vamsi Attunuru <vattunuru@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@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(+)
Comments
On Mon, Mar 16, 2020 at 03:03:43PM +0530, Harman Kalra wrote:
> From: Vamsi Attunuru <vattunuru@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@marvell.com>
Acked-by: Harman Kalra <hkalra@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
>
@@ -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
@@ -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;
+}
@@ -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__ */
@@ -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,
@@ -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__ */
@@ -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);
+}