Link events signaled on new adaptors (Medford4 and later) do
not carry any specifics, so query the link status separately.

Signed-off-by: Ivan Malov <ivan.ma...@arknetworks.am>
Reviewed-by: Andy Moreton <andy.more...@amd.com>
Reviewed-by: Pieter Jansen Van Vuuren <pieter.jansen-van-vuu...@amd.com>
---
 drivers/net/sfc/sfc.h        |  2 ++
 drivers/net/sfc/sfc_ethdev.c |  2 ++
 drivers/net/sfc/sfc_ev.c     | 51 +++++++++++++++++++++++++++++++++++-
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h
index 2432a2307e..819ce52529 100644
--- a/drivers/net/sfc/sfc.h
+++ b/drivers/net/sfc/sfc.h
@@ -309,6 +309,8 @@ struct sfc_adapter {
        uint32_t                        rxd_wait_timeout_ns;
 
        bool                            switchdev;
+
+       bool                            link_ev_need_poll;
 };
 
 static inline struct sfc_adapter_shared *
diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c
index bd0061f557..05933b1d39 100644
--- a/drivers/net/sfc/sfc_ethdev.c
+++ b/drivers/net/sfc/sfc_ethdev.c
@@ -3252,6 +3252,8 @@ sfc_eth_dev_init(struct rte_eth_dev *dev, void 
*init_params)
        if (rc != 0)
                goto fail_nic_dma_attach;
 
+       sa->link_ev_need_poll = encp->enc_link_ev_need_poll;
+
        sfc_adapter_unlock(sa);
 
        sfc_log_init(sa, "done");
diff --git a/drivers/net/sfc/sfc_ev.c b/drivers/net/sfc/sfc_ev.c
index c0d58c9554..1d1ee0671f 100644
--- a/drivers/net/sfc/sfc_ev.c
+++ b/drivers/net/sfc/sfc_ev.c
@@ -467,9 +467,58 @@ sfc_ev_link_change(void *arg, efx_link_mode_t link_mode)
 {
        struct sfc_evq *evq = arg;
        struct sfc_adapter *sa = evq->sa;
-       struct rte_eth_link new_link;
+       struct rte_eth_link new_link = {0};
 
+       if (sa->link_ev_need_poll) {
+               efx_link_mode_t new_mode;
+               bool poll_done = false;
+
+               /*
+                * The event provides only the general status. When the link is
+                * up, poll the port to get the speed, but it is not compulsory.
+                */
+               if (link_mode != EFX_LINK_DOWN) {
+                       int ret = 0;
+
+                       if (sfc_adapter_trylock(sa)) {
+                               /* Never poll when the adaptor is going down. */
+                               if (sa->state == SFC_ETHDEV_STARTED) {
+                                       ret = efx_port_poll(sa->nic, &new_mode);
+                                       poll_done = true;
+                               }
+
+                               sfc_adapter_unlock(sa);
+                       }
+
+                       if (ret != 0) {
+                               sfc_warn(sa, "port poll failed on link event");
+                               poll_done = false;
+                       }
+               }
+
+               if (poll_done) {
+                       link_mode = new_mode;
+                       goto decode_comprehensive;
+               }
+
+               new_link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+               new_link.link_autoneg = RTE_ETH_LINK_AUTONEG;
+
+               if (link_mode == EFX_LINK_DOWN) {
+                       new_link.link_speed  = RTE_ETH_SPEED_NUM_NONE;
+                       new_link.link_status = RTE_ETH_LINK_DOWN;
+               } else {
+                       new_link.link_speed  = RTE_ETH_SPEED_NUM_UNKNOWN;
+                       new_link.link_status = RTE_ETH_LINK_UP;
+               }
+
+               goto set;
+       }
+
+decode_comprehensive:
        sfc_port_link_mode_to_info(link_mode, &new_link);
+
+set:
        if (rte_eth_linkstatus_set(sa->eth_dev, &new_link) == 0)
                evq->sa->port.lsc_seq++;
 
-- 
2.39.5

Reply via email to