diff options
-rw-r--r-- | drivers/net/sfc/efx.c | 20 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 27 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 49 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 7 | ||||
-rw-r--r-- | drivers/net/sfc/siena.c | 33 |
5 files changed, 93 insertions, 43 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 9b4cfdb09516..ff162df06bd0 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2183,26 +2183,16 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) 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; + } set_bit(method, &efx->reset_pending); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index d229027dc363..bc4643af6dd1 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -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 diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index a4c7830ec9b0..94bf4aaf984d 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -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, }; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index c422eb2ce60a..4597066741f1 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -828,6 +828,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) * @init: Initialise the controller * @fini: Shut down the controller * @monitor: Periodic function for polling link state and hardware monitor + * @map_reset_reason: Map ethtool reset reason to a reset method + * @map_reset_flags: Map ethtool reset flags to a reset method, if possible * @reset: Reset the controller hardware and possibly the PHY. This will * be called while the controller is uninitialised. * @probe_port: Probe the MAC and PHY @@ -865,8 +867,6 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) * @rx_dc_base: Base address in SRAM of RX queue descriptor caches * @offload_features: net_device feature flags for protocol offload * features implemented in hardware - * @reset_world_flags: Flags for additional components covered by - * reset method RESET_TYPE_WORLD */ struct efx_nic_type { int (*probe)(struct efx_nic *efx); @@ -874,6 +874,8 @@ struct efx_nic_type { int (*init)(struct efx_nic *efx); void (*fini)(struct efx_nic *efx); void (*monitor)(struct efx_nic *efx); + enum reset_type (*map_reset_reason)(enum reset_type reason); + int (*map_reset_flags)(u32 *flags); int (*reset)(struct efx_nic *efx, enum reset_type method); int (*probe_port)(struct efx_nic *efx); void (*remove_port)(struct efx_nic *efx); @@ -908,7 +910,6 @@ struct efx_nic_type { unsigned int tx_dc_base; unsigned int rx_dc_base; u32 offload_features; - u32 reset_world_flags; }; /************************************************************************** diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index a66818ed4011..442897b14270 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -177,6 +177,36 @@ static int siena_test_registers(struct efx_nic *efx) ************************************************************************** */ +static enum reset_type siena_map_reset_reason(enum reset_type reason) +{ + return RESET_TYPE_ALL; +} + +static int siena_map_reset_flags(u32 *flags) +{ + enum { + SIENA_RESET_PORT = (ETH_RESET_DMA | ETH_RESET_FILTER | + ETH_RESET_OFFLOAD | ETH_RESET_MAC | + ETH_RESET_PHY), + SIENA_RESET_MC = (SIENA_RESET_PORT | + ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT), + }; + + if ((*flags & SIENA_RESET_MC) == SIENA_RESET_MC) { + *flags &= ~SIENA_RESET_MC; + return RESET_TYPE_WORLD; + } + + if ((*flags & SIENA_RESET_PORT) == SIENA_RESET_PORT) { + *flags &= ~SIENA_RESET_PORT; + return RESET_TYPE_ALL; + } + + /* no invisible reset implemented */ + + return -EINVAL; +} + static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) { int rc; @@ -605,6 +635,8 @@ const struct efx_nic_type siena_a0_nic_type = { .init = siena_init_nic, .fini = efx_port_dummy_op_void, .monitor = NULL, + .map_reset_reason = siena_map_reset_reason, + .map_reset_flags = siena_map_reset_flags, .reset = siena_reset_hw, .probe_port = siena_probe_port, .remove_port = siena_remove_port, @@ -641,5 +673,4 @@ const struct efx_nic_type siena_a0_nic_type = { .rx_dc_base = 0x68000, .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE), - .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, }; |