From 869b5b3888fbd2024af632e3648c00860ba3cca6 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 29 Jan 2009 17:48:10 +0000 Subject: sfc: SFT9001: Enable robust link training Enable a firmware option that appears to be necessary for reliable operation. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 9ecb77da9545..19cfc318954c 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -67,6 +67,8 @@ #define PMA_PMD_EXT_CLK312_WIDTH 1 #define PMA_PMD_EXT_LPOWER_LBN 12 #define PMA_PMD_EXT_LPOWER_WIDTH 1 +#define PMA_PMD_EXT_ROBUST_LBN 14 +#define PMA_PMD_EXT_ROBUST_WIDTH 1 #define PMA_PMD_EXT_SSR_LBN 15 #define PMA_PMD_EXT_SSR_WIDTH 1 @@ -284,7 +286,9 @@ static int tenxpress_init(struct efx_nic *efx) PMA_PMD_XCONTROL_REG); reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) | - (1 << PMA_PMD_EXT_CLK312_LBN)); + (1 << PMA_PMD_EXT_CLK312_LBN) | + (1 << PMA_PMD_EXT_ROBUST_LBN)); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, -- cgit v1.2.3 From 2d18835d65b7433e7e6583f65395f8c01e7874af Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 29 Jan 2009 17:48:43 +0000 Subject: sfc: SFX7101: Remove workaround for bad link training Early versions of the SFX7101 firmware could complete link training in a state where it would not adequately cancel noise (Solarflare bug 10750). We previously worked around this by resetting the PHY after seeing many Ethernet CRC errors. This workaround is unsafe since it takes no account of the interval between errors; it also appears to be unnecessary with production firmware. Therefore remove it. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 19cfc318954c..80c8d6e3131e 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -189,25 +189,12 @@ * rails */ #define LNPGA_PDOWN_WAIT (HZ / 5) -static int crc_error_reset_threshold = 100; -module_param(crc_error_reset_threshold, int, 0644); -MODULE_PARM_DESC(crc_error_reset_threshold, - "Max number of CRC errors before XAUI reset"); - struct tenxpress_phy_data { enum efx_loopback_mode loopback_mode; - atomic_t bad_crc_count; enum efx_phy_mode phy_mode; int bad_lp_tries; }; -void tenxpress_crc_err(struct efx_nic *efx) -{ - struct tenxpress_phy_data *phy_data = efx->phy_data; - if (phy_data != NULL) - atomic_inc(&phy_data->bad_crc_count); -} - static ssize_t show_phy_short_reach(struct device *dev, struct device_attribute *attr, char *buf) { @@ -627,13 +614,6 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (phy_data->phy_mode != PHY_MODE_NORMAL) return; - - if (EFX_WORKAROUND_10750(efx) && - atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { - EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); - falcon_reset_xaui(efx); - atomic_set(&phy_data->bad_crc_count, 0); - } } static void tenxpress_phy_fini(struct efx_nic *efx) -- cgit v1.2.3 From 8b9dc8dd447cfe27c0214761ced22a8e4aa58f5e Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 29 Jan 2009 17:49:09 +0000 Subject: sfc: SFT9001: Fix speed reporting in 1G PHY loopback Instead of disabling AN in loopback, just prevent restarting AN and override the speed in sft9001_get_settings(). Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 80c8d6e3131e..bc2833f9cbe4 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -511,7 +511,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; struct ethtool_cmd ecmd; - bool phy_mode_change, loop_reset, loop_toggle, loopback; + bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; @@ -522,12 +522,10 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); - loopback = LOOPBACK_MASK(efx) & efx->phy_op->loopbacks; - loop_toggle = LOOPBACK_CHANGED(phy_data, efx, efx->phy_op->loopbacks); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); - if (loop_reset || loop_toggle || loopback || phy_mode_change) { + if (loop_reset || phy_mode_change) { int rc; efx->phy_op->get_settings(efx, &ecmd); @@ -542,20 +540,6 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) falcon_reset_xaui(efx); } - if (efx->phy_type != PHY_TYPE_SFX7101) { - /* Only change autoneg once, on coming out or - * going into loopback */ - if (loop_toggle) - ecmd.autoneg = !loopback; - if (loopback) { - ecmd.duplex = DUPLEX_FULL; - if (efx->loopback_mode == LOOPBACK_GPHY) - ecmd.speed = SPEED_1000; - else - ecmd.speed = SPEED_10000; - } - } - rc = efx->phy_op->set_settings(efx, &ecmd); WARN_ON(rc); } @@ -813,6 +797,13 @@ static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ? DUPLEX_FULL : DUPLEX_HALF); } + + /* In loopback, the PHY automatically brings up the correct interface, + * but doesn't advertise the correct speed. So override it */ + if (efx->loopback_mode == LOOPBACK_GPHY) + ecmd->speed = SPEED_1000; + else if (LOOPBACK_MASK(efx) & SFT9001_LOOPBACKS) + ecmd->speed = SPEED_10000; } static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -- cgit v1.2.3 From 4b988280be13a1b4c17f51cc66948aef467e7601 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Thu, 29 Jan 2009 17:50:51 +0000 Subject: sfc: Reinitialise the PHY completely in case of a PHY or NIC reset In particular, set pause advertising bits properly. A PHY reset is not necessary to recover from the register self-test, so use a "invisible" reset there instead. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index bc2833f9cbe4..c9584619322a 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -337,6 +337,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = tenxpress_init(efx); if (rc < 0) goto fail; + mdio_clause45_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, -- cgit v1.2.3 From af4ad9bca0c4039355b20d760b4fd39afa48c59d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 29 Jan 2009 17:59:37 +0000 Subject: sfc: SFX7101/SFT9001: Fix AN advertisements All 10Xpress PHYs require autonegotiation all the time; enforce this in the set_settings() method and do not treat it as a workaround. Remove claimed support for 100M HD mode since it is not supported by current firmware. Do not set speed override bits when AN is enabled, and do not use register 1.49192 for AN configuration as it can override what we set elsewhere. Always set the AN selector bits to 1 (802.3). Fix confusion between Next Page and Extended Next Page. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 151 +++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 93 deletions(-) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index c9584619322a..412d209d8313 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -179,11 +179,13 @@ #define C22EXT_STATUS_LINK_LBN 2 #define C22EXT_STATUS_LINK_WIDTH 1 -#define C22EXT_MSTSLV_REG 49162 -#define C22EXT_MSTSLV_1000_HD_LBN 10 -#define C22EXT_MSTSLV_1000_HD_WIDTH 1 -#define C22EXT_MSTSLV_1000_FD_LBN 11 -#define C22EXT_MSTSLV_1000_FD_WIDTH 1 +#define C22EXT_MSTSLV_CTRL 49161 +#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN 8 +#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN 9 + +#define C22EXT_MSTSLV_STATUS 49162 +#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN 10 +#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN 11 /* Time to wait between powering down the LNPGA and turning off the power * rails */ @@ -741,114 +743,76 @@ reset: return rc; } -static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) +static void +tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy = efx->mii.phy_id; - u32 lpa = 0; + int phy_id = efx->mii.phy_id; + u32 adv = 0, lpa = 0; int reg; if (efx->phy_type != PHY_TYPE_SFX7101) { - reg = mdio_clause45_read(efx, phy, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_REG); - if (reg & (1 << C22EXT_MSTSLV_1000_HD_LBN)) + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_CTRL); + if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) + adv |= ADVERTISED_1000baseT_Full; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_STATUS); + if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) lpa |= ADVERTISED_1000baseT_Half; - if (reg & (1 << C22EXT_MSTSLV_1000_FD_LBN)) + if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) lpa |= ADVERTISED_1000baseT_Full; } - reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS); + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL); + if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN)) + adv |= ADVERTISED_10000baseT_Full; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_STATUS); if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) lpa |= ADVERTISED_10000baseT_Full; - return lpa; -} - -static void sfx7101_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full, - tenxpress_get_xnp_lpa(efx)); - ecmd->supported |= SUPPORTED_10000baseT_Full; - ecmd->advertising |= ADVERTISED_10000baseT_Full; -} - -static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - int phy_id = efx->mii.phy_id; - u32 xnp_adv = 0; - int reg; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG); - if (EFX_WORKAROUND_13204(efx) && (reg & (1 << PMA_PMD_100TX_ADV_LBN))) - xnp_adv |= ADVERTISED_100baseT_Full; - if (reg & (1 << PMA_PMD_1000T_ADV_LBN)) - xnp_adv |= ADVERTISED_1000baseT_Full; - if (reg & (1 << PMA_PMD_10000T_ADV_LBN)) - xnp_adv |= ADVERTISED_10000baseT_Full; - - mdio_clause45_get_settings_ext(efx, ecmd, xnp_adv, - tenxpress_get_xnp_lpa(efx)); - ecmd->supported |= (SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full); + mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa); - /* Use the vendor defined C22ext register for duplex settings */ - if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG); - ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ? - DUPLEX_FULL : DUPLEX_HALF); - } + if (efx->phy_type != PHY_TYPE_SFX7101) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full); /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (efx->loopback_mode == LOOPBACK_GPHY) ecmd->speed = SPEED_1000; - else if (LOOPBACK_MASK(efx) & SFT9001_LOOPBACKS) + else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) ecmd->speed = SPEED_10000; } -static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; - int rc; - - rc = mdio_clause45_set_settings(efx, ecmd); - if (rc) - return rc; + if (!ecmd->autoneg) + return -EINVAL; - if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, GPHY_DUPLEX_LBN, - ecmd->duplex == DUPLEX_FULL); + return mdio_clause45_set_settings(efx, ecmd); +} - return rc; +static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) +{ + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV_10G_LBN, + advertising & ADVERTISED_10000baseT_Full); } -static bool sft9001_set_xnp_advertise(struct efx_nic *efx, u32 advertising) +static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) { - int phy = efx->mii.phy_id; - int reg = mdio_clause45_read(efx, phy, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG); - bool enabled; - - reg &= ~((1 << 2) | (1 << 3)); - if (EFX_WORKAROUND_13204(efx) && - (advertising & ADVERTISED_100baseT_Full)) - reg |= 1 << PMA_PMD_100TX_ADV_LBN; - if (advertising & ADVERTISED_1000baseT_Full) - reg |= 1 << PMA_PMD_1000T_ADV_LBN; - if (advertising & ADVERTISED_10000baseT_Full) - reg |= 1 << PMA_PMD_10000T_ADV_LBN; - mdio_clause45_write(efx, phy, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG, reg); - - enabled = (advertising & - (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)); - if (EFX_WORKAROUND_13204(efx)) - enabled |= (advertising & ADVERTISED_100baseT_Full); - return enabled; + int phy_id = efx->mii.phy_id; + + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_CTRL, + C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, + advertising & ADVERTISED_1000baseT_Full); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV_10G_LBN, + advertising & ADVERTISED_10000baseT_Full); } struct efx_phy_operations falcon_sfx7101_phy_ops = { @@ -858,8 +822,9 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, .clear_interrupt = efx_port_dummy_op_void, - .get_settings = sfx7101_get_settings, - .set_settings = mdio_clause45_set_settings, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sfx7101_set_npage_adv, .num_tests = ARRAY_SIZE(sfx7101_test_names), .test_names = sfx7101_test_names, .run_tests = sfx7101_run_tests, @@ -874,9 +839,9 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, .clear_interrupt = efx_port_dummy_op_void, - .get_settings = sft9001_get_settings, - .set_settings = sft9001_set_settings, - .set_xnp_advertise = sft9001_set_xnp_advertise, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sft9001_set_npage_adv, .num_tests = ARRAY_SIZE(sft9001_test_names), .test_names = sft9001_test_names, .run_tests = sft9001_run_tests, -- cgit v1.2.3 From 1974cc205e63cec4a17a6b3fca31fa4240ded77e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 29 Jan 2009 18:00:07 +0000 Subject: sfc: Replace stats_enabled flag with a disable count Currently we use a spin-lock to serialise statistics fetches and also to inhibit them for short periods of time, plus a flag to enable/disable statistics fetches for longer periods of time, during online reset. This was apparently insufficient to deal with the several reasons for stats being disabled. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/tenxpress.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/sfc/tenxpress.c') diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 412d209d8313..f0efd246962c 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -370,8 +370,8 @@ static int tenxpress_special_reset(struct efx_nic *efx) /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats - * requests to fail. Since we don't often special_reset, just lock. */ - spin_lock(&efx->stats_lock); + * requests to fail. */ + efx_stats_disable(efx); /* Initiate reset */ reg = mdio_clause45_read(efx, efx->mii.phy_id, @@ -386,17 +386,17 @@ static int tenxpress_special_reset(struct efx_nic *efx) rc = mdio_clause45_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) - goto unlock; + goto out; /* Try and reconfigure the device */ rc = tenxpress_init(efx); if (rc < 0) - goto unlock; + goto out; /* Wait for the XGXS state machine to churn */ mdelay(10); -unlock: - spin_unlock(&efx->stats_lock); +out: + efx_stats_enable(efx); return rc; } -- cgit v1.2.3