Link change events on netport MCDI capable NICs do not carry
any specifics of the new link state. Such need to be queried
separately. Add processing of the events, with an indication
to the client driver telling it to collect the status itself.

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/common/sfc_efx/base/ef10_ev.c | 29 +++++++++++++++++++++++++++
 drivers/common/sfc_efx/base/efx.h     |  6 ++++++
 drivers/common/sfc_efx/base/efx_nic.c |  5 +++++
 3 files changed, 40 insertions(+)

diff --git a/drivers/common/sfc_efx/base/ef10_ev.c 
b/drivers/common/sfc_efx/base/ef10_ev.c
index 82a2284f2b..a97c1bf43e 100644
--- a/drivers/common/sfc_efx/base/ef10_ev.c
+++ b/drivers/common/sfc_efx/base/ef10_ev.c
@@ -866,6 +866,7 @@ ef10_ev_mcdi(
        __in_opt        void *arg)
 {
        efx_nic_t *enp = eep->ee_enp;
+       efx_port_t *epp = &(enp->en_port);
        unsigned int code;
        boolean_t should_abort = B_FALSE;
        boolean_t ev_is_v2 = B_FALSE;
@@ -906,6 +907,34 @@ ef10_ev_mcdi(
                break;
 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */
 
+       case MCDI_EVENT_CODE_PORT_LINKCHANGE:
+               /*
+                * These events are generated on netport MCDI capable
+                * boards. They supersede legacy LINKCHANGE_V2 events.
+                */
+               if (MCDI_EV_FIELD(eqp, PORT_LINKCHANGE_PORT_HANDLE) ==
+                   epp->ep_np_handle) {
+                       efx_link_mode_t mode;
+
+                       if (MCDI_EV_FIELD(eqp, PORT_LINKCHANGE_LINK_UP) == 1)
+                               mode = EFX_LINK_UNKNOWN;
+                       else
+                               mode = EFX_LINK_DOWN;
+
+                       /*
+                        * The event does not contain full link state details.
+                        *
+                        * Either notify the client driver with a dummy link
+                        * mode value (UNKNOWN), just to say the link is up,
+                        * or, in case the link is not up, pass DOWN value.
+                        *
+                        * The client driver will need to poll for link state
+                        * in order to get full details like speed and duplex.
+                        */
+                       should_abort = eecp->eec_link_change(arg, mode);
+               }
+               break;
+
        case MCDI_EVENT_CODE_LINKCHANGE_V2:
                if (efx_np_supported(enp) != B_FALSE) {
                        /*
diff --git a/drivers/common/sfc_efx/base/efx.h 
b/drivers/common/sfc_efx/base/efx.h
index 73dc38f84e..7b43a89551 100644
--- a/drivers/common/sfc_efx/base/efx.h
+++ b/drivers/common/sfc_efx/base/efx.h
@@ -1754,6 +1754,12 @@ typedef struct efx_nic_cfg_s {
        uint32_t                enc_mac_pdu_min;
        /* Maximum MAC PDU value to use with efx_mac_pdu_set() */
        uint32_t                enc_mac_pdu_max;
+       /*
+        * When true, the link mode value passed from eec_link_change() is
+        * either UNKNOWN (merely saying the link is up) or DOWN. In order
+        * to have exact speed/duplex, efx_port_poll() needs to be invoked.
+        */
+       boolean_t               enc_link_ev_need_poll;
 } efx_nic_cfg_t;
 
 #define        EFX_PCI_VF_INVALID 0xffff
diff --git a/drivers/common/sfc_efx/base/efx_nic.c 
b/drivers/common/sfc_efx/base/efx_nic.c
index 1c25270792..ab2bb1c160 100644
--- a/drivers/common/sfc_efx/base/efx_nic.c
+++ b/drivers/common/sfc_efx/base/efx_nic.c
@@ -494,6 +494,11 @@ efx_nic_probe(
        encp->enc_mac_pdu_max = efx_mac_pdu_from_sdu(enp, EFX_MAC_SDU_MAX);
        encp->enc_mac_pdu_min = EFX_MAC_PDU_MIN;
 
+       if (efx_np_supported(enp) == B_FALSE)
+               encp->enc_link_ev_need_poll = B_FALSE;
+       else
+               encp->enc_link_ev_need_poll = B_TRUE;
+
        if ((rc = efx_phy_probe(enp)) != 0)
                goto fail2;
 
-- 
2.39.5

Reply via email to