net/sfc: handle MC reboot event
authorAndrew Rybchenko <arybchenko@solarflare.com>
Sun, 24 Dec 2017 10:46:33 +0000 (10:46 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 16 Jan 2018 17:47:49 +0000 (18:47 +0100)
Implement handling of the MC reboot event received on management
event queue or detected by MCDI processing.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
drivers/net/sfc/sfc.c
drivers/net/sfc/sfc.h
drivers/net/sfc/sfc_mcdi.c

index 49d7e93..0dcfdd8 100644 (file)
@@ -33,6 +33,7 @@
 #include <unistd.h>
 
 #include <rte_errno.h>
+#include <rte_alarm.h>
 
 #include "efx.h"
 
@@ -389,6 +390,58 @@ sfc_stop(struct sfc_adapter *sa)
        sfc_log_init(sa, "done");
 }
 
+static int
+sfc_restart(struct sfc_adapter *sa)
+{
+       int rc;
+
+       SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+       if (sa->state != SFC_ADAPTER_STARTED)
+               return EINVAL;
+
+       sfc_stop(sa);
+
+       rc = sfc_start(sa);
+       if (rc != 0)
+               sfc_err(sa, "restart failed");
+
+       return rc;
+}
+
+static void
+sfc_restart_if_required(void *arg)
+{
+       struct sfc_adapter *sa = arg;
+
+       /* If restart is scheduled, clear the flag and do it */
+       if (rte_atomic32_cmpset((volatile uint32_t *)&sa->restart_required,
+                               1, 0)) {
+               sfc_adapter_lock(sa);
+               if (sa->state == SFC_ADAPTER_STARTED)
+                       (void)sfc_restart(sa);
+               sfc_adapter_unlock(sa);
+       }
+}
+
+void
+sfc_schedule_restart(struct sfc_adapter *sa)
+{
+       int rc;
+
+       /* Schedule restart alarm if it is not scheduled yet */
+       if (!rte_atomic32_test_and_set(&sa->restart_required))
+               return;
+
+       rc = rte_eal_alarm_set(1, sfc_restart_if_required, sa);
+       if (rc == -ENOTSUP)
+               sfc_warn(sa, "alarms are not supported, restart is pending");
+       else if (rc != 0)
+               sfc_err(sa, "cannot arm restart alarm (rc=%d)", rc);
+       else
+               sfc_info(sa, "restart scheduled");
+}
+
 int
 sfc_configure(struct sfc_adapter *sa)
 {
@@ -679,6 +732,7 @@ sfc_probe(struct sfc_adapter *sa)
        SFC_ASSERT(sfc_adapter_is_locked(sa));
 
        sa->socket_id = rte_socket_id();
+       rte_atomic32_init(&sa->restart_required);
 
        sfc_log_init(sa, "init mem bar");
        rc = sfc_mem_bar_init(sa);
@@ -743,6 +797,14 @@ sfc_unprobe(struct sfc_adapter *sa)
 
        sfc_mcdi_fini(sa);
 
+       /*
+        * Make sure there is no pending alarm to restart since we are
+        * going to free device private which is passed as the callback
+        * opaque data. A new alarm cannot be scheduled since MCDI is
+        * shut down.
+        */
+       rte_eal_alarm_cancel(sfc_restart_if_required, sa);
+
        sfc_log_init(sa, "destroy nic");
        sa->nic = NULL;
        efx_nic_destroy(enp);
index ef980a4..77882eb 100644 (file)
@@ -39,6 +39,7 @@
 #include <rte_ethdev.h>
 #include <rte_kvargs.h>
 #include <rte_spinlock.h>
+#include <rte_atomic.h>
 
 #include "efx.h"
 
@@ -197,6 +198,7 @@ struct sfc_adapter {
        efx_family_t                    family;
        efx_nic_t                       *nic;
        rte_spinlock_t                  nic_lock;
+       rte_atomic32_t                  restart_required;
 
        struct sfc_mcdi                 mcdi;
        struct sfc_intr                 intr;
@@ -329,6 +331,8 @@ void sfc_detach(struct sfc_adapter *sa);
 int sfc_start(struct sfc_adapter *sa);
 void sfc_stop(struct sfc_adapter *sa);
 
+void sfc_schedule_restart(struct sfc_adapter *sa);
+
 int sfc_mcdi_init(struct sfc_adapter *sa);
 void sfc_mcdi_fini(struct sfc_adapter *sa);
 
index 0faad3e..f4763ab 100644 (file)
@@ -176,7 +176,7 @@ sfc_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
            (eme == EFX_MCDI_EXCEPTION_MC_REBOOT) ? "REBOOT" :
            (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT) ? "BADASSERT" : "UNKNOWN");
 
-       sfc_panic(sa, "MCDI exceptions handling is not implemented\n");
+       sfc_schedule_restart(sa);
 }
 
 #define SFC_MCDI_LOG_BUF_SIZE  128