Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78c1f0a0 authored by Steve Hodgson's avatar Steve Hodgson Committed by David S. Miller
Browse files

sfc: Generalise link state monitoring



Use the efx_nic_type::monitor operation or event handling as
appropriate.

Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d3245b28
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -1174,10 +1174,18 @@ static void efx_start_all(struct efx_nic *efx)

	falcon_enable_interrupts(efx);

	/* Start the hardware monitor (if there is one) if we're in RUNNING */
	if (efx->state == STATE_RUNNING && efx->type->monitor != NULL)
	/* Start the hardware monitor if there is one. Otherwise (we're link
	 * event driven), we have to poll the PHY because after an event queue
	 * flush, we could have a missed a link state change */
	if (efx->type->monitor != NULL) {
		queue_delayed_work(efx->workqueue, &efx->monitor_work,
				   efx_monitor_interval);
	} else {
		mutex_lock(&efx->mac_lock);
		if (efx->phy_op->poll(efx))
			efx_link_status_changed(efx);
		mutex_unlock(&efx->mac_lock);
	}

	efx->type->start_stats(efx);
}
@@ -1421,6 +1429,10 @@ static int efx_net_open(struct net_device *net_dev)
	if (efx->phy_mode & PHY_MODE_SPECIAL)
		return -EBUSY;

	/* Notify the kernel of the link state polled during driver load,
	 * before the monitor starts running */
	efx_link_status_changed(efx);

	efx_start_all(efx);
	return 0;
}
+47 −32
Original line number Diff line number Diff line
@@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
	return 0;
}

/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but
 * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it
 * to delay and retry. Therefore, it's safer to just poll directly. Wait
 * for link up and any faults to dissipate. */
static int efx_wait_for_link(struct efx_nic *efx)
{
	struct efx_link_state *link_state = &efx->link_state;
	int count;
	bool link_up;

	for (count = 0; count < 40; count++) {
		schedule_timeout_uninterruptible(HZ / 10);

		if (efx->type->monitor != NULL) {
			mutex_lock(&efx->mac_lock);
			efx->type->monitor(efx);
			mutex_unlock(&efx->mac_lock);
		} else {
			struct efx_channel *channel = &efx->channel[0];
			if (channel->work_pending)
				efx_process_channel_now(channel);
		}

		mutex_lock(&efx->mac_lock);
		link_up = link_state->up;
		if (link_up)
			link_up = !efx->mac_op->check_fault(efx);
		mutex_unlock(&efx->mac_lock);

		if (link_up)
			return 0;
	}

	return -ETIMEDOUT;
}

static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
			      unsigned int loopback_modes)
{
	enum efx_loopback_mode mode;
	struct efx_loopback_state *state;
	struct efx_tx_queue *tx_queue;
	bool link_up;
	int count, rc = 0;
	int rc = 0;

	/* Set the port loopback_selftest member. From this point on
	 * all received packets will be dropped. Mark the state as
@@ -589,43 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,

		/* Move the port into the specified loopback mode. */
		state->flush = true;
		mutex_lock(&efx->mac_lock);
		efx->loopback_mode = mode;
		efx_reconfigure_port(efx);

		/* Wait for the PHY to signal the link is up. Interrupts
		 * are enabled for PHY's using LASI, otherwise we poll()
		 * quickly */
		count = 0;
		do {
			struct efx_channel *channel = &efx->channel[0];

			efx->phy_op->poll(efx);
			schedule_timeout_uninterruptible(HZ / 10);
			if (channel->work_pending)
				efx_process_channel_now(channel);
			/* Wait for PHY events to be processed */
			flush_workqueue(efx->workqueue);
			rmb();

			/* We need both the PHY and MAC-PHY links to be OK */
			link_up = efx->link_state.up;
			if (link_up)
				link_up = !efx->mac_op->check_fault(efx);

		} while ((++count < 20) && !link_up);
		rc = __efx_reconfigure_port(efx);
		mutex_unlock(&efx->mac_lock);
		if (rc) {
			EFX_ERR(efx, "unable to move into %s loopback\n",
				LOOPBACK_MODE(efx));
			goto out;
		}

		/* The link should now be up. If it isn't, there is no point
		 * in attempting a loopback test */
		if (!link_up) {
		rc = efx_wait_for_link(efx);
		if (rc) {
			EFX_ERR(efx, "loopback %s never came up\n",
				LOOPBACK_MODE(efx));
			rc = -EIO;
			goto out;
		}

		EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
			LOOPBACK_MODE(efx), count);

		/* Test every TX queue */
		efx_for_each_tx_queue(tx_queue, efx) {
			state->offload_csum = (tx_queue->queue ==