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

Commit 10d1e8ca authored by David S. Miller's avatar David S. Miller
Browse files
parents cd0d7228 ff79c8ac
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
config SFC
	tristate "Solarflare Solarstorm SFC4000/SFC9000-family support"
	tristate "Solarflare SFC4000/SFC9000-family support"
	depends on PCI && INET
	select MDIO
	select CRC32
@@ -7,13 +7,12 @@ config SFC
	select I2C_ALGOBIT
	help
	  This driver supports 10-gigabit Ethernet cards based on
	  the Solarflare Communications Solarstorm SFC4000 and
	  SFC9000-family controllers.
	  the Solarflare SFC4000 and SFC9000-family controllers.

	  To compile this driver as a module, choose M here.  The module
	  will be called sfc.
config SFC_MTD
	bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support"
	bool "Solarflare SFC4000/SFC9000-family MTD support"
	depends on SFC && MTD && !(SFC=y && MTD=m)
	default y
	help
+23 −37
Original line number Diff line number Diff line
@@ -229,8 +229,7 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
	struct efx_nic *efx = channel->efx;
	int spent;

	if (unlikely(efx->reset_pending != RESET_TYPE_NONE ||
		     !channel->enabled))
	if (unlikely(efx->reset_pending || !channel->enabled))
		return 0;

	spent = efx_nic_process_eventq(channel, budget);
@@ -1461,7 +1460,7 @@ static void efx_start_all(struct efx_nic *efx)
	 * reset_pending [modified from an atomic context], we instead guarantee
	 * that efx_mcdi_mode_poll() isn't reverted erroneously */
	efx_mcdi_mode_event(efx);
	if (efx->reset_pending != RESET_TYPE_NONE)
	if (efx->reset_pending)
		efx_mcdi_mode_poll(efx);

	/* Start the hardware monitor if there is one. Otherwise (we're link
@@ -2118,8 +2117,10 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
		goto out;
	}

	/* Allow resets to be rescheduled. */
	efx->reset_pending = RESET_TYPE_NONE;
	/* Clear flags for the scopes we covered.  We assume the NIC and
	 * driver are now quiescent so that there is no race here.
	 */
	efx->reset_pending &= -(1 << (method + 1));

	/* Reinitialise bus-mastering, which may have been turned off before
	 * the reset was scheduled. This is still appropriate, even in the
@@ -2154,12 +2155,13 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
static void efx_reset_work(struct work_struct *data)
{
	struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
	unsigned long pending = ACCESS_ONCE(efx->reset_pending);

	if (efx->reset_pending == RESET_TYPE_NONE)
	if (!pending)
		return;

	/* If we're not RUNNING then don't reset. Leave the reset_pending
	 * flag set so that efx_pci_probe_main will be retried */
	 * flags set so that efx_pci_probe_main will be retried */
	if (efx->state != STATE_RUNNING) {
		netif_info(efx, drv, efx->net_dev,
			   "scheduled reset quenched. NIC not RUNNING\n");
@@ -2167,7 +2169,7 @@ static void efx_reset_work(struct work_struct *data)
	}

	rtnl_lock();
	(void)efx_reset(efx, efx->reset_pending);
	(void)efx_reset(efx, fls(pending) - 1);
	rtnl_unlock();
}

@@ -2175,40 +2177,24 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
{
	enum reset_type method;

	if (efx->reset_pending != RESET_TYPE_NONE) {
		netif_info(efx, drv, efx->net_dev,
			   "quenching already scheduled reset\n");
		return;
	}

	switch (type) {
	case RESET_TYPE_INVISIBLE:
	case RESET_TYPE_ALL:
	case RESET_TYPE_WORLD:
	case RESET_TYPE_DISABLE:
		method = type;
		netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
			  RESET_TYPE(method));
		break;
	case RESET_TYPE_RX_RECOVERY:
	case RESET_TYPE_RX_DESC_FETCH:
	case RESET_TYPE_TX_DESC_FETCH:
	case RESET_TYPE_TX_SKIP:
		method = RESET_TYPE_INVISIBLE;
		break;
	case RESET_TYPE_MC_FAILURE:
	default:
		method = RESET_TYPE_ALL;
		break;
	}

	if (method != type)
		method = efx->type->map_reset_reason(type);
		netif_dbg(efx, drv, efx->net_dev,
			  "scheduling %s reset for %s\n",
			  RESET_TYPE(method), RESET_TYPE(type));
	else
		netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
			  RESET_TYPE(method));
		break;
	}

	efx->reset_pending = method;
	set_bit(method, &efx->reset_pending);

	/* efx_process_channel() will no longer read events once a
	 * reset is scheduled. So switch back to poll'd MCDI completions. */
@@ -2288,7 +2274,6 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type,
	efx->pci_dev = pci_dev;
	efx->msg_enable = debug;
	efx->state = STATE_INIT;
	efx->reset_pending = RESET_TYPE_NONE;
	strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));

	efx->net_dev = net_dev;
@@ -2491,7 +2476,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
		goto fail1;

	netif_info(efx, probe, efx->net_dev,
		   "Solarflare Communications NIC detected\n");
		   "Solarflare NIC detected\n");

	/* Set up basic I/O (BAR mappings etc) */
	rc = efx_init_io(efx);
@@ -2510,7 +2495,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
		cancel_work_sync(&efx->reset_work);

		if (rc == 0) {
			if (efx->reset_pending != RESET_TYPE_NONE) {
			if (efx->reset_pending) {
				/* If there was a scheduled reset during
				 * probe, the NIC is probably hosed anyway */
				efx_pci_remove_main(efx);
@@ -2521,11 +2506,12 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
		}

		/* Retry if a recoverably reset event has been scheduled */
		if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
		    (efx->reset_pending != RESET_TYPE_ALL))
		if (efx->reset_pending &
		    ~(1 << RESET_TYPE_INVISIBLE | 1 << RESET_TYPE_ALL) ||
		    !efx->reset_pending)
			goto fail3;

		efx->reset_pending = RESET_TYPE_NONE;
		efx->reset_pending = 0;
	}

	if (rc) {
@@ -2609,7 +2595,7 @@ static int efx_pm_poweroff(struct device *dev)

	efx->type->fini(efx);

	efx->reset_pending = RESET_TYPE_NONE;
	efx->reset_pending = 0;

	pci_save_state(pci_dev);
	return pci_set_power_state(pci_dev, PCI_D3hot);
+2 −1
Original line number Diff line number Diff line
@@ -134,6 +134,8 @@ enum efx_loopback_mode {
 * other valuesspecify reasons, which efx_schedule_reset() will choose
 * a method for.
 *
 * Reset methods are numbered in order of increasing scope.
 *
 * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
 * @RESET_TYPE_ALL: reset everything but PCI core blocks
 * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
@@ -147,7 +149,6 @@ enum efx_loopback_mode {
 * @RESET_TYPE_MC_FAILURE: MC reboot/assertion
 */
enum reset_type {
	RESET_TYPE_NONE = -1,
	RESET_TYPE_INVISIBLE = 0,
	RESET_TYPE_ALL = 1,
	RESET_TYPE_WORLD = 2,
+5 −22
Original line number Diff line number Diff line
@@ -796,30 +796,13 @@ static int efx_ethtool_set_wol(struct net_device *net_dev,
static 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;
	}
	int rc;

	if ((*flags & efx->type->reset_world_flags) ==
	    efx->type->reset_world_flags) {
		*flags ^= efx->type->reset_world_flags;
		method = RESET_TYPE_WORLD;
	}
	rc = efx->type->map_reset_flags(flags);
	if (rc < 0)
		return rc;

	return efx_reset(efx, method);
	return efx_reset(efx, rc);
}

static int
+48 −3
Original line number Diff line number Diff line
@@ -536,7 +536,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
	efx_oword_t reg;
	int link_speed, isolate;

	isolate = (efx->reset_pending != RESET_TYPE_NONE);
	isolate = !!ACCESS_ONCE(efx->reset_pending);

	switch (link_state->speed) {
	case 10000: link_speed = 3; break;
@@ -1051,6 +1051,49 @@ static int falcon_b0_test_registers(struct efx_nic *efx)
 **************************************************************************
 */

static enum reset_type falcon_map_reset_reason(enum reset_type reason)
{
	switch (reason) {
	case RESET_TYPE_RX_RECOVERY:
	case RESET_TYPE_RX_DESC_FETCH:
	case RESET_TYPE_TX_DESC_FETCH:
	case RESET_TYPE_TX_SKIP:
		/* These can occasionally occur due to hardware bugs.
		 * We try to reset without disrupting the link.
		 */
		return RESET_TYPE_INVISIBLE;
	default:
		return RESET_TYPE_ALL;
	}
}

static int falcon_map_reset_flags(u32 *flags)
{
	enum {
		FALCON_RESET_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
					  ETH_RESET_OFFLOAD | ETH_RESET_MAC),
		FALCON_RESET_ALL = FALCON_RESET_INVISIBLE | ETH_RESET_PHY,
		FALCON_RESET_WORLD = FALCON_RESET_ALL | ETH_RESET_IRQ,
	};

	if ((*flags & FALCON_RESET_WORLD) == FALCON_RESET_WORLD) {
		*flags &= ~FALCON_RESET_WORLD;
		return RESET_TYPE_WORLD;
	}

	if ((*flags & FALCON_RESET_ALL) == FALCON_RESET_ALL) {
		*flags &= ~FALCON_RESET_ALL;
		return RESET_TYPE_ALL;
	}

	if ((*flags & FALCON_RESET_INVISIBLE) == FALCON_RESET_INVISIBLE) {
		*flags &= ~FALCON_RESET_INVISIBLE;
		return RESET_TYPE_INVISIBLE;
	}

	return -EINVAL;
}

/* Resets NIC to known state.  This routine must be called in process
 * context and is allowed to sleep. */
static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
@@ -1709,6 +1752,8 @@ const struct efx_nic_type falcon_a1_nic_type = {
	.init = falcon_init_nic,
	.fini = efx_port_dummy_op_void,
	.monitor = falcon_monitor,
	.map_reset_reason = falcon_map_reset_reason,
	.map_reset_flags = falcon_map_reset_flags,
	.reset = falcon_reset_hw,
	.probe_port = falcon_probe_port,
	.remove_port = falcon_remove_port,
@@ -1741,7 +1786,6 @@ const struct efx_nic_type falcon_a1_nic_type = {
	.tx_dc_base = 0x130000,
	.rx_dc_base = 0x100000,
	.offload_features = NETIF_F_IP_CSUM,
	.reset_world_flags = ETH_RESET_IRQ,
};

const struct efx_nic_type falcon_b0_nic_type = {
@@ -1750,6 +1794,8 @@ const struct efx_nic_type falcon_b0_nic_type = {
	.init = falcon_init_nic,
	.fini = efx_port_dummy_op_void,
	.monitor = falcon_monitor,
	.map_reset_reason = falcon_map_reset_reason,
	.map_reset_flags = falcon_map_reset_flags,
	.reset = falcon_reset_hw,
	.probe_port = falcon_probe_port,
	.remove_port = falcon_remove_port,
@@ -1791,6 +1837,5 @@ const struct efx_nic_type falcon_b0_nic_type = {
	.tx_dc_base = 0x130000,
	.rx_dc_base = 0x100000,
	.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
	.reset_world_flags = ETH_RESET_IRQ,
};
Loading