aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/tenxpress.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc/tenxpress.c')
-rw-r--r--drivers/net/sfc/tenxpress.c196
1 files changed, 97 insertions, 99 deletions
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index b001f38..ca11572 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -1,6 +1,6 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2008 Solarflare Communications Inc.
+ * Copyright 2007-2009 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
@@ -12,7 +12,7 @@
#include <linux/seq_file.h>
#include "efx.h"
#include "mdio_10g.h"
-#include "falcon.h"
+#include "nic.h"
#include "phy.h"
#include "regs.h"
#include "workarounds.h"
@@ -30,13 +30,13 @@
#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \
(1 << LOOPBACK_PCS) | \
(1 << LOOPBACK_PMAPMD) | \
- (1 << LOOPBACK_NETWORK))
+ (1 << LOOPBACK_PHYXS_WS))
#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \
(1 << LOOPBACK_PHYXS) | \
(1 << LOOPBACK_PCS) | \
(1 << LOOPBACK_PMAPMD) | \
- (1 << LOOPBACK_NETWORK))
+ (1 << LOOPBACK_PHYXS_WS))
/* We complain if we fail to see the link partner as 10G capable this many
* times in a row (must be > 1 as sampling the autoneg. registers is racy)
@@ -199,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev,
const char *buf, size_t count)
{
struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+ int rc;
rtnl_lock();
efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
MDIO_PMA_10GBT_TXPWR_SHORT,
count != 0 && *buf != '0');
- efx_reconfigure_port(efx);
+ rc = efx_reconfigure_port(efx);
rtnl_unlock();
- return count;
+ return rc < 0 ? rc : (ssize_t)count;
}
static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
@@ -297,13 +298,29 @@ static int tenxpress_init(struct efx_nic *efx)
return 0;
}
+static int sfx7101_phy_probe(struct efx_nic *efx)
+{
+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+ return 0;
+}
+
+static int sft9001_phy_probe(struct efx_nic *efx)
+{
+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+ efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS |
+ FALCON_GMAC_LOOPBACKS);
+ return 0;
+}
+
static int tenxpress_phy_init(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data;
- u16 old_adv, adv;
int rc = 0;
- falcon_board(efx)->init_phy(efx);
+ falcon_board(efx)->type->init_phy(efx);
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
if (!phy_data)
@@ -335,14 +352,14 @@ static int tenxpress_phy_init(struct efx_nic *efx)
if (rc < 0)
goto fail;
- /* Set pause advertising */
- old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
- mii_advertise_flowctrl(efx->wanted_fc));
- if (adv != old_adv) {
- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv);
- mdio45_nway_restart(&efx->mdio);
- }
+ /* Initialise advertising flags */
+ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+ ADVERTISED_10000baseT_Full);
+ if (efx->phy_type != PHY_TYPE_SFX7101)
+ efx->link_advertising |= (ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full);
+ efx_link_set_wanted_fc(efx, efx->wanted_fc);
+ efx_mdio_an_reconfigure(efx);
if (efx->phy_type == PHY_TYPE_SFT9001B) {
rc = device_create_file(&efx->pci_dev->dev,
@@ -374,7 +391,7 @@ 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. */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
/* Initiate reset */
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
@@ -396,7 +413,7 @@ static int tenxpress_special_reset(struct efx_nic *efx)
/* Wait for the XGXS state machine to churn */
mdelay(10);
out:
- efx_stats_enable(efx);
+ falcon_start_nic_stats(efx);
return rc;
}
@@ -500,97 +517,76 @@ static void tenxpress_low_power(struct efx_nic *efx)
!!(efx->phy_mode & PHY_MODE_LOW_POWER));
}
-static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+static int tenxpress_phy_reconfigure(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
- struct efx_link_state *link_state = &efx->link_state;
- struct ethtool_cmd ecmd;
bool phy_mode_change, loop_reset;
if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
phy_data->phy_mode = efx->phy_mode;
- return;
+ return 0;
}
- tenxpress_low_power(efx);
-
phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
phy_data->phy_mode != PHY_MODE_NORMAL);
- loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
+ loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||
LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
if (loop_reset || phy_mode_change) {
- int rc;
+ tenxpress_special_reset(efx);
- efx->phy_op->get_settings(efx, &ecmd);
-
- if (loop_reset || phy_mode_change) {
- tenxpress_special_reset(efx);
-
- /* Reset XAUI if we were in 10G, and are staying
- * in 10G. If we're moving into and out of 10G
- * then xaui will be reset anyway */
- if (EFX_IS10G(efx))
- falcon_reset_xaui(efx);
- }
-
- rc = efx->phy_op->set_settings(efx, &ecmd);
- WARN_ON(rc);
+ /* Reset XAUI if we were in 10G, and are staying
+ * in 10G. If we're moving into and out of 10G
+ * then xaui will be reset anyway */
+ if (EFX_IS10G(efx))
+ falcon_reset_xaui(efx);
}
+ tenxpress_low_power(efx);
efx_mdio_transmit_disable(efx);
efx_mdio_phy_reconfigure(efx);
tenxpress_ext_loopback(efx);
+ efx_mdio_an_reconfigure(efx);
phy_data->loopback_mode = efx->loopback_mode;
phy_data->phy_mode = efx->phy_mode;
- if (efx->phy_type == PHY_TYPE_SFX7101) {
- link_state->speed = 10000;
- link_state->fd = true;
- link_state->up = sfx7101_link_ok(efx);
- } else {
- efx->phy_op->get_settings(efx, &ecmd);
- link_state->speed = ecmd.speed;
- link_state->fd = ecmd.duplex == DUPLEX_FULL;
- link_state->up = sft9001_link_ok(efx, &ecmd);
- }
- link_state->fc = efx_mdio_get_pause(efx);
+ return 0;
}
-/* Poll PHY for interrupt */
-static void tenxpress_phy_poll(struct efx_nic *efx)
+static void
+tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
+
+/* Poll for link state changes */
+static bool tenxpress_phy_poll(struct efx_nic *efx)
{
- struct tenxpress_phy_data *phy_data = efx->phy_data;
- struct efx_link_state *link_state = &efx->link_state;
- bool change = false;
+ struct efx_link_state old_state = efx->link_state;
if (efx->phy_type == PHY_TYPE_SFX7101) {
- bool link_ok = sfx7101_link_ok(efx);
- if (link_ok != link_state->up) {
- change = true;
- } else {
- unsigned int link_fc = efx_mdio_get_pause(efx);
- if (link_fc != link_state->fc)
- change = true;
- }
- sfx7101_check_bad_lp(efx, link_ok);
- } else if (efx->loopback_mode) {
- bool link_ok = sft9001_link_ok(efx, NULL);
- if (link_ok != link_state->up)
- change = true;
+ efx->link_state.up = sfx7101_link_ok(efx);
+ efx->link_state.speed = 10000;
+ efx->link_state.fd = true;
+ efx->link_state.fc = efx_mdio_get_pause(efx);
+
+ sfx7101_check_bad_lp(efx, efx->link_state.up);
} else {
- int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
- MDIO_PMA_LASI_STAT);
- if (status & MDIO_PMA_LASI_LSALARM)
- change = true;
- }
+ struct ethtool_cmd ecmd;
- if (change)
- falcon_sim_phy_event(efx);
+ /* Check the LASI alarm first */
+ if (efx->loopback_mode == LOOPBACK_NONE &&
+ !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) &
+ MDIO_PMA_LASI_LSALARM))
+ return false;
- if (phy_data->phy_mode != PHY_MODE_NORMAL)
- return;
+ tenxpress_get_settings(efx, &ecmd);
+
+ efx->link_state.up = sft9001_link_ok(efx, &ecmd);
+ efx->link_state.speed = ecmd.speed;
+ efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL);
+ efx->link_state.fc = efx_mdio_get_pause(efx);
+ }
+
+ return !efx_link_state_equal(&efx->link_state, &old_state);
}
static void tenxpress_phy_fini(struct efx_nic *efx)
@@ -648,6 +644,13 @@ static const char *const sfx7101_test_names[] = {
"bist"
};
+static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index)
+{
+ if (index < ARRAY_SIZE(sfx7101_test_names))
+ return sfx7101_test_names[index];
+ return NULL;
+}
+
static int
sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
{
@@ -659,6 +662,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
/* BIST is automatically run after a special software reset */
rc = tenxpress_special_reset(efx);
results[0] = rc ? -1 : 1;
+
+ efx_mdio_an_reconfigure(efx);
+
return rc;
}
@@ -674,14 +680,17 @@ static const char *const sft9001_test_names[] = {
"cable.pairD.length",
};
+static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index)
+{
+ if (index < ARRAY_SIZE(sft9001_test_names))
+ return sft9001_test_names[index];
+ return NULL;
+}
+
static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
{
- struct ethtool_cmd ecmd;
int rc = 0, rc2, i, ctrl_reg, res_reg;
- if (flags & ETH_TEST_FL_OFFLINE)
- efx->phy_op->get_settings(efx, &ecmd);
-
/* Initialise cable diagnostic results to unknown failure */
for (i = 1; i < 9; ++i)
results[i] = -1;
@@ -733,9 +742,7 @@ out:
if (!rc)
rc = rc2;
- rc2 = efx->phy_op->set_settings(efx, &ecmd);
- if (!rc)
- rc = rc2;
+ efx_mdio_an_reconfigure(efx);
}
return rc;
@@ -766,7 +773,6 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
- ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
if (efx->phy_type != PHY_TYPE_SFX7101) {
ecmd->supported |= (SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full);
@@ -783,7 +789,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
* 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)
+ else if (LOOPBACK_EXTERNAL(efx))
ecmd->speed = SPEED_10000;
}
@@ -813,35 +819,27 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
}
struct efx_phy_operations falcon_sfx7101_phy_ops = {
- .macs = EFX_XMAC,
+ .probe = sfx7101_phy_probe,
.init = tenxpress_phy_init,
.reconfigure = tenxpress_phy_reconfigure,
.poll = tenxpress_phy_poll,
.fini = tenxpress_phy_fini,
- .clear_interrupt = efx_port_dummy_op_void,
.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,
+ .test_name = sfx7101_test_name,
.run_tests = sfx7101_run_tests,
- .mmds = TENXPRESS_REQUIRED_DEVS,
- .loopbacks = SFX7101_LOOPBACKS,
};
struct efx_phy_operations falcon_sft9001_phy_ops = {
- .macs = EFX_GMAC | EFX_XMAC,
+ .probe = sft9001_phy_probe,
.init = tenxpress_phy_init,
.reconfigure = tenxpress_phy_reconfigure,
.poll = tenxpress_phy_poll,
.fini = tenxpress_phy_fini,
- .clear_interrupt = efx_port_dummy_op_void,
.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,
+ .test_name = sft9001_test_name,
.run_tests = sft9001_run_tests,
- .mmds = TENXPRESS_REQUIRED_DEVS,
- .loopbacks = SFT9001_LOOPBACKS,
};