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