common/sfc_efx/base: complete EvQ creation on Riverhead
authorIvan Malov <ivan.malov@oktetlabs.ru>
Thu, 24 Sep 2020 12:11:59 +0000 (13:11 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 30 Sep 2020 17:19:12 +0000 (19:19 +0200)
Client drivers relying on interrupts will fail to complete event
queue creation on Riverhead boards as the latter have no support
for INIT_DONE events which means that it's useless to wait until
initialisation callback is triggered by interrupt-driven polling.

Client drivers which avoid interrupt-driven polling still handle
INIT_DONE events by direct polling and will fail to do so.

Solve this problem by adding an extra poll-once method which
will be called by client drivers after queue creation (probably,
with driver-specific lock being held). The method will invoke
initialisation callback on Riverhead and do nothing on the other
boards. Then the drivers will proceed with normal waiting which
will complete immediately in the case of Riverhead.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
drivers/common/sfc_efx/base/efx.h
drivers/common/sfc_efx/base/efx_ev.c
drivers/common/sfc_efx/base/hunt_nic.c
drivers/common/sfc_efx/base/medford2_nic.c
drivers/common/sfc_efx/base/medford_nic.c
drivers/common/sfc_efx/base/rhead_nic.c
drivers/common/sfc_efx/base/siena_nic.c
drivers/common/sfc_efx/rte_common_sfc_efx_version.map
drivers/net/sfc/sfc_ev.c

index c7fe814..2c49280 100644 (file)
@@ -1443,6 +1443,7 @@ typedef struct efx_nic_cfg_s {
        uint32_t                enc_vf;
        uint32_t                enc_privilege_mask;
 #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */
+       boolean_t               enc_evq_init_done_ev_supported;
        boolean_t               enc_bug26807_workaround;
        boolean_t               enc_bug35388_workaround;
        boolean_t               enc_bug41750_workaround;
@@ -2430,6 +2431,13 @@ efx_ev_qprefetch(
 
 #endif /* EFSYS_OPT_EV_PREFETCH */
 
+LIBEFX_API
+extern                 void
+efx_ev_qcreate_check_init_done(
+       __in            efx_evq_t *eep,
+       __in            const efx_ev_callbacks_t *eecp,
+       __in_opt        void *arg);
+
 LIBEFX_API
 extern                 void
 efx_ev_qpoll(
index edc1b18..99a7743 100644 (file)
@@ -423,6 +423,36 @@ efx_ev_qprefetch(
 
 #endif /* EFSYS_OPT_EV_PREFETCH */
 
+/*
+ * This method is needed to ensure that eec_initialized callback
+ * is invoked after queue creation. The callback will be invoked
+ * on Riverhead boards which have no support for INIT_DONE events
+ * and will do nothing on other boards.
+ *
+ * The client drivers must call this method after calling efx_ev_create().
+ * The call must be done with the same locks being held (if any) which are
+ * normally acquired around efx_ev_qpoll() calls to ensure that
+ * eec_initialized callback is invoked within the same locking context.
+ */
+                       void
+efx_ev_qcreate_check_init_done(
+       __in            efx_evq_t *eep,
+       __in            const efx_ev_callbacks_t *eecp,
+       __in_opt        void *arg)
+{
+       const efx_nic_cfg_t *encp;
+
+       EFSYS_ASSERT(eep != NULL);
+       EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
+       EFSYS_ASSERT(eecp != NULL);
+       EFSYS_ASSERT(eecp->eec_initialized != NULL);
+
+       encp = efx_nic_cfg_get(eep->ee_enp);
+
+       if (encp->enc_evq_init_done_ev_supported == B_FALSE)
+               (void) eecp->eec_initialized(arg);
+}
+
                        void
 efx_ev_qpoll(
        __in            efx_evq_t *eep,
index 75c9050..489c2d3 100644 (file)
@@ -76,6 +76,12 @@ hunt_board_cfg(
        uint32_t bandwidth;
        efx_rc_t rc;
 
+       /*
+        * Event queue creation is complete when an
+        * EVQ_INIT_DONE_EV event is received.
+        */
+       encp->enc_evq_init_done_ev_supported = B_TRUE;
+
        /*
         * Enable firmware workarounds for hardware errata.
         * Expected responses are:
index 1a454fc..f19435a 100644 (file)
@@ -44,6 +44,12 @@ medford2_board_cfg(
        uint32_t bandwidth;
        efx_rc_t rc;
 
+       /*
+        * Event queue creation is complete when an
+        * EVQ_INIT_DONE_EV event is received.
+        */
+       encp->enc_evq_init_done_ev_supported = B_TRUE;
+
        /*
         * Enable firmware workarounds for hardware errata.
         * Expected responses are:
index 6c85b0c..6ad9af9 100644 (file)
@@ -42,6 +42,12 @@ medford_board_cfg(
        uint32_t bandwidth;
        efx_rc_t rc;
 
+       /*
+        * Event queue creation is complete when an
+        * EVQ_INIT_DONE_EV event is received.
+        */
+       encp->enc_evq_init_done_ev_supported = B_TRUE;
+
        /*
         * Enable firmware workarounds for hardware errata.
         * Expected responses are:
index c83d18e..b779b4f 100644 (file)
@@ -51,6 +51,12 @@ rhead_board_cfg(
 
        encp->enc_buftbl_limit = UINT32_MAX;
 
+       /*
+        * Riverhead event queue creation completes
+        * immediately (no initial event).
+        */
+       encp->enc_evq_init_done_ev_supported = B_FALSE;
+
        /*
         * Enable firmware workarounds for hardware errata.
         * Expected responses are:
index b9b6d19..beabac0 100644 (file)
@@ -135,6 +135,12 @@ siena_board_cfg(
        encp->enc_rx_scale_additional_modes_supported = B_FALSE;
 #endif /* EFSYS_OPT_RX_SCALE */
 
+       /*
+        * Event queue creation is complete when an
+        * EVQ_INIT_DONE_EV event is received.
+        */
+       encp->enc_evq_init_done_ev_supported = B_TRUE;
+
        encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT);
        /* Fragments must not span 4k boundaries. */
        encp->enc_tx_dma_desc_boundary = 4096;
index 5e2a7ad..9b1715b 100644 (file)
@@ -6,6 +6,7 @@ INTERNAL {
        efx_ev_fini;
        efx_ev_init;
        efx_ev_qcreate;
+       efx_ev_qcreate_check_init_done;
        efx_ev_qdestroy;
        efx_ev_qmoderate;
        efx_ev_qpending;
index 83115e8..7e5676f 100644 (file)
@@ -608,6 +608,8 @@ sfc_ev_qstart(struct sfc_evq *evq, unsigned int hw_index)
        else
                evq_flags |= EFX_EVQ_FLAGS_NOTIFY_DISABLED;
 
+       evq->init_state = SFC_EVQ_STARTING;
+
        /* Create the common code event queue */
        rc = efx_ev_qcreate(sa->nic, hw_index, esmp, evq->entries,
                            0 /* unused on EF10 */, 0, evq_flags,
@@ -632,7 +634,13 @@ sfc_ev_qstart(struct sfc_evq *evq, unsigned int hw_index)
                evq->callbacks = &sfc_ev_callbacks;
        }
 
-       evq->init_state = SFC_EVQ_STARTING;
+       /*
+        * Poll once to ensure that eec_initialized callback is invoked in
+        * case if the hardware does not support INIT_DONE events. If the
+        * hardware supports INIT_DONE events, this will do nothing, and the
+        * corresponding event will be processed by sfc_ev_qpoll() below.
+        */
+       efx_ev_qcreate_check_init_done(evq->common, evq->callbacks, evq);
 
        /* Wait for the initialization event */
        total_delay_us = 0;
@@ -665,10 +673,10 @@ done:
        return 0;
 
 fail_timedout:
-       evq->init_state = SFC_EVQ_INITIALIZED;
        efx_ev_qdestroy(evq->common);
 
 fail_ev_qcreate:
+       evq->init_state = SFC_EVQ_INITIALIZED;
        sfc_log_init(sa, "failed %d", rc);
        return rc;
 }