⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e1000_ethtool.c

📁 linux系统的网卡驱动包
💻 C
📖 第 1 页 / 共 5 页
字号:
	phy_reg |= MII_CR_LOOPBACK;	e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_reg);	/* Setup TX_CLK and TX_CRS one more time. */	e1000_phy_reset_clk_and_crs(adapter);	/* Check Phy Configuration */	e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_reg);	if (phy_reg != 0x4100)		 return 9;	e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);	if (phy_reg != 0x0070)		return 10;	e1000_read_phy_reg(&adapter->hw, 29, &phy_reg);	if (phy_reg != 0x001A)		return 11;	return 0;}static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter){	u32 ctrl_reg = 0;	u32 stat_reg = 0;	adapter->hw.mac.autoneg = FALSE;	if (adapter->hw.phy.type == e1000_phy_m88) {		/* Auto-MDI/MDIX Off */		e1000_write_phy_reg(&adapter->hw,				    M88E1000_PHY_SPEC_CTRL, 0x0808);		/* reset to update Auto-MDI/MDIX */		e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x9140);		/* autoneg off */		e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x8140);	} else if (adapter->hw.phy.type == e1000_phy_gg82563)		e1000_write_phy_reg(&adapter->hw,		                    GG82563_PHY_KMRN_MODE_CTRL,		                    0x1CC);	ctrl_reg = E1000_READ_REG(&adapter->hw, E1000_CTRL);	if (adapter->hw.phy.type == e1000_phy_ife) {		/* force 100, set loopback */		e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x6100);		/* Now set up the MAC to the same speed/duplex as the PHY. */		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */			     E1000_CTRL_FD);	 /* Force Duplex to FULL */	} else {		/* force 1000, set loopback */		e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x4140);		/* Now set up the MAC to the same speed/duplex as the PHY. */		ctrl_reg = E1000_READ_REG(&adapter->hw, E1000_CTRL);		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */			     E1000_CTRL_FD);	 /* Force Duplex to FULL */	}	if (adapter->hw.phy.media_type == e1000_media_type_copper &&	   adapter->hw.phy.type == e1000_phy_m88) {		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */	} else {		/* Set the ILOS bit on the fiber Nic if half duplex link is		 * detected. */		stat_reg = E1000_READ_REG(&adapter->hw, E1000_STATUS);		if ((stat_reg & E1000_STATUS_FD) == 0)			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);	}	E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl_reg);	/* Disable the receiver on the PHY so when a cable is plugged in, the	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.	 */	if (adapter->hw.phy.type == e1000_phy_m88)		e1000_phy_disable_receiver(adapter);	udelay(500);	return 0;}static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter){	struct e1000_hw *hw = &adapter->hw;	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);	int link = 0;	/* special requirements for 82571/82572 fiber adapters */	/* jump through hoops to make sure link is up because serdes	 * link is hardwired up */	ctrl |= E1000_CTRL_SLU;	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);	/* disable autoneg */	ctrl = E1000_READ_REG(hw, E1000_TXCW);	ctrl &= ~(1 << 31);	E1000_WRITE_REG(hw, E1000_TXCW, ctrl);	link = (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU);	if (!link) {		/* set invert loss of signal */		ctrl = E1000_READ_REG(hw, E1000_CTRL);		ctrl |= E1000_CTRL_ILOS;		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);	}	/* special write to serdes control register to enable SerDes analog	 * loopback */#define E1000_SERDES_LB_ON 0x410	E1000_WRITE_REG(hw, E1000_SCTL, E1000_SERDES_LB_ON);	msleep(10);	return 0;}static int e1000_set_phy_loopback(struct e1000_adapter *adapter){	u16 phy_reg = 0;	u16 count = 0;	switch (adapter->hw.mac.type) {	case e1000_82543:		if (adapter->hw.phy.media_type == e1000_media_type_copper) {			/* Attempt to setup Loopback mode on Non-integrated PHY.			 * Some PHY registers get corrupted at random, so			 * attempt this 10 times.			 */			while (e1000_nonintegrated_phy_loopback(adapter) &&			      count++ < 10);			if (count < 11)				return 0;		}		break;	case e1000_82544:	case e1000_82540:	case e1000_82545:	case e1000_82545_rev_3:	case e1000_82546:	case e1000_82546_rev_3:	case e1000_82541:	case e1000_82541_rev_2:	case e1000_82547:	case e1000_82547_rev_2:	case e1000_82571:	case e1000_82572:	case e1000_82573:	case e1000_80003es2lan:	case e1000_ich8lan:	case e1000_ich9lan:		return e1000_integrated_phy_loopback(adapter);		break;	default:		/* Default PHY loopback work is to read the MII		 * control register and assert bit 14 (loopback mode).		 */		e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_reg);		phy_reg |= MII_CR_LOOPBACK;		e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_reg);		return 0;		break;	}	return 8;}/* only call this for fiber/serdes connections to es2lan */static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter){	struct e1000_hw *hw = &adapter->hw;	u32 ctrlext = E1000_READ_REG(hw, E1000_CTRL_EXT);	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);	/* save CTRL_EXT to restore later, reuse an empty variable (unused	   on mac_type 80003es2lan) */	adapter->tx_fifo_head = ctrlext;	/* clear the serdes mode bits, putting the device into mac loopback */	ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrlext);	/* force speed to 1000/FD, link up */	ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);	ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX |	         E1000_CTRL_SPD_1000 | E1000_CTRL_FD);	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);	/* set mac loopback */	ctrl = E1000_READ_REG(hw, E1000_RCTL);	ctrl |= E1000_RCTL_LBM_MAC;	E1000_WRITE_REG(hw, E1000_RCTL, ctrl);	/* set testing mode parameters (no need to reset later) */#define KMRNCTRLSTA_OPMODE (0x1F << 16)#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA,		(KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));	return 0;}static int e1000_setup_loopback_test(struct e1000_adapter *adapter){	struct e1000_hw *hw = &adapter->hw;	u32 rctl;	if (hw->phy.media_type == e1000_media_type_fiber ||	    hw->phy.media_type == e1000_media_type_internal_serdes) {		switch (hw->mac.type) {		case e1000_80003es2lan:			return e1000_set_es2lan_mac_loopback(adapter);			break;		case e1000_82545:		case e1000_82546:		case e1000_82545_rev_3:		case e1000_82546_rev_3:			return e1000_set_phy_loopback(adapter);			break;		case e1000_82571:		case e1000_82572:			return e1000_set_82571_fiber_loopback(adapter);			break;		default:			rctl = E1000_READ_REG(hw, E1000_RCTL);			rctl |= E1000_RCTL_LBM_TCVR;			E1000_WRITE_REG(hw, E1000_RCTL, rctl);			return 0;		}	} else if (hw->phy.media_type == e1000_media_type_copper)		return e1000_set_phy_loopback(adapter);	return 7;}static void e1000_loopback_cleanup(struct e1000_adapter *adapter){	struct e1000_hw *hw = &adapter->hw;	u32 rctl;	u16 phy_reg;	rctl = E1000_READ_REG(hw, E1000_RCTL);	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);	E1000_WRITE_REG(hw, E1000_RCTL, rctl);	switch (hw->mac.type) {	case e1000_80003es2lan:		if (hw->phy.media_type == e1000_media_type_fiber ||		    hw->phy.media_type == e1000_media_type_internal_serdes) {			/* restore CTRL_EXT, stealing space from tx_fifo_head */			E1000_WRITE_REG(hw, E1000_CTRL_EXT, adapter->tx_fifo_head);			adapter->tx_fifo_head = 0;		}		/* fall through */	case e1000_82571:	case e1000_82572:		if (hw->phy.media_type == e1000_media_type_fiber ||		    hw->phy.media_type == e1000_media_type_internal_serdes) {#define E1000_SERDES_LB_OFF 0x400			E1000_WRITE_REG(hw, E1000_SCTL, E1000_SERDES_LB_OFF);			msleep(10);			break;		}		/* Fall Through */	case e1000_82545:	case e1000_82546:	case e1000_82545_rev_3:	case e1000_82546_rev_3:	default:		hw->mac.autoneg = TRUE;		if (hw->phy.type == e1000_phy_gg82563)			e1000_write_phy_reg(hw,					    GG82563_PHY_KMRN_MODE_CTRL,					    0x180);		e1000_read_phy_reg(hw, PHY_CONTROL, &phy_reg);		if (phy_reg & MII_CR_LOOPBACK) {			phy_reg &= ~MII_CR_LOOPBACK;			e1000_write_phy_reg(hw, PHY_CONTROL, phy_reg);			e1000_phy_commit(hw);		}		break;	}}static void e1000_create_lbtest_frame(struct sk_buff *skb,                                      unsigned int frame_size){	memset(skb->data, 0xFF, frame_size);	frame_size &= ~1;	memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);	memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);	memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);}static int e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){	frame_size &= ~1;	if (*(skb->data + 3) == 0xFF) {		if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&		   (*(skb->data + frame_size / 2 + 12) == 0xAF)) {			return 0;		}	}	return 13;}static int e1000_run_loopback_test(struct e1000_adapter *adapter){	struct e1000_tx_ring *tx_ring = &adapter->test_tx_ring;	struct e1000_rx_ring *rx_ring = &adapter->test_rx_ring;	struct pci_dev *pdev = adapter->pdev;	int i, j, k, l, lc, good_cnt, ret_val=0;	unsigned long time;	E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), rx_ring->count - 1);	/* Calculate the loop count based on the largest descriptor ring	 * The idea is to wrap the largest ring a number of times using 64	 * send/receive pairs during each loop	 */	if (rx_ring->count <= tx_ring->count)		lc = ((tx_ring->count / 64) * 2) + 1;	else		lc = ((rx_ring->count / 64) * 2) + 1;	k = l = 0;	for (j = 0; j <= lc; j++) { /* loop count loop */		for (i = 0; i < 64; i++) { /* send the packets */			e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb,					1024);			pci_dma_sync_single_for_device(pdev,					tx_ring->buffer_info[k].dma,				    	tx_ring->buffer_info[k].length,				    	PCI_DMA_TODEVICE);			if (unlikely(++k == tx_ring->count)) k = 0;		}		E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), k);		msleep(200);		time = jiffies; /* set the start time for the receive */		good_cnt = 0;		do { /* receive the sent packets */			pci_dma_sync_single_for_cpu(pdev,			                rx_ring->buffer_info[l].dma,			                E1000_RXBUFFER_2048,			                PCI_DMA_FROMDEVICE);			ret_val = e1000_check_lbtest_frame(					rx_ring->buffer_info[l].skb,				   	1024);			if (!ret_val)				good_cnt++;			if (unlikely(++l == rx_ring->count)) l = 0;			/* time + 20 msecs (200 msecs on 2.4) is more than			 * enough time to complete the receives, if it's			 * exceeded, break and error off			 */		} while (good_cnt < 64 && jiffies < (time + 20));		if (good_cnt != 64) {			ret_val = 13; /* ret_val is the same as mis-compare */			break;		}		if (jiffies >= (time + 20)) {			ret_val = 14; /* error code for time out error */			break;		}	} /* end loop count loop */	return ret_val;}static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data){	/* PHY loopback cannot be performed if SoL/IDER	 * sessions are active */	if (e1000_check_reset_block(&adapter->hw)) {		DPRINTK(DRV, ERR, "Cannot do PHY loopback test "		        "when SoL/IDER is active.\n");		*data = 0;		goto out;	}	if ((*data = e1000_setup_desc_rings(adapter)))		goto out;	if ((*data = e1000_setup_loopback_test(adapter)))		goto err_loopback;	*data = e1000_run_loopback_test(adapter);	e1000_loopback_cleanup(adapter);err_loopback:	e1000_free_desc_rings(adapter);out:	return *data;}static int e1000_link_test(struct e1000_adapter *adapter, u64 *data){	*data = 0;	if (adapter->hw.phy.media_type == e1000_media_type_internal_serdes) {		int i = 0;		adapter->hw.mac.serdes_has_link = FALSE;		/* On some blade server designs, link establishment		 * could take as long as 2-3 minutes */		do {			e1000_check_for_link(&adapter->hw);			if (adapter->hw.mac.serdes_has_link == TRUE)				return *data;			msleep(20);		} while (i++ < 3750);		*data = 1;	} else {		e1000_check_for_link(&adapter->hw);		if (adapter->hw.mac.autoneg)			msleep(4000);		if (!(E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU)) {			*data = 1;		}	}	return *data;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -