📄 e1000.c
字号:
/**************************************************************************Etherboot - BOOTP/TFTP Bootstrap ProgramInter Pro 1000 for EtherbootDrivers are port from Intel's Linux driver e1000-4.3.15***************************************************************************//******************************************************************************* Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. Contact Information: Linux NICS <linux.nics@intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************//* * Copyright (C) Archway Digital Solutions. * * written by Chrsitopher Li <cli at arcyway dot com> or <chrisl at gnuchina dot org> * 2/9/2002 * * Copyright (C) Linux Networx. * Massive upgrade to work with the new intel gigabit NICs. * <ebiederman at lnxi dot com> * * Support for 82541ei & 82547ei chips from Intel's Linux driver 5.1.13 added by * Georg Baum <gbaum@users.sf.net>, sponsored by PetaMem GmbH and linkLINE Communications, Inc. * * 01/2004: Updated to Linux driver 5.2.22 by Georg Baum <gbaum@users.sf.net> *//* to get some global routines like printf */#include "etherboot.h"/* to get the interface to the body of the program */#include "nic.h"/* to get the PCI support functions, if this is a PCI NIC */#include "pci.h"#include "timer.h"typedef unsigned char *dma_addr_t;typedef enum { FALSE = 0, TRUE = 1} boolean_t;#define DEBUG 0/* Some pieces of code are disabled with #if 0 ... #endif. * They are not deleted to show where the etherboot driver differs * from the linux driver below the function level. * Some member variables of the hw struct have been eliminated * and the corresponding inplace checks inserted instead. * Pieces such as LED handling that we definitely don't need are deleted. * * The following defines should not be needed normally, * but may be helpful for debugging purposes. *//* Define this if you want to program the transmission control register * the way the Linux driver does it. */#undef LINUX_DRIVER_TCTL/* Define this to behave more like the Linux driver. */#undef LINUX_DRIVER/* Define this (and implement the needed functions) if you want to differ * between port and memory mapped io. */#undef PORT_IO_AND_MEMORY_IO_DIFFER#include "e1000_hw.h"/* NIC specific static variables go here */static struct e1000_hw hw;static char tx_pool[128 + 16];static char rx_pool[128 + 16];static char packet[2096];static struct e1000_tx_desc *tx_base;static struct e1000_rx_desc *rx_base;static int tx_tail;static int rx_tail, rx_last;/* Function forward declarations */static int e1000_setup_link(struct e1000_hw *hw);static int e1000_setup_fiber_serdes_link(struct e1000_hw *hw);static int e1000_setup_copper_link(struct e1000_hw *hw);static int e1000_phy_setup_autoneg(struct e1000_hw *hw);static void e1000_config_collision_dist(struct e1000_hw *hw);static int e1000_config_mac_to_phy(struct e1000_hw *hw);static int e1000_config_fc_after_link_up(struct e1000_hw *hw);static int e1000_check_for_link(struct e1000_hw *hw);static int e1000_wait_autoneg(struct e1000_hw *hw);static void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed, uint16_t *duplex);static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);static int e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data);static int e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data);static void e1000_phy_hw_reset(struct e1000_hw *hw);static int e1000_phy_reset(struct e1000_hw *hw);static int e1000_detect_gig_phy(struct e1000_hw *hw);/* Printing macros... */#define E1000_ERR(args...) printf("e1000: " args)#if DEBUG >= 3#define E1000_DBG(args...) printf("e1000: " args)#else#define E1000_DBG(args...)#endif#define MSGOUT(S, A, B) printk(S "\n", A, B)#if DEBUG >= 2#define DEBUGFUNC(F) DEBUGOUT(F "\n");#else#define DEBUGFUNC(F)#endif#if DEBUG >= 1#define DEBUGOUT(S) printf(S)#define DEBUGOUT1(S,A) printf(S,A)#define DEBUGOUT2(S,A,B) printf(S,A,B)#define DEBUGOUT3(S,A,B,C) printf(S,A,B,C)#define DEBUGOUT7(S,A,B,C,D,E,F,G) printf(S,A,B,C,D,E,F,G)#else#define DEBUGOUT(S)#define DEBUGOUT1(S,A)#define DEBUGOUT2(S,A,B)#define DEBUGOUT3(S,A,B,C)#define DEBUGOUT7(S,A,B,C,D,E,F,G)#endif#define E1000_WRITE_REG(a, reg, value) ( \ ((a)->mac_type >= e1000_82543) ? \ (writel((value), ((a)->hw_addr + E1000_##reg))) : \ (writel((value), ((a)->hw_addr + E1000_82542_##reg))))#define E1000_READ_REG(a, reg) ( \ ((a)->mac_type >= e1000_82543) ? \ readl((a)->hw_addr + E1000_##reg) : \ readl((a)->hw_addr + E1000_82542_##reg))#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ ((a)->mac_type >= e1000_82543) ? \ writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \ writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ ((a)->mac_type >= e1000_82543) ? \ readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))#define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}static inline void e1000_pci_set_mwi(struct e1000_hw *hw){ pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word);}static inline void e1000_pci_clear_mwi(struct e1000_hw *hw){ pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);}/****************************************************************************** * Raises the EEPROM's clock input. * * hw - Struct containing variables accessed by shared code * eecd - EECD's current value *****************************************************************************/static voide1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd){ /* Raise the clock input to the EEPROM (by setting the SK bit), and then * wait <delay> microseconds. */ *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); udelay(hw->eeprom.delay_usec);}/****************************************************************************** * Lowers the EEPROM's clock input. * * hw - Struct containing variables accessed by shared code * eecd - EECD's current value *****************************************************************************/static voide1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd){ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then * wait 50 microseconds. */ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); udelay(hw->eeprom.delay_usec);}/****************************************************************************** * Shift data bits out to the EEPROM. * * hw - Struct containing variables accessed by shared code * data - data to send to the EEPROM * count - number of bits to shift out *****************************************************************************/static voide1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count){ struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; uint32_t mask; /* We need to shift "count" bits out to the EEPROM. So, value in the * "data" parameter will be shifted out to the EEPROM one bit at a time. * In order to do this, "data" must be broken down into bits. */ mask = 0x01 << (count - 1); eecd = E1000_READ_REG(hw, EECD); if (eeprom->type == e1000_eeprom_microwire) { eecd &= ~E1000_EECD_DO; } else if (eeprom->type == e1000_eeprom_spi) { eecd |= E1000_EECD_DO; } do { /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", * and then raising and then lowering the clock (the SK bit controls * the clock input to the EEPROM). A "0" is shifted out to the EEPROM * by setting "DI" to "0" and then raising and then lowering the clock. */ eecd &= ~E1000_EECD_DI; if(data & mask) eecd |= E1000_EECD_DI; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec); e1000_raise_ee_clk(hw, &eecd); e1000_lower_ee_clk(hw, &eecd); mask = mask >> 1; } while(mask); /* We leave the "DI" bit set to "0" when we leave this routine. */ eecd &= ~E1000_EECD_DI; E1000_WRITE_REG(hw, EECD, eecd);}/****************************************************************************** * Shift data bits in from the EEPROM * * hw - Struct containing variables accessed by shared code *****************************************************************************/static uint16_te1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count){ uint32_t eecd; uint32_t i; uint16_t data; /* In order to read a register from the EEPROM, we need to shift 'count' * bits in from the EEPROM. Bits are "shifted in" by raising the clock * input to the EEPROM (setting the SK bit), and then reading the value of * the "DO" bit. During this "shifting in" process the "DI" bit should * always be clear. */ eecd = E1000_READ_REG(hw, EECD); eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); data = 0; for(i = 0; i < count; i++) { data = data << 1; e1000_raise_ee_clk(hw, &eecd); eecd = E1000_READ_REG(hw, EECD); eecd &= ~(E1000_EECD_DI); if(eecd & E1000_EECD_DO) data |= 1; e1000_lower_ee_clk(hw, &eecd); } return data;}/****************************************************************************** * Prepares EEPROM for access * * hw - Struct containing variables accessed by shared code * * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This * function should be called before issuing a command to the EEPROM. *****************************************************************************/static int32_te1000_acquire_eeprom(struct e1000_hw *hw){ struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd, i=0; eecd = E1000_READ_REG(hw, EECD); /* Request EEPROM Access */ if(hw->mac_type > e1000_82544) { eecd |= E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); eecd = E1000_READ_REG(hw, EECD); while((!(eecd & E1000_EECD_GNT)) && (i < E1000_EEPROM_GRANT_ATTEMPTS)) { i++; udelay(5); eecd = E1000_READ_REG(hw, EECD); } if(!(eecd & E1000_EECD_GNT)) { eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); DEBUGOUT("Could not acquire EEPROM grant\n"); return -E1000_ERR_EEPROM; } } /* Setup EEPROM for Read/Write */ if (eeprom->type == e1000_eeprom_microwire) { /* Clear SK and DI */ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); /* Set CS */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); } else if (eeprom->type == e1000_eeprom_spi) { /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); udelay(1); } return E1000_SUCCESS;}/****************************************************************************** * Returns EEPROM to a "standby" state * * hw - Struct containing variables accessed by shared code *****************************************************************************/static voide1000_standby_eeprom(struct e1000_hw *hw){ struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; eecd = E1000_READ_REG(hw, EECD); if(eeprom->type == e1000_eeprom_microwire) { /* Deselect EEPROM */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec); /* Clock high */ eecd |= E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec); /* Select EEPROM */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec); /* Clock low */ eecd &= ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec); } else if(eeprom->type == e1000_eeprom_spi) { /* Toggle CS to flush commands */ eecd |= E1000_EECD_CS; E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); udelay(eeprom->delay_usec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -