aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-06-24 15:50:07 -0400
committerBen Hutchings <bhutchings@solarflare.com>2011-06-24 19:43:48 -0400
commit0e2a9c7cb941db993f481cdd6a99d70a302053e0 (patch)
tree1b71555f2b37dfcc10d7471c96a3de56293a1f84
parenta7d529ae2158b5300e4aa16c21f1828bc864449b (diff)
sfc: Fix mapping of reset reasons and flags to methods
There are certain hardware bugs that may occur on Falcon during normal operation, that require a reset to recover from. We try to minimise disruption by keeping the PHY running, following a reset sequence labelled as 'invisible'. Siena does not suffer from these hardware bugs, so we have not implemented an 'invisible' reset sequence. However, if a similar error does occur (due to a hardware fault or software bug) then the code shared with Falcon will wrongly assume that the PHY is not being reset. Since the mapping of reset reasons (internal) and flags (ethtool) to methods must differ significantly between NIC types, move it into per-NIC-type functions (replacing the insufficient reset_world_flags field). Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/sfc/efx.c20
-rw-r--r--drivers/net/sfc/ethtool.c27
-rw-r--r--drivers/net/sfc/falcon.c49
-rw-r--r--drivers/net/sfc/net_driver.h7
-rw-r--r--drivers/net/sfc/siena.c33
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)
2183 case RESET_TYPE_WORLD: 2183 case RESET_TYPE_WORLD:
2184 case RESET_TYPE_DISABLE: 2184 case RESET_TYPE_DISABLE:
2185 method = type; 2185 method = type;
2186 netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
2187 RESET_TYPE(method));
2186 break; 2188 break;
2187 case RESET_TYPE_RX_RECOVERY:
2188 case RESET_TYPE_RX_DESC_FETCH:
2189 case RESET_TYPE_TX_DESC_FETCH:
2190 case RESET_TYPE_TX_SKIP:
2191 method = RESET_TYPE_INVISIBLE;
2192 break;
2193 case RESET_TYPE_MC_FAILURE:
2194 default: 2189 default:
2195 method = RESET_TYPE_ALL; 2190 method = efx->type->map_reset_reason(type);
2196 break;
2197 }
2198
2199 if (method != type)
2200 netif_dbg(efx, drv, efx->net_dev, 2191 netif_dbg(efx, drv, efx->net_dev,
2201 "scheduling %s reset for %s\n", 2192 "scheduling %s reset for %s\n",
2202 RESET_TYPE(method), RESET_TYPE(type)); 2193 RESET_TYPE(method), RESET_TYPE(type));
2203 else 2194 break;
2204 netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", 2195 }
2205 RESET_TYPE(method));
2206 2196
2207 set_bit(method, &efx->reset_pending); 2197 set_bit(method, &efx->reset_pending);
2208 2198
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,
796static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) 796static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
797{ 797{
798 struct efx_nic *efx = netdev_priv(net_dev); 798 struct efx_nic *efx = netdev_priv(net_dev);
799 enum reset_type method; 799 int rc;
800 enum {
801 ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
802 ETH_RESET_OFFLOAD | ETH_RESET_MAC)
803 };
804
805 /* Check for minimal reset flags */
806 if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE)
807 return -EINVAL;
808 *flags ^= ETH_RESET_EFX_INVISIBLE;
809 method = RESET_TYPE_INVISIBLE;
810
811 if (*flags & ETH_RESET_PHY) {
812 *flags ^= ETH_RESET_PHY;
813 method = RESET_TYPE_ALL;
814 }
815 800
816 if ((*flags & efx->type->reset_world_flags) == 801 rc = efx->type->map_reset_flags(flags);
817 efx->type->reset_world_flags) { 802 if (rc < 0)
818 *flags ^= efx->type->reset_world_flags; 803 return rc;
819 method = RESET_TYPE_WORLD;
820 }
821 804
822 return efx_reset(efx, method); 805 return efx_reset(efx, rc);
823} 806}
824 807
825static int 808static 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)
1051 ************************************************************************** 1051 **************************************************************************
1052 */ 1052 */
1053 1053
1054static enum reset_type falcon_map_reset_reason(enum reset_type reason)
1055{
1056 switch (reason) {
1057 case RESET_TYPE_RX_RECOVERY:
1058 case RESET_TYPE_RX_DESC_FETCH:
1059 case RESET_TYPE_TX_DESC_FETCH:
1060 case RESET_TYPE_TX_SKIP:
1061 /* These can occasionally occur due to hardware bugs.
1062 * We try to reset without disrupting the link.
1063 */
1064 return RESET_TYPE_INVISIBLE;
1065 default:
1066 return RESET_TYPE_ALL;
1067 }
1068}
1069
1070static int falcon_map_reset_flags(u32 *flags)
1071{
1072 enum {
1073 FALCON_RESET_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
1074 ETH_RESET_OFFLOAD | ETH_RESET_MAC),
1075 FALCON_RESET_ALL = FALCON_RESET_INVISIBLE | ETH_RESET_PHY,
1076 FALCON_RESET_WORLD = FALCON_RESET_ALL | ETH_RESET_IRQ,
1077 };
1078
1079 if ((*flags & FALCON_RESET_WORLD) == FALCON_RESET_WORLD) {
1080 *flags &= ~FALCON_RESET_WORLD;
1081 return RESET_TYPE_WORLD;
1082 }
1083
1084 if ((*flags & FALCON_RESET_ALL) == FALCON_RESET_ALL) {
1085 *flags &= ~FALCON_RESET_ALL;
1086 return RESET_TYPE_ALL;
1087 }
1088
1089 if ((*flags & FALCON_RESET_INVISIBLE) == FALCON_RESET_INVISIBLE) {
1090 *flags &= ~FALCON_RESET_INVISIBLE;
1091 return RESET_TYPE_INVISIBLE;
1092 }
1093
1094 return -EINVAL;
1095}
1096
1054/* Resets NIC to known state. This routine must be called in process 1097/* Resets NIC to known state. This routine must be called in process
1055 * context and is allowed to sleep. */ 1098 * context and is allowed to sleep. */
1056static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method) 1099static 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 = {
1709 .init = falcon_init_nic, 1752 .init = falcon_init_nic,
1710 .fini = efx_port_dummy_op_void, 1753 .fini = efx_port_dummy_op_void,
1711 .monitor = falcon_monitor, 1754 .monitor = falcon_monitor,
1755 .map_reset_reason = falcon_map_reset_reason,
1756 .map_reset_flags = falcon_map_reset_flags,
1712 .reset = falcon_reset_hw, 1757 .reset = falcon_reset_hw,
1713 .probe_port = falcon_probe_port, 1758 .probe_port = falcon_probe_port,
1714 .remove_port = falcon_remove_port, 1759 .remove_port = falcon_remove_port,
@@ -1741,7 +1786,6 @@ const struct efx_nic_type falcon_a1_nic_type = {
1741 .tx_dc_base = 0x130000, 1786 .tx_dc_base = 0x130000,
1742 .rx_dc_base = 0x100000, 1787 .rx_dc_base = 0x100000,
1743 .offload_features = NETIF_F_IP_CSUM, 1788 .offload_features = NETIF_F_IP_CSUM,
1744 .reset_world_flags = ETH_RESET_IRQ,
1745}; 1789};
1746 1790
1747const struct efx_nic_type falcon_b0_nic_type = { 1791const struct efx_nic_type falcon_b0_nic_type = {
@@ -1750,6 +1794,8 @@ const struct efx_nic_type falcon_b0_nic_type = {
1750 .init = falcon_init_nic, 1794 .init = falcon_init_nic,
1751 .fini = efx_port_dummy_op_void, 1795 .fini = efx_port_dummy_op_void,
1752 .monitor = falcon_monitor, 1796 .monitor = falcon_monitor,
1797 .map_reset_reason = falcon_map_reset_reason,
1798 .map_reset_flags = falcon_map_reset_flags,
1753 .reset = falcon_reset_hw, 1799 .reset = falcon_reset_hw,
1754 .probe_port = falcon_probe_port, 1800 .probe_port = falcon_probe_port,
1755 .remove_port = falcon_remove_port, 1801 .remove_port = falcon_remove_port,
@@ -1791,6 +1837,5 @@ const struct efx_nic_type falcon_b0_nic_type = {
1791 .tx_dc_base = 0x130000, 1837 .tx_dc_base = 0x130000,
1792 .rx_dc_base = 0x100000, 1838 .rx_dc_base = 0x100000,
1793 .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE, 1839 .offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
1794 .reset_world_flags = ETH_RESET_IRQ,
1795}; 1840};
1796 1841
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)
828 * @init: Initialise the controller 828 * @init: Initialise the controller
829 * @fini: Shut down the controller 829 * @fini: Shut down the controller
830 * @monitor: Periodic function for polling link state and hardware monitor 830 * @monitor: Periodic function for polling link state and hardware monitor
831 * @map_reset_reason: Map ethtool reset reason to a reset method
832 * @map_reset_flags: Map ethtool reset flags to a reset method, if possible
831 * @reset: Reset the controller hardware and possibly the PHY. This will 833 * @reset: Reset the controller hardware and possibly the PHY. This will
832 * be called while the controller is uninitialised. 834 * be called while the controller is uninitialised.
833 * @probe_port: Probe the MAC and PHY 835 * @probe_port: Probe the MAC and PHY
@@ -865,8 +867,6 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
865 * @rx_dc_base: Base address in SRAM of RX queue descriptor caches 867 * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
866 * @offload_features: net_device feature flags for protocol offload 868 * @offload_features: net_device feature flags for protocol offload
867 * features implemented in hardware 869 * features implemented in hardware
868 * @reset_world_flags: Flags for additional components covered by
869 * reset method RESET_TYPE_WORLD
870 */ 870 */
871struct efx_nic_type { 871struct efx_nic_type {
872 int (*probe)(struct efx_nic *efx); 872 int (*probe)(struct efx_nic *efx);
@@ -874,6 +874,8 @@ struct efx_nic_type {
874 int (*init)(struct efx_nic *efx); 874 int (*init)(struct efx_nic *efx);
875 void (*fini)(struct efx_nic *efx); 875 void (*fini)(struct efx_nic *efx);
876 void (*monitor)(struct efx_nic *efx); 876 void (*monitor)(struct efx_nic *efx);
877 enum reset_type (*map_reset_reason)(enum reset_type reason);
878 int (*map_reset_flags)(u32 *flags);
877 int (*reset)(struct efx_nic *efx, enum reset_type method); 879 int (*reset)(struct efx_nic *efx, enum reset_type method);
878 int (*probe_port)(struct efx_nic *efx); 880 int (*probe_port)(struct efx_nic *efx);
879 void (*remove_port)(struct efx_nic *efx); 881 void (*remove_port)(struct efx_nic *efx);
@@ -908,7 +910,6 @@ struct efx_nic_type {
908 unsigned int tx_dc_base; 910 unsigned int tx_dc_base;
909 unsigned int rx_dc_base; 911 unsigned int rx_dc_base;
910 u32 offload_features; 912 u32 offload_features;
911 u32 reset_world_flags;
912}; 913};
913 914
914/************************************************************************** 915/**************************************************************************
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)
177 ************************************************************************** 177 **************************************************************************
178 */ 178 */
179 179
180static enum reset_type siena_map_reset_reason(enum reset_type reason)
181{
182 return RESET_TYPE_ALL;
183}
184
185static int siena_map_reset_flags(u32 *flags)
186{
187 enum {
188 SIENA_RESET_PORT = (ETH_RESET_DMA | ETH_RESET_FILTER |
189 ETH_RESET_OFFLOAD | ETH_RESET_MAC |
190 ETH_RESET_PHY),
191 SIENA_RESET_MC = (SIENA_RESET_PORT |
192 ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT),
193 };
194
195 if ((*flags & SIENA_RESET_MC) == SIENA_RESET_MC) {
196 *flags &= ~SIENA_RESET_MC;
197 return RESET_TYPE_WORLD;
198 }
199
200 if ((*flags & SIENA_RESET_PORT) == SIENA_RESET_PORT) {
201 *flags &= ~SIENA_RESET_PORT;
202 return RESET_TYPE_ALL;
203 }
204
205 /* no invisible reset implemented */
206
207 return -EINVAL;
208}
209
180static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) 210static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
181{ 211{
182 int rc; 212 int rc;
@@ -605,6 +635,8 @@ const struct efx_nic_type siena_a0_nic_type = {
605 .init = siena_init_nic, 635 .init = siena_init_nic,
606 .fini = efx_port_dummy_op_void, 636 .fini = efx_port_dummy_op_void,
607 .monitor = NULL, 637 .monitor = NULL,
638 .map_reset_reason = siena_map_reset_reason,
639 .map_reset_flags = siena_map_reset_flags,
608 .reset = siena_reset_hw, 640 .reset = siena_reset_hw,
609 .probe_port = siena_probe_port, 641 .probe_port = siena_probe_port,
610 .remove_port = siena_remove_port, 642 .remove_port = siena_remove_port,
@@ -641,5 +673,4 @@ const struct efx_nic_type siena_a0_nic_type = {
641 .rx_dc_base = 0x68000, 673 .rx_dc_base = 0x68000,
642 .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 674 .offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
643 NETIF_F_RXHASH | NETIF_F_NTUPLE), 675 NETIF_F_RXHASH | NETIF_F_NTUPLE),
644 .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
645}; 676};