|
@@ -68,6 +68,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
|
|
|
|
|
@@ -178,35 +180,24 @@
|
|
|
#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 */
|
|
|
#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)
|
|
|
{
|
|
@@ -285,7 +276,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,
|
|
@@ -347,6 +340,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,
|
|
@@ -377,8 +371,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,
|
|
@@ -393,17 +387,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;
|
|
|
}
|
|
|
|
|
@@ -521,7 +515,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;
|
|
@@ -532,12 +526,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);
|
|
@@ -552,20 +544,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);
|
|
|
}
|
|
@@ -624,13 +602,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)
|
|
@@ -773,107 +744,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;
|
|
|
+ mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa);
|
|
|
+
|
|
|
+ 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) & efx->phy_op->loopbacks)
|
|
|
+ ecmd->speed = SPEED_10000;
|
|
|
}
|
|
|
|
|
|
-static void sft9001_get_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;
|
|
|
- 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);
|
|
|
+ if (!ecmd->autoneg)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- /* 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);
|
|
|
- }
|
|
|
+ return mdio_clause45_set_settings(efx, ecmd);
|
|
|
}
|
|
|
|
|
|
-static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
|
|
+static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
|
|
|
{
|
|
|
- int phy_id = efx->mii.phy_id;
|
|
|
- int rc;
|
|
|
-
|
|
|
- rc = mdio_clause45_set_settings(efx, ecmd);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- 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 rc;
|
|
|
+ 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 = {
|
|
@@ -883,8 +823,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,
|
|
@@ -899,9 +840,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,
|