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;
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);
}
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
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:
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);
}
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);