common/sfc_efx/base: support creation of extended width EvQ
authorAndy Moreton <amoreton@xilinx.com>
Thu, 24 Sep 2020 12:12:31 +0000 (13:12 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 30 Sep 2020 17:19:13 +0000 (19:19 +0200)
Add a flag to request an extended width event queue, and
check that the supplied buffer is large enough to hold the
event queue descriptors.

Signed-off-by: Andy Moreton <amoreton@xilinx.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
drivers/common/sfc_efx/base/ef10_ev.c
drivers/common/sfc_efx/base/ef10_nic.c
drivers/common/sfc_efx/base/efx.h
drivers/common/sfc_efx/base/efx_ev.c
drivers/common/sfc_efx/base/efx_mcdi.c
drivers/common/sfc_efx/base/rhead_ev.c
drivers/common/sfc_efx/base/rhead_impl.h
drivers/common/sfc_efx/base/rhead_nic.c
drivers/net/sfc/sfc_ev.c

index aec1c46..8e7cc27 100644 (file)
@@ -127,6 +127,8 @@ ef10_ev_qcreate(
 
        _NOTE(ARGUNUSED(id))    /* buftbl id managed by MC */
 
+       EFSYS_ASSERT((flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) == 0);
+
        /*
         * NO_CONT_EV mode is only requested from the firmware when creating
         * receive queues, but here it needs to be specified at event queue
index 7a11930..81cd436 100644 (file)
@@ -1043,14 +1043,14 @@ ef10_get_datapath_caps(
        efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
        efx_mcdi_req_t req;
        EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN,
-               MC_CMD_GET_CAPABILITIES_V5_OUT_LEN);
+               MC_CMD_GET_CAPABILITIES_V7_OUT_LEN);
        efx_rc_t rc;
 
        req.emr_cmd = MC_CMD_GET_CAPABILITIES;
        req.emr_in_buf = payload;
        req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
        req.emr_out_buf = payload;
-       req.emr_out_length = MC_CMD_GET_CAPABILITIES_V5_OUT_LEN;
+       req.emr_out_length = MC_CMD_GET_CAPABILITIES_V7_OUT_LEN;
 
        efx_mcdi_execute_quiet(enp, &req);
 
@@ -1073,6 +1073,11 @@ ef10_get_datapath_caps(
            (MCDI_OUT_DWORD((_req), GET_CAPABILITIES_V2_OUT_FLAGS2) &   \
            (1u << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## _flag ## _LBN))))
 
+#define        CAP_FLAGS3(_req, _flag)                                         \
+       (((_req).emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V7_OUT_LEN) && \
+           (MCDI_OUT_DWORD((_req), GET_CAPABILITIES_V7_OUT_FLAGS3) &   \
+           (1u << (MC_CMD_GET_CAPABILITIES_V7_OUT_ ## _flag ## _LBN))))
+
        /* Check if RXDP firmware inserts 14 byte prefix */
        if (CAP_FLAGS1(req, RX_PREFIX_LEN_14))
                encp->enc_rx_prefix_size = 14;
@@ -1202,6 +1207,15 @@ ef10_get_datapath_caps(
        else
                encp->enc_init_evq_v2_supported = B_FALSE;
 
+       /*
+        * Check if firmware supports extended width event queues, which have
+        * a different event descriptor layout.
+        */
+       if (CAP_FLAGS3(req, EXTENDED_WIDTH_EVQS_SUPPORTED))
+               encp->enc_init_evq_extended_width_supported = B_TRUE;
+       else
+               encp->enc_init_evq_extended_width_supported = B_FALSE;
+
        /*
         * Check if the NO_CONT_EV mode for RX events is supported.
         */
index 7e747e6..ecd1671 100644 (file)
@@ -1456,6 +1456,7 @@ typedef struct efx_nic_cfg_s {
        uint32_t                enc_evq_timer_quantum_ns;
        uint32_t                enc_evq_timer_max_us;
        uint32_t                enc_clk_mult;
+       uint32_t                enc_ev_ew_desc_size;
        uint32_t                enc_ev_desc_size;
        uint32_t                enc_rx_desc_size;
        uint32_t                enc_tx_desc_size;
@@ -1557,6 +1558,7 @@ typedef struct efx_nic_cfg_s {
        boolean_t               enc_allow_set_mac_with_installed_filters;
        boolean_t               enc_enhanced_set_mac_supported;
        boolean_t               enc_init_evq_v2_supported;
+       boolean_t               enc_init_evq_extended_width_supported;
        boolean_t               enc_no_cont_ev_mode_supported;
        boolean_t               enc_init_rxq_with_buffer_size;
        boolean_t               enc_rx_packed_stream_supported;
@@ -2264,13 +2266,15 @@ LIBEFX_API
 extern __checkReturn   size_t
 efx_evq_size(
        __in    const efx_nic_t *enp,
-       __in    unsigned int ndescs);
+       __in    unsigned int ndescs,
+       __in    uint32_t flags);
 
 LIBEFX_API
 extern __checkReturn   unsigned int
 efx_evq_nbufs(
        __in    const efx_nic_t *enp,
-       __in    unsigned int ndescs);
+       __in    unsigned int ndescs,
+       __in    uint32_t flags);
 
 #define        EFX_EVQ_FLAGS_TYPE_MASK         (0x3)
 #define        EFX_EVQ_FLAGS_TYPE_AUTO         (0x0)
@@ -2291,6 +2295,10 @@ efx_evq_nbufs(
  */
 #define        EFX_EVQ_FLAGS_NO_CONT_EV        (0x10)
 
+/* Configure EVQ for extended width events (EF100 only) */
+#define        EFX_EVQ_FLAGS_EXTENDED_WIDTH    (0x20)
+
+
 LIBEFX_API
 extern __checkReturn   efx_rc_t
 efx_ev_qcreate(
index 99a7743..32e7fff 100644 (file)
@@ -201,19 +201,35 @@ fail1:
        __checkReturn   size_t
 efx_evq_size(
        __in    const efx_nic_t *enp,
-       __in    unsigned int ndescs)
+       __in    unsigned int ndescs,
+       __in    uint32_t flags)
 {
        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+       size_t desc_size;
 
-       return (ndescs * encp->enc_ev_desc_size);
+       desc_size = encp->enc_ev_desc_size;
+
+#if EFSYS_OPT_EV_EXTENDED_WIDTH
+       if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH)
+               desc_size = encp->enc_ev_ew_desc_size;
+#else
+       EFSYS_ASSERT((flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) == 0);
+#endif
+
+       return (ndescs * desc_size);
 }
 
        __checkReturn   unsigned int
 efx_evq_nbufs(
        __in    const efx_nic_t *enp,
-       __in    unsigned int ndescs)
+       __in    unsigned int ndescs,
+       __in    uint32_t flags)
 {
-       return (EFX_DIV_ROUND_UP(efx_evq_size(enp, ndescs), EFX_BUF_SIZE));
+       size_t size;
+
+       size = efx_evq_size(enp, ndescs, flags);
+
+       return (EFX_DIV_ROUND_UP(size, EFX_BUF_SIZE));
 }
 
                void
@@ -282,6 +298,13 @@ efx_ev_qcreate(
                goto fail4;
        }
 
+       if ((flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) &&
+           (encp->enc_ev_ew_desc_size == 0)) {
+               /* Extended width event descriptors are not supported. */
+               rc = EINVAL;
+               goto fail5;
+       }
+
        EFSYS_ASSERT(ISP2(encp->enc_evq_max_nevs));
        EFSYS_ASSERT(ISP2(encp->enc_evq_min_nevs));
 
@@ -289,14 +312,20 @@ efx_ev_qcreate(
            ndescs < encp->enc_evq_min_nevs ||
            ndescs > encp->enc_evq_max_nevs) {
                rc = EINVAL;
-               goto fail5;
+               goto fail6;
+       }
+
+       if (EFSYS_MEM_SIZE(esmp) < (ndescs * encp->enc_ev_desc_size)) {
+               /* Buffer too small for event queue descriptors. */
+               rc = EINVAL;
+               goto fail7;
        }
 
        /* Allocate an EVQ object */
        EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep);
        if (eep == NULL) {
                rc = ENOMEM;
-               goto fail6;
+               goto fail8;
        }
 
        eep->ee_magic = EFX_EVQ_MAGIC;
@@ -319,16 +348,20 @@ efx_ev_qcreate(
 
        if ((rc = eevop->eevo_qcreate(enp, index, esmp, ndescs, id, us, flags,
            eep)) != 0)
-               goto fail7;
+               goto fail9;
 
        return (0);
 
-fail7:
-       EFSYS_PROBE(fail7);
+fail9:
+       EFSYS_PROBE(fail9);
 
        *eepp = NULL;
        enp->en_ev_qcount--;
        EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
+fail8:
+       EFSYS_PROBE(fail8);
+fail7:
+       EFSYS_PROBE(fail7);
 fail6:
        EFSYS_PROBE(fail6);
 fail5:
@@ -1255,6 +1288,8 @@ siena_ev_qcreate(
 
        _NOTE(ARGUNUSED(esmp))
 
+       EFSYS_ASSERT((flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) == 0);
+
 #if EFSYS_OPT_RX_SCALE
        if (enp->en_intr.ei_type == EFX_INTR_LINE &&
            index >= EFX_MAXRSS_LEGACY) {
index b8e45b4..ede052a 100644 (file)
@@ -2475,6 +2475,7 @@ efx_mcdi_init_evq(
                MC_CMD_INIT_EVQ_V2_IN_LEN(INIT_EVQ_MAXNBUFS),
                MC_CMD_INIT_EVQ_V2_OUT_LEN);
        boolean_t interrupting;
+       int ev_extended_width;
        int ev_cut_through;
        int ev_merge;
        unsigned int evq_type;
@@ -2484,7 +2485,7 @@ efx_mcdi_init_evq(
        int i;
        efx_rc_t rc;
 
-       npages = efx_evq_nbufs(enp, nevs);
+       npages = efx_evq_nbufs(enp, nevs, flags);
        if (npages > INIT_EVQ_MAXNBUFS) {
                rc = EINVAL;
                goto fail1;
@@ -2558,14 +2559,27 @@ efx_mcdi_init_evq(
                }
        }
 
-       MCDI_IN_POPULATE_DWORD_7(req, INIT_EVQ_V2_IN_FLAGS,
+       /*
+        * On EF100, extended width event queues have a different event
+        * descriptor layout and are used to support descriptor proxy queues.
+        */
+       ev_extended_width = 0;
+#if EFSYS_OPT_EV_EXTENDED_WIDTH
+       if (encp->enc_init_evq_extended_width_supported) {
+               if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH)
+                       ev_extended_width = 1;
+       }
+#endif
+
+       MCDI_IN_POPULATE_DWORD_8(req, INIT_EVQ_V2_IN_FLAGS,
            INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting,
            INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0,
            INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0,
            INIT_EVQ_V2_IN_FLAG_CUT_THRU, ev_cut_through,
            INIT_EVQ_V2_IN_FLAG_RX_MERGE, ev_merge,
            INIT_EVQ_V2_IN_FLAG_TX_MERGE, ev_merge,
-           INIT_EVQ_V2_IN_FLAG_TYPE, evq_type);
+           INIT_EVQ_V2_IN_FLAG_TYPE, evq_type,
+           INIT_EVQ_V2_IN_FLAG_EXT_WIDTH, ev_extended_width);
 
        /* If the value is zero then disable the timer */
        if (us == 0) {
index 8392a2b..a83c615 100644 (file)
@@ -66,11 +66,26 @@ rhead_ev_qcreate(
        __in            uint32_t flags,
        __in            efx_evq_t *eep)
 {
+       const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+       size_t desc_size;
        uint32_t irq;
        efx_rc_t rc;
 
        _NOTE(ARGUNUSED(id))    /* buftbl id managed by MC */
 
+       desc_size = encp->enc_ev_desc_size;
+#if EFSYS_OPT_EV_EXTENDED_WIDTH
+       if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH)
+               desc_size = encp->enc_ev_ew_desc_size;
+#endif
+       EFSYS_ASSERT(desc_size != 0);
+
+       if (EFSYS_MEM_SIZE(esmp) < (ndescs * desc_size)) {
+               /* Buffer too small for event queue descriptors */
+               rc = EINVAL;
+               goto fail1;
+       }
+
        /* Set up the handler table */
        eep->ee_rx      = rhead_ev_rx_packets;
        eep->ee_tx      = rhead_ev_tx_completion;
@@ -98,10 +113,12 @@ rhead_ev_qcreate(
        rc = efx_mcdi_init_evq(enp, index, esmp, ndescs, irq, us, flags,
            B_FALSE);
        if (rc != 0)
-               goto fail1;
+               goto fail2;
 
        return (0);
 
+fail2:
+       EFSYS_PROBE(fail2);
 fail1:
        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
index 3383c47..09a991f 100644 (file)
@@ -32,6 +32,10 @@ extern "C" {
 #define        RHEAD_RXQ_DESC_SIZE     (sizeof (efx_qword_t))
 #define        RHEAD_TXQ_DESC_SIZE     (sizeof (efx_oword_t))
 
+#if EFSYS_OPT_EV_EXTENDED_WIDTH
+#define        RHEAD_EVQ_EW_DESC_SIZE  (sizeof (efx_xword_t))
+#endif
+
 
 /* NIC */
 
index 9b8f09d..66db68b 100644 (file)
@@ -129,6 +129,12 @@ rhead_board_cfg(
        encp->enc_evq_timer_quantum_ns = 0;
        encp->enc_evq_timer_max_us = 0;
 
+#if EFSYS_OPT_EV_EXTENDED_WIDTH
+       encp->enc_ev_ew_desc_size = RHEAD_EVQ_EW_DESC_SIZE;
+#else
+       encp->enc_ev_ew_desc_size = 0;
+#endif
+
        encp->enc_ev_desc_size = RHEAD_EVQ_DESC_SIZE;
        encp->enc_rx_desc_size = RHEAD_RXQ_DESC_SIZE;
        encp->enc_tx_desc_size = RHEAD_TXQ_DESC_SIZE;
index 7e5676f..cc7d5d1 100644 (file)
@@ -600,7 +600,7 @@ sfc_ev_qstart(struct sfc_evq *evq, unsigned int hw_index)
 
        /* Clear all events */
        (void)memset((void *)esmp->esm_base, 0xff,
-                    efx_evq_size(sa->nic, evq->entries));
+                    efx_evq_size(sa->nic, evq->entries, evq_flags));
 
        if ((sa->intr.lsc_intr && hw_index == sa->mgmt_evq_index) ||
            (sa->intr.rxq_intr && evq->dp_rxq != NULL))
@@ -833,8 +833,8 @@ sfc_ev_qinit(struct sfc_adapter *sa,
 
        /* Allocate DMA space */
        rc = sfc_dma_alloc(sa, sfc_evq_type2str(type), type_index,
-                          efx_evq_size(sa->nic, evq->entries), socket_id,
-                          &evq->mem);
+                          efx_evq_size(sa->nic, evq->entries, sa->evq_flags),
+                          socket_id, &evq->mem);
        if (rc != 0)
                goto fail_dma_alloc;