[ewg] [PATCH 3/5] nes: fix link reset for certain phy types

Glenn Grundstrom NetEffect glenn at lists.openfabrics.org
Fri Nov 30 10:21:06 PST 2007


Link status and link reset was not being handled correctly for
certain board phy types.  The link would always show up.

The fix was to detect the phy type and properly reset it.  A
fallout of this fix was to add rx/tx port discard counters
to ethtool.

Signed-off-by: Glenn Grundstrom <ggrundstrom at neteffect.com>

---

diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 48082ed..31d3cf5 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -249,6 +249,8 @@ struct nes_device {
 	unsigned long          mac_rx_jabber_frames;
 	unsigned long          mac_rx_oversized_frames;
 	unsigned long          mac_rx_short_frames;
+	unsigned long          port_rx_discards;
+	unsigned long          port_tx_discards;
 	unsigned int           mac_index;
 	unsigned int           nes_stack_start;
 
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 933f31c..623037d 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2102,7 +2102,7 @@ int nes_cm_disconn_true(struct nes_qp *nesqp)
 	struct iw_cm_id *cm_id;
 	struct iw_cm_event cm_event;
 	struct nes_vnic *nesvnic;
-	struct nes_cm_node *cm_node = NULL;
+	/* struct nes_cm_node *cm_node = NULL; */
 	u16 last_ae;
 	u8 original_hw_tcp_state;
 	u8 original_ibqp_state;
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index d2ab5a7..8b0193d 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -745,6 +745,10 @@ void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
 		u32temp = nes_read_indexed(nesdev, 0x000008e8);
 		u32temp |= 0x80000000;  
 		nes_write_indexed(nesdev, 0x000008e8, u32temp);
+		u32temp = nes_read_indexed(nesdev, 0x000021f8);
+		u32temp &= 0x7fffffff;
+		u32temp |= 0x7fff0010;  
+		nes_write_indexed(nesdev, 0x000021f8, u32temp);
 	}
 }
 
@@ -1934,6 +1938,32 @@ void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
 	aeq->aeq_head = head;
 }
 
+static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
+{
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	u32 reset_value;
+	u32 i=0;
+
+	if (nesadapter->hw_rev == NE020_REV) {
+		return;
+	}
+
+
+	reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+	if ((mac_index == 0)||((mac_index == 1) && (nesadapter->OneG_Mode))) {
+		reset_value |= 0x0000001d;
+	} else {
+		reset_value |= 0x0000002d;
+	}
+	nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+	while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+			& 0x00000040) != 0x00000040) && (i++ < 5000)) {
+	}
+
+
+
+}
 
 /**
  * nes_process_mac_intr
@@ -1967,6 +1997,12 @@ void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
 
 	if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
 		nesdev->link_status_interrupts++;
+		if ((++nesadapter->link_interrupt_count[mac_index]) > ((u16)NES_MAX_LINK_INTERRUPTS)) {
+			nesadapter->link_interrupt_count[mac_index] = 0;
+			spin_lock_irqsave(&nesadapter->phy_lock, flags);
+			nes_reset_link(nesdev, mac_index);
+			spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+		}
 		/* read the PHY interrupt status register */
 		if (nesadapter->OneG_Mode) {
 			do {
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 67fd2f3..21ec22c 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -80,6 +80,8 @@ enum indexed_regs {
 	NES_IDX_DST_IP_ADDR = 0x0400,
 	NES_IDX_PCIX_DIAG = 0x08e8,
 	NES_IDX_MPP_DEBUG = 0x0a00,
+	NES_IDX_PORT_RX_DISCARDS = 0x0a30,
+	NES_IDX_PORT_TX_DISCARDS = 0x0a34,
 	NES_IDX_MPP_LB_DEBUG = 0x0b00,
 	NES_IDX_DENALI_CTL_22 = 0x1058,
 	NES_IDX_MAC_TX_CONTROL = 0x2000,
@@ -571,6 +573,9 @@ enum nes_nic_cqe_word_idx {
 #define NES_PKT_TYPE_APBVT_BITS 0xC112
 #define NES_PKT_TYPE_APBVT_MASK 0xff3e
 
+#define NES_PKT_TYPE_PVALID_BITS 0x10000000
+#define NES_PKT_TYPE_PVALID_MASK 0x30000000
+
 #define NES_PKT_TYPE_TCPV4_BITS 0x0110
 #define NES_PKT_TYPE_TCPV4_MASK 0x3f30
 
@@ -959,6 +964,7 @@ struct nes_hw_tune_timer {
 #define NES_TIMER_INT_LIMIT         2
 #define NES_TIMER_INT_LIMIT_DYNAMIC 10
 #define NES_TIMER_ENABLE_LIMIT      4
+#define NES_MAX_LINK_INTERRUPTS		512
 
 struct nes_adapter {
 	u64              fw_ver;
@@ -1061,6 +1067,8 @@ struct nes_adapter {
 	u16 pd_config_size[4];
 	u16 pd_config_base[4];
 
+	u16  link_interrupt_count[4];
+
 	/* the phy index for each port */
 	u8  phy_index[4];
 	u8  mac_sw_state[4];
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index d75b327..c29ab12 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1117,6 +1117,16 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
 			NES_IDX_MAC_RX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
 	nesvnic->nesdev->mac_pause_frames_received += u32temp;
 
+	u32temp = nes_read_indexed(nesdev,
+			NES_IDX_PORT_RX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+	nesvnic->nesdev->port_rx_discards += u32temp;
+	nesvnic->netstats.rx_dropped += u32temp;
+
+	u32temp = nes_read_indexed(nesdev,
+			NES_IDX_PORT_TX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+	nesvnic->nesdev->port_tx_discards += u32temp;
+	nesvnic->netstats.tx_dropped += u32temp;
+
 	for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
 		if (nesvnic->qp_nic_index[nic_count] == 0xf)
 			break;
@@ -1661,6 +1671,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 				(0x200*(nesvnic->logical_port&1)) );
 		if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
 			if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+				nes_init_phy(nesdev);
 				nes_read_10G_phy_reg(nesdev, 1,
 						nesdev->nesadapter->phy_index[nesvnic->logical_port]);
 				temp_phy_data = (u16)nes_read_indexed(nesdev,
@@ -1692,7 +1703,9 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 		nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
 		nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp);
 
-		nes_init_phy(nesdev);
+		if (nesdev->nesadapter->phy_type[nesvnic->logical_port] != NES_PHY_TYPE_IRIS)
+			nes_init_phy(nesdev);
+
 		nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port),
 				~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
 				NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));



More information about the ewg mailing list