All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] sfc: additional virtual function support​
@ 2015-12-18 17:07 Bert Kenward
  2015-12-18 17:08 ` [PATCH net-next 1/5] sfc: Retry MCDI after NO_EVB_PORT error on a VF Bert Kenward
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:07 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers

This introduces the client side of a mechanism to defer authorisation of
operations, for example multicast subscription. Although primarily aimed at
SRIOV VFs this can also apply to unprivileged PFs.

Also handle reboot ordering corner cases better and reduce the level of some
logging.

Bert Kenward (4):
  sfc: Retry MCDI after NO_EVB_PORT error on a VF
  sfc: Handle MCDI proxy authorisation
  sfc: Make failed filter removal less noisy
  sfc: Downgrade or remove some error messages

Tomáš Pilař (1):
  sfc: Downgrade EPERM messages from MCDI to debug

 drivers/net/ethernet/sfc/ef10.c |  68 +++++++----
 drivers/net/ethernet/sfc/efx.c  |   7 +-
 drivers/net/ethernet/sfc/mcdi.c | 252 ++++++++++++++++++++++++++++++++++++----
 drivers/net/ethernet/sfc/mcdi.h |  10 ++
 4 files changed, 290 insertions(+), 47 deletions(-)

-- 
2.4.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/5] sfc: Retry MCDI after NO_EVB_PORT error on a VF
  2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
@ 2015-12-18 17:08 ` Bert Kenward
  2015-12-18 17:09 ` [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation Bert Kenward
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:08 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers

After reboot the vswitch configuration from the PF may not be
complete before the VF attempts to restore filters. In that
case we see NO_EVB_PORT errors from the MC. Retry up to a time
limit or until a different result is seen.

Signed-off-by: Bert Kenward <bkenward@solarflare.com>
---
 drivers/net/ethernet/sfc/mcdi.c | 99 ++++++++++++++++++++++++++++++++++-------
 drivers/net/ethernet/sfc/mcdi.h |  1 +
 2 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 41fb6b6..2509ca9 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -315,6 +315,7 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
 	}
 #endif
 
+	mcdi->resprc_raw = 0;
 	if (error && mcdi->resp_data_len == 0) {
 		netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
 		mcdi->resprc = -EIO;
@@ -325,8 +326,8 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
 		mcdi->resprc = -EIO;
 	} else if (error) {
 		efx->type->mcdi_read_response(efx, &hdr, mcdi->resp_hdr_len, 4);
-		mcdi->resprc =
-			efx_mcdi_errno(EFX_DWORD_FIELD(hdr, EFX_DWORD_0));
+		mcdi->resprc_raw = EFX_DWORD_FIELD(hdr, EFX_DWORD_0);
+		mcdi->resprc = efx_mcdi_errno(mcdi->resprc_raw);
 	} else {
 		mcdi->resprc = 0;
 	}
@@ -623,7 +624,8 @@ efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen)
 
 static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 				efx_dword_t *outbuf, size_t outlen,
-				size_t *outlen_actual, bool quiet)
+				size_t *outlen_actual, bool quiet,
+				int *raw_rc)
 {
 	struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
 	MCDI_DECLARE_BUF_ERR(errbuf);
@@ -669,6 +671,8 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 		 * acquiring the iface_lock. */
 		spin_lock_bh(&mcdi->iface_lock);
 		rc = mcdi->resprc;
+		if (raw_rc)
+			*raw_rc = mcdi->resprc_raw;
 		hdr_len = mcdi->resp_hdr_len;
 		data_len = mcdi->resp_data_len;
 		err_len = min(sizeof(errbuf), data_len);
@@ -708,27 +712,92 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
 			 const efx_dword_t *inbuf, size_t inlen,
 			 efx_dword_t *outbuf, size_t outlen,
-			 size_t *outlen_actual, bool quiet)
+			 size_t *outlen_actual, bool quiet, int *raw_rc)
 {
 	int rc;
 
 	rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
-	if (rc) {
-		if (outlen_actual)
-			*outlen_actual = 0;
+	if (rc)
 		return rc;
-	}
+
 	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, quiet);
+				    outlen_actual, quiet, raw_rc);
 }
 
+static int _efx_mcdi_rpc_evb_retry(struct efx_nic *efx, unsigned cmd,
+				   const efx_dword_t *inbuf, size_t inlen,
+				   efx_dword_t *outbuf, size_t outlen,
+				   size_t *outlen_actual, bool quiet)
+{
+	int raw_rc = 0;
+	int rc;
+
+	rc = _efx_mcdi_rpc(efx, cmd, inbuf, inlen,
+			   outbuf, outlen, outlen_actual, true, &raw_rc);
+
+	if ((rc == -EPROTO) && (raw_rc == MC_CMD_ERR_NO_EVB_PORT) &&
+	    efx->type->is_vf) {
+		/* If the EVB port isn't available within a VF this may
+		 * mean the PF is still bringing the switch up. We should
+		 * retry our request shortly.
+		 */
+		unsigned long abort_time = jiffies + MCDI_RPC_TIMEOUT;
+		unsigned int delay_us = 10000;
+
+		netif_dbg(efx, hw, efx->net_dev,
+			  "%s: NO_EVB_PORT; will retry request\n",
+			  __func__);
+
+		do {
+			usleep_range(delay_us, delay_us + 10000);
+			rc = _efx_mcdi_rpc(efx, cmd, inbuf, inlen,
+					   outbuf, outlen, outlen_actual,
+					   true, &raw_rc);
+			if (delay_us < 100000)
+				delay_us <<= 1;
+		} while ((rc == -EPROTO) &&
+			 (raw_rc == MC_CMD_ERR_NO_EVB_PORT) &&
+			 time_before(jiffies, abort_time));
+	}
+
+	if (rc && !quiet && !(cmd == MC_CMD_REBOOT && rc == -EIO))
+		efx_mcdi_display_error(efx, cmd, inlen,
+				       outbuf, outlen, rc);
+
+	return rc;
+}
+
+/**
+ * efx_mcdi_rpc - Issue an MCDI command and wait for completion
+ * @efx: NIC through which to issue the command
+ * @cmd: Command type number
+ * @inbuf: Command parameters
+ * @inlen: Length of command parameters, in bytes.  Must be a multiple
+ *	of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1.
+ * @outbuf: Response buffer.  May be %NULL if @outlen is 0.
+ * @outlen: Length of response buffer, in bytes.  If the actual
+ *	response is longer than @outlen & ~3, it will be truncated
+ *	to that length.
+ * @outlen_actual: Pointer through which to return the actual response
+ *	length.  May be %NULL if this is not needed.
+ *
+ * This function may sleep and therefore must be called in an appropriate
+ * context.
+ *
+ * Return: A negative error code, or zero if successful.  The error
+ *	code may come from the MCDI response or may indicate a failure
+ *	to communicate with the MC.  In the former case, the response
+ *	will still be copied to @outbuf and *@outlen_actual will be
+ *	set accordingly.  In the latter case, *@outlen_actual will be
+ *	set to zero.
+ */
 int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
 		 const efx_dword_t *inbuf, size_t inlen,
 		 efx_dword_t *outbuf, size_t outlen,
 		 size_t *outlen_actual)
 {
-	return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
-			     outlen_actual, false);
+	return _efx_mcdi_rpc_evb_retry(efx, cmd, inbuf, inlen, outbuf, outlen,
+				       outlen_actual, false);
 }
 
 /* Normally, on receiving an error code in the MCDI response,
@@ -744,8 +813,8 @@ int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd,
 		       efx_dword_t *outbuf, size_t outlen,
 		       size_t *outlen_actual)
 {
-	return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
-			     outlen_actual, true);
+	return _efx_mcdi_rpc_evb_retry(efx, cmd, inbuf, inlen, outbuf, outlen,
+				       outlen_actual, true);
 }
 
 int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
@@ -866,7 +935,7 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 			size_t *outlen_actual)
 {
 	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, false);
+				    outlen_actual, false, NULL);
 }
 
 int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
@@ -874,7 +943,7 @@ int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
 			      size_t *outlen_actual)
 {
 	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, true);
+				    outlen_actual, true, NULL);
 }
 
 void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 025d504..397660d 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -71,6 +71,7 @@ struct efx_mcdi_iface {
 	unsigned int credits;
 	unsigned int seqno;
 	int resprc;
+	int resprc_raw;
 	size_t resp_hdr_len;
 	size_t resp_data_len;
 	spinlock_t async_lock;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation
  2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
  2015-12-18 17:08 ` [PATCH net-next 1/5] sfc: Retry MCDI after NO_EVB_PORT error on a VF Bert Kenward
@ 2015-12-18 17:09 ` Bert Kenward
  2015-12-22 20:08   ` David Miller
  2015-12-18 17:09 ` [PATCH net-next 3/5] sfc: Make failed filter removal less noisy Bert Kenward
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:09 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers

For unprivileged functions operations can be authorised by an admin
function. Extra steps are introduced to the MCDI protocol in this
situation - the initial response from the MCDI tells us that the
operation has been deferred, and we must retry when told. We then
receive an event telling us to retry.

Note that this provides only the functionality for the unprivileged
functions, not the handling of the administrative side.

Signed-off-by: Bert Kenward <bkenward@solarflare.com>
---
 drivers/net/ethernet/sfc/mcdi.c | 156 +++++++++++++++++++++++++++++++++++++---
 drivers/net/ethernet/sfc/mcdi.h |   9 +++
 2 files changed, 157 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 2509ca9..ab68ff6 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -82,6 +82,7 @@ int efx_mcdi_init(struct efx_nic *efx)
 	mcdi->logging_enabled = mcdi_logging_default;
 #endif
 	init_waitqueue_head(&mcdi->wq);
+	init_waitqueue_head(&mcdi->proxy_rx_wq);
 	spin_lock_init(&mcdi->iface_lock);
 	mcdi->state = MCDI_STATE_QUIESCENT;
 	mcdi->mode = MCDI_MODE_POLL;
@@ -622,10 +623,30 @@ efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen)
 	return 0;
 }
 
-static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
+static bool efx_mcdi_get_proxy_handle(struct efx_nic *efx,
+				      size_t hdr_len, size_t data_len,
+				      u32 *proxy_handle)
+{
+	MCDI_DECLARE_BUF_ERR(testbuf);
+	const size_t buflen = sizeof(testbuf);
+
+	if (!proxy_handle || data_len < buflen)
+		return false;
+
+	efx->type->mcdi_read_response(efx, testbuf, hdr_len, buflen);
+	if (MCDI_DWORD(testbuf, ERR_CODE) == MC_CMD_ERR_PROXY_PENDING) {
+		*proxy_handle = MCDI_DWORD(testbuf, ERR_PROXY_PENDING_HANDLE);
+		return true;
+	}
+
+	return false;
+}
+
+static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned int cmd,
+				size_t inlen,
 				efx_dword_t *outbuf, size_t outlen,
 				size_t *outlen_actual, bool quiet,
-				int *raw_rc)
+				u32 *proxy_handle, int *raw_rc)
 {
 	struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
 	MCDI_DECLARE_BUF_ERR(errbuf);
@@ -659,6 +680,9 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 		spin_unlock_bh(&mcdi->iface_lock);
 	}
 
+	if (proxy_handle)
+		*proxy_handle = 0;
+
 	if (rc != 0) {
 		if (outlen_actual)
 			*outlen_actual = 0;
@@ -693,6 +717,12 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 			netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
 				  -rc);
 			efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
+		} else if (proxy_handle && (rc == -EPROTO) &&
+			   efx_mcdi_get_proxy_handle(efx, hdr_len, data_len,
+						     proxy_handle)) {
+			mcdi->proxy_rx_status = 0;
+			mcdi->proxy_rx_handle = 0;
+			mcdi->state = MCDI_STATE_PROXY_WAIT;
 		} else if (rc && !quiet) {
 			efx_mcdi_display_error(efx, cmd, inlen, errbuf, err_len,
 					       rc);
@@ -705,23 +735,121 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 		}
 	}
 
-	efx_mcdi_release(mcdi);
+	if (!proxy_handle || !*proxy_handle)
+		efx_mcdi_release(mcdi);
 	return rc;
 }
 
-static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
+static void efx_mcdi_proxy_abort(struct efx_mcdi_iface *mcdi)
+{
+	if (mcdi->state == MCDI_STATE_PROXY_WAIT) {
+		/* Interrupt the proxy wait. */
+		mcdi->proxy_rx_status = -EINTR;
+		wake_up(&mcdi->proxy_rx_wq);
+	}
+}
+
+static void efx_mcdi_ev_proxy_response(struct efx_nic *efx,
+				       u32 handle, int status)
+{
+	struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+
+	WARN_ON(mcdi->state != MCDI_STATE_PROXY_WAIT);
+
+	mcdi->proxy_rx_status = efx_mcdi_errno(status);
+	/* Ensure the status is written before we update the handle, since the
+	 * latter is used to check if we've finished.
+	 */
+	wmb();
+	mcdi->proxy_rx_handle = handle;
+	wake_up(&mcdi->proxy_rx_wq);
+}
+
+static int efx_mcdi_proxy_wait(struct efx_nic *efx, u32 handle, bool quiet)
+{
+	struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+	int rc;
+
+	/* Wait for a proxy event, or timeout. */
+	rc = wait_event_timeout(mcdi->proxy_rx_wq,
+				mcdi->proxy_rx_handle != 0 ||
+				mcdi->proxy_rx_status == -EINTR,
+				MCDI_RPC_TIMEOUT);
+
+	if (rc <= 0) {
+		netif_dbg(efx, hw, efx->net_dev,
+			  "MCDI proxy timeout %d\n", handle);
+		return -ETIMEDOUT;
+	} else if (mcdi->proxy_rx_handle != handle) {
+		netif_warn(efx, hw, efx->net_dev,
+			   "MCDI proxy unexpected handle %d (expected %d)\n",
+			   mcdi->proxy_rx_handle, handle);
+		return -EINVAL;
+	}
+
+	return mcdi->proxy_rx_status;
+}
+
+static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned int cmd,
 			 const efx_dword_t *inbuf, size_t inlen,
 			 efx_dword_t *outbuf, size_t outlen,
 			 size_t *outlen_actual, bool quiet, int *raw_rc)
 {
+	u32 proxy_handle = 0; /* Zero is an invalid proxy handle. */
 	int rc;
 
+	if (inbuf && inlen && (inbuf == outbuf)) {
+		/* The input buffer can't be aliased with the output. */
+#ifdef DEBUG
+		WARN_ON(1);
+#endif
+		return -EINVAL;
+	}
+
 	rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
 	if (rc)
 		return rc;
 
-	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, quiet, raw_rc);
+	rc = _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
+				  outlen_actual, quiet, &proxy_handle, raw_rc);
+
+	if (proxy_handle) {
+		/* Handle proxy authorisation. This allows approval of MCDI
+		 * operations to be delegated to the admin function, allowing
+		 * fine control over (eg) multicast subscriptions.
+		 */
+		struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+
+		netif_dbg(efx, hw, efx->net_dev,
+			  "MCDI waiting for proxy auth %d\n",
+			  proxy_handle);
+		rc = efx_mcdi_proxy_wait(efx, proxy_handle, quiet);
+
+		if (rc == 0) {
+			netif_dbg(efx, hw, efx->net_dev,
+				  "MCDI proxy retry %d\n", proxy_handle);
+
+			/* We now retry the original request. */
+			mcdi->state = MCDI_STATE_RUNNING_SYNC;
+			efx_mcdi_send_request(efx, cmd, inbuf, inlen);
+
+			rc = _efx_mcdi_rpc_finish(efx, cmd, inlen,
+						  outbuf, outlen, outlen_actual,
+						  quiet, NULL, raw_rc);
+		} else {
+			netif_printk(efx, hw,
+				     rc == -EPERM ? KERN_DEBUG : KERN_ERR,
+				     efx->net_dev,
+				     "MC command 0x%x failed after proxy auth rc=%d\n",
+				     cmd, rc);
+
+			if (rc == -EINTR || rc == -EIO)
+				efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
+			efx_mcdi_release(mcdi);
+		}
+	}
+
+	return rc;
 }
 
 static int _efx_mcdi_rpc_evb_retry(struct efx_nic *efx, unsigned cmd,
@@ -935,7 +1063,7 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
 			size_t *outlen_actual)
 {
 	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, false, NULL);
+				    outlen_actual, false, NULL, NULL);
 }
 
 int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
@@ -943,7 +1071,7 @@ int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
 			      size_t *outlen_actual)
 {
 	return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
-				    outlen_actual, true, NULL);
+				    outlen_actual, true, NULL, NULL);
 }
 
 void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
@@ -1083,8 +1211,13 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
 	 * receiving a REBOOT event after posting the MCDI
 	 * request. Did the mc reboot before or after the copyout? The
 	 * best we can do always is just return failure.
+	 *
+	 * If there is an outstanding proxy response expected it is not going
+	 * to arrive. We should thus abort it.
 	 */
 	spin_lock(&mcdi->iface_lock);
+	efx_mcdi_proxy_abort(mcdi);
+
 	if (efx_mcdi_complete_sync(mcdi)) {
 		if (mcdi->mode == MCDI_MODE_EVENTS) {
 			mcdi->resprc = rc;
@@ -1132,6 +1265,8 @@ static void efx_mcdi_ev_bist(struct efx_nic *efx)
 
 	spin_lock(&mcdi->iface_lock);
 	efx->mc_bist_for_other_fn = true;
+	efx_mcdi_proxy_abort(mcdi);
+
 	if (efx_mcdi_complete_sync(mcdi)) {
 		if (mcdi->mode == MCDI_MODE_EVENTS) {
 			mcdi->resprc = -EIO;
@@ -1240,6 +1375,11 @@ void efx_mcdi_process_event(struct efx_channel *channel,
 			  EFX_QWORD_VAL(*event));
 		efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
 		break;
+	case MCDI_EVENT_CODE_PROXY_RESPONSE:
+		efx_mcdi_ev_proxy_response(efx,
+				MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_HANDLE),
+				MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_RC));
+		break;
 	default:
 		netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
 			  code);
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 397660d..c9aeb07 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -17,6 +17,8 @@
  * @MCDI_STATE_RUNNING_SYNC: There is a synchronous MCDI request pending.
  *	Only the thread that moved into this state is allowed to move out of it.
  * @MCDI_STATE_RUNNING_ASYNC: There is an asynchronous MCDI request pending.
+ * @MCDI_STATE_PROXY_WAIT: An MCDI request has completed with a response that
+ *	indicates we must wait for a proxy try again message.
  * @MCDI_STATE_COMPLETED: An MCDI request has completed, but the owning thread
  *	has not yet consumed the result. For all other threads, equivalent to
  *	%MCDI_STATE_RUNNING.
@@ -25,6 +27,7 @@ enum efx_mcdi_state {
 	MCDI_STATE_QUIESCENT,
 	MCDI_STATE_RUNNING_SYNC,
 	MCDI_STATE_RUNNING_ASYNC,
+	MCDI_STATE_PROXY_WAIT,
 	MCDI_STATE_COMPLETED,
 };
 
@@ -60,6 +63,9 @@ enum efx_mcdi_mode {
  * @async_timer: Timer for asynchronous request timeout
  * @logging_buffer: buffer that may be used to build MCDI tracing messages
  * @logging_enabled: whether to trace MCDI
+ * @proxy_rx_handle: Most recently received proxy authorisation handle
+ * @proxy_rx_status: Status of most recent proxy authorisation
+ * @proxy_rx_wq: Wait queue for updates to proxy_rx_handle
  */
 struct efx_mcdi_iface {
 	struct efx_nic *efx;
@@ -81,6 +87,9 @@ struct efx_mcdi_iface {
 	char *logging_buffer;
 	bool logging_enabled;
 #endif
+	unsigned int proxy_rx_handle;
+	int proxy_rx_status;
+	wait_queue_head_t proxy_rx_wq;
 };
 
 struct efx_mcdi_mon {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 3/5] sfc: Make failed filter removal less noisy
  2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
  2015-12-18 17:08 ` [PATCH net-next 1/5] sfc: Retry MCDI after NO_EVB_PORT error on a VF Bert Kenward
  2015-12-18 17:09 ` [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation Bert Kenward
@ 2015-12-18 17:09 ` Bert Kenward
  2015-12-18 17:09 ` [PATCH net-next 4/5] sfc: Downgrade EPERM messages from MCDI to debug Bert Kenward
  2015-12-18 17:10 ` [PATCH net-next 5/5] sfc: Downgrade or remove some error messages Bert Kenward
  4 siblings, 0 replies; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:09 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers

There are situations - mostly reset related - where our view of the
filter table differs from the hardware. In this case we may try and
remove filters that aren't actually installed. This isn't that
interesting in most situations, so downgrade the logging.

Signed-off-by: Bert Kenward <bkenward@solarflare.com>
---
 drivers/net/ethernet/sfc/ef10.c | 48 ++++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index c4a0e8a..edffc9a 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -3832,13 +3832,12 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
 			       MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
 		MCDI_SET_QWORD(inbuf, FILTER_OP_IN_HANDLE,
 			       table->entry[filter_idx].handle);
-		rc = efx_mcdi_rpc(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf),
-				  NULL, 0, NULL);
+		rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FILTER_OP, inbuf,
+					sizeof(inbuf), NULL, 0, NULL);
 		if (rc)
-			netdev_WARN(efx->net_dev,
-				    "filter_idx=%#x handle=%#llx\n",
-				    filter_idx,
-				    table->entry[filter_idx].handle);
+			netif_info(efx, drv, efx->net_dev,
+				   "%s: filter %04x remove failed\n",
+				   __func__, filter_idx);
 		kfree(spec);
 	}
 
@@ -3847,11 +3846,14 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
 }
 
 #define EFX_EF10_FILTER_DO_MARK_OLD(id) \
-		if (id != EFX_EF10_FILTER_ID_INVALID) { \
-			filter_idx = efx_ef10_filter_get_unsafe_id(efx, id); \
-			WARN_ON(!table->entry[filter_idx].spec); \
-			table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; \
-		}
+	if (id != EFX_EF10_FILTER_ID_INVALID) { \
+		filter_idx = efx_ef10_filter_get_unsafe_id(efx, id); \
+		if (!table->entry[filter_idx].spec) \
+			netif_dbg(efx, drv, efx->net_dev, \
+				  "%s: marked null spec old %04x:%04x\n", \
+				  __func__, id, filter_idx); \
+		table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD;\
+	}
 static void efx_ef10_filter_mark_old(struct efx_nic *efx)
 {
 	struct efx_ef10_filter_table *table = efx->filter_state;
@@ -4070,19 +4072,31 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
 static void efx_ef10_filter_remove_old(struct efx_nic *efx)
 {
 	struct efx_ef10_filter_table *table = efx->filter_state;
-	bool remove_failed = false;
+	int remove_failed = 0;
+	int remove_noent = 0;
+	int rc;
 	int i;
 
 	for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) {
 		if (ACCESS_ONCE(table->entry[i].spec) &
 		    EFX_EF10_FILTER_FLAG_AUTO_OLD) {
-			if (efx_ef10_filter_remove_internal(
-				    efx, 1U << EFX_FILTER_PRI_AUTO,
-				    i, true) < 0)
-				remove_failed = true;
+			rc = efx_ef10_filter_remove_internal(efx,
+					1U << EFX_FILTER_PRI_AUTO, i, true);
+			if (rc == -ENOENT)
+				remove_noent++;
+			else if (rc)
+				remove_failed++;
 		}
 	}
-	WARN_ON(remove_failed);
+
+	if (remove_failed)
+		netif_info(efx, drv, efx->net_dev,
+			   "%s: failed to remove %d filters\n",
+			   __func__, remove_failed);
+	if (remove_noent)
+		netif_info(efx, drv, efx->net_dev,
+			   "%s: failed to remove %d non-existent filters\n",
+			   __func__, remove_noent);
 }
 
 static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 4/5] sfc: Downgrade EPERM messages from MCDI to debug
  2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
                   ` (2 preceding siblings ...)
  2015-12-18 17:09 ` [PATCH net-next 3/5] sfc: Make failed filter removal less noisy Bert Kenward
@ 2015-12-18 17:09 ` Bert Kenward
  2015-12-18 17:10 ` [PATCH net-next 5/5] sfc: Downgrade or remove some error messages Bert Kenward
  4 siblings, 0 replies; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:09 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers, Tomas Pilar

From: Tomáš Pilař <tpilar@solarflare.com>

When running in an unprivileged function we expect some MC commands
to fail with permission errors. To avoid log spew downgrade these to
debug only.

Signed-off-by: Bert Kenward <bkenward@solarflare.com>
---
 drivers/net/ethernet/sfc/mcdi.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index ab68ff6..7df183a 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -1084,9 +1084,10 @@ void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
 		code = MCDI_DWORD(outbuf, ERR_CODE);
 	if (outlen >= MC_CMD_ERR_ARG_OFST + 4)
 		err_arg = MCDI_DWORD(outbuf, ERR_ARG);
-	netif_err(efx, hw, efx->net_dev,
-		  "MC command 0x%x inlen %d failed rc=%d (raw=%d) arg=%d\n",
-		  cmd, (int)inlen, rc, code, err_arg);
+	netif_printk(efx, hw, rc == -EPERM ? KERN_DEBUG : KERN_ERR,
+		     efx->net_dev,
+		     "MC command 0x%x inlen %zu failed rc=%d (raw=%d) arg=%d\n",
+		     cmd, inlen, rc, code, err_arg);
 }
 
 /* Switch to polled MCDI completions.  This can be called in various
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 5/5] sfc: Downgrade or remove some error messages
  2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
                   ` (3 preceding siblings ...)
  2015-12-18 17:09 ` [PATCH net-next 4/5] sfc: Downgrade EPERM messages from MCDI to debug Bert Kenward
@ 2015-12-18 17:10 ` Bert Kenward
  4 siblings, 0 replies; 7+ messages in thread
From: Bert Kenward @ 2015-12-18 17:10 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Solarflare linux maintainers

Depending on configuration the NIC may return errors for unprivileged
functions and/or VFs. Where these are expected and handled, reduce the
level of any output.

Signed-off-by: Bert Kenward <bkenward@solarflare.com>
---
 drivers/net/ethernet/sfc/ef10.c | 20 ++++++++++++++------
 drivers/net/ethernet/sfc/efx.c  |  7 ++++---
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index edffc9a..9adb895 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -486,10 +486,17 @@ static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n)
 	BUILD_BUG_ON(MC_CMD_ALLOC_PIOBUF_IN_LEN != 0);
 
 	for (i = 0; i < n; i++) {
-		rc = efx_mcdi_rpc(efx, MC_CMD_ALLOC_PIOBUF, NULL, 0,
-				  outbuf, sizeof(outbuf), &outlen);
-		if (rc)
+		rc = efx_mcdi_rpc_quiet(efx, MC_CMD_ALLOC_PIOBUF, NULL, 0,
+					outbuf, sizeof(outbuf), &outlen);
+		if (rc) {
+			/* Don't display the MC error if we didn't have space
+			 * for a VF.
+			 */
+			if (!(efx_ef10_is_vf(efx) && rc == -ENOSPC))
+				efx_mcdi_display_error(efx, MC_CMD_ALLOC_PIOBUF,
+						       0, outbuf, outlen, rc);
 			break;
+		}
 		if (outlen < MC_CMD_ALLOC_PIOBUF_OUT_LEN) {
 			rc = -EIO;
 			break;
@@ -4027,9 +4034,10 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
 
 	rc = efx_ef10_filter_insert(efx, &spec, true);
 	if (rc < 0) {
-		netif_warn(efx, drv, efx->net_dev,
-			   "%scast mismatch filter insert failed rc=%d\n",
-			   multicast ? "Multi" : "Uni", rc);
+		netif_printk(efx, drv, rc == -EPERM ? KERN_DEBUG : KERN_WARNING,
+			     efx->net_dev,
+			     "%scast mismatch filter insert failed rc=%d\n",
+			     multicast ? "Multi" : "Uni", rc);
 	} else if (multicast) {
 		table->mcdef_id = efx_ef10_filter_get_unsafe_id(efx, rc);
 		if (!nic_data->workaround_26807) {
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 6f69743..0705ec86 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -3174,14 +3174,15 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
 	rtnl_lock();
 	rc = efx_mtd_probe(efx);
 	rtnl_unlock();
-	if (rc)
+	if (rc && rc != -EPERM)
 		netif_warn(efx, probe, efx->net_dev,
 			   "failed to create MTDs (%d)\n", rc);
 
 	rc = pci_enable_pcie_error_reporting(pci_dev);
 	if (rc && rc != -EINVAL)
-		netif_warn(efx, probe, efx->net_dev,
-			   "pci_enable_pcie_error_reporting failed (%d)\n", rc);
+		netif_notice(efx, probe, efx->net_dev,
+			     "PCIE error reporting unavailable (%d).\n",
+			     rc);
 
 	return 0;
 
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation
  2015-12-18 17:09 ` [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation Bert Kenward
@ 2015-12-22 20:08   ` David Miller
  0 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2015-12-22 20:08 UTC (permalink / raw)
  To: bkenward; +Cc: netdev, linux-net-drivers

From: Bert Kenward <bkenward@solarflare.com>
Date: Fri, 18 Dec 2015 17:09:04 +0000

> +#ifdef DEBUG
> +		WARN_ON(1);
> +#endif

Don't do stuff like this.  Either the assertion is valid and belongs
here, or it doesn't.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-12-22 20:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-18 17:07 [PATCH net-next 0/5] sfc: additional virtual function support​ Bert Kenward
2015-12-18 17:08 ` [PATCH net-next 1/5] sfc: Retry MCDI after NO_EVB_PORT error on a VF Bert Kenward
2015-12-18 17:09 ` [PATCH net-next 2/5] sfc: Handle MCDI proxy authorisation Bert Kenward
2015-12-22 20:08   ` David Miller
2015-12-18 17:09 ` [PATCH net-next 3/5] sfc: Make failed filter removal less noisy Bert Kenward
2015-12-18 17:09 ` [PATCH net-next 4/5] sfc: Downgrade EPERM messages from MCDI to debug Bert Kenward
2015-12-18 17:10 ` [PATCH net-next 5/5] sfc: Downgrade or remove some error messages Bert Kenward

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.