svn commit: r301237 - head/sys/dev/sfxge/common
Andrew Rybchenko
arybchik at FreeBSD.org
Fri Jun 3 05:27:36 UTC 2016
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:
More information about the svn-src-all
mailing list