From b82ec4de364519cd9593100c9cc3da480ad3d502 Mon Sep 17 00:00:00 2001 From: arybchik Date: Fri, 17 Jun 2016 08:59:08 +0000 Subject: [PATCH] MFC r301237 sfxge(4): support EVQ timer workaround via MCDI Submitted by: Andy Moreton Sponsored by: Solarflare Communications, Inc. Differential Revision: https://reviews.freebsd.org/6675 git-svn-id: svn://svn.freebsd.org/base/stable/10@301983 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/sfxge/common/ef10_ev.c | 105 +++++++++++++++++++++++------ sys/dev/sfxge/common/efx.h | 1 + sys/dev/sfxge/common/hunt_nic.c | 2 + sys/dev/sfxge/common/medford_nic.c | 45 +++++++++++-- 4 files changed, 127 insertions(+), 26 deletions(-) diff --git a/sys/dev/sfxge/common/ef10_ev.c b/sys/dev/sfxge/common/ef10_ev.c index 5a1c609df..bed286132 100644 --- a/sys/dev/sfxge/common/ef10_ev.c +++ b/sys/dev/sfxge/common/ef10_ev.c @@ -86,6 +86,52 @@ ef10_ev_mcdi( __in_opt void *arg); +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, @@ -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); diff --git a/sys/dev/sfxge/common/efx.h b/sys/dev/sfxge/common/efx.h index 366dc135c..4999c6efe 100644 --- a/sys/dev/sfxge/common/efx.h +++ b/sys/dev/sfxge/common/efx.h @@ -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; diff --git a/sys/dev/sfxge/common/hunt_nic.c b/sys/dev/sfxge/common/hunt_nic.c index 486e42405..9dbe1d4e6 100644 --- a/sys/dev/sfxge/common/hunt_nic.c +++ b/sys/dev/sfxge/common/hunt_nic.c @@ -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; diff --git a/sys/dev/sfxge/common/medford_nic.c b/sys/dev/sfxge/common/medford_nic.c index 0942bd77a..04d0f9b0d 100644 --- a/sys/dev/sfxge/common/medford_nic.c +++ b/sys/dev/sfxge/common/medford_nic.c @@ -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: -- 2.45.0