Skip to content

Commit

Permalink
cxgb3: detect mac link faults.
Browse files Browse the repository at this point in the history
The driver currently ignores the local or remote link faults
raised at the mac layer. This patch fixes it.
Our mac however only advertizes link events, so wait for the
phy to stabilize the link, then enable mac link events interrupts.

Signed-off-by: Divy Le Ray <divy@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Divy Le Ray authored and David S. Miller committed Mar 13, 2009
1 parent cd40658 commit bf79209
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 9 deletions.
5 changes: 5 additions & 0 deletions drivers/net/cxgb3/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ struct port_info {
struct net_device_stats netstats;
int activity;
__be32 iscsi_ipv4addr;

int link_fault; /* link fault was detected */
};

enum { /* adapter flags */
Expand Down Expand Up @@ -241,6 +243,7 @@ struct adapter {
struct delayed_work adap_check_task;
struct work_struct ext_intr_handler_task;
struct work_struct fatal_error_handler_task;
struct work_struct link_fault_handler_task;

struct dentry *debugfs_root;

Expand Down Expand Up @@ -283,6 +286,8 @@ void t3_os_ext_intr_handler(struct adapter *adapter);
void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
int speed, int duplex, int fc);
void t3_os_phymod_changed(struct adapter *adap, int port_id);
void t3_os_link_fault(struct adapter *adapter, int port_id, int state);
void t3_os_link_fault_handler(struct adapter *adapter, int port_id);

void t3_sge_start(struct adapter *adap);
void t3_sge_stop(struct adapter *adap);
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/cxgb3/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ struct mac_stats {
unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */
unsigned long num_resets; /* # times reset due to stuck TX */

unsigned long link_faults; /* # detected link faults */
};

struct tp_mib_stats {
Expand Down Expand Up @@ -701,13 +702,16 @@ int t3_phy_lasi_intr_handler(struct cphy *phy);
void t3_intr_enable(struct adapter *adapter);
void t3_intr_disable(struct adapter *adapter);
void t3_intr_clear(struct adapter *adapter);
void t3_xgm_intr_enable(struct adapter *adapter, int idx);
void t3_xgm_intr_disable(struct adapter *adapter, int idx);
void t3_port_intr_enable(struct adapter *adapter, int idx);
void t3_port_intr_disable(struct adapter *adapter, int idx);
void t3_port_intr_clear(struct adapter *adapter, int idx);
int t3_slow_intr_handler(struct adapter *adapter);
int t3_phy_intr_handler(struct adapter *adapter);

void t3_link_changed(struct adapter *adapter, int port_id);
void t3_link_fault(struct adapter *adapter, int port_id);
int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data);
Expand Down Expand Up @@ -744,6 +748,8 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,

int t3_mac_reset(struct cmac *mac);
void t3b_pcs_reset(struct cmac *mac);
void t3_mac_disable_exact_filters(struct cmac *mac);
void t3_mac_enable_exact_filters(struct cmac *mac);
int t3_mac_enable(struct cmac *mac, int which);
int t3_mac_disable(struct cmac *mac, int which);
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
Expand Down
123 changes: 120 additions & 3 deletions drivers/net/cxgb3/cxgb3_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,40 @@ static void link_report(struct net_device *dev)
}
}

void t3_os_link_fault(struct adapter *adap, int port_id, int state)
{
struct net_device *dev = adap->port[port_id];
struct port_info *pi = netdev_priv(dev);

if (state == netif_carrier_ok(dev))
return;

if (state) {
struct cmac *mac = &pi->mac;

netif_carrier_on(dev);

/* Clear local faults */
t3_xgm_intr_disable(adap, pi->port_id);
t3_read_reg(adap, A_XGM_INT_STATUS +
pi->mac.offset);
t3_write_reg(adap,
A_XGM_INT_CAUSE + pi->mac.offset,
F_XGM_INT);

t3_set_reg_field(adap,
A_XGM_INT_ENABLE +
pi->mac.offset,
F_XGM_INT, F_XGM_INT);
t3_xgm_intr_enable(adap, pi->port_id);

t3_mac_enable(mac, MAC_DIRECTION_TX);
} else
netif_carrier_off(dev);

link_report(dev);
}

/**
* t3_os_link_changed - handle link status changes
* @adapter: the adapter associated with the link change
Expand Down Expand Up @@ -197,10 +231,34 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
if (link_stat != netif_carrier_ok(dev)) {
if (link_stat) {
t3_mac_enable(mac, MAC_DIRECTION_RX);

/* Clear local faults */
t3_xgm_intr_disable(adapter, pi->port_id);
t3_read_reg(adapter, A_XGM_INT_STATUS +
pi->mac.offset);
t3_write_reg(adapter,
A_XGM_INT_CAUSE + pi->mac.offset,
F_XGM_INT);

t3_set_reg_field(adapter,
A_XGM_INT_ENABLE + pi->mac.offset,
F_XGM_INT, F_XGM_INT);
t3_xgm_intr_enable(adapter, pi->port_id);

netif_carrier_on(dev);
} else {
netif_carrier_off(dev);
pi->phy.ops->power_down(&pi->phy, 1);

t3_xgm_intr_disable(adapter, pi->port_id);
t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_set_reg_field(adapter,
A_XGM_INT_ENABLE + pi->mac.offset,
F_XGM_INT, 0);

if (is_10G(adapter))
pi->phy.ops->power_down(&pi->phy, 1);

t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
}
Expand Down Expand Up @@ -1173,6 +1231,10 @@ static int cxgb_close(struct net_device *dev)
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;

/* Stop link fault interrupts */
t3_xgm_intr_disable(adapter, pi->port_id);
t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);

t3_port_intr_disable(adapter, pi->port_id);
netif_tx_stop_all_queues(dev);
pi->phy.ops->power_down(&pi->phy, 1);
Expand Down Expand Up @@ -1299,6 +1361,7 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
"CheckTXEnToggled ",
"CheckResets ",

"LinkFaults ",
};

static int get_sset_count(struct net_device *dev, int sset)
Expand Down Expand Up @@ -1431,6 +1494,8 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,

*data++ = s->num_toggled;
*data++ = s->num_resets;

*data++ = s->link_faults;
}

static inline void reg_block_dump(struct adapter *ap, void *buf,
Expand Down Expand Up @@ -2425,8 +2490,20 @@ static void check_link_status(struct adapter *adapter)
struct net_device *dev = adapter->port[i];
struct port_info *p = netdev_priv(dev);

if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev))
spin_lock_irq(&adapter->work_lock);
if (p->link_fault) {
spin_unlock_irq(&adapter->work_lock);
continue;
}
spin_unlock_irq(&adapter->work_lock);

if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
t3_xgm_intr_disable(adapter, i);
t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);

t3_link_changed(adapter, i);
t3_xgm_intr_enable(adapter, i);
}
}
}

Expand Down Expand Up @@ -2553,9 +2630,23 @@ static void ext_intr_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
ext_intr_handler_task);
int i;

/* Disable link fault interrupts */
for_each_port(adapter, i) {
struct net_device *dev = adapter->port[i];
struct port_info *p = netdev_priv(dev);

t3_xgm_intr_disable(adapter, i);
t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
}

/* Re-enable link fault interrupts */
t3_phy_intr_handler(adapter);

for_each_port(adapter, i)
t3_xgm_intr_enable(adapter, i);

/* Now reenable external interrupts */
spin_lock_irq(&adapter->work_lock);
if (adapter->slow_intr_mask) {
Expand Down Expand Up @@ -2588,6 +2679,32 @@ void t3_os_ext_intr_handler(struct adapter *adapter)
spin_unlock(&adapter->work_lock);
}

static void link_fault_task(struct work_struct *work)
{
struct adapter *adapter = container_of(work, struct adapter,
link_fault_handler_task);
int i;

for_each_port(adapter, i) {
struct net_device *netdev = adapter->port[i];
struct port_info *pi = netdev_priv(netdev);

if (pi->link_fault)
t3_link_fault(adapter, i);
}
}

void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
{
struct net_device *netdev = adapter->port[port_id];
struct port_info *pi = netdev_priv(netdev);

spin_lock(&adapter->work_lock);
pi->link_fault = 1;
queue_work(cxgb3_wq, &adapter->link_fault_handler_task);
spin_unlock(&adapter->work_lock);
}

static int t3_adapter_error(struct adapter *adapter, int reset)
{
int i, ret = 0;
Expand Down Expand Up @@ -2704,7 +2821,6 @@ void t3_fatal_err(struct adapter *adapter)
CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
fw_status[0], fw_status[1],
fw_status[2], fw_status[3]);

}

/**
Expand Down Expand Up @@ -2962,6 +3078,7 @@ static int __devinit init_one(struct pci_dev *pdev,

INIT_LIST_HEAD(&adapter->adapter_list);
INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
INIT_WORK(&adapter->link_fault_handler_task, link_fault_task);
INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);

Expand Down
13 changes: 13 additions & 0 deletions drivers/net/cxgb3/regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2215,6 +2215,15 @@

#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854

#define A_XGM_INT_STATUS 0x86c

#define S_LINKFAULTCHANGE 9
#define V_LINKFAULTCHANGE(x) ((x) << S_LINKFAULTCHANGE)
#define F_LINKFAULTCHANGE V_LINKFAULTCHANGE(1U)

#define A_XGM_XGM_INT_ENABLE 0x874
#define A_XGM_XGM_INT_DISABLE 0x878

#define A_XGM_STAT_CTRL 0x880

#define S_CLRSTATS 2
Expand Down Expand Up @@ -2413,6 +2422,10 @@
#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U)

#define S_XGM_INT 0
#define V_XGM_INT(x) ((x) << S_XGM_INT)
#define F_XGM_INT V_XGM_INT(1U)

#define A_XGM_INT_CAUSE 0x8d8

#define A_XGM_XAUI_ACT_CTRL 0x8dc
Expand Down
Loading

0 comments on commit bf79209

Please sign in to comment.