Date: Fri, 3 Jun 2016 05:27:34 +0000 (UTC) From: Andrew Rybchenko <arybchik@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r301237 - head/sys/dev/sfxge/common Message-ID: <201606030527.u535RYUq046355@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606030527.u535RYUq046355>