Author: arybchik
Date: Fri Jun  3 05:27:34 2016
New Revision: 301237
URL: https://svnweb.freebsd.org/changeset/base/301237

Log:
  sfxge(4): support EVQ timer workaround via MCDI
  
  Submitted by:   Andy Moreton <amoreton at solarflare.com>
  Sponsored by:   Solarflare Communications, Inc.
  MFC after:      1 week
  Differential Revision:  https://reviews.freebsd.org/6675

Modified:
  head/sys/dev/sfxge/common/ef10_ev.c
  head/sys/dev/sfxge/common/efx.h
  head/sys/dev/sfxge/common/hunt_nic.c
  head/sys/dev/sfxge/common/medford_nic.c

Modified: head/sys/dev/sfxge/common/ef10_ev.c
==============================================================================
--- head/sys/dev/sfxge/common/ef10_ev.c Fri Jun  3 05:01:35 2016        
(r301236)
+++ head/sys/dev/sfxge/common/ef10_ev.c Fri Jun  3 05:27:34 2016        
(r301237)
@@ -87,6 +87,52 @@ ef10_ev_mcdi(
 
 
 static __checkReturn   efx_rc_t
+efx_mcdi_set_evq_tmr(
+       __in            efx_nic_t *enp,
+       __in            uint32_t instance,
+       __in            uint32_t mode,
+       __in            uint32_t timer_ns)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MAX(MC_CMD_SET_EVQ_TMR_IN_LEN,
+                           MC_CMD_SET_EVQ_TMR_OUT_LEN)];
+       efx_rc_t rc;
+
+       (void) memset(payload, 0, sizeof (payload));
+       req.emr_cmd = MC_CMD_SET_EVQ_TMR;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_SET_EVQ_TMR_IN_LEN;
+       req.emr_out_buf = payload;
+       req.emr_out_length = MC_CMD_SET_EVQ_TMR_OUT_LEN;
+
+       MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_INSTANCE, instance);
+       MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_LOAD_REQ_NS, timer_ns);
+       MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_RELOAD_REQ_NS, timer_ns);
+       MCDI_IN_SET_DWORD(req, SET_EVQ_TMR_IN_TMR_MODE, mode);
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail1;
+       }
+
+       if (req.emr_out_length_used < MC_CMD_SET_EVQ_TMR_OUT_LEN) {
+               rc = EMSGSIZE;
+               goto fail2;
+       }
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+static __checkReturn   efx_rc_t
 efx_mcdi_init_evq(
        __in            efx_nic_t *enp,
        __in            unsigned int instance,
@@ -437,9 +483,19 @@ ef10_ev_qmoderate(
        efx_nic_t *enp = eep->ee_enp;
        efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
        efx_dword_t dword;
-       uint32_t timer_val, mode;
+       uint32_t timer_ns, timer_val, mode;
        efx_rc_t rc;
 
+       /* Check that hardware and MCDI use the same timer MODE values */
+       EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_DIS ==
+           MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_DIS);
+       EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_IMMED_START ==
+           MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_IMMED_START);
+       EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_TRIG_START ==
+           MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_TRIG_START);
+       EFX_STATIC_ASSERT(FFE_CZ_TIMER_MODE_INT_HLDOFF ==
+           MC_CMD_SET_EVQ_TMR_IN_TIMER_MODE_INT_HLDOFF);
+
        if (us > encp->enc_evq_timer_max_us) {
                rc = EINVAL;
                goto fail1;
@@ -447,37 +503,46 @@ ef10_ev_qmoderate(
 
        /* If the value is zero then disable the timer */
        if (us == 0) {
-               timer_val = 0;
+               timer_ns = 0;
                mode = FFE_CZ_TIMER_MODE_DIS;
        } else {
+               timer_ns = us * 1000u;
+               mode = FFE_CZ_TIMER_MODE_INT_HLDOFF;
+       }
+
+       if (encp->enc_bug61265_workaround) {
+               rc = efx_mcdi_set_evq_tmr(enp, eep->ee_index, mode, timer_ns);
+               if (rc != 0)
+                       goto fail2;
+       } else {
                /* Calculate the timer value in quanta */
-               timer_val = us * 1000 / encp->enc_evq_timer_quantum_ns;
+               timer_val = timer_ns / encp->enc_evq_timer_quantum_ns;
 
                /* Moderation value is base 0 so we need to deduct 1 */
                if (timer_val > 0)
                        timer_val--;
 
-               mode = FFE_CZ_TIMER_MODE_INT_HLDOFF;
-       }
-
-       if (encp->enc_bug35388_workaround) {
-               EFX_POPULATE_DWORD_3(dword,
-                   ERF_DD_EVQ_IND_TIMER_FLAGS,
-                   EFE_DD_EVQ_IND_TIMER_FLAGS,
-                   ERF_DD_EVQ_IND_TIMER_MODE, mode,
-                   ERF_DD_EVQ_IND_TIMER_VAL, timer_val);
-               EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT,
-                   eep->ee_index, &dword, 0);
-       } else {
-               EFX_POPULATE_DWORD_2(dword,
-                   ERF_DZ_TC_TIMER_MODE, mode,
-                   ERF_DZ_TC_TIMER_VAL, timer_val);
-               EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_TMR_REG,
-                   eep->ee_index, &dword, 0);
+               if (encp->enc_bug35388_workaround) {
+                       EFX_POPULATE_DWORD_3(dword,
+                           ERF_DD_EVQ_IND_TIMER_FLAGS,
+                           EFE_DD_EVQ_IND_TIMER_FLAGS,
+                           ERF_DD_EVQ_IND_TIMER_MODE, mode,
+                           ERF_DD_EVQ_IND_TIMER_VAL, timer_val);
+                       EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT,
+                           eep->ee_index, &dword, 0);
+               } else {
+                       EFX_POPULATE_DWORD_2(dword,
+                           ERF_DZ_TC_TIMER_MODE, mode,
+                           ERF_DZ_TC_TIMER_VAL, timer_val);
+                       EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_TMR_REG,
+                           eep->ee_index, &dword, 0);
+               }
        }
 
        return (0);
 
+fail2:
+       EFSYS_PROBE(fail2);
 fail1:
        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 

Modified: head/sys/dev/sfxge/common/efx.h
==============================================================================
--- head/sys/dev/sfxge/common/efx.h     Fri Jun  3 05:01:35 2016        
(r301236)
+++ head/sys/dev/sfxge/common/efx.h     Fri Jun  3 05:27:34 2016        
(r301237)
@@ -1129,6 +1129,7 @@ typedef struct efx_nic_cfg_s {
        boolean_t               enc_bug26807_workaround;
        boolean_t               enc_bug35388_workaround;
        boolean_t               enc_bug41750_workaround;
+       boolean_t               enc_bug61265_workaround;
        boolean_t               enc_rx_batching_enabled;
        /* Maximum number of descriptors completed in an rx event. */
        uint32_t                enc_rx_batch_max;

Modified: head/sys/dev/sfxge/common/hunt_nic.c
==============================================================================
--- head/sys/dev/sfxge/common/hunt_nic.c        Fri Jun  3 05:01:35 2016        
(r301236)
+++ head/sys/dev/sfxge/common/hunt_nic.c        Fri Jun  3 05:27:34 2016        
(r301237)
@@ -291,6 +291,8 @@ hunt_board_cfg(
                FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
        }
 
+       encp->enc_bug61265_workaround = B_FALSE; /* Medford only */
+
        /* Check capabilities of running datapath firmware */
        if ((rc = ef10_get_datapath_caps(enp)) != 0)
            goto fail12;

Modified: head/sys/dev/sfxge/common/medford_nic.c
==============================================================================
--- head/sys/dev/sfxge/common/medford_nic.c     Fri Jun  3 05:01:35 2016        
(r301236)
+++ head/sys/dev/sfxge/common/medford_nic.c     Fri Jun  3 05:27:34 2016        
(r301237)
@@ -227,6 +227,23 @@ medford_board_cfg(
        epp->ep_default_adv_cap_mask = els.els_adv_cap_mask;
        epp->ep_adv_cap_mask = els.els_adv_cap_mask;
 
+       /*
+        * Enable firmware workarounds for hardware errata.
+        * Expected responses are:
+        *  - 0 (zero):
+        *      Success: workaround enabled or disabled as requested.
+        *  - MC_CMD_ERR_ENOSYS (reported as ENOTSUP):
+        *      Firmware does not support the MC_CMD_WORKAROUND request.
+        *      (assume that the workaround is not supported).
+        *  - MC_CMD_ERR_ENOENT (reported as ENOENT):
+        *      Firmware does not support the requested workaround.
+        *  - MC_CMD_ERR_EPERM  (reported as EACCES):
+        *      Unprivileged function cannot enable/disable workarounds.
+        *
+        * See efx_mcdi_request_errcode() for MCDI error translations.
+        */
+
+
        if (EFX_PCI_FUNCTION_IS_VF(encp)) {
                /*
                 * Interrupt testing does not work for VFs. See bug50084.
@@ -238,9 +255,23 @@ medford_board_cfg(
        /* Chained multicast is always enabled on Medford */
        encp->enc_bug26807_workaround = B_TRUE;
 
+       /*
+        * If the bug61265 workaround is enabled, then interrupt holdoff timers
+        * cannot be controlled by timer table writes, so MCDI must be used
+        * (timer table writes can still be used for wakeup timers).
+        */
+       rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG61265, B_TRUE,
+           NULL);
+       if ((rc == 0) || (rc == EACCES))
+               encp->enc_bug61265_workaround = B_TRUE;
+       else if ((rc == ENOTSUP) || (rc == ENOENT))
+               encp->enc_bug61265_workaround = B_FALSE;
+       else
+               goto fail8;
+
        /* Get clock frequencies (in MHz). */
        if ((rc = efx_mcdi_get_clock(enp, &sysclk, &dpcpu_clk)) != 0)
-               goto fail8;
+               goto fail9;
 
        /*
         * The Medford timer quantum is 1536 dpcpu_clk cycles, documented for
@@ -252,14 +283,14 @@ medford_board_cfg(
 
        /* Check capabilities of running datapath firmware */
        if ((rc = ef10_get_datapath_caps(enp)) != 0)
-           goto fail9;
+           goto fail10;
 
        /* Alignment for receive packet DMA buffers */
        encp->enc_rx_buf_align_start = 1;
 
        /* Get the RX DMA end padding alignment configuration */
        if ((rc = efx_mcdi_get_rxdp_config(enp, &end_padding)) != 0)
-               goto fail10;
+               goto fail11;
        encp->enc_rx_buf_align_end = end_padding;
 
        /* Alignment for WPTR updates */
@@ -288,13 +319,13 @@ medford_board_cfg(
         * can result in time-of-check/time-of-use bugs.
         */
        if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0)
-               goto fail11;
+               goto fail12;
        encp->enc_privilege_mask = mask;
 
        /* Get interrupt vector limits */
        if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) {
                if (EFX_PCI_FUNCTION_IS_PF(encp))
-                       goto fail12;
+                       goto fail13;
 
                /* Ignore error (cannot query vector limits from a VF). */
                base = 0;
@@ -317,12 +348,14 @@ medford_board_cfg(
 
        rc = medford_nic_get_required_pcie_bandwidth(enp, &bandwidth);
        if (rc != 0)
-               goto fail13;
+               goto fail14;
        encp->enc_required_pcie_bandwidth_mbps = bandwidth;
        encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN3;
 
        return (0);
 
+fail14:
+       EFSYS_PROBE(fail14);
 fail13:
        EFSYS_PROBE(fail13);
 fail12:
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to