From: Vanshika Shukla <vanshika.shu...@nxp.com>

This patch add support for link update operation.

Signed-off-by: Vanshika Shukla <vanshika.shu...@nxp.com>
Signed-off-by: Gagandeep Singh <g.si...@nxp.com>
---
 doc/guides/nics/features/enetc4.ini |   2 +
 drivers/net/enetc/base/enetc4_hw.h  |   9 ++
 drivers/net/enetc/enetc.h           |  25 ++++
 drivers/net/enetc/enetc4_ethdev.c   |  44 ++++++
 drivers/net/enetc/enetc4_vf.c       | 216 ++++++++++++++++++++++++++++
 5 files changed, 296 insertions(+)

diff --git a/doc/guides/nics/features/enetc4.ini 
b/doc/guides/nics/features/enetc4.ini
index 36d536d1f2..78b06e9841 100644
--- a/doc/guides/nics/features/enetc4.ini
+++ b/doc/guides/nics/features/enetc4.ini
@@ -4,6 +4,8 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Speed capabilities   = Y
+Link status          = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
 RSS hash             = Y
diff --git a/drivers/net/enetc/base/enetc4_hw.h 
b/drivers/net/enetc/base/enetc4_hw.h
index f0b7563d22..d899b82b9c 100644
--- a/drivers/net/enetc/base/enetc4_hw.h
+++ b/drivers/net/enetc/base/enetc4_hw.h
@@ -109,6 +109,15 @@ struct enetc_msg_swbd {
 #define IFMODE_SGMII                   5
 #define PM_IF_MODE_ENA                 BIT(15)
 
+/* Port MAC 0 Interface Status Register */
+#define ENETC4_PM_IF_STATUS(mac)       (0x5304 + (mac) * 0x400)
+#define ENETC4_LINK_MODE                 0x0000000000080000ULL
+#define ENETC4_LINK_STATUS               0x0000000000010000ULL
+#define ENETC4_LINK_SPEED_MASK           0x0000000000060000ULL
+#define ENETC4_LINK_SPEED_10M            0x0ULL
+#define ENETC4_LINK_SPEED_100M           0x0000000000020000ULL
+#define ENETC4_LINK_SPEED_1G             0x0000000000040000ULL
+
 #define ENETC4_DEF_VSI_WAIT_TIMEOUT_UPDATE     100
 #define ENETC4_DEF_VSI_WAIT_DELAY_UPDATE       2000 /* us */
 
diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h
index 902912f4fb..7f5329de33 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -151,6 +151,8 @@ struct enetc_eth_adapter {
 enum enetc_msg_cmd_class_id {
        ENETC_CLASS_ID_MAC_FILTER = 0x20,
        ENETC_CLASS_ID_VLAN_FILTER = 0x21,
+       ENETC_CLASS_ID_LINK_STATUS = 0x80,
+       ENETC_CLASS_ID_LINK_SPEED = 0x81
 };
 
 /* Enum for command IDs */
@@ -158,6 +160,8 @@ enum enetc_msg_cmd_id {
        ENETC_CMD_ID_SET_PRIMARY_MAC = 0,
        ENETC_CMD_ID_SET_MAC_PROMISCUOUS = 5,
        ENETC_CMD_ID_SET_VLAN_PROMISCUOUS = 4,
+       ENETC_CMD_ID_GET_LINK_STATUS = 0,
+       ENETC_CMD_ID_GET_LINK_SPEED = 0
 };
 
 enum mac_addr_status {
@@ -166,6 +170,27 @@ enum mac_addr_status {
        ENETC_MAC_ADDR_NOT_FOUND = 0X2,
 };
 
+enum link_status {
+       ENETC_LINK_UP = 0x0,
+       ENETC_LINK_DOWN = 0x1
+};
+
+enum speed {
+       ENETC_SPEED_UNKNOWN = 0x0,
+       ENETC_SPEED_10_HALF_DUPLEX = 0x1,
+       ENETC_SPEED_10_FULL_DUPLEX = 0x2,
+       ENETC_SPEED_100_HALF_DUPLEX = 0x3,
+       ENETC_SPEED_100_FULL_DUPLEX = 0x4,
+       ENETC_SPEED_1000 = 0x5,
+       ENETC_SPEED_2500 = 0x6,
+       ENETC_SPEED_5000 = 0x7,
+       ENETC_SPEED_10G = 0x8,
+       ENETC_SPEED_25G = 0x9,
+       ENETC_SPEED_50G = 0xA,
+       ENETC_SPEED_100G = 0xB,
+       ENETC_SPEED_NOT_SUPPORTED = 0xF
+};
+
 /* PSI-VSI command header format */
 struct enetc_msg_cmd_header {
        uint16_t csum;          /* INET_CHECKSUM */
diff --git a/drivers/net/enetc/enetc4_ethdev.c 
b/drivers/net/enetc/enetc4_ethdev.c
index 9df01b1e4d..29283f2d44 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -75,6 +75,49 @@ enetc4_dev_stop(struct rte_eth_dev *dev)
        return 0;
 }
 
+/* return 0 means link status changed, -1 means not changed */
+static int
+enetc4_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+       struct enetc_eth_hw *hw =
+               ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct enetc_hw *enetc_hw = &hw->hw;
+       struct rte_eth_link link;
+       uint32_t status;
+
+       PMD_INIT_FUNC_TRACE();
+
+       memset(&link, 0, sizeof(link));
+
+       status = enetc4_port_rd(enetc_hw, ENETC4_PM_IF_STATUS(0));
+
+       if (status & ENETC4_LINK_MODE)
+               link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+       else
+               link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+
+       if (status & ENETC4_LINK_STATUS)
+               link.link_status = RTE_ETH_LINK_UP;
+       else
+               link.link_status = RTE_ETH_LINK_DOWN;
+
+       switch (status & ENETC4_LINK_SPEED_MASK) {
+       case ENETC4_LINK_SPEED_1G:
+               link.link_speed = RTE_ETH_SPEED_NUM_1G;
+               break;
+
+       case ENETC4_LINK_SPEED_100M:
+               link.link_speed = RTE_ETH_SPEED_NUM_100M;
+               break;
+
+       default:
+       case ENETC4_LINK_SPEED_10M:
+               link.link_speed = RTE_ETH_SPEED_NUM_10M;
+       }
+
+       return rte_eth_linkstatus_set(dev, &link);
+}
+
 static int
 enetc4_mac_init(struct enetc_eth_hw *hw, struct rte_eth_dev *eth_dev)
 {
@@ -867,6 +910,7 @@ static const struct eth_dev_ops enetc4_ops = {
        .dev_stop             = enetc4_dev_stop,
        .dev_close            = enetc4_dev_close,
        .dev_infos_get        = enetc4_dev_infos_get,
+       .link_update          = enetc4_link_update,
        .stats_get            = enetc4_stats_get,
        .stats_reset          = enetc4_stats_reset,
        .promiscuous_enable   = enetc4_promiscuous_enable,
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index 28cf83077c..307fabf2c6 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -206,6 +206,8 @@ enetc4_msg_vsi_send(struct enetc_hw *enetc_hw, struct 
enetc_msg_swbd *msg)
                        err = -EINVAL;
                        break;
                case ENETC_CLASS_ID_MAC_FILTER:
+               case ENETC_CLASS_ID_LINK_STATUS:
+               case ENETC_CLASS_ID_LINK_SPEED:
                        break;
                default:
                        err = -EIO;
@@ -479,6 +481,216 @@ enetc4_vf_promisc_disable(struct rte_eth_dev *dev)
        return 0;
 }
 
+static int
+enetc4_vf_get_link_status(struct rte_eth_dev *dev, struct enetc_psi_reply_msg 
*reply_msg)
+{
+       struct enetc_eth_hw *hw = 
ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct enetc_hw *enetc_hw = &hw->hw;
+       struct enetc_msg_swbd *msg;
+       int msg_size;
+       int err = 0;
+
+       msg = rte_zmalloc(NULL, sizeof(*msg), RTE_CACHE_LINE_SIZE);
+       if (!msg) {
+               ENETC_PMD_ERR("Failed to alloc msg");
+               err = -ENOMEM;
+               return err;
+       }
+
+       msg_size = RTE_ALIGN(sizeof(struct enetc_msg_cmd_get_link_status),
+                       ENETC_VSI_PSI_MSG_SIZE);
+       msg->vaddr = rte_zmalloc(NULL, msg_size, 0);
+       if (!msg->vaddr) {
+               ENETC_PMD_ERR("Failed to alloc memory for msg");
+               rte_free(msg);
+               return -ENOMEM;
+       }
+
+       msg->dma = rte_mem_virt2iova((const void *)msg->vaddr);
+       msg->size = msg_size;
+
+       enetc_msg_vf_fill_common_hdr(msg, ENETC_CLASS_ID_LINK_STATUS,
+                       ENETC_CMD_ID_GET_LINK_STATUS, 0, 0, 0);
+
+       /* send the command and wait */
+       err = enetc4_msg_vsi_send(enetc_hw, msg);
+       if (err) {
+               ENETC_PMD_ERR("VSI message send error");
+               goto end;
+       }
+
+       enetc4_msg_vsi_reply_msg(enetc_hw, reply_msg);
+end:
+       /* free memory no longer required */
+       rte_free(msg->vaddr);
+       rte_free(msg);
+       return err;
+}
+
+static int
+enetc4_vf_get_link_speed(struct rte_eth_dev *dev, struct enetc_psi_reply_msg 
*reply_msg)
+{
+       struct enetc_eth_hw *hw = 
ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct enetc_hw *enetc_hw = &hw->hw;
+       struct enetc_msg_swbd *msg;
+       int msg_size;
+       int err = 0;
+
+       msg = rte_zmalloc(NULL, sizeof(*msg), RTE_CACHE_LINE_SIZE);
+       if (!msg) {
+               ENETC_PMD_ERR("Failed to alloc msg");
+               err = -ENOMEM;
+               return err;
+       }
+
+       msg_size = RTE_ALIGN(sizeof(struct enetc_msg_cmd_get_link_speed),
+                               ENETC_VSI_PSI_MSG_SIZE);
+       msg->vaddr = rte_zmalloc(NULL, msg_size, 0);
+       if (!msg->vaddr) {
+               ENETC_PMD_ERR("Failed to alloc memory for msg");
+               rte_free(msg);
+               return -ENOMEM;
+       }
+
+       msg->dma = rte_mem_virt2iova((const void *)msg->vaddr);
+       msg->size = msg_size;
+
+       enetc_msg_vf_fill_common_hdr(msg, ENETC_CLASS_ID_LINK_SPEED,
+                       ENETC_CMD_ID_GET_LINK_SPEED, 0, 0, 0);
+
+       /* send the command and wait */
+       err = enetc4_msg_vsi_send(enetc_hw, msg);
+       if (err) {
+               ENETC_PMD_ERR("VSI message send error");
+               goto end;
+       }
+
+       enetc4_msg_vsi_reply_msg(enetc_hw, reply_msg);
+end:
+       /* free memory no longer required */
+       rte_free(msg->vaddr);
+       rte_free(msg);
+       return err;
+}
+
+static int
+enetc4_vf_link_update(struct rte_eth_dev *dev, int wait_to_complete 
__rte_unused)
+{
+       struct enetc_psi_reply_msg *reply_msg;
+       struct rte_eth_link link;
+       int err;
+
+       PMD_INIT_FUNC_TRACE();
+       reply_msg = rte_zmalloc(NULL, sizeof(*reply_msg), RTE_CACHE_LINE_SIZE);
+       if (!reply_msg) {
+               ENETC_PMD_ERR("Failed to alloc memory for reply_msg");
+               return -ENOMEM;
+       }
+
+       memset(&link, 0, sizeof(struct rte_eth_link));
+
+       err = enetc4_vf_get_link_status(dev, reply_msg);
+       if (err) {
+               ENETC_PMD_ERR("Failed to get link status");
+               rte_free(reply_msg);
+               return err;
+       }
+
+       if (reply_msg->class_id == ENETC_CLASS_ID_LINK_STATUS) {
+               switch (reply_msg->status) {
+               case ENETC_LINK_UP:
+                       link.link_status = RTE_ETH_LINK_UP;
+                       break;
+               case ENETC_LINK_DOWN:
+                       link.link_status = RTE_ETH_LINK_DOWN;
+                       break;
+               default:
+                       ENETC_PMD_ERR("Unknown link status");
+                       break;
+               }
+       } else {
+               ENETC_PMD_ERR("Wrong reply message");
+               return -1;
+       }
+
+       err = enetc4_vf_get_link_speed(dev, reply_msg);
+       if (err) {
+               ENETC_PMD_ERR("Failed to get link speed");
+               rte_free(reply_msg);
+               return err;
+       }
+
+       if (reply_msg->class_id == ENETC_CLASS_ID_LINK_SPEED) {
+               switch (reply_msg->status) {
+               case ENETC_SPEED_UNKNOWN:
+                       ENETC_PMD_DEBUG("Speed unknown");
+                       link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+                       break;
+               case ENETC_SPEED_10_HALF_DUPLEX:
+                       link.link_speed = RTE_ETH_SPEED_NUM_10M;
+                       link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+                       break;
+               case ENETC_SPEED_10_FULL_DUPLEX:
+                       link.link_speed = RTE_ETH_SPEED_NUM_10M;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_100_HALF_DUPLEX:
+                       link.link_speed = RTE_ETH_SPEED_NUM_100M;
+                       link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+                       break;
+               case ENETC_SPEED_100_FULL_DUPLEX:
+                       link.link_speed = RTE_ETH_SPEED_NUM_100M;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_1000:
+                       link.link_speed = RTE_ETH_SPEED_NUM_1G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_2500:
+                       link.link_speed = RTE_ETH_SPEED_NUM_2_5G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_5000:
+                       link.link_speed = RTE_ETH_SPEED_NUM_5G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_10G:
+                       link.link_speed = RTE_ETH_SPEED_NUM_10G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_25G:
+                       link.link_speed = RTE_ETH_SPEED_NUM_25G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_50G:
+                       link.link_speed = RTE_ETH_SPEED_NUM_50G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_100G:
+                       link.link_speed = RTE_ETH_SPEED_NUM_100G;
+                       link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+                       break;
+               case ENETC_SPEED_NOT_SUPPORTED:
+                       ENETC_PMD_DEBUG("Speed not supported");
+                       link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+                       break;
+               default:
+                       ENETC_PMD_ERR("Unknown speed status");
+                       break;
+               }
+       } else {
+               ENETC_PMD_ERR("Wrong reply message");
+               return -1;
+       }
+
+       link.link_autoneg = 1;
+
+       rte_eth_linkstatus_set(dev, &link);
+
+       rte_free(reply_msg);
+       return 0;
+}
+
 static int
 enetc4_vf_vlan_promisc(struct rte_eth_dev *dev, bool promisc_en)
 {
@@ -584,6 +796,7 @@ static const struct eth_dev_ops enetc4_vf_ops = {
        .promiscuous_disable  = enetc4_vf_promisc_disable,
        .allmulticast_enable  = enetc4_vf_multicast_enable,
        .allmulticast_disable = enetc4_vf_multicast_disable,
+       .link_update          = enetc4_vf_link_update,
        .vlan_offload_set     = enetc4_vf_vlan_offload_set,
        .rx_queue_setup       = enetc4_rx_queue_setup,
        .rx_queue_start       = enetc4_rx_queue_start,
@@ -685,6 +898,9 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev)
        ENETC_PMD_DEBUG("port_id %d vendorID=0x%x deviceID=0x%x",
                        eth_dev->data->port_id, pci_dev->id.vendor_id,
                        pci_dev->id.device_id);
+       /* update link */
+       enetc4_vf_link_update(eth_dev, 0);
+
        return 0;
 }
 
-- 
2.25.1

Reply via email to