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

Commit eb9f6744 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller
Browse files

sfc: Implement ethtool reset operation



Refactor efx_reset_down() and efx_reset_up() accordingly.

Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 89c758fa
Loading
Loading
Loading
Loading
+48 −50
Original line number Diff line number Diff line
@@ -1754,58 +1754,49 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
	rc = efx->type->init(efx);
	if (rc) {
		EFX_ERR(efx, "failed to initialise NIC\n");
		ok = false;
		goto fail;
	}

	if (!ok)
		goto fail;

	if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
		if (ok) {
		rc = efx->phy_op->init(efx);
		if (rc)
				ok = false;
			goto fail;
		if (efx->phy_op->reconfigure(efx))
			EFX_ERR(efx, "could not restore PHY settings\n");
	}
		if (!ok)
			efx->port_initialized = false;
	}

	if (ok) {
	efx->mac_op->reconfigure(efx);

	efx_init_channels(efx);
	}

	mutex_unlock(&efx->spi_lock);
	mutex_unlock(&efx->mac_lock);

	if (ok)
	efx_start_all(efx);

	return 0;

fail:
	efx->port_initialized = false;

	mutex_unlock(&efx->spi_lock);
	mutex_unlock(&efx->mac_lock);

	return rc;
}

/* Reset the NIC as transparently as possible. Do not reset the PHY
 * Note that the reset may fail, in which case the card will be left
 * in a most-probably-unusable state.
/* Reset the NIC using the specified method.  Note that the reset may
 * fail, in which case the card will be left in an unusable state.
 *
 * This function will sleep.  You cannot reset from within an atomic
 * state; use efx_schedule_reset() instead.
 *
 * Grabs the rtnl_lock.
 * Caller must hold the rtnl_lock.
 */
static int efx_reset(struct efx_nic *efx)
int efx_reset(struct efx_nic *efx, enum reset_type method)
{
	enum reset_type method = efx->reset_pending;
	int rc = 0;

	/* Serialise with kernel interfaces */
	rtnl_lock();

	/* If we're not RUNNING then don't reset. Leave the reset_pending
	 * flag set so that efx_pci_probe_main will be retried */
	if (efx->state != STATE_RUNNING) {
		EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
		goto out_unlock;
	}
	int rc, rc2;
	bool disabled;

	EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));

@@ -1814,7 +1805,7 @@ static int efx_reset(struct efx_nic *efx)
	rc = efx->type->reset(efx, method);
	if (rc) {
		EFX_ERR(efx, "failed to reset hardware\n");
		goto out_disable;
		goto out;
	}

	/* Allow resets to be rescheduled. */
@@ -1826,25 +1817,22 @@ static int efx_reset(struct efx_nic *efx)
	 * can respond to requests. */
	pci_set_master(efx->pci_dev);

out:
	/* Leave device stopped if necessary */
	if (method == RESET_TYPE_DISABLE) {
		efx_reset_up(efx, method, false);
		rc = -EIO;
	} else {
		rc = efx_reset_up(efx, method, true);
	disabled = rc || method == RESET_TYPE_DISABLE;
	rc2 = efx_reset_up(efx, method, !disabled);
	if (rc2) {
		disabled = true;
		if (!rc)
			rc = rc2;
	}

out_disable:
	if (rc) {
	if (disabled) {
		EFX_ERR(efx, "has been disabled\n");
		efx->state = STATE_DISABLED;
		dev_close(efx->net_dev);
	} else {
		EFX_LOG(efx, "reset complete\n");
	}

out_unlock:
	rtnl_unlock();
	return rc;
}

@@ -1853,9 +1841,19 @@ static int efx_reset(struct efx_nic *efx)
 */
static void efx_reset_work(struct work_struct *data)
{
	struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
	struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);

	efx_reset(nic);
	/* If we're not RUNNING then don't reset. Leave the reset_pending
	 * flag set so that efx_pci_probe_main will be retried */
	if (efx->state != STATE_RUNNING) {
		EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
		return;
	}

	rtnl_lock();
	if (efx_reset(efx, efx->reset_pending))
		dev_close(efx->net_dev);
	rtnl_unlock();
}

void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
+1 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev,
extern const struct ethtool_ops efx_ethtool_ops;

/* Reset handling */
extern int efx_reset(struct efx_nic *efx, enum reset_type method);
extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);

+30 −0
Original line number Diff line number Diff line
@@ -754,6 +754,35 @@ static int efx_ethtool_set_wol(struct net_device *net_dev,
	return efx->type->set_wol(efx, wol->wolopts);
}

extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
{
	struct efx_nic *efx = netdev_priv(net_dev);
	enum reset_type method;
	enum {
		ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
					   ETH_RESET_OFFLOAD | ETH_RESET_MAC)
	};

	/* Check for minimal reset flags */
	if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE)
		return -EINVAL;
	*flags ^= ETH_RESET_EFX_INVISIBLE;
	method = RESET_TYPE_INVISIBLE;

	if (*flags & ETH_RESET_PHY) {
		*flags ^= ETH_RESET_PHY;
		method = RESET_TYPE_ALL;
	}

	if ((*flags & efx->type->reset_world_flags) ==
	    efx->type->reset_world_flags) {
		*flags ^= efx->type->reset_world_flags;
		method = RESET_TYPE_WORLD;
	}

	return efx_reset(efx, method);
}

const struct ethtool_ops efx_ethtool_ops = {
	.get_settings		= efx_ethtool_get_settings,
	.set_settings		= efx_ethtool_set_settings,
@@ -784,4 +813,5 @@ const struct ethtool_ops efx_ethtool_ops = {
	.get_ethtool_stats	= efx_ethtool_get_stats,
	.get_wol                = efx_ethtool_get_wol,
	.set_wol                = efx_ethtool_set_wol,
	.reset			= efx_ethtool_reset,
};
+2 −0
Original line number Diff line number Diff line
@@ -3305,6 +3305,7 @@ struct efx_nic_type falcon_a1_nic_type = {
	.phys_addr_channels = 4,
	.tx_dc_base = 0x130000,
	.rx_dc_base = 0x100000,
	.reset_world_flags = ETH_RESET_IRQ,
};

struct efx_nic_type falcon_b0_nic_type = {
@@ -3348,5 +3349,6 @@ struct efx_nic_type falcon_b0_nic_type = {
				   * channels */
	.tx_dc_base = 0x130000,
	.rx_dc_base = 0x100000,
	.reset_world_flags = ETH_RESET_IRQ,
};
+3 −0
Original line number Diff line number Diff line
@@ -880,6 +880,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
 *	descriptors
 * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
 * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
 * @reset_world_flags: Flags for additional components covered by
 *	reset method RESET_TYPE_WORLD
 */
struct efx_nic_type {
	int (*probe)(struct efx_nic *efx);
@@ -915,6 +917,7 @@ struct efx_nic_type {
	unsigned int phys_addr_channels;
	unsigned int tx_dc_base;
	unsigned int rx_dc_base;
	u32 reset_world_flags;
};

/**************************************************************************