net/sfc: do not hold management event queue lock while MCDI
authorAndrew Rybchenko <arybchenko@solarflare.com>
Sun, 24 Dec 2017 10:46:32 +0000 (10:46 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 16 Jan 2018 17:47:49 +0000 (18:47 +0100)
MCDI execution may require MCDI proxy handling which involves
management event queue polling. So, it is a bad idea to hold
managment event queue lock when MCDI is executed.

Event queue creation and destruction are MCDI operations.

Fixes: 4650ed44c120 ("net/sfc: support MCDI proxy")
Cc: stable@dpdk.org
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.h
drivers/net/sfc/sfc_ev.c
drivers/net/sfc/sfc_intr.c

index b72eba0..ef980a4 100644 (file)
@@ -212,7 +212,29 @@ struct sfc_adapter {
        unsigned int                    evq_count;
 
        unsigned int                    mgmt_evq_index;
+       /*
+        * The lock is used to serialise management event queue polling
+        * which can be done from different context. Also the lock
+        * guarantees that mgmt_evq_running is preserved while the lock
+        * is held. It is used to serialise polling and start/stop
+        * operations.
+        *
+        * Locks which may be held when the lock is acquired:
+        *  - adapter lock, when:
+        *    - device start/stop to change mgmt_evq_running
+        *    - any control operations in client side MCDI proxy handling to
+        *      poll management event queue waiting for proxy response
+        *  - MCDI lock, when:
+        *    - any control operations in client side MCDI proxy handling to
+        *      poll management event queue waiting for proxy response
+        *
+        * Locks which are acquired with the lock held:
+        *  - nic_lock, when:
+        *    - MC event processing on management event queue polling
+        *      (e.g. MC REBOOT or BADASSERT events)
+        */
        rte_spinlock_t                  mgmt_evq_lock;
+       bool                            mgmt_evq_running;
        struct sfc_evq                  *mgmt_evq;
 
        unsigned int                    rxq_count;
index b29eb2f..5fbebbf 100644 (file)
@@ -565,10 +565,8 @@ void
 sfc_ev_mgmt_qpoll(struct sfc_adapter *sa)
 {
        if (rte_spinlock_trylock(&sa->mgmt_evq_lock)) {
-               struct sfc_evq *mgmt_evq = sa->mgmt_evq;
-
-               if (mgmt_evq->init_state == SFC_EVQ_STARTED)
-                       sfc_ev_qpoll(mgmt_evq);
+               if (sa->mgmt_evq_running)
+                       sfc_ev_qpoll(sa->mgmt_evq);
 
                rte_spinlock_unlock(&sa->mgmt_evq_lock);
        }
@@ -734,20 +732,26 @@ sfc_ev_start(struct sfc_adapter *sa)
                goto fail_ev_init;
 
        /* Start management EVQ used for global events */
-       rte_spinlock_lock(&sa->mgmt_evq_lock);
 
+       /*
+        * Management event queue start polls the queue, but it cannot
+        * interfere with other polling contexts since mgmt_evq_running
+        * is false yet.
+        */
        rc = sfc_ev_qstart(sa->mgmt_evq, sa->mgmt_evq_index);
        if (rc != 0)
                goto fail_mgmt_evq_start;
 
+       rte_spinlock_lock(&sa->mgmt_evq_lock);
+       sa->mgmt_evq_running = true;
+       rte_spinlock_unlock(&sa->mgmt_evq_lock);
+
        if (sa->intr.lsc_intr) {
                rc = sfc_ev_qprime(sa->mgmt_evq);
                if (rc != 0)
                        goto fail_mgmt_evq_prime;
        }
 
-       rte_spinlock_unlock(&sa->mgmt_evq_lock);
-
        /*
         * Start management EVQ polling. If interrupts are disabled
         * (not used), it is required to process link status change
@@ -767,7 +771,6 @@ fail_mgmt_evq_prime:
        sfc_ev_qstop(sa->mgmt_evq);
 
 fail_mgmt_evq_start:
-       rte_spinlock_unlock(&sa->mgmt_evq_lock);
        efx_ev_fini(sa->nic);
 
 fail_ev_init:
@@ -783,9 +786,11 @@ sfc_ev_stop(struct sfc_adapter *sa)
        sfc_ev_mgmt_periodic_qpoll_stop(sa);
 
        rte_spinlock_lock(&sa->mgmt_evq_lock);
-       sfc_ev_qstop(sa->mgmt_evq);
+       sa->mgmt_evq_running = false;
        rte_spinlock_unlock(&sa->mgmt_evq_lock);
 
+       sfc_ev_qstop(sa->mgmt_evq);
+
        efx_ev_fini(sa->nic);
 }
 
index ee59cb1..de65f8c 100644 (file)
@@ -57,8 +57,9 @@ sfc_intr_handle_mgmt_evq(struct sfc_adapter *sa)
 
        evq = sa->mgmt_evq;
 
-       if (evq->init_state != SFC_EVQ_STARTED) {
-               sfc_log_init(sa, "interrupt on stopped EVQ %u", evq->evq_index);
+       if (!sa->mgmt_evq_running) {
+               sfc_log_init(sa, "interrupt on not running management EVQ %u",
+                            evq->evq_index);
        } else {
                sfc_ev_qpoll(evq);