Commit fdaa9aed authored by Steve Hodgson's avatar Steve Hodgson Committed by David S. Miller

sfc: Simplify PHY polling

Falcon can generate events for LASI interrupts from the PHY, but in
practice we have never implemented this in reference designs.  Instead
we have polled, inserted the appropriate events, and then handled the
events later.  This is a waste of time and code.

Instead, make PHY poll functions update the link state synchronously
and report whether it changed.  We can still make use of the LASI
registers as a shortcut on the SFT9001.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5e756593
...@@ -583,7 +583,7 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) ...@@ -583,7 +583,7 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
* netif_carrier_on/off) of the link status, and also maintains the * netif_carrier_on/off) of the link status, and also maintains the
* link status's stop on the port's TX queue. * link status's stop on the port's TX queue.
*/ */
static void efx_link_status_changed(struct efx_nic *efx) void efx_link_status_changed(struct efx_nic *efx)
{ {
struct efx_link_state *link_state = &efx->link_state; struct efx_link_state *link_state = &efx->link_state;
...@@ -675,19 +675,6 @@ void efx_reconfigure_port(struct efx_nic *efx) ...@@ -675,19 +675,6 @@ void efx_reconfigure_port(struct efx_nic *efx)
mutex_unlock(&efx->mac_lock); mutex_unlock(&efx->mac_lock);
} }
/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
* we don't efx_reconfigure_port() if the port is disabled. Care is taken
* in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
static void efx_phy_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, phy_work);
mutex_lock(&efx->mac_lock);
if (efx->port_enabled)
__efx_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
}
/* Asynchronous work item for changing MAC promiscuity and multicast /* Asynchronous work item for changing MAC promiscuity and multicast
* hash. Avoid a drain/rx_ingress enable by reconfiguring the current * hash. Avoid a drain/rx_ingress enable by reconfiguring the current
* MAC directly. */ * MAC directly. */
...@@ -768,9 +755,6 @@ fail1: ...@@ -768,9 +755,6 @@ fail1:
return rc; return rc;
} }
/* Allow efx_reconfigure_port() to be scheduled, and close the window
* between efx_stop_port and efx_flush_all whereby a previously scheduled
* efx_phy_work()/efx_mac_work() may have been cancelled */
static void efx_start_port(struct efx_nic *efx) static void efx_start_port(struct efx_nic *efx)
{ {
EFX_LOG(efx, "start port\n"); EFX_LOG(efx, "start port\n");
...@@ -787,10 +771,7 @@ static void efx_start_port(struct efx_nic *efx) ...@@ -787,10 +771,7 @@ static void efx_start_port(struct efx_nic *efx)
mutex_unlock(&efx->mac_lock); mutex_unlock(&efx->mac_lock);
} }
/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, /* Prevent efx_mac_work() and efx_monitor() from working */
* and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work
* and efx_mac_work may still be scheduled via NAPI processing until
* efx_flush_all() is called */
static void efx_stop_port(struct efx_nic *efx) static void efx_stop_port(struct efx_nic *efx)
{ {
EFX_LOG(efx, "stop port\n"); EFX_LOG(efx, "stop port\n");
...@@ -1188,8 +1169,6 @@ static void efx_flush_all(struct efx_nic *efx) ...@@ -1188,8 +1169,6 @@ static void efx_flush_all(struct efx_nic *efx)
/* Stop scheduled port reconfigurations */ /* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->mac_work); cancel_work_sync(&efx->mac_work);
cancel_work_sync(&efx->phy_work);
} }
/* Quiesce hardware and software without bringing the link down. /* Quiesce hardware and software without bringing the link down.
...@@ -1227,7 +1206,7 @@ static void efx_stop_all(struct efx_nic *efx) ...@@ -1227,7 +1206,7 @@ static void efx_stop_all(struct efx_nic *efx)
* window to loose phy events */ * window to loose phy events */
efx_stop_port(efx); efx_stop_port(efx);
/* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ /* Flush efx_mac_work(), refill_workqueue, monitor_work */
efx_flush_all(efx); efx_flush_all(efx);
/* Isolate the MAC from the TX and RX engines, so that queue /* Isolate the MAC from the TX and RX engines, so that queue
...@@ -1907,6 +1886,10 @@ void efx_port_dummy_op_void(struct efx_nic *efx) {} ...@@ -1907,6 +1886,10 @@ void efx_port_dummy_op_void(struct efx_nic *efx) {}
void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
{ {
} }
bool efx_port_dummy_op_poll(struct efx_nic *efx)
{
return false;
}
static struct efx_mac_operations efx_dummy_mac_operations = { static struct efx_mac_operations efx_dummy_mac_operations = {
.reconfigure = efx_port_dummy_op_void, .reconfigure = efx_port_dummy_op_void,
...@@ -1915,9 +1898,8 @@ static struct efx_mac_operations efx_dummy_mac_operations = { ...@@ -1915,9 +1898,8 @@ static struct efx_mac_operations efx_dummy_mac_operations = {
static struct efx_phy_operations efx_dummy_phy_operations = { static struct efx_phy_operations efx_dummy_phy_operations = {
.init = efx_port_dummy_op_int, .init = efx_port_dummy_op_int,
.reconfigure = efx_port_dummy_op_void, .reconfigure = efx_port_dummy_op_void,
.poll = efx_port_dummy_op_void, .poll = efx_port_dummy_op_poll,
.fini = efx_port_dummy_op_void, .fini = efx_port_dummy_op_void,
.clear_interrupt = efx_port_dummy_op_void,
}; };
/************************************************************************** /**************************************************************************
...@@ -1957,7 +1939,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, ...@@ -1957,7 +1939,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
efx->mac_op = &efx_dummy_mac_operations; efx->mac_op = &efx_dummy_mac_operations;
efx->phy_op = &efx_dummy_phy_operations; efx->phy_op = &efx_dummy_phy_operations;
efx->mdio.dev = net_dev; efx->mdio.dev = net_dev;
INIT_WORK(&efx->phy_work, efx_phy_work);
INIT_WORK(&efx->mac_work, efx_mac_work); INIT_WORK(&efx->mac_work, efx_mac_work);
atomic_set(&efx->netif_stop_count, 1); atomic_set(&efx->netif_stop_count, 1);
......
...@@ -90,6 +90,7 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx); ...@@ -90,6 +90,7 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx);
extern void efx_port_dummy_op_void(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx);
extern void extern void
efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
extern bool efx_port_dummy_op_poll(struct efx_nic *efx);
/* MTD */ /* MTD */
#ifdef CONFIG_SFC_MTD #ifdef CONFIG_SFC_MTD
...@@ -113,4 +114,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel) ...@@ -113,4 +114,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel)
napi_schedule(&channel->napi_str); napi_schedule(&channel->napi_str);
} }
extern void efx_link_status_changed(struct efx_nic *efx);
#endif /* EFX_EFX_H */ #endif /* EFX_EFX_H */
...@@ -893,8 +893,7 @@ static void falcon_handle_global_event(struct efx_channel *channel, ...@@ -893,8 +893,7 @@ static void falcon_handle_global_event(struct efx_channel *channel,
if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
efx->phy_op->clear_interrupt(efx); /* Ignored */
queue_work(efx->workqueue, &efx->phy_work);
handled = true; handled = true;
} }
...@@ -1140,20 +1139,6 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) ...@@ -1140,20 +1139,6 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
falcon_generate_event(channel, &test_event); falcon_generate_event(channel, &test_event);
} }
void falcon_sim_phy_event(struct efx_nic *efx)
{
efx_qword_t phy_event;
EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE,
FSE_AZ_EV_CODE_GLOBAL_EV);
if (EFX_IS10G(efx))
EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1);
else
EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1);
falcon_generate_event(&efx->channel[0], &phy_event);
}
/************************************************************************** /**************************************************************************
* *
* Flush handling * Flush handling
...@@ -2063,6 +2048,25 @@ static void falcon_stats_timer_func(unsigned long context) ...@@ -2063,6 +2048,25 @@ static void falcon_stats_timer_func(unsigned long context)
spin_unlock(&efx->stats_lock); spin_unlock(&efx->stats_lock);
} }
static bool falcon_loopback_link_poll(struct efx_nic *efx)
{
struct efx_link_state old_state = efx->link_state;
WARN_ON(!mutex_is_locked(&efx->mac_lock));
WARN_ON(!LOOPBACK_INTERNAL(efx));
efx->link_state.fd = true;
efx->link_state.fc = efx->wanted_fc;
efx->link_state.up = true;
if (efx->loopback_mode == LOOPBACK_GMAC)
efx->link_state.speed = 1000;
else
efx->link_state.speed = 10000;
return !efx_link_state_equal(&efx->link_state, &old_state);
}
/************************************************************************** /**************************************************************************
* *
* PHY access via GMII * PHY access via GMII
...@@ -2225,15 +2229,6 @@ int falcon_switch_mac(struct efx_nic *efx) ...@@ -2225,15 +2229,6 @@ int falcon_switch_mac(struct efx_nic *efx)
/* Don't try to fetch MAC stats while we're switching MACs */ /* Don't try to fetch MAC stats while we're switching MACs */
falcon_stop_nic_stats(efx); falcon_stop_nic_stats(efx);
/* Internal loopbacks override the phy speed setting */
if (efx->loopback_mode == LOOPBACK_GMAC) {
efx->link_state.speed = 1000;
efx->link_state.fd = true;
} else if (LOOPBACK_INTERNAL(efx)) {
efx->link_state.speed = 10000;
efx->link_state.fd = true;
}
WARN_ON(!mutex_is_locked(&efx->mac_lock)); WARN_ON(!mutex_is_locked(&efx->mac_lock));
efx->mac_op = (EFX_IS10G(efx) ? efx->mac_op = (EFX_IS10G(efx) ?
&falcon_xmac_operations : &falcon_gmac_operations); &falcon_xmac_operations : &falcon_gmac_operations);
...@@ -2610,16 +2605,36 @@ fail5: ...@@ -2610,16 +2605,36 @@ fail5:
void falcon_monitor(struct efx_nic *efx) void falcon_monitor(struct efx_nic *efx)
{ {
bool link_changed;
int rc; int rc;
BUG_ON(!mutex_is_locked(&efx->mac_lock));
rc = falcon_board(efx)->type->monitor(efx); rc = falcon_board(efx)->type->monitor(efx);
if (rc) { if (rc) {
EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
(rc == -ERANGE) ? "reported fault" : "failed"); (rc == -ERANGE) ? "reported fault" : "failed");
efx->phy_mode |= PHY_MODE_LOW_POWER; efx->phy_mode |= PHY_MODE_LOW_POWER;
falcon_sim_phy_event(efx); __efx_reconfigure_port(efx);
} }
efx->phy_op->poll(efx);
if (LOOPBACK_INTERNAL(efx))
link_changed = falcon_loopback_link_poll(efx);
else
link_changed = efx->phy_op->poll(efx);
if (link_changed) {
falcon_stop_nic_stats(efx);
falcon_deconfigure_mac_wrapper(efx);
falcon_switch_mac(efx);
efx->mac_op->reconfigure(efx);
falcon_start_nic_stats(efx);
efx_link_status_changed(efx);
}
if (EFX_IS10G(efx)) if (EFX_IS10G(efx))
falcon_poll_xmac(efx); falcon_poll_xmac(efx);
} }
......
...@@ -145,7 +145,6 @@ extern int falcon_init_interrupt(struct efx_nic *efx); ...@@ -145,7 +145,6 @@ extern int falcon_init_interrupt(struct efx_nic *efx);
extern void falcon_enable_interrupts(struct efx_nic *efx); extern void falcon_enable_interrupts(struct efx_nic *efx);
extern void falcon_generate_test_event(struct efx_channel *channel, extern void falcon_generate_test_event(struct efx_channel *channel,
unsigned int magic); unsigned int magic);
extern void falcon_sim_phy_event(struct efx_nic *efx);
extern void falcon_generate_interrupt(struct efx_nic *efx); extern void falcon_generate_interrupt(struct efx_nic *efx);
extern void falcon_set_int_moderation(struct efx_channel *channel); extern void falcon_set_int_moderation(struct efx_channel *channel);
extern void falcon_disable_interrupts(struct efx_nic *efx); extern void falcon_disable_interrupts(struct efx_nic *efx);
......
...@@ -503,6 +503,13 @@ struct efx_link_state { ...@@ -503,6 +503,13 @@ struct efx_link_state {
unsigned int speed; unsigned int speed;
}; };
static inline bool efx_link_state_equal(const struct efx_link_state *left,
const struct efx_link_state *right)
{
return left->up == right->up && left->fd == right->fd &&
left->fc == right->fc && left->speed == right->speed;
}
/** /**
* struct efx_mac_operations - Efx MAC operations table * struct efx_mac_operations - Efx MAC operations table
* @reconfigure: Reconfigure MAC. Serialised by the mac_lock * @reconfigure: Reconfigure MAC. Serialised by the mac_lock
...@@ -520,8 +527,8 @@ struct efx_mac_operations { ...@@ -520,8 +527,8 @@ struct efx_mac_operations {
* @init: Initialise PHY * @init: Initialise PHY
* @fini: Shut down PHY * @fini: Shut down PHY
* @reconfigure: Reconfigure PHY (e.g. for new link parameters) * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
* @clear_interrupt: Clear down interrupt * @poll: Update @link_state and report whether it changed.
* @poll: Poll for hardware state. Serialised by the mac_lock. * Serialised by the mac_lock.
* @get_settings: Get ethtool settings. Serialised by the mac_lock. * @get_settings: Get ethtool settings. Serialised by the mac_lock.
* @set_settings: Set ethtool settings. Serialised by the mac_lock. * @set_settings: Set ethtool settings. Serialised by the mac_lock.
* @set_npage_adv: Set abilities advertised in (Extended) Next Page * @set_npage_adv: Set abilities advertised in (Extended) Next Page
...@@ -538,8 +545,7 @@ struct efx_phy_operations { ...@@ -538,8 +545,7 @@ struct efx_phy_operations {
int (*init) (struct efx_nic *efx); int (*init) (struct efx_nic *efx);
void (*fini) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx);
void (*reconfigure) (struct efx_nic *efx); void (*reconfigure) (struct efx_nic *efx);
void (*clear_interrupt) (struct efx_nic *efx); bool (*poll) (struct efx_nic *efx);
void (*poll) (struct efx_nic *efx);
void (*get_settings) (struct efx_nic *efx, void (*get_settings) (struct efx_nic *efx,
struct ethtool_cmd *ecmd); struct ethtool_cmd *ecmd);
int (*set_settings) (struct efx_nic *efx, int (*set_settings) (struct efx_nic *efx,
...@@ -700,10 +706,10 @@ union efx_multicast_hash { ...@@ -700,10 +706,10 @@ union efx_multicast_hash {
* @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
* @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_inhibited, efx_monitor() and efx_reconfigure_port()
* @port_enabled: Port enabled indicator. * @port_enabled: Port enabled indicator.
* Serialises efx_stop_all(), efx_start_all(), efx_monitor(), * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and
* efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read * efx_mac_work() with kernel interfaces. Safe to read under any
* under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
* three must be held to modify it. * be held to modify it.
* @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock
* @port_initialized: Port initialized? * @port_initialized: Port initialized?
* @net_dev: Operating system network device. Consider holding the rtnl lock * @net_dev: Operating system network device. Consider holding the rtnl lock
...@@ -729,7 +735,6 @@ union efx_multicast_hash { ...@@ -729,7 +735,6 @@ union efx_multicast_hash {
* @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
* @multicast_hash: Multicast hash table * @multicast_hash: Multicast hash table
* @wanted_fc: Wanted flow control flags * @wanted_fc: Wanted flow control flags
* @phy_work: work item for dealing with PHY events
* @mac_work: Work item for changing MAC promiscuity and multicast hash * @mac_work: Work item for changing MAC promiscuity and multicast hash
* @loopback_mode: Loopback status * @loopback_mode: Loopback status
* @loopback_modes: Supported loopback mode bitmask * @loopback_modes: Supported loopback mode bitmask
...@@ -802,7 +807,6 @@ struct efx_nic { ...@@ -802,7 +807,6 @@ struct efx_nic {
enum phy_type phy_type; enum phy_type phy_type;
spinlock_t phy_lock; spinlock_t phy_lock;
struct work_struct phy_work;
struct efx_phy_operations *phy_op; struct efx_phy_operations *phy_op;
void *phy_data; void *phy_data;
struct mdio_if_info mdio; struct mdio_if_info mdio;
......
...@@ -167,29 +167,26 @@ static int qt202x_phy_init(struct efx_nic *efx) ...@@ -167,29 +167,26 @@ static int qt202x_phy_init(struct efx_nic *efx)
return rc; return rc;
} }
static void qt202x_phy_clear_interrupt(struct efx_nic *efx)
{
/* Read to clear link status alarm */
efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT);
}
static int qt202x_link_ok(struct efx_nic *efx) static int qt202x_link_ok(struct efx_nic *efx)
{ {
return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS); return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS);
} }
static void qt202x_phy_poll(struct efx_nic *efx) static bool qt202x_phy_poll(struct efx_nic *efx)
{ {
int link_up = qt202x_link_ok(efx); bool was_up = efx->link_state.up;
/* Simulate a PHY event if link state has changed */
if (link_up != efx->link_state.up) efx->link_state.up = qt202x_link_ok(efx);
falcon_sim_phy_event(efx); efx->link_state.speed = 10000;
efx->link_state.fd = true;
efx->link_state.fc = efx->wanted_fc;
return efx->link_state.up != was_up;
} }
static void qt202x_phy_reconfigure(struct efx_nic *efx) static void qt202x_phy_reconfigure(struct efx_nic *efx)
{ {
struct qt202x_phy_data *phy_data = efx->phy_data; struct qt202x_phy_data *phy_data = efx->phy_data;
struct efx_link_state *link_state = &efx->link_state;
if (efx->phy_type == PHY_TYPE_QT2025C) { if (efx->phy_type == PHY_TYPE_QT2025C) {
/* There are several different register bits which can /* There are several different register bits which can
...@@ -216,10 +213,6 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx) ...@@ -216,10 +213,6 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx)
efx_mdio_phy_reconfigure(efx); efx_mdio_phy_reconfigure(efx);
phy_data->phy_mode = efx->phy_mode; phy_data->phy_mode = efx->phy_mode;
link_state->up = qt202x_link_ok(efx);
link_state->speed = 10000;
link_state->fd = true;
link_state->fc = efx->wanted_fc;
} }
static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
...@@ -240,7 +233,6 @@ struct efx_phy_operations falcon_qt202x_phy_ops = { ...@@ -240,7 +233,6 @@ struct efx_phy_operations falcon_qt202x_phy_ops = {
.reconfigure = qt202x_phy_reconfigure, .reconfigure = qt202x_phy_reconfigure,
.poll = qt202x_phy_poll, .poll = qt202x_phy_poll,
.fini = qt202x_phy_fini, .fini = qt202x_phy_fini,
.clear_interrupt = qt202x_phy_clear_interrupt,
.get_settings = qt202x_phy_get_settings, .get_settings = qt202x_phy_get_settings,
.set_settings = efx_mdio_set_settings, .set_settings = efx_mdio_set_settings,
.mmds = QT202X_REQUIRED_DEVS, .mmds = QT202X_REQUIRED_DEVS,
......
...@@ -503,7 +503,6 @@ static void tenxpress_low_power(struct efx_nic *efx) ...@@ -503,7 +503,6 @@ static void tenxpress_low_power(struct efx_nic *efx)
static void tenxpress_phy_reconfigure(struct efx_nic *efx) static void tenxpress_phy_reconfigure(struct efx_nic *efx)
{ {
struct tenxpress_phy_data *phy_data = efx->phy_data; struct tenxpress_phy_data *phy_data = efx->phy_data;
struct efx_link_state *link_state = &efx->link_state;
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd;
bool phy_mode_change, loop_reset; bool phy_mode_change, loop_reset;
...@@ -544,53 +543,41 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) ...@@ -544,53 +543,41 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
phy_data->loopback_mode = efx->loopback_mode; phy_data->loopback_mode = efx->loopback_mode;
phy_data->phy_mode = efx->phy_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);
} }
/* Poll PHY for interrupt */ static void
static void tenxpress_phy_poll(struct efx_nic *efx) 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 old_state = efx->link_state;
struct efx_link_state *link_state = &efx->link_state;
bool change = false;
if (efx->phy_type == PHY_TYPE_SFX7101) { if (efx->phy_type == PHY_TYPE_SFX7101) {
bool link_ok = sfx7101_link_ok(efx); efx->link_state.up = sfx7101_link_ok(efx);
if (link_ok != link_state->up) { efx->link_state.speed = 10000;
change = true; efx->link_state.fd = true;
} else { efx->link_state.fc = efx_mdio_get_pause(efx);
unsigned int link_fc = efx_mdio_get_pause(efx);
if (link_fc != link_state->fc) sfx7101_check_bad_lp(efx, efx->link_state.up);
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;
} else { } else {
int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, struct ethtool_cmd ecmd;
MDIO_PMA_LASI_STAT);
if (status & MDIO_PMA_LASI_LSALARM)
change = true;
}
if (change) /* Check the LASI alarm first */
falcon_sim_phy_event(efx); 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) tenxpress_get_settings(efx, &ecmd);
return;
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) static void tenxpress_phy_fini(struct efx_nic *efx)
...@@ -818,7 +805,6 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { ...@@ -818,7 +805,6 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
.reconfigure = tenxpress_phy_reconfigure, .reconfigure = tenxpress_phy_reconfigure,
.poll = tenxpress_phy_poll, .poll = tenxpress_phy_poll,
.fini = tenxpress_phy_fini, .fini = tenxpress_phy_fini,
.clear_interrupt = efx_port_dummy_op_void,
.get_settings = tenxpress_get_settings, .get_settings = tenxpress_get_settings,
.set_settings = tenxpress_set_settings, .set_settings = tenxpress_set_settings,
.set_npage_adv = sfx7101_set_npage_adv, .set_npage_adv = sfx7101_set_npage_adv,
...@@ -835,7 +821,6 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { ...@@ -835,7 +821,6 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
.reconfigure = tenxpress_phy_reconfigure, .reconfigure = tenxpress_phy_reconfigure,
.poll = tenxpress_phy_poll, .poll = tenxpress_phy_poll,
.fini = tenxpress_phy_fini, .fini = tenxpress_phy_fini,
.clear_interrupt = efx_port_dummy_op_void,
.get_settings = tenxpress_get_settings, .get_settings = tenxpress_get_settings,
.set_settings = tenxpress_set_settings, .set_settings = tenxpress_set_settings,
.set_npage_adv = sft9001_set_npage_adv, .set_npage_adv = sft9001_set_npage_adv,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment