From: thantry Date: Fri, 3 Jan 2003 00:53:19 +0000 (+0000) Subject: Adding patches necessary for intel kernels into sourceforge. X-Git-Tag: v1_7_0_51~2^13~92 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=ab39903ed36850b91eebfaf078ba462a37b2fcc7;p=fs%2Flustre-release.git Adding patches necessary for intel kernels into sourceforge. The rh-8.0-intel series captures, in addition to all the lustre specific patches the remaining two patches necessary(or of interest) to the Intel cluster. --- diff --git a/lustre/kernel_patches/patches/e1000.patch b/lustre/kernel_patches/patches/e1000.patch new file mode 100644 index 0000000..ed63058 --- /dev/null +++ b/lustre/kernel_patches/patches/e1000.patch @@ -0,0 +1,11535 @@ + +This patch creates the necessary drivers +for the e1000 card that are not included with +the standard RH distribution. This is used for the +GigE e1000 cards. + + + 0 files changed + +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000.h 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,362 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++ ++/* Linux PRO/1000 Ethernet Driver main header file */ ++ ++#ifndef _E1000_H_ ++#define _E1000_H_ ++ ++#ifndef __E1000_MAIN__ ++#define __NO_VERSION__ ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ethtool support */ ++#ifdef SIOCETHTOOL ++#include ++#include ++#define E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS (SUPPORTED_10baseT_Half | \ ++ SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | \ ++ SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | \ ++ SUPPORTED_Autoneg | SUPPORTED_MII) ++#define E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE (ADVERTISED_10baseT_Half | \ ++ ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | \ ++ ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | \ ++ ADVERTISED_Autoneg | ADVERTISED_MII) ++#define E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS (SUPPORTED_Autoneg | \ ++ SUPPORTED_FIBRE) ++#define E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE (ADVERTISED_Autoneg | \ ++ ADVERTISED_FIBRE) ++#endif /* SIOCETHTOOL */ ++ ++ ++ ++struct e1000_adapter; ++ ++#include "e1000_mac.h" ++#include "e1000_phy.h" ++ ++#ifdef IANS ++#include "base_comm.h" ++#include "ans_driver.h" ++#include "ans.h" ++#endif ++ ++#ifdef IDIAG ++#include "idiag_pro.h" ++#include "idiag_e1000.h" ++#endif ++ ++#define BAR_0 0 ++ ++/* 8254x can use Dual Address Cycles for 64-bit addressing */ ++ ++/* Advertise that we can DMA from any address location */ ++#define E1000_DMA_MASK (~0x0UL) ++#define E1000_DBG(args...) ++// #define E1000_DBG(args...) printk("e1000: " args) ++#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args) ++#ifdef CONFIG_PPC ++#define E1000_MAX_INTR 1 ++#else ++#define E1000_MAX_INTR 10 ++#endif ++#define MAX_NUM_MULTICAST_ADDRESSES 128 ++ ++/* command line options defaults */ ++#define DEFAULT_TXD 256 ++#define MAX_TXD 256 ++#define MIN_TXD 80 ++#define MAX_82544_TXD 4096 ++#define DEFAULT_RXD 256 ++#define MAX_RXD 256 ++#define MIN_RXD 80 ++#define MAX_82544_RXD 4096 ++#define DEFAULT_TIDV 64 ++#define MAX_TIDV 0xFFFF ++#define MIN_TIDV 0 ++#define DEFAULT_RIDV 64 ++#define MAX_RIDV 0xFFFF ++#define MIN_RIDV 0 ++#define DEFAULT_MDIX 0 ++#define MAX_MDIX 3 ++#define MIN_MDIX 0 ++ ++#define OPTION_UNSET -1 ++#define OPTION_DISABLED 0 ++#define OPTION_ENABLED 1 ++#define XSUMRX_DEFAULT OPTION_ENABLED ++#define WAITFORLINK_DEFAULT OPTION_ENABLED ++#define AUTONEG_ADV_DEFAULT 0x2F ++#define AUTONEG_ADV_MASK 0x2F ++#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL ++ ++#define E1000_REPORT_TX_EARLY 2 ++ ++/* Supported RX Buffer Sizes */ ++#define E1000_RXBUFFER_2048 2048 ++#define E1000_RXBUFFER_4096 4096 ++#define E1000_RXBUFFER_8192 8192 ++#define E1000_RXBUFFER_16384 16384 ++ ++#define E1000_JUMBO_PBA 0x00000028 ++#define E1000_DEFAULT_PBA 0x00000030 ++ ++/* Round size up to the next multiple of unit */ ++#define E1000_ROUNDUP(size, unit) ((((size) + (unit) - 1) / (unit)) * (unit)) ++ ++/* This is better, but only works for unit sizes that are powers of 2 */ ++#define E1000_ROUNDUP2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) ++ ++/* wrapper around a pointer to a socket buffer, ++ * so a DMA handle can be stored along with the buffer */ ++struct e1000_buffer { ++ struct sk_buff *skb; ++ uint64_t dma; ++ unsigned long length; ++}; ++ ++/* Adapter->flags definitions */ ++#define E1000_BOARD_OPEN 0 ++#define E1000_RX_REFILL 1 ++#define E1000_DIAG_OPEN 2 ++#define E1000_LINK_STATUS_CHANGED 3 ++ ++typedef enum _XSUM_CONTEXT_T { ++ OFFLOAD_NONE, ++ OFFLOAD_TCP_IP, ++ OFFLOAD_UDP_IP ++} XSUM_CONTEXT_T; ++ ++struct e1000_desc_ring { ++ void *desc; /* pointer to the descriptor ring memory */ ++ dma_addr_t dma; /* physical address of the descriptor ring */ ++ unsigned int size; /* length of descriptor ring in bytes */ ++ unsigned int count; /* number of descriptors in the ring */ ++ atomic_t unused; /* number of descriptors with no buffer */ ++ unsigned int next_to_use; /* next descriptor to associate a buffer with */ ++ unsigned int next_to_clean; /* next descriptor to check for DD status bit */ ++ struct e1000_buffer *buffer_info; /* array of buffer information structs */ ++}; ++ ++#define E1000_RX_DESC(ring, i) \ ++ (&(((struct e1000_rx_desc *)(ring.desc))[i])) ++ ++#define E1000_TX_DESC(ring, i) \ ++ (&(((struct e1000_tx_desc *)(ring.desc))[i])) ++ ++#define E1000_CONTEXT_DESC(ring, i) \ ++ (&(((struct e1000_context_desc *)(ring.desc))[i])) ++ ++/* board specific private data structure */ ++ ++struct e1000_adapter { ++ struct e1000_adapter *next; ++ struct e1000_adapter *prev; ++ ++ struct e1000_shared_adapter shared; ++ ++#ifdef IANS ++ void *iANSReserved; ++ piANSsupport_t iANSdata; ++ uint32_t ans_link; ++ uint32_t ans_speed; ++ uint32_t ans_duplex; ++ uint32_t ans_suspend; ++ IANS_BD_TAGGING_MODE tag_mode; ++#endif ++ ++ spinlock_t stats_lock; ++ spinlock_t rx_fill_lock; ++ ++ unsigned long flags; ++ uint32_t bd_number; ++ struct timer_list timer_id; ++ ++ /* Ethernet Node Address */ ++ uint8_t perm_net_addr[ETH_LENGTH_OF_ADDRESS]; ++ ++ /* Status Flags */ ++ boolean_t link_active; ++ uint16_t link_speed; ++ uint16_t link_duplex; ++ uint32_t rx_buffer_len; ++ ++ /* PCI Device Info */ ++ uint16_t vendor_id; ++ uint16_t device_id; ++ uint8_t rev_id; ++ uint16_t subven_id; ++ uint16_t subsys_id; ++ ++ uint32_t part_num; ++ ++ uint32_t int_mask; ++ ++ /* driver specific */ ++ struct tasklet_struct rx_fill_tasklet; ++ ++ struct e1000_desc_ring tx_ring; ++ uint32_t tx_int_delay; ++ uint32_t TxdCmd; ++ atomic_t tx_timeout; ++ ++ struct e1000_desc_ring rx_ring; ++ uint32_t rx_int_delay; ++ ++ uint64_t XsumRXGood; ++ uint64_t XsumRXError; ++ ++ /* Linux driver specific */ ++ struct net_device *netdev; ++ struct pci_dev *pdev; ++ struct net_device_stats net_stats; ++ char *id_string; ++ boolean_t RxChecksum; ++ XSUM_CONTEXT_T ActiveChecksumContext; ++ ++ struct e1000_phy_info phy_info; ++ struct e1000_shared_stats stats; ++ ++ /* PHY Statistics */ ++ struct e1000_phy_stats phy_stats; ++}; ++ ++/* Prototypes */ ++ ++/* e1000_main.c */ ++extern int e1000_init_module(void); ++extern int e1000_probe_all(void); ++extern void e1000_exit_module(void); ++extern int e1000_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent); ++extern void e1000_remove(struct pci_dev *pdev); ++extern void e1000_delete(struct e1000_adapter *Adapter); ++extern int e1000_open(struct net_device *netdev); ++extern int e1000_close(struct net_device *netdev); ++extern void e1000_set_multi(struct net_device *netdev); ++extern int e1000_xmit_frame(struct sk_buff *skb, ++ struct net_device *netdev); ++extern struct net_device_stats *e1000_get_stats(struct net_device *netdev); ++extern int e1000_change_mtu(struct net_device *netdev, ++ int new_mtu); ++extern int e1000_set_mac(struct net_device *netdev, ++ void *p); ++extern void e1000_intr(int irq, ++ void *data, ++ struct pt_regs *regs); ++extern int e1000_ioctl(struct net_device *netdev, ++ struct ifreq *ifr, ++ int cmd); ++extern void e1000_watchdog(unsigned long data); ++extern void e1000_diag_ioctl(struct net_device *netdev, ++ struct ifreq *ifr); ++ ++#ifdef CONFIG_PROC_FS ++#include "e1000_proc.h" ++#endif ++#ifdef IDIAG ++#include "e1000_idiag.h" ++#endif ++#endif /* _E1000_H_ */ +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_mac.c 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,2093 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/* e1000_mac.c ++ * Shared functions for accessing and configuring the MAC ++ */ ++ ++#include "e1000_mac.h" ++#include "e1000_phy.h" ++ ++/****************************************************************************** ++ * Raises the EEPROM's clock input. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * eecd_reg - EECD's current value ++ *****************************************************************************/ ++static void ++e1000_raise_clock(struct e1000_shared_adapter *shared, ++ uint32_t *eecd_reg) ++{ ++ /* Raise the clock input to the EEPROM (by setting the SK bit), and then ++ * wait 50 microseconds. ++ */ ++ *eecd_reg = *eecd_reg | E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, *eecd_reg); ++ usec_delay(50); ++ return; ++} ++ ++/****************************************************************************** ++ * Lowers the EEPROM's clock input. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * eecd_reg - EECD's current value ++ *****************************************************************************/ ++static void ++e1000_lower_clock(struct e1000_shared_adapter *shared, ++ uint32_t *eecd_reg) ++{ ++ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then ++ * wait 50 microseconds. ++ */ ++ *eecd_reg = *eecd_reg & ~E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, *eecd_reg); ++ usec_delay(50); ++ return; ++} ++ ++/****************************************************************************** ++ * Shift data bits out to the EEPROM. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * data - data to send to the EEPROM ++ * count - number of bits to shift out ++ *****************************************************************************/ ++static void ++e1000_shift_out_bits(struct e1000_shared_adapter *shared, ++ uint16_t data, ++ uint16_t count) ++{ ++ uint32_t eecd_reg; ++ 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_reg = E1000_READ_REG(shared, EECD); ++ eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); ++ 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_reg &= ~E1000_EECD_DI; ++ ++ if(data & mask) ++ eecd_reg |= E1000_EECD_DI; ++ ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ ++ usec_delay(50); ++ ++ e1000_raise_clock(shared, &eecd_reg); ++ e1000_lower_clock(shared, &eecd_reg); ++ ++ mask = mask >> 1; ++ ++ } while(mask); ++ ++ /* We leave the "DI" bit set to "0" when we leave this routine. */ ++ eecd_reg &= ~E1000_EECD_DI; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ return; ++} ++ ++/****************************************************************************** ++ * Shift data bits in from the EEPROM ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++static uint16_t ++e1000_shift_in_bits(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ uint32_t i; ++ uint16_t data; ++ ++ /* In order to read a register from the EEPROM, we need to shift 16 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_reg = E1000_READ_REG(shared, EECD); ++ ++ eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); ++ data = 0; ++ ++ for(i = 0; i < 16; i++) { ++ data = data << 1; ++ e1000_raise_clock(shared, &eecd_reg); ++ ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ eecd_reg &= ~(E1000_EECD_DI); ++ if(eecd_reg & E1000_EECD_DO) ++ data |= 1; ++ ++ e1000_lower_clock(shared, &eecd_reg); ++ } ++ ++ return data; ++} ++ ++/****************************************************************************** ++ * Prepares EEPROM for access ++ * ++ * shared - 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 void ++e1000_setup_eeprom(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ /* Clear SK and DI */ ++ eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI); ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ ++ /* Set CS */ ++ eecd_reg |= E1000_EECD_CS; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ return; ++} ++ ++/****************************************************************************** ++ * Returns EEPROM to a "standby" state ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++static void ++e1000_standby_eeprom(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ /* Deselct EEPROM */ ++ eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK); ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ ++ /* Clock high */ ++ eecd_reg |= E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ ++ /* Select EEPROM */ ++ eecd_reg |= E1000_EECD_CS; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ ++ /* Clock low */ ++ eecd_reg &= ~E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ return; ++} ++ ++/****************************************************************************** ++ * Raises then lowers the EEPROM's clock pin ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++static void ++e1000_clock_eeprom(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ /* Rising edge of clock */ ++ eecd_reg |= E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ ++ /* Falling edge of clock */ ++ eecd_reg &= ~E1000_EECD_SK; ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ usec_delay(50); ++ return; ++} ++ ++/****************************************************************************** ++ * Terminates a command by lowering the EEPROM's chip select pin ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++static void ++e1000_cleanup_eeprom(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_DI); ++ ++ E1000_WRITE_REG(shared, EECD, eecd_reg); ++ ++ e1000_clock_eeprom(shared); ++ return; ++} ++ ++/****************************************************************************** ++ * Waits for the EEPROM to finish the current command. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * The command is done when the EEPROM's data out pin goes high. ++ *****************************************************************************/ ++static uint16_t ++e1000_wait_eeprom_command(struct e1000_shared_adapter *shared) ++{ ++ uint32_t eecd_reg; ++ uint32_t i; ++ ++ ++ /* Toggle the CS line. This in effect tells to EEPROM to actually execute ++ * the command in question. ++ */ ++ e1000_standby_eeprom(shared); ++ ++ /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will ++ * signal that the command has been completed by raising the DO signal. ++ * If DO does not go high in 10 milliseconds, then error out. ++ */ ++ for(i = 0; i < 200; i++) { ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ ++ if(eecd_reg & E1000_EECD_DO) ++ return (TRUE); ++ ++ usec_delay(50); ++ } ++ ASSERT(0); ++ return (FALSE); ++} ++ ++/****************************************************************************** ++ * Forces the MAC's flow control settings. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Sets the TFCE and RFCE bits in the device control register to reflect ++ * the adapter settings. TFCE and RFCE need to be explicitly set by ++ * software when a Copper PHY is used because autonegotiation is managed ++ * by the PHY rather than the MAC. Software must also configure these ++ * bits when link is forced on a fiber connection. ++ *****************************************************************************/ ++static void ++e1000_force_mac_fc(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ ++ DEBUGFUNC("e1000_force_mac_fc"); ++ ++ /* Get the current configuration of the Device Control Register */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Because we didn't get link via the internal auto-negotiation ++ * mechanism (we either forced link or we got link via PHY ++ * auto-neg), we have to manually enable/disable transmit an ++ * receive flow control. ++ * ++ * The "Case" statement below enables/disable flow control ++ * according to the "shared->fc" parameter. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause ++ * frames but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames ++ * frames but we do not receive pause frames). ++ * 3: Both Rx and TX flow control (symmetric) is enabled. ++ * other: No other values should be possible at this point. ++ */ ++ ++ switch (shared->fc) { ++ case e1000_fc_none: ++ ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); ++ break; ++ case e1000_fc_rx_pause: ++ ctrl_reg &= (~E1000_CTRL_TFCE); ++ ctrl_reg |= E1000_CTRL_RFCE; ++ break; ++ case e1000_fc_tx_pause: ++ ctrl_reg &= (~E1000_CTRL_RFCE); ++ ctrl_reg |= E1000_CTRL_TFCE; ++ break; ++ case e1000_fc_full: ++ ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); ++ break; ++ default: ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ /* Disable TX Flow Control for 82542 (rev 2.0) */ ++ if(shared->mac_type == e1000_82542_rev2_0) ++ ctrl_reg &= (~E1000_CTRL_TFCE); ++ ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ return; ++} ++ ++/****************************************************************************** ++ * Reset the transmit and receive units; mask and clear all interrupts. ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_adapter_stop(struct e1000_shared_adapter *shared) ++{ ++#if DBG ++ uint32_t ctrl_reg; ++#endif ++ uint32_t ctrl_ext_reg; ++ uint32_t icr_reg; ++ uint16_t pci_cmd_word; ++ ++ DEBUGFUNC("e1000_shared_adapter_stop"); ++ ++ /* If we are stopped or resetting exit gracefully and wait to be ++ * started again before accessing the hardware. ++ */ ++ if(shared->adapter_stopped) { ++ DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); ++ return; ++ } ++ ++ /* Set the Adapter Stopped flag so other driver functions stop ++ * touching the Hardware. ++ */ ++ shared->adapter_stopped = TRUE; ++ ++ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ ++ if(shared->mac_type == e1000_82542_rev2_0) { ++ if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { ++ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); ++ ++ pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; ++ ++ e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); ++ } ++ } ++ ++ /* Clear interrupt mask to stop board from generating interrupts */ ++ DEBUGOUT("Masking off all interrupts\n"); ++ E1000_WRITE_REG(shared, IMC, 0xffffffff); ++ ++ /* Disable the Transmit and Receive units. Then delay to allow ++ * any pending transactions to complete before we hit the MAC with ++ * the global reset. ++ */ ++ E1000_WRITE_REG(shared, RCTL, 0); ++ E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); ++ ++ /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ ++ shared->tbi_compatibility_on = FALSE; ++ ++ msec_delay(10); ++ ++ /* Issue a global reset to the MAC. This will reset the chip's ++ * transmit, receive, DMA, and link units. It will not effect ++ * the current PCI configuration. The global reset bit is self- ++ * clearing, and should clear within a microsecond. ++ */ ++ DEBUGOUT("Issuing a global reset to MAC\n"); ++ E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST); ++ ++ /* Delay a few ms just to allow the reset to complete */ ++ msec_delay(10); ++ ++#if DBG ++ /* Make sure the self-clearing global reset bit did self clear */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ ASSERT(!(ctrl_reg & E1000_CTRL_RST)); ++#endif ++ ++ /* Force a reload from the EEPROM */ ++ ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); ++ ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST; ++ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); ++ msec_delay(2); ++ ++ /* Clear interrupt mask to stop board from generating interrupts */ ++ DEBUGOUT("Masking off all interrupts\n"); ++ E1000_WRITE_REG(shared, IMC, 0xffffffff); ++ ++ /* Clear any pending interrupt events. */ ++ icr_reg = E1000_READ_REG(shared, ICR); ++ ++ /* If MWI was previously enabled, reenable it. */ ++ if(shared->mac_type == e1000_82542_rev2_0) { ++ if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { ++ e1000_write_pci_cfg(shared, ++ PCI_COMMAND_REGISTER, &shared->pci_cmd_word); ++ } ++ } ++ return; ++} ++ ++/****************************************************************************** ++ * Performs basic configuration of the adapter. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Assumes that the controller has previously been reset and is in a ++ * post-reset uninitialized state. Initializes the receive address registers, ++ * multicast table, and VLAN filter table. Calls routines to setup link ++ * configuration and flow control settings. Clears all on-chip counters. Leaves ++ * the transmit and receive units disabled and uninitialized. ++ *****************************************************************************/ ++boolean_t ++e1000_init_hw(struct e1000_shared_adapter *shared) ++{ ++ uint32_t status_reg; ++ uint32_t i; ++ uint16_t pci_cmd_word; ++ boolean_t status; ++ ++ DEBUGFUNC("e1000_init_hw"); ++ ++ /* Set the Media Type and exit with error if it is not valid. */ ++ if(shared->mac_type != e1000_82543) { ++ /* tbi_compatibility is only valid on 82543 */ ++ shared->tbi_compatibility_en = FALSE; ++ } ++ ++ if(shared->mac_type >= e1000_82543) { ++ status_reg = E1000_READ_REG(shared, STATUS); ++ if(status_reg & E1000_STATUS_TBIMODE) { ++ shared->media_type = e1000_media_type_fiber; ++ /* tbi_compatibility not valid on fiber */ ++ shared->tbi_compatibility_en = FALSE; ++ } else { ++ shared->media_type = e1000_media_type_copper; ++ } ++ } else { ++ /* This is an 82542 (fiber only) */ ++ shared->media_type = e1000_media_type_fiber; ++ } ++ ++ /* Disabling VLAN filtering. */ ++ DEBUGOUT("Initializing the IEEE VLAN\n"); ++ E1000_WRITE_REG(shared, VET, 0); ++ ++ e1000_clear_vfta(shared); ++ ++ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ ++ if(shared->mac_type == e1000_82542_rev2_0) { ++ if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { ++ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); ++ pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; ++ e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); ++ } ++ E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST); ++ ++ msec_delay(5); ++ } ++ ++ /* Setup the receive address. This involves initializing all of the Receive ++ * Address Registers (RARs 0 - 15). ++ */ ++ e1000_init_rx_addrs(shared); ++ ++ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ ++ if(shared->mac_type == e1000_82542_rev2_0) { ++ E1000_WRITE_REG(shared, RCTL, 0); ++ ++ msec_delay(1); ++ ++ if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { ++ e1000_write_pci_cfg(shared, ++ PCI_COMMAND_REGISTER, &shared->pci_cmd_word); ++ } ++ } ++ ++ /* Zero out the Multicast HASH table */ ++ DEBUGOUT("Zeroing the MTA\n"); ++ for(i = 0; i < E1000_MC_TBL_SIZE; i++) ++ E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); ++ ++ /* Call a subroutine to configure the link and setup flow control. */ ++ status = e1000_setup_fc_and_link(shared); ++ ++ /* Clear all of the statistics registers (clear on read). It is ++ * important that we do this after we have tried to establish link ++ * because the symbol error count will increment wildly if there ++ * is no link. ++ */ ++ e1000_clear_hw_cntrs(shared); ++ ++ shared->low_profile = FALSE; ++ if(shared->mac_type == e1000_82544) { ++ if(e1000_read_eeprom(shared, E1000_EEPROM_LED_LOGIC) & ++ E1000_EEPROM_SWDPIN0) ++ shared->low_profile = TRUE; ++ } ++ ++ return (status); ++} ++ ++/****************************************************************************** ++ * Initializes receive address filters. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Places the MAC address in receive address register 0 and clears the rest ++ * of the receive addresss registers. Clears the multicast table. Assumes ++ * the receiver is in reset when the routine is called. ++ *****************************************************************************/ ++void ++e1000_init_rx_addrs(struct e1000_shared_adapter *shared) ++{ ++ uint32_t i; ++ uint32_t addr_low; ++ uint32_t addr_high; ++ ++ DEBUGFUNC("e1000_init_rx_addrs"); ++ ++ /* Setup the receive address. */ ++ DEBUGOUT("Programming MAC Address into RAR[0]\n"); ++ addr_low = (shared->mac_addr[0] | ++ (shared->mac_addr[1] << 8) | ++ (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24)); ++ ++ addr_high = (shared->mac_addr[4] | ++ (shared->mac_addr[5] << 8) | E1000_RAH_AV); ++ ++ E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low); ++ E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high); ++ ++ /* Zero out the other 15 receive addresses. */ ++ DEBUGOUT("Clearing RAR[1-15]\n"); ++ for(i = 1; i < E1000_RAR_ENTRIES; i++) { ++ E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); ++ E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); ++ } ++ ++ return; ++} ++ ++/****************************************************************************** ++ * Updates the MAC's list of multicast addresses. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * mc_addr_list - the list of new multicast addresses ++ * mc_addr_count - number of addresses ++ * pad - number of bytes between addresses in the list ++ * ++ * The given list replaces any existing list. Clears the last 15 receive ++ * address registers and the multicast table. Uses receive address registers ++ * for the first 15 multicast addresses, and hashes the rest into the ++ * multicast table. ++ *****************************************************************************/ ++void ++e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, ++ uint8_t *mc_addr_list, ++ uint32_t mc_addr_count, ++ uint32_t pad) ++{ ++ uint32_t hash_value; ++ uint32_t i; ++ uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ ++ ++ DEBUGFUNC("e1000_mc_addr_list_update"); ++ ++ /* Set the new number of MC addresses that we are being requested to use. */ ++ shared->num_mc_addrs = mc_addr_count; ++ ++ /* Clear RAR[1-15] */ ++ DEBUGOUT(" Clearing RAR[1-15]\n"); ++ for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { ++ E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); ++ E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); ++ } ++ ++ /* Clear the MTA */ ++ DEBUGOUT(" Clearing MTA\n"); ++ for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { ++ E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); ++ } ++ ++ /* Add the new addresses */ ++ for(i = 0; i < mc_addr_count; i++) { ++ DEBUGOUT(" Adding the multicast addresses:\n"); ++ DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1], ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2], ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3], ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4], ++ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]); ++ ++ hash_value = e1000_hash_mc_addr(shared, ++ mc_addr_list + ++ (i * (ETH_LENGTH_OF_ADDRESS + pad))); ++ ++ DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); ++ ++ /* Place this multicast address in the RAR if there is room, * ++ * else put it in the MTA ++ */ ++ if(rar_used_count < E1000_RAR_ENTRIES) { ++ e1000_rar_set(shared, ++ mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), ++ rar_used_count); ++ rar_used_count++; ++ } else { ++ e1000_mta_set(shared, hash_value); ++ } ++ } ++ ++ DEBUGOUT("MC Update Complete\n"); ++ return; ++} ++ ++/****************************************************************************** ++ * Hashes an address to determine its location in the multicast table ++ * ++ * shared - Struct containing variables accessed by shared code ++ * mc_addr - the multicast address to hash ++ *****************************************************************************/ ++uint32_t ++e1000_hash_mc_addr(struct e1000_shared_adapter *shared, ++ uint8_t *mc_addr) ++{ ++ uint32_t hash_value = 0; ++ ++ /* The portion of the address that is used for the hash table is ++ * determined by the mc_filter_type setting. ++ */ ++ switch (shared->mc_filter_type) { ++ /* [0] [1] [2] [3] [4] [5] ++ * 01 AA 00 12 34 56 ++ * LSB MSB - According to H/W docs */ ++ case 0: ++ /* [47:36] i.e. 0x563 for above example address */ ++ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); ++ break; ++ case 1: /* [46:35] i.e. 0xAC6 for above example address */ ++ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); ++ break; ++ case 2: /* [45:34] i.e. 0x5D8 for above example address */ ++ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); ++ break; ++ case 3: /* [43:32] i.e. 0x634 for above example address */ ++ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); ++ break; ++ } ++ ++ hash_value &= 0xFFF; ++ return (hash_value); ++} ++ ++/****************************************************************************** ++ * Sets the bit in the multicast table corresponding to the hash value. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * hash_value - Multicast address hash value ++ *****************************************************************************/ ++void ++e1000_mta_set(struct e1000_shared_adapter *shared, ++ uint32_t hash_value) ++{ ++ uint32_t hash_bit, hash_reg; ++ uint32_t mta_reg; ++ uint32_t temp; ++ ++ /* The MTA is a register array of 128 32-bit registers. ++ * It is treated like an array of 4096 bits. We want to set ++ * bit BitArray[hash_value]. So we figure out what register ++ * the bit is in, read it, OR in the new bit, then write ++ * back the new value. The register is determined by the ++ * upper 7 bits of the hash value and the bit within that ++ * register are determined by the lower 5 bits of the value. ++ */ ++ hash_reg = (hash_value >> 5) & 0x7F; ++ hash_bit = hash_value & 0x1F; ++ ++ mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg); ++ ++ mta_reg |= (1 << hash_bit); ++ ++ /* If we are on an 82544 and we are trying to write an odd offset ++ * in the MTA, save off the previous entry before writing and ++ * restore the old value after writing. ++ */ ++ if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { ++ temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1)); ++ E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); ++ E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp); ++ } else { ++ E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); ++ } ++ return; ++} ++ ++/****************************************************************************** ++ * Puts an ethernet address into a receive address register. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * addr - Address to put into receive address register ++ * index - Receive address register to write ++ *****************************************************************************/ ++void ++e1000_rar_set(struct e1000_shared_adapter *shared, ++ uint8_t *addr, ++ uint32_t index) ++{ ++ uint32_t rar_low, rar_high; ++ ++ /* HW expects these in little endian so we reverse the byte order ++ * from network order (big endian) to little endian ++ */ ++ rar_low = ((uint32_t) addr[0] | ++ ((uint32_t) addr[1] << 8) | ++ ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); ++ ++ rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); ++ ++ E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low); ++ E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high); ++ return; ++} ++ ++/****************************************************************************** ++ * Writes a value to the specified offset in the VLAN filter table. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * offset - Offset in VLAN filer table to write ++ * value - Value to write into VLAN filter table ++ *****************************************************************************/ ++void ++e1000_write_vfta(struct e1000_shared_adapter *shared, ++ uint32_t offset, ++ uint32_t value) ++{ ++ uint32_t temp; ++ ++ if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { ++ temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1)); ++ E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); ++ E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp); ++ } else { ++ E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); ++ } ++ return; ++} ++ ++/****************************************************************************** ++ * Clears the VLAN filer table ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_clear_vfta(struct e1000_shared_adapter *shared) ++{ ++ uint32_t offset; ++ ++ for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) ++ E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0); ++ return; ++} ++ ++/****************************************************************************** ++ * Configures flow control and link settings. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Determines which flow control settings to use. Calls the apropriate media- ++ * specific link configuration function. Configures the flow control settings. ++ * Assuming the adapter has a valid link partner, a valid link should be ++ * established. Assumes the hardware has previously been reset and the ++ * transmitter and receiver are not enabled. ++ *****************************************************************************/ ++boolean_t ++e1000_setup_fc_and_link(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ uint32_t eecd_reg; ++ uint32_t ctrl_ext_reg; ++ boolean_t status = TRUE; ++ ++ DEBUGFUNC("e1000_setup_fc_and_link"); ++ ++ /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the ++ * EEPROM. Store these bits in a variable that we will later write ++ * to the Device Control Register (CTRL). ++ */ ++ eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG); ++ ++ ctrl_reg = ++ (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | ++ ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); ++ ++ /* Set the PCI priority bit correctly in the CTRL register. This ++ * determines if the adapter gives priority to receives, or if it ++ * gives equal priority to transmits and receives. ++ */ ++ if(shared->dma_fairness) ++ ctrl_reg |= E1000_CTRL_PRIOR; ++ ++ /* Read and store word 0x0F of the EEPROM. This word contains bits ++ * that determine the hardware's default PAUSE (flow control) mode, ++ * a bit that determines whether the HW defaults to enabling or ++ * disabling auto-negotiation, and the direction of the ++ * SW defined pins. If there is no SW over-ride of the flow ++ * control setting, then the variable shared->fc will ++ * be initialized based on a value in the EEPROM. ++ */ ++ eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG); ++ ++ if(shared->fc > e1000_fc_full) { ++ if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0) ++ shared->fc = e1000_fc_none; ++ else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) ++ shared->fc = e1000_fc_tx_pause; ++ else ++ shared->fc = e1000_fc_full; ++ } ++ ++ /* We want to save off the original Flow Control configuration just ++ * in case we get disconnected and then reconnected into a different ++ * hub or switch with different Flow Control capabilities. ++ */ ++ shared->original_fc = shared->fc; ++ ++ if(shared->mac_type == e1000_82542_rev2_0) ++ shared->fc &= (~e1000_fc_tx_pause); ++ ++ if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1)) ++ shared->fc &= (~e1000_fc_rx_pause); ++ ++ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc); ++ ++ /* Take the 4 bits from EEPROM word 0x0F that determine the initial ++ * polarity value for the SW controlled pins, and setup the ++ * Extended Device Control reg with that info. ++ * This is needed because one of the SW controlled pins is used for ++ * signal detection. So this should be done before e1000_setup_pcs_link() ++ * or e1000_phy_setup() is called. ++ */ ++ if(shared->mac_type == e1000_82543) { ++ ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT) ++ << SWDPIO__EXT_SHIFT); ++ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); ++ } ++ ++ /* Call the necessary subroutine to configure the link. */ ++ if(shared->media_type == e1000_media_type_fiber) ++ status = e1000_setup_pcs_link(shared, ctrl_reg); ++ else ++ status = e1000_phy_setup(shared, ctrl_reg); ++ ++ /* Initialize the flow control address, type, and PAUSE timer ++ * registers to their default values. This is done even if flow ++ * control is disabled, because it does not hurt anything to ++ * initialize these registers. ++ */ ++ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); ++ ++ E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW); ++ E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH); ++ E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE); ++ E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time); ++ ++ /* Set the flow control receive threshold registers. Normally, ++ * these registers will be set to a default threshold that may be ++ * adjusted later by the driver's runtime code. However, if the ++ * ability to transmit pause frames in not enabled, then these ++ * registers will be set to 0. ++ */ ++ if(!(shared->fc & e1000_fc_tx_pause)) { ++ E1000_WRITE_REG(shared, FCRTL, 0); ++ E1000_WRITE_REG(shared, FCRTH, 0); ++ } else { ++ /* We need to set up the Receive Threshold high and low water marks ++ * as well as (optionally) enabling the transmission of XON frames. ++ */ ++ if(shared->fc_send_xon) { ++ E1000_WRITE_REG(shared, FCRTL, ++ (shared->fc_low_water | E1000_FCRTL_XONE)); ++ E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); ++ } else { ++ E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water); ++ E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); ++ } ++ } ++ return (status); ++} ++ ++/****************************************************************************** ++ * Sets up link for a fiber based adapter ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ctrl_reg - Current value of the device control register ++ * ++ * Manipulates Physical Coding Sublayer functions in order to configure ++ * link. Assumes the hardware has been previously reset and the transmitter ++ * and receiver are not enabled. ++ *****************************************************************************/ ++boolean_t ++e1000_setup_pcs_link(struct e1000_shared_adapter *shared, ++ uint32_t ctrl_reg) ++{ ++ uint32_t status_reg; ++ uint32_t tctl_reg; ++ uint32_t txcw_reg = 0; ++ uint32_t i; ++ ++ DEBUGFUNC("e1000_setup_pcs_link"); ++ ++ /* Setup the collsion distance. Since this is configuring the ++ * TBI it is assumed that we are in Full Duplex. ++ */ ++ tctl_reg = E1000_READ_REG(shared, TCTL); ++ i = E1000_FDX_COLLISION_DISTANCE; ++ i <<= E1000_COLD_SHIFT; ++ tctl_reg |= i; ++ E1000_WRITE_REG(shared, TCTL, tctl_reg); ++ ++ /* Check for a software override of the flow control settings, and ++ * setup the device accordingly. If auto-negotiation is enabled, ++ * then software will have to set the "PAUSE" bits to the correct ++ * value in the Tranmsit Config Word Register (TXCW) and re-start ++ * auto-negotiation. However, if auto-negotiation is disabled, ++ * then software will have to manually configure the two flow ++ * control enable bits in the CTRL register. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause frames ++ * but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames ++ * but we do not support receiving pause frames). ++ * 3: Both Rx and TX flow control (symmetric) are enabled. ++ * other: No software override. The flow control configuration ++ * in the EEPROM is used. ++ */ ++ switch (shared->fc) { ++ case e1000_fc_none: /* 0 */ ++ /* Flow control (RX & TX) is completely disabled by a ++ * software over-ride. ++ */ ++ txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD); ++ break; ++ case e1000_fc_rx_pause: /* 1 */ ++ /* RX Flow control is enabled, and TX Flow control is ++ * disabled, by a software over-ride. ++ */ ++ /* Since there really isn't a way to advertise that we are ++ * capable of RX Pause ONLY, we will advertise that we ++ * support both symmetric and asymmetric RX PAUSE. Later ++ * we will disable the adapter's ability to send PAUSE ++ * frames. ++ */ ++ txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); ++ break; ++ case e1000_fc_tx_pause: /* 2 */ ++ /* TX Flow control is enabled, and RX Flow control is ++ * disabled, by a software over-ride. ++ */ ++ txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); ++ break; ++ case e1000_fc_full: /* 3 */ ++ /* Flow control (both RX and TX) is enabled by a software ++ * over-ride. ++ */ ++ txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); ++ break; ++ default: ++ /* We should never get here. The value should be 0-3. */ ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ /* Since auto-negotiation is enabled, take the link out of reset. ++ * (the link will be in reset, because we previously reset the ++ * chip). This will restart auto-negotiation. If auto-neogtiation ++ * is successful then the link-up status bit will be set and the ++ * flow control enable bits (RFCE and TFCE) will be set according ++ * to their negotiated value. ++ */ ++ DEBUGOUT("Auto-negotiation enabled\n"); ++ ++ E1000_WRITE_REG(shared, TXCW, txcw_reg); ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ shared->txcw_reg = txcw_reg; ++ msec_delay(1); ++ ++ /* If we have a signal then poll for a "Link-Up" indication in the ++ * Device Status Register. Time-out if a link isn't seen in 500 ++ * milliseconds seconds (Auto-negotiation should complete in less ++ * than 500 milliseconds even if the other end is doing it in SW). ++ */ ++ if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) { ++ ++ DEBUGOUT("Looking for Link\n"); ++ for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { ++ msec_delay(10); ++ status_reg = E1000_READ_REG(shared, STATUS); ++ if(status_reg & E1000_STATUS_LU) ++ break; ++ } ++ ++ if(i == (LINK_UP_TIMEOUT / 10)) { ++ /* AutoNeg failed to achieve a link, so we'll call the ++ * "CheckForLink" routine. This routine will force the link ++ * up if we have "signal-detect". This will allow us to ++ * communicate with non-autonegotiating link partners. ++ */ ++ DEBUGOUT("Never got a valid link from auto-neg!!!\n"); ++ ++ shared->autoneg_failed = 1; ++ e1000_check_for_link(shared); ++ shared->autoneg_failed = 0; ++ } else { ++ shared->autoneg_failed = 0; ++ DEBUGOUT("Valid Link Found\n"); ++ } ++ } else { ++ DEBUGOUT("No Signal Detected\n"); ++ } ++ ++ return (TRUE); ++} ++ ++/****************************************************************************** ++ * Configures flow control settings after link is established ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Should be called immediately after a valid link has been established. ++ * Forces MAC flow control settings if link was forced. When in MII/GMII mode ++ * and autonegotiation is enabled, the MAC flow control settings will be set ++ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE ++ * and RFCE bits will be automaticaly set to the negotiated flow control mode. ++ *****************************************************************************/ ++void ++e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared) ++{ ++ uint16_t mii_status_reg; ++ uint16_t mii_nway_adv_reg; ++ uint16_t mii_nway_lp_ability_reg; ++ uint16_t speed; ++ uint16_t duplex; ++ ++ DEBUGFUNC("e1000_config_fc_after_link_up"); ++ ++ /* Check for the case where we have fiber media and auto-neg failed ++ * so we had to force link. In this case, we need to force the ++ * configuration of the MAC to match the "fc" parameter. ++ */ ++ if(((shared->media_type == e1000_media_type_fiber) ++ && (shared->autoneg_failed)) ++ || ((shared->media_type == e1000_media_type_copper) ++ && (!shared->autoneg))) { ++ e1000_force_mac_fc(shared); ++ } ++ ++ /* Check for the case where we have copper media and auto-neg is ++ * enabled. In this case, we need to check and see if Auto-Neg ++ * has completed, and if so, how the PHY and link partner has ++ * flow control configured. ++ */ ++ if((shared->media_type == e1000_media_type_copper) && shared->autoneg) { ++ /* Read the MII Status Register and check to see if AutoNeg ++ * has completed. We read this twice because this reg has ++ * some "sticky" (latched) bits. ++ */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { ++ /* The AutoNeg process has completed, so we now need to ++ * read both the Auto Negotiation Advertisement Register ++ * (Address 4) and the Auto_Negotiation Base Page Ability ++ * Register (Address 5) to determine how flow control was ++ * negotiated. ++ */ ++ mii_nway_adv_reg = e1000_read_phy_reg(shared, ++ PHY_AUTONEG_ADV); ++ mii_nway_lp_ability_reg = e1000_read_phy_reg(shared, ++ PHY_LP_ABILITY); ++ ++ /* Two bits in the Auto Negotiation Advertisement Register ++ * (Address 4) and two bits in the Auto Negotiation Base ++ * Page Ability Register (Address 5) determine flow control ++ * for both the PHY and the link partner. The following ++ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, ++ * 1999, describes these PAUSE resolution bits and how flow ++ * control is determined based upon these settings. ++ * NOTE: DC = Don't Care ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution ++ *-------|---------|-------|---------|-------------------- ++ * 0 | 0 | DC | DC | e1000_fc_none ++ * 0 | 1 | 0 | DC | e1000_fc_none ++ * 0 | 1 | 1 | 0 | e1000_fc_none ++ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause ++ * 1 | 0 | 0 | DC | e1000_fc_none ++ * 1 | DC | 1 | DC | e1000_fc_full ++ * 1 | 1 | 0 | 0 | e1000_fc_none ++ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause ++ * ++ */ ++ /* Are both PAUSE bits set to 1? If so, this implies ++ * Symmetric Flow Control is enabled at both ends. The ++ * ASM_DIR bits are irrelevant per the spec. ++ * ++ * For Symmetric Flow Control: ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 1 | DC | 1 | DC | e1000_fc_full ++ * ++ */ ++ if((mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { ++ /* Now we need to check if the user selected RX ONLY ++ * of pause frames. In this case, we had to advertise ++ * FULL flow control because we could not advertise RX ++ * ONLY. Hence, we must now check to see if we need to ++ * turn OFF the TRANSMISSION of PAUSE frames. ++ */ ++ if(shared->original_fc == e1000_fc_full) { ++ shared->fc = e1000_fc_full; ++ DEBUGOUT("Flow Control = FULL.\r\n"); ++ } else { ++ shared->fc = e1000_fc_rx_pause; ++ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); ++ } ++ } ++ /* For receiving PAUSE frames ONLY. ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause ++ * ++ */ ++ else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { ++ shared->fc = e1000_fc_tx_pause; ++ DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); ++ } ++ /* For transmitting PAUSE frames ONLY. ++ * ++ * LOCAL DEVICE | LINK PARTNER ++ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result ++ *-------|---------|-------|---------|-------------------- ++ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause ++ * ++ */ ++ else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && ++ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && ++ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && ++ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { ++ shared->fc = e1000_fc_rx_pause; ++ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); ++ } ++ /* Per the IEEE spec, at this point flow control should be ++ * disabled. However, we want to consider that we could ++ * be connected to a legacy switch that doesn't advertise ++ * desired flow control, but can be forced on the link ++ * partner. So if we advertised no flow control, that is ++ * what we will resolve to. If we advertised some kind of ++ * receive capability (Rx Pause Only or Full Flow Control) ++ * and the link partner advertised none, we will configure ++ * ourselves to enable Rx Flow Control only. We can do ++ * this safely for two reasons: If the link partner really ++ * didn't want flow control enabled, and we enable Rx, no ++ * harm done since we won't be receiving any PAUSE frames ++ * anyway. If the intent on the link partner was to have ++ * flow control enabled, then by us enabling RX only, we ++ * can at least receive pause frames and process them. ++ * This is a good idea because in most cases, since we are ++ * predominantly a server NIC, more times than not we will ++ * be asked to delay transmission of packets than asking ++ * our link partner to pause transmission of frames. ++ */ ++ else if(shared->original_fc == e1000_fc_none || ++ shared->original_fc == e1000_fc_tx_pause) { ++ shared->fc = e1000_fc_none; ++ DEBUGOUT("Flow Control = NONE.\r\n"); ++ } else { ++ shared->fc = e1000_fc_rx_pause; ++ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); ++ } ++ ++ /* Now we need to do one last check... If we auto- ++ * negotiated to HALF DUPLEX, flow control should not be ++ * enabled per IEEE 802.3 spec. ++ */ ++ e1000_get_speed_and_duplex(shared, &speed, &duplex); ++ ++ if(duplex == HALF_DUPLEX) ++ shared->fc = e1000_fc_none; ++ ++ /* Now we call a subroutine to actually force the MAC ++ * controller to use the correct flow control settings. ++ */ ++ e1000_force_mac_fc(shared); ++ } else { ++ DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); ++ } ++ } ++ return; ++} ++ ++/****************************************************************************** ++ * Checks to see if the link status of the hardware has changed. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Called by any function that needs to check the link status of the adapter. ++ *****************************************************************************/ ++void ++e1000_check_for_link(struct e1000_shared_adapter *shared) ++{ ++ uint32_t rxcw_reg; ++ uint32_t ctrl_reg; ++ uint32_t status_reg; ++ uint32_t rctl_reg; ++ uint16_t phy_data; ++ uint16_t lp_capability; ++ ++ DEBUGFUNC("e1000_check_for_link"); ++ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ status_reg = E1000_READ_REG(shared, STATUS); ++ rxcw_reg = E1000_READ_REG(shared, RXCW); ++ ++ /* If we have a copper PHY then we only want to go out to the PHY ++ * registers to see if Auto-Neg has completed and/or if our link ++ * status has changed. The get_link_status flag will be set if we ++ * receive a Link Status Change interrupt or we have Rx Sequence ++ * Errors. ++ */ ++ if(shared->media_type == e1000_media_type_copper ++ && shared->get_link_status) { ++ /* First we want to see if the MII Status Register reports ++ * link. If so, then we want to get the current speed/duplex ++ * of the PHY. ++ * Read the register twice since the link bit is sticky. ++ */ ++ phy_data = e1000_read_phy_reg(shared, PHY_STATUS); ++ phy_data = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ if(phy_data & MII_SR_LINK_STATUS) { ++ shared->get_link_status = FALSE; ++ } else { ++ DEBUGOUT("**** CFL - No link detected. ****\r\n"); ++ return; ++ } ++ ++ /* If we are forcing speed/duplex, then we simply return since ++ * we have already determined whether we have link or not. ++ */ ++ if(!shared->autoneg) { ++ return; ++ } ++ ++ switch (shared->phy_id) { ++ case M88E1000_12_PHY_ID: ++ case M88E1000_14_PHY_ID: ++ case M88E1000_I_PHY_ID: ++ case M88E1011_I_PHY_ID: ++ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we ++ * have Si on board that is 82544 or newer, Auto ++ * Speed Detection takes care of MAC speed/duplex ++ * configuration. So we only need to configure Collision ++ * Distance in the MAC. Otherwise, we need to force ++ * speed/duplex on the MAC to the current PHY speed/duplex ++ * settings. ++ */ ++ if(shared->mac_type >= e1000_82544) { ++ DEBUGOUT("CFL - Auto-Neg complete."); ++ DEBUGOUT("Configuring Collision Distance."); ++ e1000_config_collision_dist(shared); ++ } else { ++ /* Read the Phy Specific Status register to get the ++ * resolved speed/duplex settings. Then call ++ * e1000_config_mac_to_phy which will retrieve ++ * PHY register information and configure the MAC to ++ * equal the negotiated speed/duplex. ++ */ ++ phy_data = e1000_read_phy_reg(shared, ++ M88E1000_PHY_SPEC_STATUS); ++ ++ DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n", ++ phy_data); ++ e1000_config_mac_to_phy(shared, phy_data); ++ } ++ ++ /* Configure Flow Control now that Auto-Neg has completed. ++ * We need to first restore the users desired Flow ++ * Control setting since we may have had to re-autoneg ++ * with a different link partner. ++ */ ++ e1000_config_fc_after_link_up(shared); ++ break; ++ ++ default: ++ DEBUGOUT("CFL - Invalid PHY detected.\r\n"); ++ ++ } /* end switch statement */ ++ ++ /* At this point we know that we are on copper, link is up, ++ * and we are auto-neg'd. These are pre-conditions for checking ++ * the link parter capabilities register. We use the link partner ++ * capabilities to determine if TBI Compatibility needs to be turned on ++ * or turned off. If the link partner advertises any speed in addition ++ * to Gigabit, then we assume that they are GMII-based and TBI ++ * compatibility is not needed. ++ * If no other speeds are advertised, then we assume the link partner ++ * is TBI-based and we turn on TBI Compatibility. ++ */ ++ if(shared->tbi_compatibility_en) { ++ lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY); ++ if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | ++ NWAY_LPAR_10T_FD_CAPS | ++ NWAY_LPAR_100TX_HD_CAPS | ++ NWAY_LPAR_100TX_FD_CAPS | ++ NWAY_LPAR_100T4_CAPS)) { ++ /* If our link partner advertises below Gig, then they do not ++ * need the special Tbi Compatibility mode. ++ */ ++ if(shared->tbi_compatibility_on) { ++ /* If we previously were in the mode, turn it off, now. */ ++ rctl_reg = E1000_READ_REG(shared, RCTL); ++ rctl_reg &= ~E1000_RCTL_SBP; ++ E1000_WRITE_REG(shared, RCTL, rctl_reg); ++ shared->tbi_compatibility_on = FALSE; ++ } ++ } else { ++ /* If the mode is was previously off, turn it on. ++ * For compatibility with a suspected Tbi link partners, ++ * we will store bad packets. ++ * (Certain frames have an additional byte on the end and will ++ * look like CRC errors to to the hardware). ++ */ ++ if(!shared->tbi_compatibility_on) { ++ shared->tbi_compatibility_on = TRUE; ++ rctl_reg = E1000_READ_REG(shared, RCTL); ++ rctl_reg |= E1000_RCTL_SBP; ++ E1000_WRITE_REG(shared, RCTL, rctl_reg); ++ } ++ } ++ } ++ } /* end if e1000_media_type_copper statement */ ++ /* If we don't have link (auto-negotiation failed or link partner ++ * cannot auto-negotiate) and the cable is plugged in since we don't ++ * have Loss-Of-Signal (we HAVE a signal) and our link partner is ++ * not trying to AutoNeg with us (we are receiving idles/data ++ * then we need to force our link to connect to a non ++ * auto-negotiating link partner. We also need to give ++ * auto-negotiation time to complete in case the cable was just ++ * plugged in. The autoneg_failed flag does this. ++ */ ++ else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */ ++ (!(status_reg & E1000_STATUS_LU)) && /* no link and */ ++ (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */ ++ (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */ ++ if(shared->autoneg_failed == 0) { /* given AutoNeg time */ ++ shared->autoneg_failed = 1; ++ return; ++ } ++ ++ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); ++ ++ /* Disable auto-negotiation in the TXCW register */ ++ E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE)); ++ ++ /* Force link-up and also force full-duplex. */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD); ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ /* Configure Flow Control after forcing link up. */ ++ e1000_config_fc_after_link_up(shared); ++ ++ } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */ ++ (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */ ++ (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */ ++ /* If we are forcing link and we are receiving /C/ ordered sets, ++ * then re-enable auto-negotiation in the RXCW register and ++ * disable forced link in the Device Control register in an attempt ++ * to AutoNeg with our link partner. ++ */ ++ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); ++ ++ /* Enable auto-negotiation in the TXCW register and stop ++ * forcing link. ++ */ ++ E1000_WRITE_REG(shared, TXCW, shared->txcw_reg); ++ ++ E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU)); ++ } ++ ++ return; ++} ++ ++/****************************************************************************** ++ * Clears all hardware statistics counters. ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared) ++{ ++ volatile uint32_t temp_reg; ++ ++ DEBUGFUNC("e1000_clear_hw_cntrs"); ++ ++ /* if we are stopped or resetting exit gracefully */ ++ if(shared->adapter_stopped) { ++ DEBUGOUT("Exiting because the adapter is stopped!!!\n"); ++ return; ++ } ++ ++ temp_reg = E1000_READ_REG(shared, CRCERRS); ++ temp_reg = E1000_READ_REG(shared, SYMERRS); ++ temp_reg = E1000_READ_REG(shared, MPC); ++ temp_reg = E1000_READ_REG(shared, SCC); ++ temp_reg = E1000_READ_REG(shared, ECOL); ++ temp_reg = E1000_READ_REG(shared, MCC); ++ temp_reg = E1000_READ_REG(shared, LATECOL); ++ temp_reg = E1000_READ_REG(shared, COLC); ++ temp_reg = E1000_READ_REG(shared, DC); ++ temp_reg = E1000_READ_REG(shared, SEC); ++ temp_reg = E1000_READ_REG(shared, RLEC); ++ temp_reg = E1000_READ_REG(shared, XONRXC); ++ temp_reg = E1000_READ_REG(shared, XONTXC); ++ temp_reg = E1000_READ_REG(shared, XOFFRXC); ++ temp_reg = E1000_READ_REG(shared, XOFFTXC); ++ temp_reg = E1000_READ_REG(shared, FCRUC); ++ temp_reg = E1000_READ_REG(shared, PRC64); ++ temp_reg = E1000_READ_REG(shared, PRC127); ++ temp_reg = E1000_READ_REG(shared, PRC255); ++ temp_reg = E1000_READ_REG(shared, PRC511); ++ temp_reg = E1000_READ_REG(shared, PRC1023); ++ temp_reg = E1000_READ_REG(shared, PRC1522); ++ temp_reg = E1000_READ_REG(shared, GPRC); ++ temp_reg = E1000_READ_REG(shared, BPRC); ++ temp_reg = E1000_READ_REG(shared, MPRC); ++ temp_reg = E1000_READ_REG(shared, GPTC); ++ temp_reg = E1000_READ_REG(shared, GORCL); ++ temp_reg = E1000_READ_REG(shared, GORCH); ++ temp_reg = E1000_READ_REG(shared, GOTCL); ++ temp_reg = E1000_READ_REG(shared, GOTCH); ++ temp_reg = E1000_READ_REG(shared, RNBC); ++ temp_reg = E1000_READ_REG(shared, RUC); ++ temp_reg = E1000_READ_REG(shared, RFC); ++ temp_reg = E1000_READ_REG(shared, ROC); ++ temp_reg = E1000_READ_REG(shared, RJC); ++ temp_reg = E1000_READ_REG(shared, TORL); ++ temp_reg = E1000_READ_REG(shared, TORH); ++ temp_reg = E1000_READ_REG(shared, TOTL); ++ temp_reg = E1000_READ_REG(shared, TOTH); ++ temp_reg = E1000_READ_REG(shared, TPR); ++ temp_reg = E1000_READ_REG(shared, TPT); ++ temp_reg = E1000_READ_REG(shared, PTC64); ++ temp_reg = E1000_READ_REG(shared, PTC127); ++ temp_reg = E1000_READ_REG(shared, PTC255); ++ temp_reg = E1000_READ_REG(shared, PTC511); ++ temp_reg = E1000_READ_REG(shared, PTC1023); ++ temp_reg = E1000_READ_REG(shared, PTC1522); ++ temp_reg = E1000_READ_REG(shared, MPTC); ++ temp_reg = E1000_READ_REG(shared, BPTC); ++ ++ if(shared->mac_type < e1000_82543) ++ return; ++ ++ temp_reg = E1000_READ_REG(shared, ALGNERRC); ++ temp_reg = E1000_READ_REG(shared, RXERRC); ++ temp_reg = E1000_READ_REG(shared, TNCRS); ++ temp_reg = E1000_READ_REG(shared, CEXTERR); ++ temp_reg = E1000_READ_REG(shared, TSCTC); ++ temp_reg = E1000_READ_REG(shared, TSCTFC); ++ return; ++} ++ ++/****************************************************************************** ++ * Detects the current speed and duplex settings of the hardware. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * speed - Speed of the connection ++ * duplex - Duplex setting of the connection ++ *****************************************************************************/ ++void ++e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, ++ uint16_t *speed, ++ uint16_t *duplex) ++{ ++ uint32_t status_reg; ++#if DBG ++ uint16_t phy_data; ++#endif ++ ++ DEBUGFUNC("e1000_get_speed_and_duplex"); ++ ++ /* If the adapter is stopped we don't have a speed or duplex */ ++ if(shared->adapter_stopped) { ++ *speed = 0; ++ *duplex = 0; ++ return; ++ } ++ ++ if(shared->mac_type >= e1000_82543) { ++ status_reg = E1000_READ_REG(shared, STATUS); ++ if(status_reg & E1000_STATUS_SPEED_1000) { ++ *speed = SPEED_1000; ++ DEBUGOUT("1000 Mbs, "); ++ } else if(status_reg & E1000_STATUS_SPEED_100) { ++ *speed = SPEED_100; ++ DEBUGOUT("100 Mbs, "); ++ } else { ++ *speed = SPEED_10; ++ DEBUGOUT("10 Mbs, "); ++ } ++ ++ if(status_reg & E1000_STATUS_FD) { ++ *duplex = FULL_DUPLEX; ++ DEBUGOUT("Full Duplex\r\n"); ++ } else { ++ *duplex = HALF_DUPLEX; ++ DEBUGOUT(" Half Duplex\r\n"); ++ } ++ } else { ++ DEBUGOUT("1000 Mbs, Full Duplex\r\n"); ++ *speed = SPEED_1000; ++ *duplex = FULL_DUPLEX; ++ } ++ ++#if DBG ++ if(shared->phy_id == M88E1000_12_PHY_ID || ++ shared->phy_id == M88E1000_14_PHY_ID || ++ shared->phy_id == M88E1000_I_PHY_ID || ++ shared->phy_id == M88E1011_I_PHY_ID) { ++ /* read the phy specific status register */ ++ phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); ++ DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data); ++ phy_data = e1000_read_phy_reg(shared, PHY_STATUS); ++ DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data); ++ DEBUGOUT1("Device Status Reg contents = %x\n", ++ E1000_READ_REG(shared, STATUS)); ++ } ++#endif ++ return; ++} ++ ++/****************************************************************************** ++ * Reads a 16 bit word from the EEPROM. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * offset - offset of 16 bit word in the EEPROM to read ++ *****************************************************************************/ ++uint16_t ++e1000_read_eeprom(struct e1000_shared_adapter *shared, ++ uint16_t offset) ++{ ++ boolean_t large_eeprom = FALSE; ++ uint16_t data; ++ uint32_t eecd_reg; ++ uint32_t tmp = 0; ++ ++ if((shared->mac_type > e1000_82544) && ++ (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE; ++ ++ /* Request EEPROM Access */ ++ if(shared->mac_type > e1000_82544) { ++ E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ); ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) { ++ tmp++; ++ usec_delay(5); ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ } ++ if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE); ++ } ++ ++ /* Prepare the EEPROM for reading */ ++ e1000_setup_eeprom(shared); ++ ++ /* Send the READ command (opcode + addr) */ ++ e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3); ++ /* If we have a 256 word EEPROM, there are 8 address bits ++ * if we have a 64 word EEPROM, there are 6 address bits ++ */ ++ if(large_eeprom) ++ e1000_shift_out_bits(shared, offset, 8); ++ else ++ e1000_shift_out_bits(shared, offset, 6); ++ ++ /* Read the data */ ++ data = e1000_shift_in_bits(shared); ++ ++ /* End this read operation */ ++ e1000_standby_eeprom(shared); ++ ++ /* Stop requestiong EEPROM access */ ++ if(shared->mac_type > e1000_82544) ++ E1000_WRITE_REG(shared, EECD, (uint32_t) 0); ++ ++ return (data); ++} ++ ++/****************************************************************************** ++ * Verifies that the EEPROM has a valid checksum ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Reads the first 64 16 bit words of the EEPROM and sums the values read. ++ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is ++ * valid. ++ *****************************************************************************/ ++boolean_t ++e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared) ++{ ++ uint16_t checksum = 0; ++ uint16_t i; ++ ++ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) ++ checksum += e1000_read_eeprom(shared, i); ++ ++ if(checksum == (uint16_t) EEPROM_SUM) ++ return (TRUE); ++ else ++ return (FALSE); ++} ++ ++/****************************************************************************** ++ * Calculates the EEPROM checksum and writes it to the EEPROM ++ * ++ * shared - Struct containing variables accessed by shared code ++ * ++ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA. ++ * Writes the difference to word offset 63 of the EEPROM. ++ *****************************************************************************/ ++void ++e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared) ++{ ++ uint16_t checksum = 0; ++ uint16_t i; ++ ++ for(i = 0; i < EEPROM_CHECKSUM_REG; i++) ++ checksum += e1000_read_eeprom(shared, i); ++ ++ checksum = (uint16_t) EEPROM_SUM - checksum; ++ ++ e1000_write_eeprom(shared, EEPROM_CHECKSUM_REG, checksum); ++ return; ++} ++ ++/****************************************************************************** ++ * Writes a 16 bit word to a given offset in the EEPROM. ++ * ++ * shared - Struct containing variables accessed by shared code ++ * offset - offset within the EEPROM to be written to ++ * data - 16 bit word to be writen to the EEPROM ++ * ++ * If e1000_update_eeprom_checksum is not called after this function, the ++ * EEPROM will most likely contain an invalid checksum. ++ *****************************************************************************/ ++boolean_t ++e1000_write_eeprom(struct e1000_shared_adapter *shared, ++ uint16_t offset, ++ uint16_t data) ++{ ++ boolean_t large_eeprom = FALSE; ++ uint32_t eecd_reg; ++ uint32_t tmp = 0; ++ ++ if((shared->mac_type > e1000_82544) && ++ (E1000_READ_REG(shared, EECD) & E1000_EECD_SIZE)) large_eeprom = TRUE; ++ ++ /* Request EEPROM Access */ ++ if(shared->mac_type > e1000_82544) { ++ E1000_WRITE_REG(shared, EECD, (uint32_t) E1000_EECD_REQ); ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ while((!(eecd_reg & E1000_EECD_GNT)) && (tmp < 100)) { ++ tmp++; ++ usec_delay(5); ++ eecd_reg = E1000_READ_REG(shared, EECD); ++ } ++ if(!(eecd_reg & E1000_EECD_GNT)) return(FALSE); ++ } ++ ++ /* Prepare the EEPROM for writing */ ++ e1000_setup_eeprom(shared); ++ ++ /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) ++ * command to the EEPROM (5-bit opcode plus 4/6-bit dummy). ++ * This puts the EEPROM into write/erase mode. ++ */ ++ e1000_shift_out_bits(shared, EEPROM_EWEN_OPCODE, 5); ++ if(large_eeprom) ++ e1000_shift_out_bits(shared, 0, 6); ++ else ++ e1000_shift_out_bits(shared, 0, 4); ++ ++ /* Prepare the EEPROM */ ++ e1000_standby_eeprom(shared); ++ ++ /* Send the Write command (3-bit opcode + addr) */ ++ e1000_shift_out_bits(shared, EEPROM_WRITE_OPCODE, 3); ++ /* If we have a 256 word EEPROM, there are 8 address bits ++ * if we have a 64 word EEPROM, there are 6 address bits ++ */ ++ if(large_eeprom) ++ e1000_shift_out_bits(shared, offset, 8); ++ else ++ e1000_shift_out_bits(shared, offset, 6); ++ ++ /* Send the data */ ++ e1000_shift_out_bits(shared, data, 16); ++ e1000_wait_eeprom_command(shared); ++ ++ /* Recover from write */ ++ e1000_standby_eeprom(shared); ++ ++ /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) ++ * command to the EEPROM (5-bit opcode plus 4/6-bit dummy). ++ * This takes the EEPROM out of write/erase mode. ++ */ ++ e1000_shift_out_bits(shared, EEPROM_EWDS_OPCODE, 5); ++ if(large_eeprom) ++ e1000_shift_out_bits(shared, 0, 6); ++ else ++ e1000_shift_out_bits(shared, 0, 4); ++ ++ /* Done with writing */ ++ e1000_cleanup_eeprom(shared); ++ ++ /* Stop requestiong EEPROM access */ ++ if(shared->mac_type > e1000_82544) ++ E1000_WRITE_REG(shared, EECD, (uint32_t) 0); ++ ++ return (TRUE); ++} ++ ++/****************************************************************************** ++ * Reads the adapter's part number from the EEPROM ++ * ++ * shared - Struct containing variables accessed by shared code ++ * part_num - Adapter's part number ++ *****************************************************************************/ ++boolean_t ++e1000_read_part_num(struct e1000_shared_adapter *shared, ++ uint32_t *part_num) ++{ ++ uint16_t eeprom_word; ++ ++ DEBUGFUNC("e1000_read_part_num"); ++ ++ /* Don't read the EEPROM if we are stopped */ ++ if(shared->adapter_stopped) { ++ *part_num = 0; ++ return (FALSE); ++ } ++ ++ /* Get word 0 from EEPROM */ ++ eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1)); ++ ++ DEBUGOUT("Read first part number word\n"); ++ ++ /* Save word 0 in upper half is PartNumber */ ++ *part_num = (uint32_t) eeprom_word; ++ *part_num = *part_num << 16; ++ ++ /* Get word 1 from EEPROM */ ++ eeprom_word = ++ e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1)); ++ ++ DEBUGOUT("Read second part number word\n"); ++ ++ /* Save word 1 in lower half of PartNumber */ ++ *part_num |= eeprom_word; ++ ++ /* read a valid part number */ ++ return (TRUE); ++} ++ ++/****************************************************************************** ++ * Turns on the software controllable LED ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_led_on(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ ++ /* if we're stopped don't touch the hardware */ ++ if(shared->adapter_stopped) ++ return; ++ ++ /* Read the content of the device control reg */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Set the LED control pin to an output */ ++ ctrl_reg |= E1000_CTRL_SWDPIO0; ++ ++ /* Drive it high on normal boards, low on low profile boards */ ++ if(shared->low_profile) ++ ctrl_reg &= ~E1000_CTRL_SWDPIN0; ++ else ++ ctrl_reg |= E1000_CTRL_SWDPIN0; ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ return; ++} ++ ++/****************************************************************************** ++ * Turns off the software controllable LED ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_led_off(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ ++ /* if we're stopped don't touch the hardware */ ++ if(shared->adapter_stopped) ++ return; ++ ++ /* Read the content of the device control reg */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Set the LED control pin to an output */ ++ ctrl_reg |= E1000_CTRL_SWDPIO0; ++ ++ /* Drive it low on normal boards, high on low profile boards */ ++ if(shared->low_profile) ++ ctrl_reg |= E1000_CTRL_SWDPIN0; ++ else ++ ctrl_reg &= ~E1000_CTRL_SWDPIN0; ++ ++ /* Write the device control reg. back */ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ return; ++} ++ ++/****************************************************************************** ++ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT ++ * ++ * shared - Struct containing variables accessed by shared code ++ * frame_len - The length of the frame in question ++ * mac_addr - The Ethernet destination address of the frame in question ++ *****************************************************************************/ ++uint32_t ++e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, ++ struct e1000_shared_stats *stats, ++ uint32_t frame_len, ++ uint8_t *mac_addr) ++{ ++ uint64_t carry_bit; ++ ++ /* First adjust the frame length. */ ++ frame_len--; ++ /* We need to adjust the statistics counters, since the hardware ++ * counters overcount this packet as a CRC error and undercount ++ * the packet as a good packet ++ */ ++ /* This packet should not be counted as a CRC error. */ ++ stats->crcerrs--; ++ /* This packet does count as a Good Packet Received. */ ++ stats->gprc++; ++ ++ /* Adjust the Good Octets received counters */ ++ carry_bit = 0x80000000 & stats->gorcl; ++ stats->gorcl += frame_len; ++ /* If the high bit of Gorcl (the low 32 bits of the Good Octets ++ * Received Count) was one before the addition, ++ * AND it is zero after, then we lost the carry out, ++ * need to add one to Gorch (Good Octets Received Count High). ++ * This could be simplified if all environments supported ++ * 64-bit integers. ++ */ ++ if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) ++ stats->gorch++; ++ /* Is this a broadcast or multicast? Check broadcast first, ++ * since the test for a multicast frame will test positive on ++ * a broadcast frame. ++ */ ++ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) ++ /* Broadcast packet */ ++ stats->bprc++; ++ else if(*mac_addr & 0x01) ++ /* Multicast packet */ ++ stats->mprc++; ++ ++ if(frame_len == shared->max_frame_size) { ++ /* In this case, the hardware has overcounted the number of ++ * oversize frames. ++ */ ++ if(stats->roc > 0) ++ stats->roc--; ++ } ++ ++ /* Adjust the bin counters when the extra byte put the frame in the ++ * wrong bin. Remember that the frame_len was adjusted above. ++ */ ++ if(frame_len == 64) { ++ stats->prc64++; ++ stats->prc127--; ++ } else if(frame_len == 127) { ++ stats->prc127++; ++ stats->prc255--; ++ } else if(frame_len == 255) { ++ stats->prc255++; ++ stats->prc511--; ++ } else if(frame_len == 511) { ++ stats->prc511++; ++ stats->prc1023--; ++ } else if(frame_len == 1023) { ++ stats->prc1023++; ++ stats->prc1522--; ++ } else if(frame_len == 1522) { ++ stats->prc1522++; ++ } ++ return frame_len; ++} ++ ++/****************************************************************************** ++ * Gets the current PCI bus type, speed, and width of the hardware ++ * ++ * shared - Struct containing variables accessed by shared code ++ *****************************************************************************/ ++void ++e1000_get_bus_info(struct e1000_shared_adapter *shared) ++{ ++ uint32_t status_reg; ++ ++ if(shared->mac_type < e1000_82543) { ++ shared->bus_type = e1000_bus_type_unknown; ++ shared->bus_speed = e1000_bus_speed_unknown; ++ shared->bus_width = e1000_bus_width_unknown; ++ return; ++ } ++ ++ status_reg = E1000_READ_REG(shared, STATUS); ++ ++ shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ? ++ e1000_bus_type_pcix : e1000_bus_type_pci; ++ ++ if(shared->bus_type == e1000_bus_type_pci) { ++ shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ? ++ e1000_bus_speed_66 : e1000_bus_speed_33; ++ } else { ++ switch (status_reg & E1000_STATUS_PCIX_SPEED) { ++ case E1000_STATUS_PCIX_SPEED_66: ++ shared->bus_speed = e1000_bus_speed_66; ++ break; ++ case E1000_STATUS_PCIX_SPEED_100: ++ shared->bus_speed = e1000_bus_speed_100; ++ break; ++ case E1000_STATUS_PCIX_SPEED_133: ++ shared->bus_speed = e1000_bus_speed_133; ++ break; ++ default: ++ shared->bus_speed = e1000_bus_speed_reserved; ++ break; ++ } ++ } ++ ++ shared->bus_width = (status_reg & E1000_STATUS_BUS64) ? ++ e1000_bus_width_64 : e1000_bus_width_32; ++ ++ return; ++} +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_mac.h 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,1381 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/* e1000_mac.h ++ * Structures, enums, and macros for the MAC ++ */ ++ ++#ifndef _E1000_MAC_H_ ++#define _E1000_MAC_H_ ++ ++#include "e1000_osdep.h" ++ ++/* Forward declarations of structures used by the shared code */ ++struct e1000_shared_adapter; ++struct e1000_shared_stats; ++ ++/* Enumerated types specific to the e1000 hardware */ ++/* Media Access Controlers */ ++typedef enum { ++ e1000_82542_rev2_0 = 0, ++ e1000_82542_rev2_1, ++ e1000_82543, ++ e1000_82544, ++ e1000_82540, ++ e1000_num_macs ++} e1000_mac_type; ++ ++/* Media Types */ ++typedef enum { ++ e1000_media_type_copper = 0, ++ e1000_media_type_fiber = 1, ++ e1000_num_media_types ++} e1000_media_type; ++ ++typedef enum { ++ e1000_10_half = 0, ++ e1000_10_full = 1, ++ e1000_100_half = 2, ++ e1000_100_full = 3 ++} e1000_speed_duplex_type; ++ ++/* Flow Control Settings */ ++typedef enum { ++ e1000_fc_none = 0, ++ e1000_fc_rx_pause = 1, ++ e1000_fc_tx_pause = 2, ++ e1000_fc_full = 3, ++ e1000_fc_default = 0xFF ++} e1000_fc_type; ++ ++/* PCI bus types */ ++typedef enum { ++ e1000_bus_type_unknown = 0, ++ e1000_bus_type_pci, ++ e1000_bus_type_pcix ++} e1000_bus_type; ++ ++/* PCI bus speeds */ ++typedef enum { ++ e1000_bus_speed_unknown = 0, ++ e1000_bus_speed_33, ++ e1000_bus_speed_66, ++ e1000_bus_speed_100, ++ e1000_bus_speed_133, ++ e1000_bus_speed_reserved ++} e1000_bus_speed; ++ ++/* PCI bus widths */ ++typedef enum { ++ e1000_bus_width_unknown = 0, ++ e1000_bus_width_32, ++ e1000_bus_width_64 ++} e1000_bus_width; ++ ++ ++ ++/* Function prototypes */ ++/* Setup */ ++void e1000_adapter_stop(struct e1000_shared_adapter *shared); ++boolean_t e1000_init_hw(struct e1000_shared_adapter *shared); ++void e1000_init_rx_addrs(struct e1000_shared_adapter *shared); ++ ++/* Filters (multicast, vlan, receive) */ ++void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); ++uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr); ++void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value); ++void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index); ++void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value); ++void e1000_clear_vfta(struct e1000_shared_adapter *shared); ++ ++/* Link layer setup functions */ ++boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared); ++boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg); ++void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared); ++void e1000_check_for_link(struct e1000_shared_adapter *shared); ++void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex); ++ ++/* EEPROM Functions */ ++uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg); ++boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared); ++void e1000_update_eeprom_checksum(struct e1000_shared_adapter *shared); ++boolean_t e1000_write_eeprom(struct e1000_shared_adapter *shared, uint16_t reg, uint16_t data); ++ ++/* Everything else */ ++void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared); ++boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num); ++void e1000_led_on(struct e1000_shared_adapter *shared); ++void e1000_led_off(struct e1000_shared_adapter *shared); ++void e1000_get_bus_info(struct e1000_shared_adapter *shared); ++uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr); ++void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value); ++ ++/* PCI Device IDs */ ++#define E1000_DEV_ID_82542 0x1000 ++#define E1000_DEV_ID_82543GC_FIBER 0x1001 ++#define E1000_DEV_ID_82543GC_COPPER 0x1004 ++#define E1000_DEV_ID_82544EI_COPPER 0x1008 ++#define E1000_DEV_ID_82544EI_FIBER 0x1009 ++#define E1000_DEV_ID_82544GC_COPPER 0x100C ++#define E1000_DEV_ID_82544GC_LOM 0x100D ++#define E1000_DEV_ID_82540EM 0x100E ++#define NUM_DEV_IDS 8 ++ ++#define NODE_ADDRESS_SIZE 6 ++#define ETH_LENGTH_OF_ADDRESS 6 ++ ++/* MAC decode size is 128K - This is the size of BAR0 */ ++#define MAC_DECODE_SIZE (128 * 1024) ++ ++#define E1000_82542_2_0_REV_ID 2 ++#define E1000_82542_2_1_REV_ID 3 ++ ++#define SPEED_10 10 ++#define SPEED_100 100 ++#define SPEED_1000 1000 ++#define HALF_DUPLEX 1 ++#define FULL_DUPLEX 2 ++ ++/* The sizes (in bytes) of a ethernet packet */ ++#define ENET_HEADER_SIZE 14 ++#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */ ++#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */ ++#define CRC_LENGTH 4 ++#define MAX_JUMBO_FRAME_SIZE 0x3F00 ++ ++ ++/* 802.1q VLAN Packet Sizes */ ++#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ ++ ++/* Ethertype field values */ ++#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ ++#define ETHERNET_IP_TYPE 0x0800 /* IP packets */ ++#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */ ++ ++/* Packet Header defines */ ++#define IP_PROTOCOL_TCP 6 ++#define IP_PROTOCOL_UDP 0x11 ++ ++/* This defines the bits that are set in the Interrupt Mask ++ * Set/Read Register. Each bit is documented below: ++ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) ++ * o RXSEQ = Receive Sequence Error ++ */ ++#define POLL_IMS_ENABLE_MASK ( \ ++ E1000_IMS_RXDMT0 | \ ++ E1000_IMS_RXSEQ) ++ ++/* This defines the bits that are set in the Interrupt Mask ++ * Set/Read Register. Each bit is documented below: ++ * o RXT0 = Receiver Timer Interrupt (ring 0) ++ * o TXDW = Transmit Descriptor Written Back ++ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) ++ * o RXSEQ = Receive Sequence Error ++ * o LSC = Link Status Change ++ */ ++#define IMS_ENABLE_MASK ( \ ++ E1000_IMS_RXT0 | \ ++ E1000_IMS_TXDW | \ ++ E1000_IMS_RXDMT0 | \ ++ E1000_IMS_RXSEQ | \ ++ E1000_IMS_LSC) ++ ++/* The number of high/low register pairs in the RAR. The RAR (Receive Address ++ * Registers) holds the directed and multicast addresses that we monitor. We ++ * reserve one of these spots for our directed address, allowing us room for ++ * E1000_RAR_ENTRIES - 1 multicast addresses. ++ */ ++#define E1000_RAR_ENTRIES 16 ++ ++#define MIN_NUMBER_OF_DESCRIPTORS 8 ++#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 ++ ++/* Receive Descriptor */ ++struct e1000_rx_desc { ++ uint64_t buffer_addr; /* Address of the descriptor's data buffer */ ++ uint16_t length; /* Length of data DMAed into data buffer */ ++ uint16_t csum; /* Packet checksum */ ++ uint8_t status; /* Descriptor status */ ++ uint8_t errors; /* Descriptor Errors */ ++ uint16_t special; ++}; ++ ++/* Receive Decriptor bit definitions */ ++#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ ++#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ ++#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ ++#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ ++#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ ++#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ ++#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ ++#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ ++#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ ++#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ ++#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ ++#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ ++#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ ++#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ ++#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ ++#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ ++#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ ++#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ ++#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ ++ ++/* mask to determine if packets should be dropped due to frame errors */ ++#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ ++ E1000_RXD_ERR_CE | \ ++ E1000_RXD_ERR_SE | \ ++ E1000_RXD_ERR_SEQ | \ ++ E1000_RXD_ERR_CXE | \ ++ E1000_RXD_ERR_RXE) ++ ++/* Transmit Descriptor */ ++struct e1000_tx_desc { ++ uint64_t buffer_addr; /* Address of the descriptor's data buffer */ ++ union { ++ uint32_t data; ++ struct { ++ uint16_t length; /* Data buffer length */ ++ uint8_t cso; /* Checksum offset */ ++ uint8_t cmd; /* Descriptor control */ ++ } flags; ++ } lower; ++ union { ++ uint32_t data; ++ struct { ++ uint8_t status; /* Descriptor status */ ++ uint8_t css; /* Checksum start */ ++ uint16_t special; ++ } fields; ++ } upper; ++}; ++ ++/* Transmit Descriptor bit definitions */ ++#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ ++#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ ++#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ ++#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ ++#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ ++#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ ++#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ ++#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ ++#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ ++#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ ++#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ ++#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ ++#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ ++#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ ++#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ ++#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ ++#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ ++#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ ++#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ ++#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ ++ ++/* Offload Context Descriptor */ ++struct e1000_context_desc { ++ union { ++ uint32_t ip_config; ++ struct { ++ uint8_t ipcss; /* IP checksum start */ ++ uint8_t ipcso; /* IP checksum offset */ ++ uint16_t ipcse; /* IP checksum end */ ++ } ip_fields; ++ } lower_setup; ++ union { ++ uint32_t tcp_config; ++ struct { ++ uint8_t tucss; /* TCP checksum start */ ++ uint8_t tucso; /* TCP checksum offset */ ++ uint16_t tucse; /* TCP checksum end */ ++ } tcp_fields; ++ } upper_setup; ++ uint32_t cmd_and_length; /* */ ++ union { ++ uint32_t data; ++ struct { ++ uint8_t status; /* Descriptor status */ ++ uint8_t hdr_len; /* Header length */ ++ uint16_t mss; /* Maximum segment size */ ++ } fields; ++ } tcp_seg_setup; ++}; ++ ++/* Offload data descriptor */ ++struct e1000_data_desc { ++ uint64_t buffer_addr; /* Address of the descriptor's buffer address */ ++ union { ++ uint32_t data; ++ struct { ++ uint16_t length; /* Data buffer length */ ++ uint8_t typ_len_ext; /* */ ++ uint8_t cmd; /* */ ++ } flags; ++ } lower; ++ union { ++ uint32_t data; ++ struct { ++ uint8_t status; /* Descriptor status */ ++ uint8_t popts; /* Packet Options */ ++ uint16_t special; /* */ ++ } fields; ++ } upper; ++}; ++ ++/* Filters */ ++#define E1000_NUM_UNICAST 16 /* Unicast filter entries */ ++#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ ++#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ ++ ++ ++/* Receive Address Register */ ++struct e1000_rar { ++ volatile uint32_t low; /* receive address low */ ++ volatile uint32_t high; /* receive address high */ ++}; ++ ++/* The number of entries in the Multicast Table Array (MTA). */ ++#define E1000_NUM_MTA_REGISTERS 128 ++ ++/* IPv4 Address Table Entry */ ++struct e1000_ipv4_at_entry { ++ volatile uint32_t ipv4_addr; /* IP Address (RW) */ ++ volatile uint32_t reserved; ++}; ++ ++/* Four wakeup IP addresses are supported */ ++#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 ++#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX ++#define E1000_IP6AT_SIZE 1 ++ ++/* IPv6 Address Table Entry */ ++struct e1000_ipv6_at_entry { ++ volatile uint8_t ipv6_addr[16]; ++}; ++ ++/* Flexible Filter Length Table Entry */ ++struct e1000_fflt_entry { ++ volatile uint32_t length; /* Flexible Filter Length (RW) */ ++ volatile uint32_t reserved; ++}; ++ ++/* Flexible Filter Mask Table Entry */ ++struct e1000_ffmt_entry { ++ volatile uint32_t mask; /* Flexible Filter Mask (RW) */ ++ volatile uint32_t reserved; ++}; ++ ++/* Flexible Filter Value Table Entry */ ++struct e1000_ffvt_entry { ++ volatile uint32_t value; /* Flexible Filter Value (RW) */ ++ volatile uint32_t reserved; ++}; ++ ++/* Four Flexible Filters are supported */ ++#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 ++ ++/* Each Flexible Filter is at most 128 (0x80) bytes in length */ ++#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 ++ ++#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX ++#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX ++#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX ++ ++/* Register Set. (82543, 82544) ++ * ++ * Registers are defined to be 32 bits and should be accessed as 32 bit values. ++ * These registers are physically located on the NIC, but are mapped into the ++ * host memory address space. ++ * ++ * RW - register is both readable and writable ++ * RO - register is read only ++ * WO - register is write only ++ * R/clr - register is read only and is cleared when read ++ * A - register array ++ */ ++#define E1000_CTRL 0x00000 /* Device Control - RW */ ++#define E1000_STATUS 0x00008 /* Device Status - RO */ ++#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ ++#define E1000_EERD 0x00014 /* EEPROM Read - RW */ ++#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ ++#define E1000_MDIC 0x00020 /* MDI Control - RW */ ++#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ ++#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ ++#define E1000_FCT 0x00030 /* Flow Control Type - RW */ ++#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ ++#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ ++#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ ++#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ ++#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ ++#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ ++#define E1000_RCTL 0x00100 /* RX Control - RW */ ++#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ ++#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ ++#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ ++#define E1000_TCTL 0x00400 /* TX Control - RW */ ++#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ ++#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ ++#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ ++#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ ++#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ ++#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ ++#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ ++#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ ++#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ ++#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ ++#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ ++#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ ++#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ ++#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ ++#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ ++#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ ++#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ ++#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ ++#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ ++#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ ++#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ ++#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ ++#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ ++#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ ++#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ ++#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ ++#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ ++#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ ++#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ ++#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ ++#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ ++#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ ++#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ ++#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ ++#define E1000_COLC 0x04028 /* Collision Count - R/clr */ ++#define E1000_DC 0x04030 /* Defer Count - R/clr */ ++#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ ++#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ ++#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ ++#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ ++#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ ++#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ ++#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ ++#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ ++#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ ++#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ ++#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ ++#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ ++#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ ++#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ ++#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ ++#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ ++#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ ++#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ ++#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ ++#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ ++#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ ++#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ ++#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ ++#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ ++#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ ++#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ ++#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ ++#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ ++#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ ++#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ ++#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ ++#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ ++#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ ++#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ ++#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ ++#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ ++#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ ++#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ ++#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ ++#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ ++#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ ++#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ ++#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ ++#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ ++#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ ++#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ ++#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ ++#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ ++#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ ++#define E1000_RA 0x05400 /* Receive Address - RW Array */ ++#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ ++#define E1000_WUC 0x05800 /* Wakeup Control - RW */ ++#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ ++#define E1000_WUS 0x05810 /* Wakeup Status - RO */ ++#define E1000_MANC 0x05820 /* Management Control - RW */ ++#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ ++#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ ++#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ ++#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ ++#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ ++#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ ++#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ ++#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ ++ ++/* Register Set (82542) ++ * ++ * Some of the 82542 registers are located at different offsets than they are ++ * in more current versions of the 8254x. Despite the difference in location, ++ * the registers function in the same manner. ++ */ ++#define E1000_82542_CTRL E1000_CTRL ++#define E1000_82542_STATUS E1000_STATUS ++#define E1000_82542_EECD E1000_EECD ++#define E1000_82542_EERD E1000_EERD ++#define E1000_82542_CTRL_EXT E1000_CTRL_EXT ++#define E1000_82542_MDIC E1000_MDIC ++#define E1000_82542_FCAL E1000_FCAL ++#define E1000_82542_FCAH E1000_FCAH ++#define E1000_82542_FCT E1000_FCT ++#define E1000_82542_VET E1000_VET ++#define E1000_82542_RA 0x00040 ++#define E1000_82542_ICR E1000_ICR ++#define E1000_82542_ITR E1000_ITR ++#define E1000_82542_ICS E1000_ICS ++#define E1000_82542_IMS E1000_IMS ++#define E1000_82542_IMC E1000_IMC ++#define E1000_82542_RCTL E1000_RCTL ++#define E1000_82542_RDTR 0x00108 ++#define E1000_82542_RDBAL 0x00110 ++#define E1000_82542_RDBAH 0x00114 ++#define E1000_82542_RDLEN 0x00118 ++#define E1000_82542_RDH 0x00120 ++#define E1000_82542_RDT 0x00128 ++#define E1000_82542_FCRTH 0x00160 ++#define E1000_82542_FCRTL 0x00168 ++#define E1000_82542_FCTTV E1000_FCTTV ++#define E1000_82542_TXCW E1000_TXCW ++#define E1000_82542_RXCW E1000_RXCW ++#define E1000_82542_MTA 0x00200 ++#define E1000_82542_TCTL E1000_TCTL ++#define E1000_82542_TIPG E1000_TIPG ++#define E1000_82542_TDBAL 0x00420 ++#define E1000_82542_TDBAH 0x00424 ++#define E1000_82542_TDLEN 0x00428 ++#define E1000_82542_TDH 0x00430 ++#define E1000_82542_TDT 0x00438 ++#define E1000_82542_TIDV 0x00440 ++#define E1000_82542_TBT E1000_TBT ++#define E1000_82542_VFTA 0x00600 ++#define E1000_82542_LEDCTL E1000_LEDCTL ++#define E1000_82542_PBA E1000_PBA ++#define E1000_82542_RXDCTL E1000_RXDCTL ++#define E1000_82542_RADV E1000_RADV ++#define E1000_82542_RSRPD E1000_RSRPD ++#define E1000_82542_TXDMAC E1000_TXDMAC ++#define E1000_82542_TXDCTL E1000_TXDCTL ++#define E1000_82542_TADV E1000_TADV ++#define E1000_82542_TSPMT E1000_TSPMT ++#define E1000_82542_CRCERRS E1000_CRCERRS ++#define E1000_82542_ALGNERRC E1000_ALGNERRC ++#define E1000_82542_SYMERRS E1000_SYMERRS ++#define E1000_82542_RXERRC E1000_RXERRC ++#define E1000_82542_MPC E1000_MPC ++#define E1000_82542_SCC E1000_SCC ++#define E1000_82542_ECOL E1000_ECOL ++#define E1000_82542_MCC E1000_MCC ++#define E1000_82542_LATECOL E1000_LATECOL ++#define E1000_82542_COLC E1000_COLC ++#define E1000_82542_DC E1000_DC ++#define E1000_82542_TNCRS E1000_TNCRS ++#define E1000_82542_SEC E1000_SEC ++#define E1000_82542_CEXTERR E1000_CEXTERR ++#define E1000_82542_RLEC E1000_RLEC ++#define E1000_82542_XONRXC E1000_XONRXC ++#define E1000_82542_XONTXC E1000_XONTXC ++#define E1000_82542_XOFFRXC E1000_XOFFRXC ++#define E1000_82542_XOFFTXC E1000_XOFFTXC ++#define E1000_82542_FCRUC E1000_FCRUC ++#define E1000_82542_PRC64 E1000_PRC64 ++#define E1000_82542_PRC127 E1000_PRC127 ++#define E1000_82542_PRC255 E1000_PRC255 ++#define E1000_82542_PRC511 E1000_PRC511 ++#define E1000_82542_PRC1023 E1000_PRC1023 ++#define E1000_82542_PRC1522 E1000_PRC1522 ++#define E1000_82542_GPRC E1000_GPRC ++#define E1000_82542_BPRC E1000_BPRC ++#define E1000_82542_MPRC E1000_MPRC ++#define E1000_82542_GPTC E1000_GPTC ++#define E1000_82542_GORCL E1000_GORCL ++#define E1000_82542_GORCH E1000_GORCH ++#define E1000_82542_GOTCL E1000_GOTCL ++#define E1000_82542_GOTCH E1000_GOTCH ++#define E1000_82542_RNBC E1000_RNBC ++#define E1000_82542_RUC E1000_RUC ++#define E1000_82542_RFC E1000_RFC ++#define E1000_82542_ROC E1000_ROC ++#define E1000_82542_RJC E1000_RJC ++#define E1000_82542_MGTPRC E1000_MGTPRC ++#define E1000_82542_MGTPDC E1000_MGTPDC ++#define E1000_82542_MGTPTC E1000_MGTPTC ++#define E1000_82542_TORL E1000_TORL ++#define E1000_82542_TORH E1000_TORH ++#define E1000_82542_TOTL E1000_TOTL ++#define E1000_82542_TOTH E1000_TOTH ++#define E1000_82542_TPR E1000_TPR ++#define E1000_82542_TPT E1000_TPT ++#define E1000_82542_PTC64 E1000_PTC64 ++#define E1000_82542_PTC127 E1000_PTC127 ++#define E1000_82542_PTC255 E1000_PTC255 ++#define E1000_82542_PTC511 E1000_PTC511 ++#define E1000_82542_PTC1023 E1000_PTC1023 ++#define E1000_82542_PTC1522 E1000_PTC1522 ++#define E1000_82542_MPTC E1000_MPTC ++#define E1000_82542_BPTC E1000_BPTC ++#define E1000_82542_TSCTC E1000_TSCTC ++#define E1000_82542_TSCTFC E1000_TSCTFC ++#define E1000_82542_RXCSUM E1000_RXCSUM ++#define E1000_82542_WUC E1000_WUC ++#define E1000_82542_WUFC E1000_WUFC ++#define E1000_82542_WUS E1000_WUS ++#define E1000_82542_MANC E1000_MANC ++#define E1000_82542_IPAV E1000_IPAV ++#define E1000_82542_IP4AT E1000_IP4AT ++#define E1000_82542_IP6AT E1000_IP6AT ++#define E1000_82542_WUPL E1000_WUPL ++#define E1000_82542_WUPM E1000_WUPM ++#define E1000_82542_FFLT E1000_FFLT ++#define E1000_82542_FFMT E1000_FFMT ++#define E1000_82542_FFVT E1000_FFVT ++ ++/* Statistics counters collected by the MAC */ ++struct e1000_shared_stats { ++ uint64_t crcerrs; ++ uint64_t algnerrc; ++ uint64_t symerrs; ++ uint64_t rxerrc; ++ uint64_t mpc; ++ uint64_t scc; ++ uint64_t ecol; ++ uint64_t mcc; ++ uint64_t latecol; ++ uint64_t colc; ++ uint64_t dc; ++ uint64_t tncrs; ++ uint64_t sec; ++ uint64_t cexterr; ++ uint64_t rlec; ++ uint64_t xonrxc; ++ uint64_t xontxc; ++ uint64_t xoffrxc; ++ uint64_t xofftxc; ++ uint64_t fcruc; ++ uint64_t prc64; ++ uint64_t prc127; ++ uint64_t prc255; ++ uint64_t prc511; ++ uint64_t prc1023; ++ uint64_t prc1522; ++ uint64_t gprc; ++ uint64_t bprc; ++ uint64_t mprc; ++ uint64_t gptc; ++ uint64_t gorcl; ++ uint64_t gorch; ++ uint64_t gotcl; ++ uint64_t gotch; ++ uint64_t rnbc; ++ uint64_t ruc; ++ uint64_t rfc; ++ uint64_t roc; ++ uint64_t rjc; ++ uint64_t mgprc; ++ uint64_t mgpdc; ++ uint64_t mgptc; ++ uint64_t torl; ++ uint64_t torh; ++ uint64_t totl; ++ uint64_t toth; ++ uint64_t tpr; ++ uint64_t tpt; ++ uint64_t ptc64; ++ uint64_t ptc127; ++ uint64_t ptc255; ++ uint64_t ptc511; ++ uint64_t ptc1023; ++ uint64_t ptc1522; ++ uint64_t mptc; ++ uint64_t bptc; ++ uint64_t tsctc; ++ uint64_t tsctfc; ++}; ++ ++/* Structure containing variables used by the shared code (e1000_mac.c and ++ * e1000_phy.c) ++ */ ++struct e1000_shared_adapter { ++ uint8_t *hw_addr; ++ e1000_mac_type mac_type; ++ e1000_media_type media_type; ++ void *back; ++ e1000_fc_type fc; ++ e1000_bus_speed bus_speed; ++ e1000_bus_width bus_width; ++ e1000_bus_type bus_type; ++ uint32_t phy_id; ++ uint32_t phy_addr; ++ uint32_t original_fc; ++ uint32_t txcw_reg; ++ uint32_t autoneg_failed; ++ uint32_t max_frame_size; ++ uint32_t min_frame_size; ++ uint32_t mc_filter_type; ++ uint32_t num_mc_addrs; ++ uint16_t autoneg_advertised; ++ uint16_t pci_cmd_word; ++ uint16_t fc_high_water; ++ uint16_t fc_low_water; ++ uint16_t fc_pause_time; ++ uint16_t device_id; ++ uint16_t vendor_id; ++ uint16_t subsystem_id; ++ uint16_t subsystem_vendor_id; ++ uint8_t revision_id; ++ boolean_t disable_polarity_correction; ++ boolean_t get_link_status; ++ boolean_t tbi_compatibility_en; ++ boolean_t tbi_compatibility_on; ++ boolean_t adapter_stopped; ++ boolean_t fc_send_xon; ++ boolean_t report_tx_early; ++ boolean_t low_profile; ++ uint8_t autoneg; ++ uint8_t mdix; ++ uint8_t forced_speed_duplex; ++ uint8_t wait_autoneg_complete; ++ uint8_t dma_fairness; ++ uint8_t mac_addr[NODE_ADDRESS_SIZE]; ++}; ++ ++ ++#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ ++#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ ++ ++/* Register Bit Masks */ ++/* Device Control */ ++#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ ++#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ ++#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ ++#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ ++#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ ++#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ ++#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ ++#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ ++#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ ++#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ ++#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ ++#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ ++#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ ++#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ ++#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ ++#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ ++#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ ++#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ ++#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ ++#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ ++#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ ++#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ ++#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ ++#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ ++#define E1000_CTRL_RST 0x04000000 /* Global reset */ ++#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ ++#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ ++#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ ++#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ ++#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ ++ ++/* Device Status */ ++#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ ++#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ ++#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ ++#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ ++#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ ++#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ ++#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ ++#define E1000_STATUS_SPEED_MASK 0x000000C0 ++#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ ++#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ ++#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ ++#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ ++#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ ++#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ ++#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ ++#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ ++#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ ++ ++/* Constants used to intrepret the masked PCI-X bus speed. */ ++#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ ++#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ ++#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ ++ ++/* EEPROM/Flash Control */ ++#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ ++#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ ++#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ ++#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ ++#define E1000_EECD_FWE_MASK 0x00000030 ++#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ ++#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ ++#define E1000_EECD_FWE_SHIFT 4 ++#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ ++#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ ++#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ ++#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ ++ ++/* EEPROM Read */ ++#define E1000_EERD_START 0x00000001 /* Start Read */ ++#define E1000_EERD_DONE 0x00000010 /* Read Done */ ++#define E1000_EERD_ADDR_SHIFT 8 ++#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */ ++#define E1000_EERD_DATA_SHIFT 16 ++#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ ++ ++/* Extended Device Control */ ++#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ ++#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ ++#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN ++#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ ++#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ ++#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ ++#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ ++#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA ++#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ ++#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ ++#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ ++#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ ++#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ ++#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ ++#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ ++#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ ++#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 ++#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 ++#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 ++#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 ++#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 ++#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 ++#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 ++#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 ++ ++/* MDI Control */ ++#define E1000_MDIC_DATA_MASK 0x0000FFFF ++#define E1000_MDIC_REG_MASK 0x001F0000 ++#define E1000_MDIC_REG_SHIFT 16 ++#define E1000_MDIC_PHY_MASK 0x03E00000 ++#define E1000_MDIC_PHY_SHIFT 21 ++#define E1000_MDIC_OP_WRITE 0x04000000 ++#define E1000_MDIC_OP_READ 0x08000000 ++#define E1000_MDIC_READY 0x10000000 ++#define E1000_MDIC_INT_EN 0x20000000 ++#define E1000_MDIC_ERROR 0x40000000 ++ ++/* LED Control */ ++#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F ++#define E1000_LEDCTL_LED0_MODE_SHIFT 0 ++#define E1000_LEDCTL_LED0_IVRT 0x00000040 ++#define E1000_LEDCTL_LED0_BLINK 0x00000080 ++#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 ++#define E1000_LEDCTL_LED1_MODE_SHIFT 8 ++#define E1000_LEDCTL_LED1_IVRT 0x00004000 ++#define E1000_LEDCTL_LED1_BLINK 0x00008000 ++#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 ++#define E1000_LEDCTL_LED2_MODE_SHIFT 16 ++#define E1000_LEDCTL_LED2_IVRT 0x00400000 ++#define E1000_LEDCTL_LED2_BLINK 0x00800000 ++#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 ++#define E1000_LEDCTL_LED3_MODE_SHIFT 24 ++#define E1000_LEDCTL_LED3_IVRT 0x40000000 ++#define E1000_LEDCTL_LED3_BLINK 0x80000000 ++ ++#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 ++#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 ++#define E1000_LEDCTL_MODE_LINK_UP 0x2 ++#define E1000_LEDCTL_MODE_ACTIVITY 0x3 ++#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 ++#define E1000_LEDCTL_MODE_LINK_10 0x5 ++#define E1000_LEDCTL_MODE_LINK_100 0x6 ++#define E1000_LEDCTL_MODE_LINK_1000 0x7 ++#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 ++#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 ++#define E1000_LEDCTL_MODE_COLLISION 0xA ++#define E1000_LEDCTL_MODE_BUS_SPEED 0xB ++#define E1000_LEDCTL_MODE_BUS_SIZE 0xC ++#define E1000_LEDCTL_MODE_PAUSED 0xD ++#define E1000_LEDCTL_MODE_LED_ON 0xE ++#define E1000_LEDCTL_MODE_LED_OFF 0xF ++ ++/* Receive Address */ ++#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ ++ ++/* Interrupt Cause Read */ ++#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ ++#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ ++#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ ++#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ ++#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ ++#define E1000_ICR_RXO 0x00000040 /* rx overrun */ ++#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ ++#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ ++#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ ++#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ ++#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ ++#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ ++#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ ++#define E1000_ICR_TXD_LOW 0x00008000 ++#define E1000_ICR_SRPD 0x00010000 ++ ++/* Interrupt Cause Set */ ++#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ ++#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ ++#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ ++#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ ++#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ ++#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ ++#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ ++#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ ++#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ ++#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ ++#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ ++#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ ++#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ ++#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW ++#define E1000_ICS_SRPD E1000_ICR_SRPD ++ ++/* Interrupt Mask Set */ ++#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ ++#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ ++#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ ++#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ ++#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ ++#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ ++#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ ++#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ ++#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ ++#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ ++#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ ++#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ ++#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ ++#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW ++#define E1000_IMS_SRPD E1000_ICR_SRPD ++ ++/* Interrupt Mask Clear */ ++#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ ++#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ ++#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ ++#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ ++#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ ++#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ ++#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ ++#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ ++#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ ++#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ ++#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ ++#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ ++#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ ++#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW ++#define E1000_IMC_SRPD E1000_ICR_SRPD ++ ++/* Receive Control */ ++#define E1000_RCTL_RST 0x00000001 /* Software reset */ ++#define E1000_RCTL_EN 0x00000002 /* enable */ ++#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ ++#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ ++#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ ++#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ ++#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ ++#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ ++#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ ++#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ ++#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ ++#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ ++#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ ++#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ ++#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ ++#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ ++#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ ++#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ ++#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ ++#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ ++/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ ++#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ ++#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ ++#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ ++#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ ++/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ ++#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ ++#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ ++#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ ++#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ ++#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ ++#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ ++#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ ++#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ ++#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ ++ ++/* Receive Descriptor */ ++#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ ++#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ ++#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */ ++#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */ ++#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */ ++ ++/* Flow Control */ ++#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ ++#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ ++#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ ++#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ ++ ++/* Receive Descriptor Control */ ++#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ ++#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ ++#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */ ++#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ ++ ++/* Transmit Descriptor Control */ ++#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ ++#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ ++#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ ++#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ ++#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ ++ ++/* Transmit Configuration Word */ ++#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ ++#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ ++#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ ++#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ ++#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ ++#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ ++#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ ++#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ ++#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ ++#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ ++ ++/* Receive Configuration Word */ ++#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ ++#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ ++#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ ++#define E1000_RXCW_CC 0x10000000 /* Receive config change */ ++#define E1000_RXCW_C 0x20000000 /* Receive config */ ++#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ ++#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ ++ ++/* Transmit Control */ ++#define E1000_TCTL_RST 0x00000001 /* software reset */ ++#define E1000_TCTL_EN 0x00000002 /* enable tx */ ++#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ ++#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ ++#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ ++#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ ++#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ ++#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ ++#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ ++#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ ++ ++/* Receive Checksum Control */ ++#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ ++#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ ++#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ ++#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ ++ ++/* Definitions for power management and wakeup registers */ ++/* Wake Up Control */ ++#define E1000_WUC_APME 0x00000001 /* APM Enable */ ++#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ ++#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ ++#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ ++ ++/* Wake Up Filter Control */ ++#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ ++#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ ++#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ ++#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ ++#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ ++#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ ++#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ ++#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ ++#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ ++#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ ++#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ ++#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ ++#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ ++#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ ++#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ ++ ++/* Wake Up Status */ ++#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */ ++#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */ ++#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */ ++#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */ ++#define E1000_WUS_BC 0x00000010 /* Broadcast Received */ ++#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */ ++#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */ ++#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */ ++#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */ ++#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */ ++#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */ ++#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */ ++#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ ++ ++/* Management Control */ ++#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ ++#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ ++#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ ++#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ ++#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ ++#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ ++#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ ++#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ ++#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ ++#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery ++ * Filtering */ ++#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ ++#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ ++#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ ++#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ ++#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ ++#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ ++#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ ++#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ ++#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ ++ ++#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ ++#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ ++ ++/* Wake Up Packet Length */ ++#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ ++ ++#define E1000_MDALIGN 4096 ++ ++/* EEPROM Commands */ ++#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ ++#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ ++#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ ++#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ ++#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ ++ ++/* EEPROM Word Offsets */ ++#define EEPROM_INIT_CONTROL1_REG 0x000A ++#define EEPROM_INIT_CONTROL2_REG 0x000F ++#define EEPROM_FLASH_VERSION 0x0032 ++#define EEPROM_CHECKSUM_REG 0x003F ++ ++/* Mask bits for fields in Word 0x0a of the EEPROM */ ++#define EEPROM_WORD0A_ILOS 0x0010 ++#define EEPROM_WORD0A_SWDPIO 0x01E0 ++#define EEPROM_WORD0A_LRST 0x0200 ++#define EEPROM_WORD0A_FD 0x0400 ++#define EEPROM_WORD0A_66MHZ 0x0800 ++ ++/* Mask bits for fields in Word 0x0f of the EEPROM */ ++#define EEPROM_WORD0F_PAUSE_MASK 0x3000 ++#define EEPROM_WORD0F_PAUSE 0x1000 ++#define EEPROM_WORD0F_ASM_DIR 0x2000 ++#define EEPROM_WORD0F_ANE 0x0800 ++#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 ++ ++/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ ++#define EEPROM_SUM 0xBABA ++ ++/* EEPROM Map defines (WORD OFFSETS)*/ ++#define EEPROM_NODE_ADDRESS_BYTE_0 0 ++#define EEPROM_PBA_BYTE_1 8 ++ ++/* EEPROM Map Sizes (Byte Counts) */ ++#define PBA_SIZE 4 ++ ++/* Collision related configuration parameters */ ++#define E1000_COLLISION_THRESHOLD 16 ++#define E1000_CT_SHIFT 4 ++#define E1000_FDX_COLLISION_DISTANCE 64 ++#define E1000_HDX_COLLISION_DISTANCE 64 ++#define E1000_GB_HDX_COLLISION_DISTANCE 512 ++#define E1000_COLD_SHIFT 12 ++ ++/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ ++#define REQ_TX_DESCRIPTOR_MULTIPLE 8 ++#define REQ_RX_DESCRIPTOR_MULTIPLE 8 ++ ++/* Default values for the transmit IPG register */ ++#define DEFAULT_82542_TIPG_IPGT 10 ++#define DEFAULT_82543_TIPG_IPGT_FIBER 9 ++#define DEFAULT_82543_TIPG_IPGT_COPPER 8 ++ ++#define E1000_TIPG_IPGT_MASK 0x000003FF ++#define E1000_TIPG_IPGR1_MASK 0x000FFC00 ++#define E1000_TIPG_IPGR2_MASK 0x3FF00000 ++ ++#define DEFAULT_82542_TIPG_IPGR1 2 ++#define DEFAULT_82543_TIPG_IPGR1 8 ++#define E1000_TIPG_IPGR1_SHIFT 10 ++ ++#define DEFAULT_82542_TIPG_IPGR2 10 ++#define DEFAULT_82543_TIPG_IPGR2 6 ++#define E1000_TIPG_IPGR2_SHIFT 20 ++ ++#define E1000_TXDMAC_DPP 0x00000001 ++ ++/* PBA constants */ ++#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ ++#define E1000_PBA_24K 0x0018 ++#define E1000_PBA_40K 0x0028 ++#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ ++ ++/* Flow Control Constants */ ++#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 ++#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 ++#define FLOW_CONTROL_TYPE 0x8808 ++ ++/* The historical defaults for the flow control values are given below. */ ++#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */ ++#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */ ++#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */ ++ ++ ++/* The number of bits that we need to shift right to move the "pause" ++ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field ++ * in the TXCW register ++ */ ++#define PAUSE_SHIFT 5 ++ ++/* The number of bits that we need to shift left to move the "SWDPIO" ++ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field ++ * in the CTRL register ++ */ ++#define SWDPIO_SHIFT 17 ++ ++/* The number of bits that we need to shift left to move the "SWDPIO_EXT" ++ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The ++ * Extended CTRL register. ++ * in the CTRL register ++ */ ++#define SWDPIO__EXT_SHIFT 4 ++ ++/* The number of bits that we need to shift left to move the "ILOS" ++ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field ++ * in the CTRL register ++ */ ++#define ILOS_SHIFT 3 ++ ++ ++#define RECEIVE_BUFFER_ALIGN_SIZE (256) ++ ++/* The number of milliseconds we wait for auto-negotiation to complete */ ++#define LINK_UP_TIMEOUT 500 ++ ++#define E1000_TX_BUFFER_SIZE ((uint32_t)1514) ++ ++/* The carrier extension symbol, as received by the NIC. */ ++#define CARRIER_EXTENSION 0x0F ++ ++/* TBI_ACCEPT macro definition: ++ * ++ * This macro requires: ++ * adapter = a pointer to struct e1000_shared_adapter ++ * status = the 8 bit status field of the RX descriptor with EOP set ++ * error = the 8 bit error field of the RX descriptor with EOP set ++ * length = the sum of all the length fields of the RX descriptors that ++ * make up the current frame ++ * last_byte = the last byte of the frame DMAed by the hardware ++ * max_frame_length = the maximum frame length we want to accept. ++ * min_frame_length = the minimum frame length we want to accept. ++ * ++ * This macro is a conditional that should be used in the interrupt ++ * handler's Rx processing routine when RxErrors have been detected. ++ * ++ * Typical use: ++ * ... ++ * if (TBI_ACCEPT) { ++ * accept_frame = TRUE; ++ * e1000_tbi_adjust_stats(adapter, MacAddress); ++ * frame_length--; ++ * } else { ++ * accept_frame = FALSE; ++ * } ++ * ... ++ */ ++ ++#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \ ++ ((adapter)->tbi_compatibility_on && \ ++ (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ ++ ((last_byte) == CARRIER_EXTENSION) && \ ++ (((status) & E1000_RXD_STAT_VP) ? \ ++ (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \ ++ ((length) <= ((adapter)->max_frame_size + 1))) : \ ++ (((length) > (adapter)->min_frame_size) && \ ++ ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1))))) ++ ++ ++#endif /* _E1000_MAC_H_ */ +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_main.c 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,3780 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++ ++#define __E1000_MAIN__ ++#ifdef IANS ++#define _IANS_MAIN_MODULE_C_ ++#endif ++#include "e1000.h" ++ ++/* Driver name string */ ++char e1000_driver_name[] = "e1000"; ++ ++/* Driver ID string, displayed when loading */ ++char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; ++ ++/* Driver version */ ++char e1000_driver_version[] = "4.1.7"; ++ ++/* Copyright string, displayed when loading */ ++char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; ++ ++/* Linked list of board private structures for all NICs found */ ++struct e1000_adapter *e1000_adapter_list = NULL; ++ ++/* e1000_strings - PCI Device ID Table ++ * ++ * for selecting devices to load on ++ * private driver_data field (last one) stores an index ++ * into e1000_strings ++ * Wildcard entries (PCI_ANY_ID) should come last ++ * Last entry must be all 0s ++ * ++ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, ++ * Class, Class Mask, String Index } ++ */ ++static struct pci_device_id e1000_pci_table[] = { ++ /* Intel(R) PRO/1000 Network Connection */ ++ {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, ++ {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, ++ {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, ++ {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, ++ {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, ++ {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, ++ {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0}, ++ /* Compaq Gigabit Ethernet Server Adapter */ ++ {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, ++ {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, ++ {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, ++ /* IBM Mobile, Desktop & Server Adapters */ ++ {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, ++ {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, ++ {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, ++ /* Generic */ ++ {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ /* required last entry */ ++ {0,} ++}; ++ ++MODULE_DEVICE_TABLE(pci, e1000_pci_table); ++ ++/* e1000_pci_table - Table of branding strings for all supported NICs. */ ++ ++static char *e1000_strings[] = { ++ "Intel(R) PRO/1000 Network Connection", ++ "Compaq Gigabit Ethernet Server Adapter", ++ "IBM Mobile, Desktop & Server Adapters" ++}; ++ ++/* PCI driver information (Linux 2.4 driver API) */ ++static struct pci_driver e1000_driver = { ++ name: e1000_driver_name, ++ id_table: e1000_pci_table, ++ probe: e1000_probe, ++ remove: e1000_remove, ++ /* Power Managment Hooks */ ++ suspend: NULL, ++ resume: NULL ++}; ++ ++/* Module Parameters are always initialized to -1, so that the driver ++ * can tell the difference between no user specified value or the ++ * user asking for the default value. ++ * The true default values are loaded in when e1000_check_options is called. ++ */ ++ ++/* This is the only thing that needs to be changed to adjust the ++ * maximum number of ports that the driver can manage. ++ */ ++ ++#define E1000_MAX_NIC 8 ++ ++/* This is a GCC extension to ANSI C. ++ * See the item "Labeled Elements in Initializers" in the section ++ * "Extensions to the C Language Family" of the GCC documentation. ++ */ ++ ++#define E1000_OPTION_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } ++ ++/* Transmit Descriptor Count ++ * ++ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers ++ * Valid Range: 80-4096 for 82544 ++ * ++ * Default Value: 256 ++ */ ++ ++static int TxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* Receive Descriptor Count ++ * ++ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers ++ * Valid Range: 80-4096 for 82544 ++ * ++ * Default Value: 256 ++ */ ++ ++static int RxDescriptors[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* User Specified Speed Override ++ * ++ * Valid Range: 0, 10, 100, 1000 ++ * - 0 - auto-negotiate at all supported speeds ++ * - 10 - only link at 10 Mbps ++ * - 100 - only link at 100 Mbps ++ * - 1000 - only link at 1000 Mbps ++ * ++ * Default Value: 0 ++ */ ++ ++static int Speed[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* User Specified Duplex Override ++ * ++ * Valid Range: 0-2 ++ * - 0 - auto-negotiate for duplex ++ * - 1 - only link at half duplex ++ * - 2 - only link at full duplex ++ * ++ * Default Value: 0 ++ */ ++ ++static int Duplex[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* Auto-negotiation Advertisement Override ++ * ++ * Valid Range: 0x00-0x0F, 0x20-0x2F ++ * ++ * The AutoNeg value is a bit mask describing which speed and duplex ++ * combinations should be advertised during auto-negotiation. ++ * The supported speed and duplex modes are listed below ++ * ++ * Bit 7 6 5 4 3 2 1 0 ++ * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 ++ * Duplex Full Full Half Full Half ++ * ++ * Default Value: 0x2F ++ */ ++ ++static int AutoNeg[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* User Specified Flow Control Override ++ * ++ * Valid Range: 0-3 ++ * - 0 - No Flow Control ++ * - 1 - Rx only, respond to PAUSE frames but do not generate them ++ * - 2 - Tx only, generate PAUSE frames but ignore them on receive ++ * - 3 - Full Flow Control Support ++ * ++ * Default Value: Read flow control settings from the EEPROM ++ */ ++ ++static int FlowControl[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* XsumRX - Receive Checksum Offload Enable/Disable ++ * ++ * Valid Range: 0, 1 ++ * - 0 - disables all checksum offload ++ * - 1 - enables receive IP/TCP/UDP checksum offload ++ * on 82543 based NICs ++ * ++ * Default Value: 1 ++ */ ++ ++static int XsumRX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* Transmit Interrupt Delay in units of 1.024 microseconds ++ * ++ * Valid Range: 0-65535 ++ * ++ * Default Value: 64 ++ */ ++ ++static int TxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* Receive Interrupt Delay in units of 1.024 microseconds ++ * ++ * Valid Range: 0-65535 ++ * ++ * Default Value: 64 ++ */ ++ ++static int RxIntDelay[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* MDI-X Support Enable/Disable - Applies only to Copper PHY ++ * ++ * Valid Range: 0, 3 ++ * - 0 - Auto in all modes ++ * - 1 - MDI ++ * - 2 - MDI-X ++ * - 3 - Auto in 1000 Base-T mode (MDI in 10 Base-T and 100 Base-T) ++ * ++ * Default Value: 0 (Auto) ++ */ ++ ++static int MdiX[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++/* Automatic Correction of Reversed Cable Polarity Enable/Disable ++ * This setting applies only to Copper PHY ++ * ++ * Valid Range: 0, 1 ++ * - 0 - Disabled ++ * - 1 - Enabled ++ * ++ * Default Value: 1 (Enabled) ++ */ ++ ++static int DisablePolarityCorrection[E1000_MAX_NIC + 1] = E1000_OPTION_INIT; ++ ++#ifdef MODULE ++ ++MODULE_AUTHOR("Intel Corporation, "); ++MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); ++ ++#if defined(MODULE_LICENSE) ++MODULE_LICENSE("BSD with patent grant"); ++#endif ++ ++MODULE_PARM(TxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(RxDescriptors, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(Speed, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(Duplex, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(AutoNeg, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(XsumRX, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(FlowControl, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(TxIntDelay, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(RxIntDelay, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(MdiX, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++MODULE_PARM(DisablePolarityCorrection, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); ++ ++MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors"); ++MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors"); ++MODULE_PARM_DESC(Speed, "Speed setting"); ++MODULE_PARM_DESC(Duplex, "Duplex setting"); ++MODULE_PARM_DESC(AutoNeg, "Advertised auto-negotiation setting"); ++MODULE_PARM_DESC(XsumRX, "Disable or enable Receive Checksum offload"); ++MODULE_PARM_DESC(FlowControl, "Flow Control setting"); ++MODULE_PARM_DESC(TxIntDelay, "Transmit Interrupt Delay"); ++MODULE_PARM_DESC(RxIntDelay, "Receive Interrupt Delay"); ++MODULE_PARM_DESC(MdiX, "Set MDI/MDI-X Mode"); ++MODULE_PARM_DESC(DisablePolarityCorrection, ++ "Disable or enable Automatic Correction for Reversed Cable Polarity"); ++ ++#ifdef EXPORT_SYMTAB ++/*EXPORT_SYMBOL(e1000_init_module); ++EXPORT_SYMBOL(e1000_exit_module); ++EXPORT_SYMBOL(e1000_probe); ++EXPORT_SYMBOL(e1000_remove); ++EXPORT_SYMBOL(e1000_open); ++EXPORT_SYMBOL(e1000_close); ++EXPORT_SYMBOL(e1000_xmit_frame); ++EXPORT_SYMBOL(e1000_intr); ++EXPORT_SYMBOL(e1000_set_multi); ++EXPORT_SYMBOL(e1000_change_mtu); ++EXPORT_SYMBOL(e1000_set_mac); ++EXPORT_SYMBOL(e1000_get_stats); ++EXPORT_SYMBOL(e1000_watchdog); ++EXPORT_SYMBOL(e1000_ioctl); ++EXPORT_SYMBOL(e1000_adapter_list);*/ ++#endif ++ ++#endif ++ ++/* Local Function Prototypes */ ++ ++static void e1000_check_options(struct e1000_adapter *adapter); ++static void e1000_check_fiber_options(struct e1000_adapter *adapter); ++static void e1000_check_copper_options(struct e1000_adapter *adapter); ++static int e1000_sw_init(struct e1000_adapter *adapter); ++static int e1000_hw_init(struct e1000_adapter *adapter); ++static void e1000_read_address(struct e1000_adapter *adapter, ++ uint8_t *addr); ++static int e1000_setup_tx_resources(struct e1000_adapter *adapter); ++static int e1000_setup_rx_resources(struct e1000_adapter *adapter); ++static void e1000_setup_rctl(struct e1000_adapter *adapter); ++static void e1000_configure_rx(struct e1000_adapter *adapter); ++static void e1000_configure_tx(struct e1000_adapter *adapter); ++static void e1000_free_tx_resources(struct e1000_adapter *adapter); ++static void e1000_free_rx_resources(struct e1000_adapter *adapter); ++static void e1000_update_stats(struct e1000_adapter *adapter); ++static inline void e1000_irq_disable(struct e1000_adapter *adapter); ++static inline void e1000_irq_enable(struct e1000_adapter *adapter); ++static void e1000_clean_tx_irq(struct e1000_adapter *adapter); ++static void e1000_clean_rx_irq(struct e1000_adapter *adapter); ++static inline void e1000_rx_checksum(struct e1000_adapter *adapter, ++ struct e1000_rx_desc *rx_desc, ++ struct sk_buff *skb); ++static void e1000_alloc_rx_buffers(unsigned long data); ++static void e1000_clean_tx_ring(struct e1000_adapter *adapter); ++static void e1000_clean_rx_ring(struct e1000_adapter *adapter); ++void e1000_hibernate_adapter(struct net_device *netdev); ++void e1000_wakeup_adapter(struct net_device *netdev); ++static void e1000_enable_WOL(struct e1000_adapter *adapter); ++ ++#ifdef SIOCETHTOOL ++static int e1000_ethtool_ioctl(struct net_device *netdev, ++ struct ifreq *ifr); ++#endif ++#ifdef IDIAG ++static int e1000_check_lbtest_frame(struct sk_buff *skb, ++ unsigned int frame_size); ++#endif ++ ++/** ++ * e1000_init_module - Driver Registration Routine ++ * ++ * e1000_init_module is the first routine called when the driver is ++ * loaded. All it does is register with the PCI subsystem. ++ **/ ++ ++int ++e1000_init_module() ++{ ++ E1000_DBG("e1000_init_module\n"); ++ ++ /* Print the driver ID string and copyright notice */ ++ ++ printk("%s - version %s\n%s\n", e1000_driver_string, e1000_driver_version, ++ e1000_copyright); ++ ++ /* register the driver with the PCI subsystem */ ++ ++ return pci_module_init(&e1000_driver); ++} ++ ++/* this macro creates a special symbol in the object file that ++ * identifies the driver initialization routine ++ */ ++module_init(e1000_init_module); ++ ++/** ++ * e1000_exit_module - Driver Exit Cleanup Routine ++ * ++ * e1000_exit_module is called just before the driver is removed ++ * from memory. ++ **/ ++ ++void ++e1000_exit_module() ++{ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *de; ++#endif ++ ++ E1000_DBG("e1000_exit_module\n"); ++ ++ pci_unregister_driver(&e1000_driver); ++ ++#ifdef CONFIG_PROC_FS ++ /* if there is no e1000_proc_dir (proc creation failure on load) ++ * then we're done ++ */ ++ if(e1000_proc_dir == NULL) ++ return; ++ ++ /* If ADAPTERS_PROC_DIR (/proc/net/PRO_LAN_Adapters) is empty ++ * it can be removed now (might still be in use by e100) ++ */ ++ for(de = e1000_proc_dir->subdir; de; de = de->next) { ++ ++ /* ignore . and .. */ ++ ++ if(*(de->name) == '.') ++ continue; ++ break; ++ } ++ if(de) ++ return; ++ remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); ++#endif ++ ++ return; ++} ++ ++/* this macro creates a special symbol in the object file that ++ * identifies the driver cleanup routine ++ */ ++module_exit(e1000_exit_module); ++ ++/** ++ * e1000_probe - Device Initialization Routine ++ * @pdev: PCI device information struct ++ * @ent: entry in e1000_pci_table ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * e1000_probe initializes an adapter identified by a pci_dev ++ * structure. The OS initialization is handled here, and ++ * e1000_sw_init and e1000_hw_init are called to handle the driver ++ * specific software structures and hardware initialization ++ * respectively. ++ **/ ++ ++int ++e1000_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct net_device *netdev = NULL; ++ struct e1000_adapter *adapter; ++ static int cards_found = 0; ++ ++#ifdef CONFIG_PROC_FS ++ int len; ++#endif ++ ++ E1000_DBG("e1000_probe\n"); ++ ++ /* Make sure the PCI device has the proper resources available */ ++ ++ if(pci_enable_device(pdev) != 0) { ++ E1000_ERR("pci_enable_device failed\n"); ++ return -ENODEV; ++ } ++ ++ /* Make sure we are enabled as a bus mastering device */ ++ ++ pci_set_master(pdev); ++ ++ /* Check to see if our PCI addressing needs are supported */ ++ if(pci_set_dma_mask(pdev, E1000_DMA_MASK) < 0) { ++ E1000_ERR("PCI DMA not supported by the system\n"); ++ return -ENODEV; ++ } ++ ++ /* Allocate private data structure (struct e1000_adapter) ++ */ ++ netdev = alloc_etherdev(sizeof(struct e1000_adapter)); ++ ++ if(netdev == NULL) { ++ E1000_ERR("Unable to allocate net_device struct\n"); ++ return -ENOMEM; ++ } ++ ++ /* Calling alloc_etherdev with sizeof(struct e1000_adapter) allocates ++ * a single buffer of size net_device + struct e1000_adapter + ++ * alignment. If this is not done then the struct e1000_adapter needs ++ * to be allocated and freed separately. ++ */ ++ adapter = (struct e1000_adapter *) netdev->priv; ++ memset(adapter, 0, sizeof(struct e1000_adapter)); ++ adapter->netdev = netdev; ++ adapter->pdev = pdev; ++ ++ /* link the struct e1000_adapter into the list */ ++ ++ if(e1000_adapter_list != NULL) ++ e1000_adapter_list->prev = adapter; ++ adapter->next = e1000_adapter_list; ++ e1000_adapter_list = adapter; ++ adapter->shared.back = (void *) adapter; ++ ++ /* reserve the MMIO region as ours */ ++ ++ if(!request_mem_region ++ (pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0), ++ e1000_driver_name)) { ++ E1000_ERR("request_mem_region failed\n"); ++ e1000_remove(pdev); ++ return -ENODEV; ++ } ++ ++ /* map the MMIO region into the kernel virtual address space */ ++ ++ adapter->shared.hw_addr = ++ ioremap(pci_resource_start(pdev, BAR_0), pci_resource_len(pdev, BAR_0)); ++ ++ if(adapter->shared.hw_addr == NULL) { ++ E1000_ERR("ioremap failed\n"); ++ release_mem_region(pci_resource_start(pdev, BAR_0), ++ pci_resource_len(pdev, BAR_0)); ++ e1000_remove(pdev); ++ return -ENOMEM; ++ } ++ ++ /* don't actually register the interrupt handler until e1000_open */ ++ ++ netdev->irq = pdev->irq; ++ ++ /* Set the MMIO base address for the NIC */ ++ ++#ifdef IANS ++ netdev->base_addr = pci_resource_start(pdev, BAR_0); ++#endif ++ netdev->mem_start = pci_resource_start(pdev, BAR_0); ++ netdev->mem_end = netdev->mem_start + pci_resource_len(pdev, BAR_0); ++ ++ /* set up function pointers to driver entry points */ ++ ++ netdev->open = &e1000_open; ++ netdev->stop = &e1000_close; ++ netdev->hard_start_xmit = &e1000_xmit_frame; ++ netdev->get_stats = &e1000_get_stats; ++ netdev->set_multicast_list = &e1000_set_multi; ++ netdev->set_mac_address = &e1000_set_mac; ++ netdev->change_mtu = &e1000_change_mtu; ++ netdev->do_ioctl = &e1000_ioctl; ++ ++ /* set up the struct e1000_adapter */ ++ ++ adapter->bd_number = cards_found; ++ adapter->id_string = e1000_strings[ent->driver_data]; ++ printk("\n%s\n", adapter->id_string); ++ ++ /* Order is important here. e1000_sw_init also identifies the ++ * hardware, so that e1000_check_options can treat command line parameters ++ * differently depending on the hardware. ++ */ ++ e1000_sw_init(adapter); ++ e1000_check_options(adapter); ++ ++#ifdef MAX_SKB_FRAGS ++ if(adapter->shared.mac_type >= e1000_82543) { ++ netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; ++ } else { ++ netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA; ++ } ++#endif ++ ++#ifdef IANS ++ adapter->iANSdata = kmalloc(sizeof(iANSsupport_t), GFP_KERNEL); ++ if(adapter->iANSdata == NULL) { ++ e1000_remove(pdev); ++ return -ENOMEM; ++ } ++ memset(adapter->iANSdata, 0, sizeof(iANSsupport_t)); ++ bd_ans_drv_InitANS(adapter, adapter->iANSdata); ++#endif ++ ++ /* finally, we get around to setting up the hardware */ ++ ++ if(e1000_hw_init(adapter) < 0) { ++ e1000_remove(pdev); ++ return -ENODEV; ++ } ++ cards_found++; ++ ++ /* reset stats */ ++ ++ e1000_clear_hw_cntrs(&adapter->shared); ++ e1000_phy_get_info(&adapter->shared, &adapter->phy_info); ++ ++ /* Then register the net device once everything initializes ++ */ ++ register_netdev(netdev); ++ ++#ifdef CONFIG_PROC_FS ++ /* set up the proc fs entry */ ++ ++ len = strlen(ADAPTERS_PROC_DIR); ++ ++ for(e1000_proc_dir = proc_net->subdir; e1000_proc_dir; ++ e1000_proc_dir = e1000_proc_dir->next) { ++ if((e1000_proc_dir->namelen == len) && ++ (memcmp(e1000_proc_dir->name, ADAPTERS_PROC_DIR, len) == 0)) ++ break; ++ } ++ ++ if(e1000_proc_dir == NULL) ++ e1000_proc_dir = ++ create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net); ++ ++ if(e1000_proc_dir != NULL) ++ if(e1000_create_proc_dev(adapter) < 0) { ++ e1000_remove_proc_dev(adapter->netdev); ++ } ++#endif ++ ++ /* print the link status */ ++ ++ if(adapter->link_active == 1) ++ printk("%s: Mem:0x%p IRQ:%d Speed:%d Mbps Duplex:%s\n", ++ netdev->name, (void *) netdev->mem_start, netdev->irq, ++ adapter->link_speed, ++ adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half"); ++ else ++ printk("%s: Mem:0x%p IRQ:%d Speed:N/A Duplex:N/A\n", netdev->name, ++ (void *) netdev->mem_start, netdev->irq); ++ ++ return 0; ++} ++ ++/** ++ * e1000_remove - Device Removal Routine ++ * @pdev: PCI device information struct ++ * ++ * e1000_remove is called by the PCI subsystem to alert the driver ++ * that it should release a PCI device. The could be caused by a ++ * Hot-Plug event, or because the driver is going to be removed from ++ * memory. ++ * ++ * This routine is also called to clean up from a failure in ++ * e1000_probe. The Adapter struct and netdev will always exist, ++ * all other pointers must be checked for NULL before freeing. ++ **/ ++ ++void ++e1000_remove(struct pci_dev *pdev) ++{ ++ struct net_device *netdev; ++ struct e1000_adapter *adapter; ++ ++ /* find the Adapter struct that matches this PCI device */ ++ ++ for(adapter = e1000_adapter_list; adapter != NULL; adapter = adapter->next) { ++ if(adapter->pdev == pdev) ++ break; ++ } ++ if(adapter == NULL) ++ return; ++ ++ netdev = adapter->netdev; ++ ++ /* this must be called before freeing anything, ++ * otherwise there is a case where the open entry point can be ++ * running at the same time as remove. Calling unregister_netdev on an ++ * open interface results in a call to dev_close, which locks ++ * properly against the other netdev entry points, so this takes ++ * care of the hotplug issue of removing an active interface as well. ++ */ ++ unregister_netdev(netdev); ++ ++ e1000_phy_hw_reset(&adapter->shared); ++ ++#ifdef CONFIG_PROC_FS ++ /* remove the proc nodes */ ++ ++ if(e1000_proc_dir != NULL) ++ e1000_remove_proc_dev(adapter->netdev); ++#endif ++ ++ /* remove from the adapter list */ ++ ++ if(e1000_adapter_list == adapter) ++ e1000_adapter_list = adapter->next; ++ if(adapter->next != NULL) ++ adapter->next->prev = adapter->prev; ++ if(adapter->prev != NULL) ++ adapter->prev->next = adapter->next; ++ ++ /* free system resources */ ++ ++#ifdef IANS ++ if(adapter->iANSdata != NULL) ++ kfree(adapter->iANSdata); ++#endif ++ ++ if(adapter->shared.hw_addr != NULL) { ++ iounmap((void *) adapter->shared.hw_addr); ++ release_mem_region(pci_resource_start(pdev, BAR_0), ++ pci_resource_len(pdev, BAR_0)); ++ } ++ ++ /* free the net_device _and_ struct e1000_adapter memory */ ++ ++ kfree(netdev); ++ ++ return; ++} ++ ++/** ++ * e1000_check_options - Range Checking for Command Line Parameters ++ * @adapter: board private structure ++ * ++ * This routine checks all command line paramters for valid user ++ * input. If an invalid value is given, or if no user specified ++ * value exists, a default value is used. The final value is stored ++ * in a variable in the Adapter structure. ++ **/ ++ ++static void ++e1000_check_options(struct e1000_adapter *adapter) ++{ ++ int board = adapter->bd_number; ++ ++ if(board >= E1000_MAX_NIC) { ++ printk("Warning: no configuration for board #%i\n", board); ++ printk("Using defaults for all values\n"); ++ board = E1000_MAX_NIC; ++ } ++ ++ E1000_DBG("e1000_check_options\n"); ++ ++ /* Transmit Descriptor Count */ ++ ++ if(TxDescriptors[board] == OPTION_UNSET) { ++ adapter->tx_ring.count = DEFAULT_TXD; ++ TxDescriptors[board] = DEFAULT_TXD; ++ } else ++ if(((TxDescriptors[board] > MAX_TXD) || ++ (TxDescriptors[board] < MIN_TXD)) && ++ (adapter->shared.mac_type <= e1000_82543)) { ++ printk("Invalid TxDescriptors specified (%i), using default %i\n", ++ TxDescriptors[board], DEFAULT_TXD); ++ adapter->tx_ring.count = DEFAULT_TXD; ++ } else ++ if(((TxDescriptors[board] > MAX_82544_TXD) || ++ (TxDescriptors[board] < MIN_TXD)) && ++ (adapter->shared.mac_type > e1000_82543)) { ++ printk("Invalid TxDescriptors specified (%i), using default %i\n", ++ TxDescriptors[board], DEFAULT_TXD); ++ adapter->tx_ring.count = DEFAULT_TXD; ++ } else { ++ printk("Using specified value of %i TxDescriptors\n", ++ TxDescriptors[board]); ++ adapter->tx_ring.count = TxDescriptors[board]; ++ } ++ ++ /* tx_ring.count must be a multiple of 8 */ ++ ++ adapter->tx_ring.count = E1000_ROUNDUP2(adapter->tx_ring.count, ++ REQ_TX_DESCRIPTOR_MULTIPLE); ++ ++ /* Receive Descriptor Count */ ++ ++ if(RxDescriptors[board] == OPTION_UNSET) { ++ adapter->rx_ring.count = DEFAULT_RXD; ++ RxDescriptors[board] = DEFAULT_RXD; ++ } else ++ if(((RxDescriptors[board] > MAX_RXD) || ++ (RxDescriptors[board] < MIN_RXD)) && ++ (adapter->shared.mac_type <= e1000_82543)) { ++ printk("Invalid RxDescriptors specified (%i), using default %i\n", ++ RxDescriptors[board], DEFAULT_RXD); ++ adapter->rx_ring.count = DEFAULT_RXD; ++ } else ++ if(((RxDescriptors[board] > MAX_82544_RXD) || ++ (RxDescriptors[board] < MIN_RXD)) && ++ (adapter->shared.mac_type > e1000_82543)) { ++ printk("Invalid RxDescriptors specified (%i), using default %i\n", ++ RxDescriptors[board], DEFAULT_RXD); ++ adapter->rx_ring.count = DEFAULT_RXD; ++ } else { ++ printk("Using specified value of %i RxDescriptors\n", ++ RxDescriptors[board]); ++ adapter->rx_ring.count = RxDescriptors[board]; ++ } ++ ++ /* rx_ring.count must be a multiple of 8 */ ++ ++ adapter->rx_ring.count = ++ E1000_ROUNDUP2(adapter->rx_ring.count, REQ_RX_DESCRIPTOR_MULTIPLE); ++ ++ /* Receive Checksum Offload Enable */ ++ ++ if(XsumRX[board] == OPTION_UNSET) { ++ adapter->RxChecksum = XSUMRX_DEFAULT; ++ XsumRX[board] = XSUMRX_DEFAULT; ++ } else if((XsumRX[board] != OPTION_ENABLED) && ++ (XsumRX[board] != OPTION_DISABLED)) { ++ printk("Invalid XsumRX specified (%i), using default of %i\n", ++ XsumRX[board], XSUMRX_DEFAULT); ++ adapter->RxChecksum = XSUMRX_DEFAULT; ++ } else { ++ printk("Receive Checksum Offload %s\n", ++ XsumRX[board] == OPTION_ENABLED ? "Enabled" : "Disabled"); ++ adapter->RxChecksum = XsumRX[board]; ++ } ++ ++ /* Flow Control */ ++ ++ if(FlowControl[board] == OPTION_UNSET) { ++ adapter->shared.fc = e1000_fc_default; ++ FlowControl[board] = e1000_fc_default; ++ } else if((FlowControl[board] > e1000_fc_full) || ++ (FlowControl[board] < e1000_fc_none)) { ++ printk("Invalid FlowControl specified (%i), " ++ "reading default settings from the EEPROM\n", ++ FlowControl[board]); ++ adapter->shared.fc = e1000_fc_default; ++ } else { ++ adapter->shared.fc = FlowControl[board]; ++ switch (adapter->shared.fc) { ++ case e1000_fc_none: ++ printk("Flow Control Disabled\n"); ++ break; ++ case e1000_fc_rx_pause: ++ printk("Flow Control Receive Only\n"); ++ break; ++ case e1000_fc_tx_pause: ++ printk("Flow Control Transmit Only\n"); ++ break; ++ case e1000_fc_full: ++ printk("Flow Control Enabled\n"); ++ case e1000_fc_default: ++ printk("Flow Control Hardware Default\n"); ++ } ++ } ++ ++ /* Transmit Interrupt Delay */ ++ ++ if(TxIntDelay[board] == OPTION_UNSET) { ++ adapter->tx_int_delay = DEFAULT_TIDV; ++ TxIntDelay[board] = DEFAULT_TIDV; ++ } else if((TxIntDelay[board] > MAX_TIDV) || (TxIntDelay[board] < MIN_TIDV)) { ++ printk("Invalid TxIntDelay specified (%i), using default %i\n", ++ TxIntDelay[board], DEFAULT_TIDV); ++ adapter->tx_int_delay = DEFAULT_TIDV; ++ } else { ++ printk("Using specified TxIntDelay of %i\n", TxIntDelay[board]); ++ adapter->tx_int_delay = TxIntDelay[board]; ++ } ++ ++ /* Receive Interrupt Delay */ ++ ++ if(RxIntDelay[board] == OPTION_UNSET) { ++ adapter->rx_int_delay = DEFAULT_RIDV; ++ RxIntDelay[board] = DEFAULT_RIDV; ++ } else if((RxIntDelay[board] > MAX_RIDV) || (RxIntDelay[board] < MIN_RIDV)) { ++ printk("Invalid RxIntDelay specified (%i), using default %i\n", ++ RxIntDelay[board], DEFAULT_RIDV); ++ adapter->rx_int_delay = DEFAULT_RIDV; ++ } else { ++ printk("Using specified RxIntDelay of %i\n", RxIntDelay[board]); ++ adapter->rx_int_delay = RxIntDelay[board]; ++ } ++ ++ if(adapter->shared.media_type == e1000_media_type_copper) { ++ /* MDI/MDI-X Support */ ++ ++ if(MdiX[board] == OPTION_UNSET) { ++ adapter->shared.mdix = DEFAULT_MDIX; ++ MdiX[board] = DEFAULT_MDIX; ++ } else if((MdiX[board] > MAX_MDIX) || (MdiX[board] < MIN_MDIX)) { ++ printk("Invalid MDI/MDI-X specified (%i), using default %i\n", ++ MdiX[board], DEFAULT_MDIX); ++ adapter->shared.mdix = DEFAULT_MDIX; ++ } else { ++ printk("Using specified MDI/MDI-X of %i\n", MdiX[board]); ++ adapter->shared.mdix = MdiX[board]; ++ } ++ ++ /* Automatic Correction for Reverse Cable Polarity */ ++ ++ if(DisablePolarityCorrection[board] == OPTION_UNSET) { ++ adapter->shared.disable_polarity_correction = OPTION_DISABLED; ++ DisablePolarityCorrection[board] = OPTION_DISABLED; ++ } else if((DisablePolarityCorrection[board] != OPTION_ENABLED) && ++ (DisablePolarityCorrection[board] != OPTION_DISABLED)) { ++ printk("Invalid polarity correction specified (%i)," ++ " using default %i\n", DisablePolarityCorrection[board], ++ OPTION_DISABLED); ++ adapter->shared.disable_polarity_correction = OPTION_DISABLED; ++ } else { ++ printk("Using specified polarity correction of %i\n", ++ DisablePolarityCorrection[board]); ++ adapter->shared.disable_polarity_correction = ++ DisablePolarityCorrection[board]; ++ } ++ } ++ ++ /* Speed, Duplex, and AutoNeg */ ++ ++ switch (adapter->shared.media_type) { ++ ++ case e1000_media_type_fiber: ++ e1000_check_fiber_options(adapter); ++ break; ++ ++ case e1000_media_type_copper: ++ e1000_check_copper_options(adapter); ++ break; ++ ++ default: ++ printk("Unknown Media Type\n"); ++ break; ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version ++ * @adapter: board private structure ++ * ++ * Handles speed and duplex options on fiber based adapters ++ **/ ++ ++static void ++e1000_check_fiber_options(struct e1000_adapter *adapter) ++{ ++ int board = ++ adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number; ++ ++ E1000_DBG("CheckSpeedDuplexFiber\n"); ++ ++ /* Speed, Duplex, and AutoNeg are not valid on fiber NICs */ ++ ++ if((Speed[board] != OPTION_UNSET)) { ++ Speed[board] = 0; ++ printk("Warning: Speed not valid for fiber adapters\n"); ++ printk("Speed Parameter Ignored\n"); ++ } ++ if((Duplex[board] != OPTION_UNSET)) { ++ Duplex[board] = 0; ++ printk("Warning: Duplex not valid for fiber adapters\n"); ++ printk("Duplex Parameter Ignored\n"); ++ } ++ if((AutoNeg[board] != OPTION_UNSET)) { ++ AutoNeg[board] = AUTONEG_ADV_DEFAULT; ++ printk("Warning: AutoNeg not valid for fiber adapters\n"); ++ printk("AutoNeg Parameter Ignored\n"); ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_check_copper_options - Range Checking for Link Options, Copper Version ++ * @adapter: board private structure ++ * ++ * Handles speed and duplex options on copper based adapters ++ **/ ++ ++static void ++e1000_check_copper_options(struct e1000_adapter *adapter) ++{ ++ int board = ++ adapter->bd_number > E1000_MAX_NIC ? E1000_MAX_NIC : adapter->bd_number; ++ int speed, duplex; ++ boolean_t all_default = TRUE; ++ ++ E1000_DBG("CheckSpeedDuplexCopper\n"); ++ ++ /* User Specified Auto-negotiation Settings */ ++ ++ if(AutoNeg[board] == OPTION_UNSET) { ++ ++ adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; ++ AutoNeg[board] = AUTONEG_ADV_DEFAULT; ++ ++ } else if((Speed[board] != 0 && Speed[board] != OPTION_UNSET) || ++ (Duplex[board] != 0 && Duplex[board] != OPTION_UNSET)) { ++ ++ printk("Warning: AutoNeg specified along with Speed or Duplex\n"); ++ printk("AutoNeg Parameter Ignored\n"); ++ ++ adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; ++ ++ } else { ++ ++ if(AutoNeg[board] & ~AUTONEG_ADV_MASK) { ++ ++ printk("Invalid AutoNeg Specified (0x%X), Parameter Ignored\n", ++ AutoNeg[board]); ++ ++ adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; ++ ++ } else { ++ ++ adapter->shared.autoneg_advertised = AutoNeg[board]; ++ } ++ ++ printk("AutoNeg Advertising "); ++ if(adapter->shared.autoneg_advertised & ADVERTISE_1000_FULL) { ++ printk("1000/FD"); ++ if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_FULL - 1)) ++ printk(", "); ++ } ++ if(adapter->shared.autoneg_advertised & ADVERTISE_1000_HALF) { ++ printk("1000/HD"); ++ if(adapter->shared.autoneg_advertised & (ADVERTISE_1000_HALF - 1)) ++ printk(", "); ++ } ++ if(adapter->shared.autoneg_advertised & ADVERTISE_100_FULL) { ++ printk("100/FD"); ++ if(adapter->shared.autoneg_advertised & (ADVERTISE_100_FULL - 1)) ++ printk(", "); ++ } ++ if(adapter->shared.autoneg_advertised & ADVERTISE_100_HALF) { ++ printk("100/HD"); ++ if(adapter->shared.autoneg_advertised & (ADVERTISE_100_HALF - 1)) ++ printk(", "); ++ } ++ if(adapter->shared.autoneg_advertised & ADVERTISE_10_FULL) { ++ printk("10/FD"); ++ if(adapter->shared.autoneg_advertised & (ADVERTISE_10_FULL - 1)) ++ printk(", "); ++ } ++ if(adapter->shared.autoneg_advertised & ADVERTISE_10_HALF) ++ printk("10/HD"); ++ printk("\n"); ++ } ++ ++ /* Forced Speed and Duplex */ ++ ++ switch (Speed[board]) { ++ default: ++ printk("Invalid Speed Specified (%i), Parameter Ignored\n", ++ Speed[board]); ++ all_default = FALSE; ++ case OPTION_UNSET: ++ speed = 0; ++ Speed[board] = 0; ++ break; ++ case 0: ++ case 10: ++ case 100: ++ case 1000: ++ speed = Speed[board]; ++ all_default = FALSE; ++ break; ++ } ++ ++ switch (Duplex[board]) { ++ default: ++ printk("Invalid Duplex Specified (%i), Parameter Ignored\n", ++ Duplex[board]); ++ all_default = FALSE; ++ case OPTION_UNSET: ++ duplex = 0; ++ Duplex[board] = 0; ++ break; ++ case 0: ++ case 1: ++ case 2: ++ duplex = Duplex[board]; ++ all_default = FALSE; ++ break; ++ } ++ ++ switch (speed + duplex) { ++ case 0: ++ if(all_default == FALSE) ++ printk("Speed and Duplex Auto-negotiation Enabled\n"); ++ adapter->shared.autoneg = 1; ++ break; ++ case 1: ++ printk("Warning: Half Duplex specified without Speed\n"); ++ printk("Using Auto-negotiation at Half Duplex only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ++ ADVERTISE_10_HALF | ADVERTISE_100_HALF; ++ break; ++ case 2: ++ printk("Warning: Full Duplex specified without Speed\n"); ++ printk("Using Auto-negotiation at Full Duplex only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ++ ADVERTISE_10_FULL | ADVERTISE_100_FULL | ADVERTISE_1000_FULL; ++ break; ++ case 10: ++ printk("Warning: 10 Mbps Speed specified without Duplex\n"); ++ printk("Using Auto-negotiation at 10 Mbps only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ++ ADVERTISE_10_HALF | ADVERTISE_10_FULL; ++ break; ++ case 11: ++ printk("Forcing to 10 Mbps Half Duplex\n"); ++ adapter->shared.autoneg = 0; ++ adapter->shared.forced_speed_duplex = e1000_10_half; ++ adapter->shared.autoneg_advertised = 0; ++ break; ++ case 12: ++ printk("Forcing to 10 Mbps Full Duplex\n"); ++ adapter->shared.autoneg = 0; ++ adapter->shared.forced_speed_duplex = e1000_10_full; ++ adapter->shared.autoneg_advertised = 0; ++ break; ++ case 100: ++ printk("Warning: 100 Mbps Speed specified without Duplex\n"); ++ printk("Using Auto-negotiation at 100 Mbps only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ++ ADVERTISE_100_HALF | ADVERTISE_100_FULL; ++ break; ++ case 101: ++ printk("Forcing to 100 Mbps Half Duplex\n"); ++ adapter->shared.autoneg = 0; ++ adapter->shared.forced_speed_duplex = e1000_100_half; ++ adapter->shared.autoneg_advertised = 0; ++ break; ++ case 102: ++ printk("Forcing to 100 Mbps Full Duplex\n"); ++ adapter->shared.autoneg = 0; ++ adapter->shared.forced_speed_duplex = e1000_100_full; ++ adapter->shared.autoneg_advertised = 0; ++ break; ++ case 1000: ++ printk("Warning: 1000 Mbps Speed specified without Duplex\n"); ++ printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ case 1001: ++ printk("Warning: Half Duplex is not supported at 1000 Mbps\n"); ++ printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ case 1002: ++ printk("Using Auto-negotiation at 1000 Mbps Full Duplex only\n"); ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ default: ++ panic("something is wrong in e1000_check_copper_options"); ++ } ++ ++ /* Speed, AutoNeg and MDI/MDI-X */ ++ if (!e1000_validate_mdi_setting(&(adapter->shared))) { ++ printk ("Speed, AutoNeg and MDI-X specifications are incompatible." ++ " Setting MDI-X to a compatible value.\n"); ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_sw_init - Initialize general software structures (struct e1000_adapter) ++ * @adapter: board private structure to initialize ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * e1000_sw_init initializes the Adapter private data structure. ++ * Fields are initialized based on PCI device information and ++ * OS network device settings (MTU size). ++ **/ ++ ++static int ++e1000_sw_init(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ uint32_t status; ++ ++ E1000_DBG("e1000_sw_init\n"); ++ ++ /* PCI config space info */ ++ ++ pci_read_config_word(pdev, PCI_VENDOR_ID, &adapter->vendor_id); ++ pci_read_config_word(pdev, PCI_DEVICE_ID, &adapter->device_id); ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->rev_id); ++ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &adapter->subven_id); ++ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &adapter->subsys_id); ++ pci_read_config_word(pdev, PCI_COMMAND, &adapter->shared.pci_cmd_word); ++ adapter->shared.vendor_id = adapter->vendor_id; ++ adapter->shared.device_id = adapter->device_id; ++ adapter->shared.revision_id = adapter->rev_id; ++ adapter->shared.subsystem_vendor_id = adapter->subven_id; ++ adapter->shared.subsystem_id = adapter->subsys_id; ++ ++ /* Initial Receive Buffer Length */ ++ ++ if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_2048) ++ adapter->rx_buffer_len = E1000_RXBUFFER_2048; ++ else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_4096) ++ adapter->rx_buffer_len = E1000_RXBUFFER_4096; ++ else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_8192) ++ adapter->rx_buffer_len = E1000_RXBUFFER_8192; ++ else ++ adapter->rx_buffer_len = E1000_RXBUFFER_16384; ++ ++ adapter->shared.max_frame_size = ++ netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH; ++ adapter->shared.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH; ++ ++ /* MAC and Phy settings */ ++ ++ switch (adapter->device_id) { ++ case E1000_DEV_ID_82542: ++ switch (adapter->rev_id) { ++ case E1000_82542_2_0_REV_ID: ++ adapter->shared.mac_type = e1000_82542_rev2_0; ++ break; ++ case E1000_82542_2_1_REV_ID: ++ adapter->shared.mac_type = e1000_82542_rev2_1; ++ break; ++ default: ++ adapter->shared.mac_type = e1000_82542_rev2_0; ++ E1000_ERR("Could not identify 82542 revision\n"); ++ } ++ break; ++ case E1000_DEV_ID_82543GC_FIBER: ++ case E1000_DEV_ID_82543GC_COPPER: ++ adapter->shared.mac_type = e1000_82543; ++ break; ++ case E1000_DEV_ID_82544EI_COPPER: ++ case E1000_DEV_ID_82544EI_FIBER: ++ case E1000_DEV_ID_82544GC_COPPER: ++ case E1000_DEV_ID_82544GC_LOM: ++ adapter->shared.mac_type = e1000_82544; ++ break; ++ case E1000_DEV_ID_82540EM: ++ adapter->shared.mac_type = e1000_82540; ++ break; ++ default: ++ E1000_ERR("Could not identify hardware\n"); ++ return -ENODEV; ++ } ++ ++ adapter->shared.fc_high_water = FC_DEFAULT_HI_THRESH; ++ adapter->shared.fc_low_water = FC_DEFAULT_LO_THRESH; ++ adapter->shared.fc_pause_time = FC_DEFAULT_TX_TIMER; ++ adapter->shared.fc_send_xon = 1; ++ ++ /* Identify the Hardware - this is done by the gigabit shared code ++ * in e1000_init_hw, but it would help to identify the NIC ++ * before bringing the hardware online for use in e1000_check_options. ++ */ ++ if(adapter->shared.mac_type >= e1000_82543) { ++ status = E1000_READ_REG(&adapter->shared, STATUS); ++ if(status & E1000_STATUS_TBIMODE) { ++ adapter->shared.media_type = e1000_media_type_fiber; ++ } else { ++ adapter->shared.media_type = e1000_media_type_copper; ++ } ++ } else { ++ adapter->shared.media_type = e1000_media_type_fiber; ++ } ++ ++ if((E1000_REPORT_TX_EARLY == 0) || (E1000_REPORT_TX_EARLY == 1)) { ++ adapter->shared.report_tx_early = E1000_REPORT_TX_EARLY; ++ } else { ++ if(adapter->shared.mac_type < e1000_82543) { ++ ++ adapter->shared.report_tx_early = 0; ++ } else { ++ adapter->shared.report_tx_early = 1; ++ } ++ } ++ ++ adapter->shared.wait_autoneg_complete = WAITFORLINK_DEFAULT; ++ ++ adapter->shared.tbi_compatibility_en = 1; ++ ++ atomic_set(&adapter->tx_timeout, 0); ++ ++ spin_lock_init(&adapter->stats_lock); ++ spin_lock_init(&adapter->rx_fill_lock); ++ ++ return 0; ++} ++ ++/** ++ * e1000_hw_init - prepare the hardware ++ * @adapter: board private struct containing configuration ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * Initialize the hardware to a configuration as specified by the ++ * Adapter structure. The controler is reset, the EEPROM is ++ * verified, the MAC address is set, then the shared initilization ++ * routines are called. ++ **/ ++ ++static int ++e1000_hw_init(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ ++ E1000_DBG("e1000_hw_init\n"); ++ ++ /* Repartition Pba for greater than 9k mtu ++ * To take effect Ctrl_Rst is required. ++ */ ++ if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) ++ E1000_WRITE_REG(&adapter->shared, PBA, E1000_JUMBO_PBA); ++ else ++ E1000_WRITE_REG(&adapter->shared, PBA, E1000_DEFAULT_PBA); ++ ++ /* Issue a global reset */ ++ ++ adapter->shared.adapter_stopped = 0; ++ e1000_adapter_stop(&adapter->shared); ++ adapter->shared.adapter_stopped = 0; ++ ++ /* make sure the EEPROM is good */ ++ ++ if(!e1000_validate_eeprom_checksum(&adapter->shared)) { ++ E1000_ERR("The EEPROM Checksum Is Not Valid\n"); ++ return -1; ++ } ++ ++ /* copy the MAC address out of the EEPROM */ ++ ++ e1000_read_address(adapter, adapter->perm_net_addr); ++ memcpy(netdev->dev_addr, adapter->perm_net_addr, netdev->addr_len); ++ memcpy(adapter->shared.mac_addr, netdev->dev_addr, netdev->addr_len); ++ ++ e1000_read_part_num(&adapter->shared, &(adapter->part_num)); ++ ++ if(!e1000_init_hw(&adapter->shared)) { ++ E1000_ERR("Hardware Initialization Failed\n"); ++ return -1; ++ } ++ ++ e1000_enable_WOL(adapter); ++ ++ adapter->shared.get_link_status = 1; ++ e1000_check_for_link(&adapter->shared); ++ ++ if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) ++ adapter->link_active = TRUE; ++ else ++ adapter->link_active = FALSE; ++ ++ if(adapter->link_active == TRUE) { ++ e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, ++ &adapter->link_duplex); ++ } else { ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ } ++ ++ e1000_get_bus_info(&adapter->shared); ++ ++ return 0; ++} ++ ++/** ++ * e1000_read_address - Reads the MAC address from the EEPROM ++ * @adapter: board private structure ++ * @addr: pointer to an array of bytes ++ **/ ++ ++static void ++e1000_read_address(struct e1000_adapter *adapter, ++ uint8_t *addr) ++{ ++ uint16_t eeprom_word; ++ int i; ++ ++ E1000_DBG("e1000_read_address\n"); ++ ++ for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { ++ eeprom_word = ++ e1000_read_eeprom(&adapter->shared, ++ EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); ++ addr[i] = (uint8_t) (eeprom_word & 0x00FF); ++ addr[i + 1] = (uint8_t) (eeprom_word >> 8); ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_open - Called when a network interface is made active ++ * @netdev: network interface device structure ++ * ++ * Returns 0 on success, negative value on failure ++ * ++ * The open entry point is called when a network interface is made ++ * active by the system (IFF_UP). At this point all resources needed ++ * for transmit and receive operations are allocated, the interrupt ++ * handler is registered with the OS, the watchdog timer is started, ++ * and the stack is notified that the interface is ready. ++ **/ ++ ++int ++e1000_open(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ ++ E1000_DBG("e1000_open\n"); ++ ++ /* prevent multiple opens when dealing with iANS */ ++ ++ if(test_and_set_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ return -EBUSY; ++ } ++ ++ adapter->shared.fc = adapter->shared.original_fc; ++ ++ /* e1000_close issues a global reset (e1000_adapter_stop) ++ * so e1000_hw_init must be called again or the hardware ++ * will resume in it's default state ++ */ ++ if(e1000_hw_init(adapter) < 0) { ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ return -EBUSY; ++ } ++#ifdef IANS ++ /* restore VLAN settings */ ++ if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) != ++ IANS_BD_TAGGING_NONE) ++ bd_ans_hw_EnableVLAN(adapter); ++#endif ++ ++ adapter->shared.adapter_stopped = 0; ++ ++ /* allocate transmit descriptors */ ++ ++ if(e1000_setup_tx_resources(adapter) != 0) { ++ e1000_adapter_stop(&adapter->shared); ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ return -ENOMEM; ++ } ++ e1000_configure_tx(adapter); ++ ++ /* allocate receive descriptors and buffers */ ++ ++ if(e1000_setup_rx_resources(adapter) != 0) { ++ e1000_adapter_stop(&adapter->shared); ++ e1000_free_tx_resources(adapter); ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ return -ENOMEM; ++ } ++ e1000_setup_rctl(adapter); ++ e1000_configure_rx(adapter); ++ ++ /* hook the interrupt */ ++ ++ if(request_irq(netdev->irq, &e1000_intr, ++ SA_SHIRQ, e1000_driver_name, netdev) != 0) { ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ e1000_adapter_stop(&adapter->shared); ++ e1000_free_tx_resources(adapter); ++ e1000_free_rx_resources(adapter); ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ return -EBUSY; ++ } ++ ++ /* fill Rx ring with sk_buffs */ ++ ++ tasklet_init(&adapter->rx_fill_tasklet, e1000_alloc_rx_buffers, ++ (unsigned long) adapter); ++ ++ tasklet_schedule(&adapter->rx_fill_tasklet); ++ ++ /* Set the watchdog timer for 2 seconds */ ++ ++ init_timer(&adapter->timer_id); ++ adapter->timer_id.function = &e1000_watchdog; ++ adapter->timer_id.data = (unsigned long) netdev; ++ mod_timer(&adapter->timer_id, (jiffies + 2 * HZ)); ++ ++ /* stats accumulated while down are dropped ++ * this does not clear the running total ++ */ ++ ++ e1000_clear_hw_cntrs(&adapter->shared); ++ ++ adapter->int_mask = IMS_ENABLE_MASK; ++ e1000_irq_enable(adapter); ++ netif_start_queue(netdev); ++ ++#ifdef MODULE ++ ++ /* Incrementing the module use count prevents a driver from being ++ * unloaded while an active network interface is using it. ++ */ ++ MOD_INC_USE_COUNT; ++ ++#endif ++ ++ return 0; ++} ++ ++/** ++ * e1000_close - Disables a network interface ++ * @netdev: network interface device structure ++ * ++ * Returns 0, this is not allowed to fail ++ * ++ * The close entry point is called when an interface is de-activated ++ * by the OS. The hardware is still under the drivers control, but ++ * needs to be disabled. A global MAC reset is issued to stop the ++ * hardware, and all transmit and receive resources are freed. ++ **/ ++ ++int ++e1000_close(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ ++ E1000_DBG("e1000_close\n"); ++ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ return 0; ++ ++ /* Issue a global reset */ ++ ++ e1000_adapter_stop((&adapter->shared)); ++ ++ /* Enable receiver unit after Global reset ++ * for WOL, so that receiver can still recive ++ * wake up packet and will not drop it. ++ */ ++ if(adapter->shared.mac_type > e1000_82543) ++ E1000_WRITE_REG(&adapter->shared, RCTL, E1000_RCTL_EN); ++ ++ /* free OS resources */ ++ ++ netif_stop_queue(netdev); ++ free_irq(netdev->irq, netdev); ++ del_timer_sync(&adapter->timer_id); ++ ++ /* Make sure the tasklet won't be left after ifconfig down */ ++ ++ /* ++ * Assumption: tasklet is ALREADY enabled, ie, t->count == 0. ++ * Otherwise, tasklet is still left in the tasklet list, and, ++ * tasklet_kill will not be able to return (hang). ++ */ ++ tasklet_kill(&adapter->rx_fill_tasklet); ++ ++ /* free software resources */ ++ ++ e1000_free_tx_resources(adapter); ++ e1000_free_rx_resources(adapter); ++ ++#ifdef MODULE ++ ++ /* decrement the module usage count ++ * so that the driver can be unloaded ++ */ ++ MOD_DEC_USE_COUNT; ++ ++#endif ++ ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ return 0; ++} ++ ++/** ++ * e1000_setup_tx_resources - allocate Tx resources (Descriptors) ++ * @adapter: board private structure ++ * ++ * Return 0 on success, negative on failure ++ * ++ * e1000_setup_tx_resources allocates all software transmit resources ++ * and enabled the Tx unit of the MAC. ++ **/ ++ ++static int ++e1000_setup_tx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ int size; ++ ++ E1000_DBG("e1000_setup_tx_resources\n"); ++ ++ size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; ++ adapter->tx_ring.buffer_info = kmalloc(size, GFP_KERNEL); ++ if(adapter->tx_ring.buffer_info == NULL) { ++ return -ENOMEM; ++ } ++ memset(adapter->tx_ring.buffer_info, 0, size); ++ ++ /* round up to nearest 4K */ ++ ++ adapter->tx_ring.size = E1000_ROUNDUP2(adapter->tx_ring.count * ++ sizeof(struct e1000_tx_desc), ++ 4096); ++ ++ adapter->tx_ring.desc = pci_alloc_consistent(pdev, adapter->tx_ring.size, ++ &adapter->tx_ring.dma); ++ if(adapter->tx_ring.desc == NULL) { ++ kfree(adapter->tx_ring.buffer_info); ++ return -ENOMEM; ++ } ++ memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); ++ ++ atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); ++ adapter->tx_ring.next_to_use = 0; ++ adapter->tx_ring.next_to_clean = 0; ++ ++ return 0; ++} ++ ++/** ++ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset ++ * @adapter: board private structure ++ * ++ * Configure the Tx unit of the MAC after a reset. ++ **/ ++ ++static void ++e1000_configure_tx(struct e1000_adapter *adapter) ++{ ++ uint32_t tctl, tipg; ++ ++ /* Setup the Base and Length of the Rx Descriptor Ring */ ++ /* tx_ring.dma can be either a 32 or 64 bit value */ ++ ++#if (BITS_PER_LONG == 32) ++ E1000_WRITE_REG(&adapter->shared, TDBAL, adapter->tx_ring.dma); ++ E1000_WRITE_REG(&adapter->shared, TDBAH, 0); ++#elif ( BITS_PER_LONG == 64) ++ E1000_WRITE_REG(&adapter->shared, TDBAL, ++ (uint32_t) (adapter->tx_ring.dma & 0x00000000FFFFFFFF)); ++ E1000_WRITE_REG(&adapter->shared, TDBAH, ++ (uint32_t) (adapter->tx_ring.dma >> 32)); ++#else ++#error "Unsupported System - does not use 32 or 64 bit pointers!" ++#endif ++ ++ E1000_WRITE_REG(&adapter->shared, TDLEN, ++ adapter->tx_ring.count * sizeof(struct e1000_tx_desc)); ++ ++ /* Setup the HW Tx Head and Tail descriptor pointers */ ++ ++ E1000_WRITE_REG(&adapter->shared, TDH, 0); ++ E1000_WRITE_REG(&adapter->shared, TDT, 0); ++ ++ /* Set the default values for the Tx Inter Packet Gap timer */ ++ ++ switch (adapter->shared.mac_type) { ++ case e1000_82543: ++ case e1000_82544: ++ case e1000_82540: ++ if(adapter->shared.media_type == e1000_media_type_fiber) ++ tipg = DEFAULT_82543_TIPG_IPGT_FIBER; ++ else ++ tipg = DEFAULT_82543_TIPG_IPGT_COPPER; ++ tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; ++ tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; ++ break; ++ case e1000_82542_rev2_0: ++ case e1000_82542_rev2_1: ++ default: ++ tipg = DEFAULT_82542_TIPG_IPGT; ++ tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; ++ tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; ++ break; ++ } ++ E1000_WRITE_REG(&adapter->shared, TIPG, tipg); ++ ++ /* Set the Tx Interrupt Delay register */ ++ ++ E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay); ++ ++ /* Program the Transmit Control Register */ ++ ++ tctl = ++ E1000_TCTL_PSP | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << ++ E1000_CT_SHIFT); ++ if(adapter->link_duplex == FULL_DUPLEX) { ++ tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; ++ } else { ++ tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; ++ } ++ E1000_WRITE_REG(&adapter->shared, TCTL, tctl); ++ ++#ifdef CONFIG_PPC ++ if(adapter->shared.mac_type >= e1000_82543) { ++ E1000_WRITE_REG(&adapter->shared, TXDCTL, 0x00020000); ++ } ++#endif ++ ++ /* Setup Transmit Descriptor Settings for this adapter */ ++ adapter->TxdCmd = E1000_TXD_CMD_IFCS; ++ ++ if(adapter->tx_int_delay > 0) ++ adapter->TxdCmd |= E1000_TXD_CMD_IDE; ++ if(adapter->shared.report_tx_early == 1) ++ adapter->TxdCmd |= E1000_TXD_CMD_RS; ++ else ++ adapter->TxdCmd |= E1000_TXD_CMD_RPS; ++ ++ adapter->ActiveChecksumContext = OFFLOAD_NONE; ++ ++ return; ++} ++ ++/** ++ * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs) ++ * @adapter: board private structure ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * e1000_setup_rx_resources allocates all software receive resources ++ * and network buffers, and enables the Rx unit of the MAC. ++ **/ ++ ++static int ++e1000_setup_rx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ int size; ++ ++ E1000_DBG("e1000_setup_rx_resources\n"); ++ ++ size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; ++ adapter->rx_ring.buffer_info = kmalloc(size, GFP_KERNEL); ++ if(adapter->rx_ring.buffer_info == NULL) { ++ return -ENOMEM; ++ } ++ memset(adapter->rx_ring.buffer_info, 0, size); ++ ++ /* Round up to nearest 4K */ ++ ++ adapter->rx_ring.size = E1000_ROUNDUP2(adapter->rx_ring.count * ++ sizeof(struct e1000_rx_desc), ++ 4096); ++ ++ adapter->rx_ring.desc = pci_alloc_consistent(pdev, adapter->rx_ring.size, ++ &adapter->rx_ring.dma); ++ ++ if(adapter->rx_ring.desc == NULL) { ++ kfree(adapter->rx_ring.buffer_info); ++ return -ENOMEM; ++ } ++ memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); ++ ++ adapter->rx_ring.next_to_clean = 0; ++ atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count); ++ ++ adapter->rx_ring.next_to_use = 0; ++ ++ return 0; ++} ++ ++/** ++ * e1000_setup_rctl - configure the receive control register ++ * @adapter: Board private structure ++ **/ ++ ++static void ++e1000_setup_rctl(struct e1000_adapter *adapter) ++{ ++ uint32_t rctl; ++ ++ /* Setup the Receive Control Register */ ++ rctl = ++ E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO | ++ E1000_RCTL_RDMTS_HALF | (adapter->shared. ++ mc_filter_type << E1000_RCTL_MO_SHIFT); ++ ++ if(adapter->shared.tbi_compatibility_on == 1) ++ rctl |= E1000_RCTL_SBP; ++ ++ switch (adapter->rx_buffer_len) { ++ case E1000_RXBUFFER_2048: ++ default: ++ rctl |= E1000_RCTL_SZ_2048; ++ break; ++ case E1000_RXBUFFER_4096: ++ rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; ++ break; ++ case E1000_RXBUFFER_8192: ++ rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; ++ break; ++ case E1000_RXBUFFER_16384: ++ rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; ++ break; ++ } ++ ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++} ++ ++/** ++ * e1000_configure_rx - Configure 8254x Receive Unit after Reset ++ * @adapter: board private structure ++ * ++ * Configure the Rx unit of the MAC after a reset. ++ **/ ++ ++static void ++e1000_configure_rx(struct e1000_adapter *adapter) ++{ ++ uint32_t rctl; ++ uint32_t rxcsum; ++ ++ /* make sure receives are disabled while setting up the descriptor ring */ ++ rctl = E1000_READ_REG(&adapter->shared, RCTL); ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN); ++ ++ /* set the Receive Delay Timer Register */ ++ E1000_WRITE_REG(&adapter->shared, RDTR, ++ adapter->rx_int_delay | E1000_RDT_FPDB); ++ ++ /* Setup the Base and Length of the Rx Descriptor Ring */ ++ /* rx_ring.dma can be either a 32 or 64 bit value */ ++ ++#if (BITS_PER_LONG == 32) ++ E1000_WRITE_REG(&adapter->shared, RDBAL, adapter->rx_ring.dma); ++ E1000_WRITE_REG(&adapter->shared, RDBAH, 0); ++#elif ( BITS_PER_LONG == 64) ++ E1000_WRITE_REG(&adapter->shared, RDBAL, ++ (uint32_t) (adapter->rx_ring.dma & 0x00000000FFFFFFFF)); ++ E1000_WRITE_REG(&adapter->shared, RDBAH, ++ (uint32_t) (adapter->rx_ring.dma >> 32)); ++#else ++#error "Unsupported System - does not use 32 or 64 bit pointers!" ++#endif ++ ++ E1000_WRITE_REG(&adapter->shared, RDLEN, ++ adapter->rx_ring.count * sizeof(struct e1000_rx_desc)); ++ ++ /* Setup the HW Rx Head and Tail Descriptor Pointers */ ++ E1000_WRITE_REG(&adapter->shared, RDH, 0); ++ E1000_WRITE_REG(&adapter->shared, RDT, 0); ++ ++ /* Enable 82543 Receive Checksum Offload for TCP and UDP */ ++ if((adapter->shared.mac_type >= e1000_82543) && ++ (adapter->RxChecksum == TRUE)) { ++ rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM); ++ rxcsum |= E1000_RXCSUM_TUOFL; ++ E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum); ++ } ++#ifdef CONFIG_PPC ++ if(adapter->shared.mac_type >= e1000_82543) { ++ E1000_WRITE_REG(&adapter->shared, RXDCTL, 0x00020000); ++ } ++#endif ++ ++ /* Enable Receives */ ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ ++ return; ++} ++ ++/** ++ * e1000_free_tx_resources - Free Tx Resources ++ * @adapter: board private structure ++ * ++ * Free all transmit software resources ++ **/ ++ ++static void ++e1000_free_tx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ ++ E1000_DBG("e1000_free_tx_resources\n"); ++ ++ e1000_clean_tx_ring(adapter); ++ ++ kfree(adapter->tx_ring.buffer_info); ++ adapter->tx_ring.buffer_info = NULL; ++ ++ pci_free_consistent(pdev, adapter->tx_ring.size, adapter->tx_ring.desc, ++ adapter->tx_ring.dma); ++ ++ adapter->tx_ring.desc = NULL; ++ ++ return; ++} ++ ++/** ++ * e1000_clean_tx_ring - Free Tx Buffers ++ * @adapter: board private structure ++ **/ ++ ++static void ++e1000_clean_tx_ring(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ unsigned long size; ++ int i; ++ ++ /* Free all the Tx ring sk_buffs */ ++ ++ for(i = 0; i < adapter->tx_ring.count; i++) { ++ if(adapter->tx_ring.buffer_info[i].skb != NULL) { ++ ++ pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma, ++ adapter->tx_ring.buffer_info[i].length, ++ PCI_DMA_TODEVICE); ++ ++ dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb); ++ ++ adapter->tx_ring.buffer_info[i].skb = NULL; ++ } ++ } ++ ++ size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; ++ memset(adapter->tx_ring.buffer_info, 0, size); ++ ++ /* Zero out the descriptor ring */ ++ ++ memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); ++ ++ atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); ++ adapter->tx_ring.next_to_use = 0; ++ adapter->tx_ring.next_to_clean = 0; ++ ++ return; ++} ++ ++/** ++ * e1000_free_rx_resources - Free Rx Resources ++ * @adapter: board private structure ++ * ++ * Free all receive software resources ++ **/ ++ ++static void ++e1000_free_rx_resources(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ ++ E1000_DBG("e1000_free_rx_resources\n"); ++ ++ tasklet_disable(&adapter->rx_fill_tasklet); ++ ++ e1000_clean_rx_ring(adapter); ++ ++ kfree(adapter->rx_ring.buffer_info); ++ adapter->rx_ring.buffer_info = NULL; ++ ++ pci_free_consistent(pdev, adapter->rx_ring.size, adapter->rx_ring.desc, ++ adapter->rx_ring.dma); ++ ++ adapter->rx_ring.desc = NULL; ++ ++ return; ++} ++ ++/** ++ * e1000_clean_rx_ring - Free Rx Buffers ++ * @adapter: board private structure ++ **/ ++ ++static void ++e1000_clean_rx_ring(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ unsigned long size; ++ int i; ++ ++ /* Free all the Rx ring sk_buffs */ ++ ++ for(i = 0; i < adapter->rx_ring.count; i++) { ++ if(adapter->rx_ring.buffer_info[i].skb != NULL) { ++ ++ pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, ++ adapter->rx_ring.buffer_info[i].length, ++ PCI_DMA_FROMDEVICE); ++ ++ dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb); ++ ++ adapter->rx_ring.buffer_info[i].skb = NULL; ++ } ++ } ++ ++ size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; ++ memset(adapter->rx_ring.buffer_info, 0, size); ++ ++ /* Zero out the descriptor ring */ ++ ++ memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); ++ ++ atomic_set(&adapter->rx_ring.unused, adapter->rx_ring.count); ++ adapter->rx_ring.next_to_clean = 0; ++ adapter->rx_ring.next_to_use = 0; ++ ++ return; ++} ++ ++/** ++ * e1000_set_multi - Multicast and Promiscuous mode set ++ * @netdev: network interface device structure ++ * ++ * The set_multi entry point is called whenever the multicast address ++ * list or the network interface flags are updated. This routine is ++ * resposible for configuring the hardware for proper multicast, ++ * promiscuous mode, and all-multi behavior. ++ **/ ++ ++void ++e1000_set_multi(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ struct pci_dev *pdev = adapter->pdev; ++ uint32_t rctl; ++ uint8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS]; ++ uint16_t pci_command_word; ++ struct dev_mc_list *mc_ptr; ++ int i; ++ ++ E1000_DBG("e1000_set_multi\n"); ++ ++ rctl = E1000_READ_REG(&adapter->shared, RCTL); ++ ++ if(adapter->shared.mac_type == e1000_82542_rev2_0) { ++ if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { ++ pci_command_word = ++ adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE; ++ pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); ++ } ++ rctl |= E1000_RCTL_RST; ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ mdelay(5); ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ tasklet_disable(&adapter->rx_fill_tasklet); ++ e1000_clean_rx_ring(adapter); ++ } ++ } ++ ++ /* Check for Promiscuous and All Multicast modes */ ++ ++ if(netdev->flags & IFF_PROMISC) { ++ rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); ++ } else if(netdev->flags & IFF_ALLMULTI) { ++ rctl |= E1000_RCTL_MPE; ++ rctl &= ~E1000_RCTL_UPE; ++ } else { ++ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); ++ } ++ ++ if(netdev->mc_count > MAX_NUM_MULTICAST_ADDRESSES) { ++ rctl |= E1000_RCTL_MPE; ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ } else { ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ for(i = 0, mc_ptr = netdev->mc_list; mc_ptr; i++, mc_ptr = mc_ptr->next) ++ memcpy(&mta[i * ETH_LENGTH_OF_ADDRESS], mc_ptr->dmi_addr, ++ ETH_LENGTH_OF_ADDRESS); ++ e1000_mc_addr_list_update(&adapter->shared, mta, netdev->mc_count, 0); ++ } ++ ++ if(adapter->shared.mac_type == e1000_82542_rev2_0) { ++ rctl = E1000_READ_REG(&adapter->shared, RCTL); ++ rctl &= ~E1000_RCTL_RST; ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ mdelay(5); ++ if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { ++ pci_write_config_word(pdev, PCI_COMMAND, ++ adapter->shared.pci_cmd_word); ++ } ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ e1000_configure_rx(adapter); ++ tasklet_enable(&adapter->rx_fill_tasklet); ++ } ++ } ++ ++ return; ++} ++ ++#ifdef IANS ++ ++/* flush Tx queue without link */ ++static void ++e1000_tx_flush(struct e1000_adapter *adapter) ++{ ++ uint32_t ctrl, txcw, icr; ++ ++ adapter->int_mask = 0; ++ e1000_irq_disable(adapter); ++ synchronize_irq(); ++ ++ if(adapter->shared.mac_type < e1000_82543) { ++ /* Transmit Unit Reset */ ++ E1000_WRITE_REG(&adapter->shared, TCTL, E1000_TCTL_RST); ++ E1000_WRITE_REG(&adapter->shared, TCTL, 0); ++ e1000_clean_tx_ring(adapter); ++ e1000_configure_tx(adapter); ++ } else { ++ /* turn off autoneg, set link up, and invert loss of signal */ ++ txcw = E1000_READ_REG(&adapter->shared, TXCW); ++ ctrl = E1000_READ_REG(&adapter->shared, CTRL); ++ E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE); ++ E1000_WRITE_REG(&adapter->shared, CTRL, ++ (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS)); ++ /* delay to flush queue, then clean up */ ++ mdelay(20); ++ e1000_clean_tx_irq(adapter); ++ E1000_WRITE_REG(&adapter->shared, CTRL, ctrl); ++ E1000_WRITE_REG(&adapter->shared, TXCW, txcw); ++ /* clear the link status change interrupts this caused */ ++ icr = E1000_READ_REG(&adapter->shared, ICR); ++ } ++ ++ adapter->int_mask = IMS_ENABLE_MASK; ++ e1000_irq_enable(adapter); ++ return; ++} ++#endif ++ ++/** ++ * e1000_watchdog - Timer Call-back ++ * @data: pointer to netdev cast into an unsigned long ++ **/ ++ ++void ++e1000_watchdog(unsigned long data) ++{ ++ struct net_device *netdev = (struct net_device *) data; ++ struct e1000_adapter *adapter = netdev->priv; ++ ++#ifdef IANS ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) ++ int flags; ++#endif ++#endif ++ ++ e1000_check_for_link(&adapter->shared); ++ ++ if (test_and_clear_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags)) ++ e1000_phy_get_info(&adapter->shared, &adapter->phy_info); ++ ++ if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) { ++ if(adapter->link_active != TRUE) { ++ ++#ifdef IANS ++ if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && ++ (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) ++ if(ans_notify) ++ ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY); ++#endif ++ netif_wake_queue(netdev); ++ ++ e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, ++ &adapter->link_duplex); ++ printk(KERN_ERR "e1000: %s NIC Link is Up %d Mbps %s\n", ++ netdev->name, adapter->link_speed, ++ adapter->link_duplex == ++ FULL_DUPLEX ? "Full Duplex" : "Half Duplex"); ++ ++ adapter->link_active = TRUE; ++ set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags); ++ } ++ } else { ++ if(adapter->link_active != FALSE) { ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ printk(KERN_ERR "e1000: %s NIC Link is Down\n", netdev->name); ++ adapter->link_active = FALSE; ++ atomic_set(&adapter->tx_timeout, 0); ++ } ++ } ++ ++ e1000_update_stats(adapter); ++ ++ if(atomic_read(&adapter->tx_timeout) > 1) ++ atomic_dec(&adapter->tx_timeout); ++ ++ if((adapter->link_active == TRUE) && ++ (atomic_read(&adapter->tx_timeout) == 1)) { ++ ++ if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF) { ++ atomic_set(&adapter->tx_timeout, 3); ++ } else { ++ ++ e1000_hibernate_adapter(netdev); ++ ++#ifdef IANS ++ if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && ++ (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) { ++ adapter->link_active = FALSE; ++ bd_ans_os_Watchdog(netdev, adapter); ++ adapter->link_active = TRUE; ++ } ++#endif ++ atomic_set(&adapter->tx_timeout, 0); ++ e1000_wakeup_adapter(netdev); ++ } ++ } ++#ifdef IANS ++ if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { ++ ++ if(adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON) ++ bd_ans_os_Watchdog(netdev, adapter); ++ ++ if(adapter->link_active == FALSE) { ++ /* don't sit on SKBs while link is down */ ++ ++ if(atomic_read(&adapter->tx_ring.unused) < adapter->tx_ring.count) { ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) ++ spin_lock_irqsave(&netdev->xmit_lock, flags); ++ e1000_tx_flush(adapter); ++ spin_unlock_irqrestore(&netdev->xmit_lock, flags); ++#else ++ e1000_tx_flush(adapter); ++#endif ++ } ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) ++ spin_lock_irqsave(&netdev->queue_lock, flags); ++ qdisc_reset(netdev->qdisc); ++ spin_unlock_irqrestore(&netdev->queue_lock, flags); ++#else ++ qdisc_reset(netdev->qdisc); ++#endif ++ } ++ } ++#endif ++ ++ if(test_bit(E1000_RX_REFILL, &adapter->flags)) { ++ tasklet_schedule(&adapter->rx_fill_tasklet); ++ } ++ ++ /* Reset the timer */ ++ mod_timer(&adapter->timer_id, jiffies + 2 * HZ); ++ ++ return; ++} ++ ++/** ++ * e1000_tx_checksum_setup ++ * @adapter: ++ * @skb: ++ * @txd_upper: ++ * @txd_lower: ++ **/ ++ ++static inline void ++e1000_tx_checksum_setup(struct e1000_adapter *adapter, ++ struct sk_buff *skb, ++ uint32_t *txd_upper, ++ uint32_t *txd_lower) ++{ ++ ++ struct e1000_context_desc *desc; ++ int i; ++ ++ if(skb->protocol != __constant_htons(ETH_P_IP)) { ++ *txd_upper = 0; ++ *txd_lower = adapter->TxdCmd; ++ return; ++ } ++ ++ switch (skb->nh.iph->protocol) { ++ case IPPROTO_TCP: ++ /* Offload TCP checksum */ ++ *txd_upper = E1000_TXD_POPTS_TXSM << 8; ++ *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; ++ if(adapter->ActiveChecksumContext == OFFLOAD_TCP_IP) ++ return; ++ else ++ adapter->ActiveChecksumContext = OFFLOAD_TCP_IP; ++ break; ++ case IPPROTO_UDP: ++ /* Offload UDP checksum */ ++ *txd_upper = E1000_TXD_POPTS_TXSM << 8; ++ *txd_lower = adapter->TxdCmd | E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; ++ if(adapter->ActiveChecksumContext == OFFLOAD_UDP_IP) ++ return; ++ else ++ adapter->ActiveChecksumContext = OFFLOAD_UDP_IP; ++ break; ++ default: ++ /* no checksum to offload */ ++ *txd_upper = 0; ++ *txd_lower = adapter->TxdCmd; ++ return; ++ } ++ ++ /* If we reach this point, the checksum offload context ++ * needs to be reset ++ */ ++ ++ i = adapter->tx_ring.next_to_use; ++ desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); ++ ++ desc->lower_setup.ip_fields.ipcss = skb->nh.raw - skb->data; ++ desc->lower_setup.ip_fields.ipcso = ++ ((skb->nh.raw + offsetof(struct iphdr, check)) - skb->data); ++ desc->lower_setup.ip_fields.ipcse = cpu_to_le16(skb->h.raw - skb->data - 1); ++ ++ desc->upper_setup.tcp_fields.tucss = (skb->h.raw - skb->data); ++ desc->upper_setup.tcp_fields.tucso = ((skb->h.raw + skb->csum) - skb->data); ++ desc->upper_setup.tcp_fields.tucse = 0; ++ ++ desc->tcp_seg_setup.data = 0; ++ desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT) | adapter->TxdCmd; ++ ++ i = (i + 1) % adapter->tx_ring.count; ++ atomic_dec(&adapter->tx_ring.unused); ++ adapter->tx_ring.next_to_use = i; ++ E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); ++ return; ++} ++ ++/** ++ * e1000_xmit_frame - Transmit entry point ++ * @skb: buffer with frame data to transmit ++ * @netdev: network interface device structure ++ * ++ * Returns 0 on success, negative on error ++ * ++ * e1000_xmit_frame is called by the stack to initiate a transmit. ++ * The out of resource condition is checked after each successful Tx ++ * so that the stack can be notified, preventing the driver from ++ * ever needing to drop a frame. The atomic operations on ++ * tx_ring.unused are used to syncronize with the transmit ++ * interrupt processing code without the need for a spinlock. ++ **/ ++ ++int ++e1000_xmit_frame(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_tx_desc *tx_desc; ++ int i, len, offset, txd_needed; ++ uint32_t txd_upper, txd_lower; ++ ++#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0)) ++ ++#ifdef MAX_SKB_FRAGS ++ int f; ++ skb_frag_t *frag; ++#endif ++ ++ E1000_DBG("e1000_xmit_frame\n"); ++ ++ if(adapter->link_active == FALSE) { ++#ifdef IANS ++ if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && ++ (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) ++ if(ans_notify) ++ ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL); ++#endif ++ netif_stop_queue(netdev); ++ return 1; ++ } ++ ++#ifdef MAX_SKB_FRAGS ++ txd_needed = TXD_USE_COUNT(skb->len - skb->data_len); ++ for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { ++ frag = &skb_shinfo(skb)->frags[f]; ++ txd_needed += TXD_USE_COUNT(frag->size); ++ } ++#else ++ txd_needed = TXD_USE_COUNT(skb->len); ++#endif ++ ++ /* make sure there are enough Tx descriptors available in the ring */ ++ if(atomic_read(&adapter->tx_ring.unused) <= (txd_needed + 1)) { ++ adapter->net_stats.tx_dropped++; ++#ifdef IANS ++ if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && ++ (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) ++ if(ans_notify) ++ ans_notify(netdev, IANS_IND_XMIT_QUEUE_FULL); ++#endif ++ netif_stop_queue(netdev); ++ ++ return 1; ++ } ++ ++ if(skb->ip_summed == CHECKSUM_HW) { ++ e1000_tx_checksum_setup(adapter, skb, &txd_upper, &txd_lower); ++ } else { ++ txd_upper = 0; ++ txd_lower = adapter->TxdCmd; ++ } ++ ++ i = adapter->tx_ring.next_to_use; ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ ++#ifdef IANS ++ if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { ++ tx_desc->lower.data = cpu_to_le32(txd_lower); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ if(bd_ans_os_Transmit(adapter, tx_desc, &skb) == BD_ANS_FAILURE) { ++ return 1; ++ } ++ txd_lower = le32_to_cpu(tx_desc->lower.data); ++ txd_upper = le32_to_cpu(tx_desc->upper.data); ++ } ++#endif ++ ++#ifdef MAX_SKB_FRAGS ++ len = skb->len - skb->data_len; ++#else ++ len = skb->len; ++#endif ++ offset = 0; ++ ++ while(len > 4096) { ++ adapter->tx_ring.buffer_info[i].length = 4096; ++ adapter->tx_ring.buffer_info[i].dma = ++ pci_map_page(pdev, virt_to_page(skb->data + offset), ++ (unsigned long) (skb->data + offset) & ~PAGE_MASK, ++ 4096, PCI_DMA_TODEVICE); ++ ++ tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); ++ tx_desc->lower.data = cpu_to_le32(txd_lower | 4096); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ ++ len -= 4096; ++ offset += 4096; ++ i = (i + 1) % adapter->tx_ring.count; ++ atomic_dec(&adapter->tx_ring.unused); ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ } ++ adapter->tx_ring.buffer_info[i].length = len; ++ adapter->tx_ring.buffer_info[i].dma = ++ pci_map_page(pdev, virt_to_page(skb->data + offset), ++ (unsigned long) (skb->data + offset) & ~PAGE_MASK, len, ++ PCI_DMA_TODEVICE); ++ ++ tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); ++ tx_desc->lower.data = cpu_to_le32(txd_lower | len); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ ++#ifdef MAX_SKB_FRAGS ++ for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { ++ frag = &skb_shinfo(skb)->frags[f]; ++ i = (i + 1) % adapter->tx_ring.count; ++ atomic_dec(&adapter->tx_ring.unused); ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ ++ len = frag->size; ++ offset = 0; ++ ++ while(len > 4096) { ++ adapter->tx_ring.buffer_info[i].length = 4096; ++ adapter->tx_ring.buffer_info[i].dma = ++ pci_map_page(pdev, frag->page, frag->page_offset + offset, ++ 4096, PCI_DMA_TODEVICE); ++ ++ tx_desc->buffer_addr = ++ cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); ++ tx_desc->lower.data = cpu_to_le32(txd_lower | 4096); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ ++ len -= 4096; ++ offset += 4096; ++ i = (i + 1) % adapter->tx_ring.count; ++ atomic_dec(&adapter->tx_ring.unused); ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ } ++ adapter->tx_ring.buffer_info[i].length = len; ++ adapter->tx_ring.buffer_info[i].dma = ++ pci_map_page(pdev, frag->page, frag->page_offset + offset, len, ++ PCI_DMA_TODEVICE); ++ tx_desc->buffer_addr = ++ cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); ++ ++ tx_desc->lower.data = cpu_to_le32(txd_lower | len); ++ tx_desc->upper.data = cpu_to_le32(txd_upper); ++ } ++#endif ++ ++ /* EOP and SKB pointer go with the last fragment */ ++ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); ++ adapter->tx_ring.buffer_info[i].skb = skb; ++ ++ i = (i + 1) % adapter->tx_ring.count; ++ atomic_dec(&adapter->tx_ring.unused); ++ ++ /* Move the HW Tx Tail Pointer */ ++ adapter->tx_ring.next_to_use = i; ++ ++ E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); ++ ++ if(atomic_read(&adapter->tx_timeout) == 0) ++ atomic_set(&adapter->tx_timeout, 3); ++ ++ netdev->trans_start = jiffies; ++ ++ return 0; ++} ++ ++/** ++ * e1000_get_stats - Get System Network Statistics ++ * @netdev: network interface device structure ++ * ++ * Returns the address of the device statistics structure. ++ * The statistics are actually updated from the timer callback. ++ **/ ++ ++struct net_device_stats * ++e1000_get_stats(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ ++ E1000_DBG("e1000_get_stats\n"); ++ ++ return &adapter->net_stats; ++} ++ ++/** ++ * e1000_change_mtu - Change the Maximum Transfer Unit ++ * @netdev: network interface device structure ++ * @new_mtu: new value for maximum frame size ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++ ++int ++e1000_change_mtu(struct net_device *netdev, ++ int new_mtu) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ uint32_t old_mtu = adapter->rx_buffer_len; ++ ++ E1000_DBG("e1000_change_mtu\n"); ++ if((new_mtu < MINIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) || ++ (new_mtu > MAX_JUMBO_FRAME_SIZE - ENET_HEADER_SIZE)) { ++ E1000_ERR("Invalid MTU setting\n"); ++ return -EINVAL; ++ } ++ ++ if(new_mtu <= MAXIMUM_ETHERNET_PACKET_SIZE - ENET_HEADER_SIZE) { ++ /* 2k buffers */ ++ adapter->rx_buffer_len = E1000_RXBUFFER_2048; ++ ++ } else if(adapter->shared.mac_type < e1000_82543) { ++ E1000_ERR("Jumbo Frames not supported on 82542\n"); ++ return -EINVAL; ++ ++ } else if(new_mtu <= E1000_RXBUFFER_4096 - ENET_HEADER_SIZE - CRC_LENGTH) { ++ /* 4k buffers */ ++ adapter->rx_buffer_len = E1000_RXBUFFER_4096; ++ ++ } else if(new_mtu <= E1000_RXBUFFER_8192 - ENET_HEADER_SIZE - CRC_LENGTH) { ++ /* 8k buffers */ ++ adapter->rx_buffer_len = E1000_RXBUFFER_8192; ++ ++ } else { ++ /* 16k buffers */ ++ adapter->rx_buffer_len = E1000_RXBUFFER_16384; ++ } ++ ++ if(old_mtu != adapter->rx_buffer_len && ++ test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ ++ /* stop */ ++ tasklet_disable(&adapter->rx_fill_tasklet); ++ netif_stop_queue(netdev); ++ adapter->shared.adapter_stopped = 0; ++ e1000_adapter_stop(&adapter->shared); ++ ++ /* clean out old buffers */ ++ e1000_clean_rx_ring(adapter); ++ e1000_clean_tx_ring(adapter); ++ ++ /* reset hardware */ ++ adapter->shared.adapter_stopped = 0; ++ e1000_hw_init(adapter); ++ ++ /* go */ ++ e1000_setup_rctl(adapter); ++ e1000_configure_rx(adapter); ++ e1000_configure_tx(adapter); ++#ifdef IANS ++ /* restore VLAN settings */ ++ if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) ++ != IANS_BD_TAGGING_NONE) ++ bd_ans_hw_EnableVLAN(adapter); ++#endif ++ tasklet_enable(&adapter->rx_fill_tasklet); ++ tasklet_schedule(&adapter->rx_fill_tasklet); ++ e1000_irq_enable(adapter); ++ netif_start_queue(netdev); ++ } ++ ++ netdev->mtu = new_mtu; ++ adapter->shared.max_frame_size = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH; ++ ++ return 0; ++} ++ ++/** ++ * e1000_set_mac - Change the Ethernet Address of the NIC ++ * @netdev: network interface device structure ++ * @p: pointer to an address structure ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++ ++int ++e1000_set_mac(struct net_device *netdev, ++ void *p) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ struct pci_dev *pdev = adapter->pdev; ++ struct sockaddr *addr = (struct sockaddr *) p; ++ uint32_t pci_command; ++ uint32_t rctl; ++ ++ E1000_DBG("e1000_set_mac\n"); ++ ++ rctl = E1000_READ_REG(&adapter->shared, RCTL); ++ ++ if(adapter->shared.mac_type == e1000_82542_rev2_0) { ++ if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { ++ pci_command = ++ adapter->shared.pci_cmd_word & ~PCI_COMMAND_INVALIDATE; ++ pci_write_config_word(pdev, PCI_COMMAND, pci_command); ++ } ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl | E1000_RCTL_RST); ++ mdelay(5); ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ tasklet_disable(&adapter->rx_fill_tasklet); ++ e1000_clean_rx_ring(adapter); ++ } ++ } ++ ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len); ++ ++ e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0); ++ ++ if(adapter->shared.mac_type == e1000_82542_rev2_0) { ++ E1000_WRITE_REG(&adapter->shared, RCTL, rctl); ++ mdelay(5); ++ if(adapter->shared.pci_cmd_word & PCI_COMMAND_INVALIDATE) { ++ pci_write_config_word(pdev, PCI_COMMAND, ++ adapter->shared.pci_cmd_word); ++ } ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ e1000_configure_rx(adapter); ++ tasklet_enable(&adapter->rx_fill_tasklet); ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * e1000_update_stats - Update the board statistics counters ++ * @adapter: board private structure ++ **/ ++ ++static void ++e1000_update_stats(struct e1000_adapter *adapter) ++{ ++ unsigned long flags; ++ ++#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF ++ ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ ++ adapter->stats.crcerrs += E1000_READ_REG(&adapter->shared, CRCERRS); ++ adapter->stats.symerrs += E1000_READ_REG(&adapter->shared, SYMERRS); ++ adapter->stats.mpc += E1000_READ_REG(&adapter->shared, MPC); ++ adapter->stats.scc += E1000_READ_REG(&adapter->shared, SCC); ++ adapter->stats.ecol += E1000_READ_REG(&adapter->shared, ECOL); ++ adapter->stats.mcc += E1000_READ_REG(&adapter->shared, MCC); ++ adapter->stats.latecol += E1000_READ_REG(&adapter->shared, LATECOL); ++ adapter->stats.colc += E1000_READ_REG(&adapter->shared, COLC); ++ adapter->stats.dc += E1000_READ_REG(&adapter->shared, DC); ++ adapter->stats.sec += E1000_READ_REG(&adapter->shared, SEC); ++ adapter->stats.rlec += E1000_READ_REG(&adapter->shared, RLEC); ++ adapter->stats.xonrxc += E1000_READ_REG(&adapter->shared, XONRXC); ++ adapter->stats.xontxc += E1000_READ_REG(&adapter->shared, XONTXC); ++ adapter->stats.xoffrxc += E1000_READ_REG(&adapter->shared, XOFFRXC); ++ adapter->stats.xofftxc += E1000_READ_REG(&adapter->shared, XOFFTXC); ++ adapter->stats.fcruc += E1000_READ_REG(&adapter->shared, FCRUC); ++ adapter->stats.prc64 += E1000_READ_REG(&adapter->shared, PRC64); ++ adapter->stats.prc127 += E1000_READ_REG(&adapter->shared, PRC127); ++ adapter->stats.prc255 += E1000_READ_REG(&adapter->shared, PRC255); ++ adapter->stats.prc511 += E1000_READ_REG(&adapter->shared, PRC511); ++ adapter->stats.prc1023 += E1000_READ_REG(&adapter->shared, PRC1023); ++ adapter->stats.prc1522 += E1000_READ_REG(&adapter->shared, PRC1522); ++ adapter->stats.gprc += E1000_READ_REG(&adapter->shared, GPRC); ++ adapter->stats.bprc += E1000_READ_REG(&adapter->shared, BPRC); ++ adapter->stats.mprc += E1000_READ_REG(&adapter->shared, MPRC); ++ adapter->stats.gptc += E1000_READ_REG(&adapter->shared, GPTC); ++ ++ /* for the 64-bit byte counters the low dword must be read first */ ++ /* both registers clear on the read of the high dword */ ++ ++ adapter->stats.gorcl += E1000_READ_REG(&adapter->shared, GORCL); ++ adapter->stats.gorch += E1000_READ_REG(&adapter->shared, GORCH); ++ adapter->stats.gotcl += E1000_READ_REG(&adapter->shared, GOTCL); ++ adapter->stats.gotch += E1000_READ_REG(&adapter->shared, GOTCH); ++ ++ adapter->stats.rnbc += E1000_READ_REG(&adapter->shared, RNBC); ++ adapter->stats.ruc += E1000_READ_REG(&adapter->shared, RUC); ++ adapter->stats.rfc += E1000_READ_REG(&adapter->shared, RFC); ++ adapter->stats.roc += E1000_READ_REG(&adapter->shared, ROC); ++ adapter->stats.rjc += E1000_READ_REG(&adapter->shared, RJC); ++ ++ adapter->stats.torl += E1000_READ_REG(&adapter->shared, TORL); ++ adapter->stats.torh += E1000_READ_REG(&adapter->shared, TORH); ++ adapter->stats.totl += E1000_READ_REG(&adapter->shared, TOTL); ++ adapter->stats.toth += E1000_READ_REG(&adapter->shared, TOTH); ++ ++ adapter->stats.tpr += E1000_READ_REG(&adapter->shared, TPR); ++ adapter->stats.tpt += E1000_READ_REG(&adapter->shared, TPT); ++ adapter->stats.ptc64 += E1000_READ_REG(&adapter->shared, PTC64); ++ adapter->stats.ptc127 += E1000_READ_REG(&adapter->shared, PTC127); ++ adapter->stats.ptc255 += E1000_READ_REG(&adapter->shared, PTC255); ++ adapter->stats.ptc511 += E1000_READ_REG(&adapter->shared, PTC511); ++ adapter->stats.ptc1023 += E1000_READ_REG(&adapter->shared, PTC1023); ++ adapter->stats.ptc1522 += E1000_READ_REG(&adapter->shared, PTC1522); ++ adapter->stats.mptc += E1000_READ_REG(&adapter->shared, MPTC); ++ adapter->stats.bptc += E1000_READ_REG(&adapter->shared, BPTC); ++ ++ if(adapter->shared.mac_type >= e1000_82543) { ++ adapter->stats.algnerrc += E1000_READ_REG(&adapter->shared, ALGNERRC); ++ adapter->stats.rxerrc += E1000_READ_REG(&adapter->shared, RXERRC); ++ adapter->stats.tncrs += E1000_READ_REG(&adapter->shared, TNCRS); ++ adapter->stats.cexterr += E1000_READ_REG(&adapter->shared, CEXTERR); ++ adapter->stats.tsctc += E1000_READ_REG(&adapter->shared, TSCTC); ++ adapter->stats.tsctfc += E1000_READ_REG(&adapter->shared, TSCTFC); ++ } ++ ++ /* Fill out the OS statistics structure */ ++ ++ adapter->net_stats.rx_packets = adapter->stats.gprc; ++ adapter->net_stats.tx_packets = adapter->stats.gptc; ++ adapter->net_stats.rx_bytes = adapter->stats.gorcl; ++ adapter->net_stats.tx_bytes = adapter->stats.gotcl; ++ adapter->net_stats.multicast = adapter->stats.mprc; ++ adapter->net_stats.collisions = adapter->stats.colc; ++ ++ /* Rx Errors */ ++ ++ adapter->net_stats.rx_errors = ++ adapter->stats.rxerrc + adapter->stats.crcerrs + ++ adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.rnbc + ++ adapter->stats.mpc + adapter->stats.cexterr; ++ adapter->net_stats.rx_dropped = adapter->stats.rnbc; ++ adapter->net_stats.rx_length_errors = adapter->stats.rlec; ++ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; ++ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; ++ adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; ++ adapter->net_stats.rx_missed_errors = adapter->stats.mpc; ++ ++ /* Tx Errors */ ++ ++ adapter->net_stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol; ++ adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; ++ adapter->net_stats.tx_window_errors = adapter->stats.latecol; ++ ++ /* Tx Dropped needs to be maintained elsewhere */ ++ ++ if(adapter->shared.media_type == e1000_media_type_copper) { ++ adapter->phy_stats.idle_errors += ++ (e1000_read_phy_reg(&adapter->shared, PHY_1000T_STATUS) ++ & PHY_IDLE_ERROR_COUNT_MASK); ++ adapter->phy_stats.receive_errors += ++ e1000_read_phy_reg(&adapter->shared, M88E1000_RX_ERR_CNTR); ++ } ++ ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ return; ++} ++ ++/** ++ * e1000_irq_disable - Mask off interrupt generation on the NIC ++ * @adapter: board private structure ++ **/ ++ ++static inline void ++e1000_irq_disable(struct e1000_adapter *adapter) ++{ ++ E1000_DBG("e1000_irq_disable\n"); ++ ++ /* Mask off all interrupts */ ++ ++ E1000_WRITE_REG(&adapter->shared, IMC, ~0); ++ return; ++} ++ ++/** ++ * e1000_irq_enable - Enable default interrupt generation settings ++ * @adapter: board private structure ++ **/ ++ ++static inline void ++e1000_irq_enable(struct e1000_adapter *adapter) ++{ ++ E1000_DBG("e1000_irq_enable\n"); ++ ++ E1000_WRITE_REG(&adapter->shared, IMS, adapter->int_mask); ++ return; ++} ++ ++/** ++ * e1000_intr - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ * @pt_regs: CPU registers structure ++ **/ ++ ++void ++e1000_intr(int irq, ++ void *data, ++ struct pt_regs *regs) ++{ ++ struct net_device *netdev = (struct net_device *) data; ++ struct e1000_adapter *adapter = netdev->priv; ++ uint32_t icr; ++ uint loop_count = E1000_MAX_INTR; ++ ++ E1000_DBG("e1000_intr\n"); ++ ++ e1000_irq_disable(adapter); ++ ++ while(loop_count > 0 && (icr = E1000_READ_REG(&adapter->shared, ICR)) != 0) { ++ ++ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { ++ adapter->shared.get_link_status = 1; ++ set_bit(E1000_LINK_STATUS_CHANGED, &adapter->flags); ++ /* run the watchdog ASAP */ ++ mod_timer(&adapter->timer_id, jiffies); ++ } ++ ++ e1000_clean_rx_irq(adapter); ++ e1000_clean_tx_irq(adapter); ++ loop_count--; ++ } ++ ++ e1000_irq_enable(adapter); ++ ++ return; ++} ++ ++/** ++ * e1000_clean_tx_irq - Reclaim resources after transmit completes ++ * @adapter: board private structure ++ **/ ++ ++static void ++e1000_clean_tx_irq(struct e1000_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ int i; ++ ++ struct e1000_tx_desc *tx_desc; ++ struct net_device *netdev = adapter->netdev; ++ ++ E1000_DBG("e1000_clean_tx_irq\n"); ++ ++ i = adapter->tx_ring.next_to_clean; ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ ++ while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { ++ ++ if(adapter->tx_ring.buffer_info[i].dma != 0) { ++ pci_unmap_page(pdev, adapter->tx_ring.buffer_info[i].dma, ++ adapter->tx_ring.buffer_info[i].length, ++ PCI_DMA_TODEVICE); ++ adapter->tx_ring.buffer_info[i].dma = 0; ++ } ++ ++ if(adapter->tx_ring.buffer_info[i].skb != NULL) { ++ dev_kfree_skb_irq(adapter->tx_ring.buffer_info[i].skb); ++ adapter->tx_ring.buffer_info[i].skb = NULL; ++ } ++ ++ atomic_inc(&adapter->tx_ring.unused); ++ i = (i + 1) % adapter->tx_ring.count; ++ ++ tx_desc->upper.data = 0; ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ } ++ ++ adapter->tx_ring.next_to_clean = i; ++ ++ if(adapter->tx_ring.next_to_clean == adapter->tx_ring.next_to_use) ++ atomic_set(&adapter->tx_timeout, 0); ++ else ++ atomic_set(&adapter->tx_timeout, 3); ++ ++ if(netif_queue_stopped(netdev) && ++ (atomic_read(&adapter->tx_ring.unused) > ++ (adapter->tx_ring.count * 3 / 4))) { ++ ++#ifdef IANS ++ if((adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) && ++ (adapter->iANSdata->reporting_mode == IANS_STATUS_REPORTING_ON)) ++ if(ans_notify) ++ ans_notify(netdev, IANS_IND_XMIT_QUEUE_READY); ++#endif ++ netif_wake_queue(netdev); ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_clean_rx_irq - Send received data up the network stack, ++ * @adapter: board private structure ++ **/ ++ ++static void ++e1000_clean_rx_irq(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_rx_desc *rx_desc; ++ int i; ++ uint32_t length; ++ struct sk_buff *skb; ++ uint8_t last_byte; ++ unsigned long flags; ++ ++ E1000_DBG("e1000_clean_rx_irq\n"); ++ ++ i = adapter->rx_ring.next_to_clean; ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ ++ while(rx_desc->status & E1000_RXD_STAT_DD) { ++ pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, ++ adapter->rx_ring.buffer_info[i].length, ++ PCI_DMA_FROMDEVICE); ++ ++ skb = adapter->rx_ring.buffer_info[i].skb; ++ length = le16_to_cpu(rx_desc->length); ++ ++ if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { ++ ++ /* All receives must fit into a single buffer */ ++ ++ E1000_DBG("Receive packet consumed multiple buffers\n"); ++ ++ dev_kfree_skb_irq(skb); ++ memset(rx_desc, 0, 16); ++ mb(); ++ adapter->rx_ring.buffer_info[i].skb = NULL; ++ ++ atomic_inc(&adapter->rx_ring.unused); ++ ++ i = (i + 1) % adapter->rx_ring.count; ++ ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ continue; ++ } ++ ++ if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { ++ ++ last_byte = *(skb->data + length - 1); ++ ++ if(TBI_ACCEPT ++ (&adapter->shared, rx_desc->status, rx_desc->errors, length, ++ last_byte)) { ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ e1000_tbi_adjust_stats(&adapter->shared, &adapter->stats, ++ length, skb->data); ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ length--; ++ } else { ++ ++ E1000_DBG("Receive Errors Reported by Hardware\n"); ++ ++ dev_kfree_skb_irq(skb); ++ memset(rx_desc, 0, 16); ++ mb(); ++ adapter->rx_ring.buffer_info[i].skb = NULL; ++ ++ atomic_inc(&adapter->rx_ring.unused); ++ i = (i + 1) % adapter->rx_ring.count; ++ ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ continue; ++ } ++ } ++ ++ /* Good Receive */ ++ skb_put(skb, length - CRC_LENGTH); ++ ++ /* Adjust socket buffer accounting to only cover the ethernet frame ++ * Not what the stack intends, but there exist TCP problems that ++ * break NFS for network interfaces that need 2k receive buffers ++ */ ++ skb->truesize = skb->len; ++ ++ /* Receive Checksum Offload */ ++ e1000_rx_checksum(adapter, rx_desc, skb); ++ ++#ifdef IANS ++ if(adapter->iANSdata->iANS_status == IANS_COMMUNICATION_UP) { ++ if(bd_ans_os_Receive(adapter, rx_desc, skb) == BD_ANS_FAILURE) ++ dev_kfree_skb_irq(skb); ++ else ++ netif_rx(skb); ++ } else { ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_rx(skb); ++ } ++#else ++ skb->protocol = eth_type_trans(skb, netdev); ++ netif_rx(skb); ++#endif ++ memset(rx_desc, 0, 16); ++ mb(); ++ adapter->rx_ring.buffer_info[i].skb = NULL; ++ ++ atomic_inc(&adapter->rx_ring.unused); ++ ++ i = (i + 1) % adapter->rx_ring.count; ++ ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ } ++ ++ /* if the Rx ring is less than 3/4 full, allocate more sk_buffs */ ++ ++ if(atomic_read(&adapter->rx_ring.unused) > (adapter->rx_ring.count / 4)) { ++ tasklet_schedule(&adapter->rx_fill_tasklet); ++ } ++ adapter->rx_ring.next_to_clean = i; ++ ++ return; ++} ++ ++/** ++ * e1000_alloc_rx_buffers - Replace used receive buffers ++ * @data: address of board private structure ++ **/ ++ ++static void ++e1000_alloc_rx_buffers(unsigned long data) ++{ ++ struct e1000_adapter *adapter = (struct e1000_adapter *) data; ++ struct net_device *netdev = adapter->netdev; ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_rx_desc *rx_desc; ++ struct sk_buff *skb; ++ int i; ++ int reserve_len; ++ ++ E1000_DBG("e1000_alloc_rx_buffers\n"); ++ ++ /* kernel 2.4.7 seems to be broken with respect to tasklet locking */ ++ if(!spin_trylock(&adapter->rx_fill_lock)) ++ return; ++ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ spin_unlock(&adapter->rx_fill_lock); ++ return; ++ } ++ ++#ifdef IANS ++ reserve_len = E1000_ROUNDUP2(BD_ANS_INFO_SIZE, 16) + 2; ++#else ++ reserve_len = 2; ++#endif ++ ++ i = adapter->rx_ring.next_to_use; ++ ++ while(adapter->rx_ring.buffer_info[i].skb == NULL) { ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ ++ skb = alloc_skb(adapter->rx_buffer_len + reserve_len, GFP_ATOMIC); ++ ++ if(skb == NULL) { ++ /* Alloc Failed; If we could not allocate a ++ * skb during this schedule. Wait for a while before ++ * tasklet to allocate skb is called again. ++ */ ++ set_bit(E1000_RX_REFILL, &adapter->flags); ++ break; ++ } ++ ++ /* Make buffer alignment 2 beyond a 16 byte boundary ++ * this will result in a 16 byte aligned IP header after ++ * the 14 byte MAC header is removed ++ */ ++ skb_reserve(skb, reserve_len); ++ ++ skb->dev = netdev; ++ ++ adapter->rx_ring.buffer_info[i].skb = skb; ++ adapter->rx_ring.buffer_info[i].length = adapter->rx_buffer_len; ++ adapter->rx_ring.buffer_info[i].dma = ++ pci_map_single(pdev, skb->data, adapter->rx_buffer_len, ++ PCI_DMA_FROMDEVICE); ++ ++ rx_desc->buffer_addr = cpu_to_le64(adapter->rx_ring.buffer_info[i].dma); ++ ++ /* move tail */ ++ E1000_WRITE_REG(&adapter->shared, RDT, i); ++ ++ atomic_dec(&adapter->rx_ring.unused); ++ ++ i = (i + 1) % adapter->rx_ring.count; ++ ++ if(test_and_clear_bit(E1000_RX_REFILL, &adapter->flags)) { ++ /* Trigger Soft Interrupt */ ++ E1000_WRITE_REG(&adapter->shared, ICS, E1000_ICS_RXT0); ++ } ++ } ++ ++ adapter->rx_ring.next_to_use = i; ++ ++ spin_unlock(&adapter->rx_fill_lock); ++ return; ++} ++ ++/** ++ * e1000_ioctl - ++ * @netdev: ++ * @ifreq: ++ * @cmd: ++ **/ ++ ++int ++e1000_ioctl(struct net_device *netdev, ++ struct ifreq *ifr, ++ int cmd) ++{ ++#ifdef IANS ++ IANS_BD_PARAM_HEADER *header; ++#endif ++ ++ E1000_DBG("e1000_do_ioctl\n"); ++ ++ switch (cmd) { ++ ++#ifdef IANS ++ case IANS_BASE_SIOC: ++ header = (IANS_BD_PARAM_HEADER *) ifr->ifr_data; ++ if((header->Opcode != IANS_OP_EXT_GET_STATUS) && ++ (!capable(CAP_NET_ADMIN))) ++ return -EPERM; ++ return bd_ans_os_Ioctl(netdev, ifr, cmd); ++ break; ++#endif ++ ++#ifdef IDIAG ++ case IDIAG_PRO_BASE_SIOC: ++ if(!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++#ifdef DIAG_DEBUG ++ printk("Entering diagnostics\n"); ++#endif ++ e1000_diag_ioctl(netdev, ifr); ++ break; ++#endif /* IDIAG */ ++ ++#ifdef SIOCETHTOOL ++ case SIOCETHTOOL: ++ ++ return e1000_ethtool_ioctl(netdev, ifr); ++ ++ break; ++#endif ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++/** ++ * e1000_rx_checksum - Receive Checksum Offload for 82543 ++ * @adapter: board private structure ++ * @rx_desc: receive descriptor ++ * @sk_buff: socket buffer with received data ++ **/ ++ ++static inline void ++e1000_rx_checksum(struct e1000_adapter *adapter, ++ struct e1000_rx_desc *rx_desc, ++ struct sk_buff *skb) ++{ ++ /* 82543 or newer only */ ++ if((adapter->shared.mac_type < e1000_82543) || ++ /* Ignore Checksum bit is set */ ++ (rx_desc->status & E1000_RXD_STAT_IXSM) || ++ /* TCP Checksum has not been calculated */ ++ (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ return; ++ } ++ ++ /* At this point we know the hardware did the TCP checksum */ ++ /* now look at the TCP checksum error bit */ ++ if(rx_desc->errors & E1000_RXD_ERR_TCPE) { ++ /* let the stack verify checksum errors */ ++ skb->ip_summed = CHECKSUM_NONE; ++ adapter->XsumRXError++; ++ } else { ++ /* TCP checksum is good */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ adapter->XsumRXGood++; ++ } ++ ++ return; ++} ++ ++void ++e1000_hibernate_adapter(struct net_device *netdev) ++{ ++ uint32_t icr; ++ struct e1000_adapter *adapter = netdev->priv; ++ ++ e1000_irq_disable(adapter); ++ netif_stop_queue(netdev); ++ adapter->shared.adapter_stopped = 0; ++ e1000_adapter_stop(&adapter->shared); ++ ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ ++ /* Disable tasklet only when interface is opened. */ ++ tasklet_disable(&adapter->rx_fill_tasklet); ++ ++ /* clean out old buffers */ ++ e1000_clean_rx_ring(adapter); ++ e1000_clean_tx_ring(adapter); ++ ++ /* Delete watchdog timer */ ++ del_timer(&adapter->timer_id); ++ ++ /* Unhook irq */ ++ e1000_irq_disable(adapter); ++ icr = E1000_READ_REG(&adapter->shared, ICR); ++ free_irq(netdev->irq, netdev); ++ } ++} ++ ++void ++e1000_wakeup_adapter(struct net_device *netdev) ++{ ++ uint32_t icr; ++ struct e1000_adapter *adapter = netdev->priv; ++ ++ adapter->shared.adapter_stopped = 0; ++ e1000_adapter_stop(&adapter->shared); ++ adapter->shared.adapter_stopped = 0; ++ adapter->shared.fc = adapter->shared.original_fc; ++ ++ if(!e1000_init_hw(&adapter->shared)) ++ printk("Hardware Init Failed at wakeup\n"); ++ ++ if(test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ ++ /* Setup Rctl */ ++ e1000_setup_rctl(adapter); ++ e1000_configure_rx(adapter); ++ e1000_alloc_rx_buffers((unsigned long) adapter); ++ e1000_set_multi(netdev); ++ e1000_configure_tx(adapter); ++ ++#ifdef IANS ++ if((IANS_BD_TAGGING_MODE) (ANS_PRIVATE_DATA_FIELD(adapter)->tag_mode) ++ != IANS_BD_TAGGING_NONE) ++ bd_ans_hw_EnableVLAN(adapter); ++#endif ++ ++ /* Set the watchdog timer for 2 seconds */ ++ init_timer(&adapter->timer_id); ++ adapter->timer_id.function = &e1000_watchdog; ++ adapter->timer_id.data = (unsigned long) netdev; ++ mod_timer(&adapter->timer_id, (jiffies + 2 * HZ)); ++ ++ tasklet_enable(&adapter->rx_fill_tasklet); ++ ++ /* Hook irq */ ++ e1000_irq_disable(adapter); ++ icr = E1000_READ_REG(&adapter->shared, ICR); ++ if(request_irq ++ (netdev->irq, &e1000_intr, SA_SHIRQ, e1000_driver_name, netdev) != 0) ++ printk(KERN_ERR "e1000: Unable to hook irq.\n"); ++ ++ e1000_irq_enable(adapter); ++ netif_start_queue(netdev); ++ } ++} ++ ++#ifdef IDIAG ++int ++e1000_xmit_lbtest_frame(struct sk_buff *skb, ++ struct e1000_adapter *adapter) ++{ ++ /*struct e1000_adapter *adapter = netdev->priv; */ ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_tx_desc *tx_desc; ++ int i; ++ ++ i = adapter->tx_ring.next_to_use; ++ tx_desc = E1000_TX_DESC(adapter->tx_ring, i); ++ ++ adapter->tx_ring.buffer_info[i].skb = skb; ++ adapter->tx_ring.buffer_info[i].length = skb->len; ++ adapter->tx_ring.buffer_info[i].dma = ++ pci_map_page(pdev, virt_to_page(skb->data), ++ (unsigned long) skb->data & ~PAGE_MASK, skb->len, ++ PCI_DMA_TODEVICE); ++ ++ tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring.buffer_info[i].dma); ++ tx_desc->lower.data = cpu_to_le32(skb->len); ++ ++ /* zero out the status field in the descriptor */ ++ ++ tx_desc->upper.data = 0; ++ ++ tx_desc->lower.data |= E1000_TXD_CMD_EOP; ++ tx_desc->lower.data |= E1000_TXD_CMD_IFCS; ++ tx_desc->lower.data |= E1000_TXD_CMD_IDE; ++ ++ if(adapter->shared.report_tx_early == 1) ++ tx_desc->lower.data |= E1000_TXD_CMD_RS; ++ else ++ tx_desc->lower.data |= E1000_TXD_CMD_RPS; ++ ++ /* Move the HW Tx Tail Pointer */ ++ ++ adapter->tx_ring.next_to_use++; ++ adapter->tx_ring.next_to_use %= adapter->tx_ring.count; ++ ++ E1000_WRITE_REG(&adapter->shared, TDT, adapter->tx_ring.next_to_use); ++ mdelay(10); ++ ++ atomic_dec(&adapter->tx_ring.unused); ++ ++ if(atomic_read(&adapter->tx_ring.unused) <= 1) { ++ ++ /* this driver never actually drops transmits, ++ * so use tx_dropped count to indicate the number of times ++ * netif_stop_queue is called due to no available descriptors ++ */ ++ ++ adapter->net_stats.tx_dropped++; ++ return (0); ++ } ++ return (1); ++} ++ ++int ++e1000_rcv_lbtest_frame(struct e1000_adapter *adapter, ++ unsigned int frame_size) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ struct e1000_rx_desc *rx_desc; ++ int i, j = 0, rcved_pkt = 0; ++ uint32_t Length; ++ struct sk_buff *skb; ++ ++ mdelay(500); ++ i = adapter->rx_ring.next_to_clean; ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ ++ while(rx_desc->status & E1000_RXD_STAT_DD) { ++ Length = le16_to_cpu(rx_desc->length) - CRC_LENGTH; ++ skb = adapter->rx_ring.buffer_info[i].skb; ++ ++ /* Snoop the packet for pattern */ ++ rcved_pkt = e1000_check_lbtest_frame(skb, frame_size); ++ ++ pci_unmap_single(pdev, adapter->rx_ring.buffer_info[i].dma, ++ adapter->rx_ring.buffer_info[i].length, ++ PCI_DMA_FROMDEVICE); ++ ++ dev_kfree_skb_irq(skb); ++ adapter->rx_ring.buffer_info[i].skb = NULL; ++ ++ rx_desc->status = 0; ++ atomic_inc(&adapter->rx_ring.unused); ++ ++ i++; ++ i %= adapter->rx_ring.count; ++ rx_desc = E1000_RX_DESC(adapter->rx_ring, i); ++ ++ if(rcved_pkt) ++ break; ++ ++ /* waited enough */ ++ if(j++ >= adapter->rx_ring.count) ++ return 0; ++ ++ mdelay(5); ++ ++ } ++ ++ adapter->rx_ring.next_to_clean = i; ++ ++ return (rcved_pkt); ++ ++} ++ ++void ++e1000_selective_wakeup_adapter(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ uint32_t ctrl, txcw; ++ ++ e1000_init_hw(&adapter->shared); ++ ++ if((adapter->link_active == FALSE) && ++ (adapter->shared.mac_type == e1000_82543)) { ++ ++ txcw = E1000_READ_REG(&adapter->shared, TXCW); ++ ctrl = E1000_READ_REG(&adapter->shared, CTRL); ++ E1000_WRITE_REG(&adapter->shared, TXCW, txcw & ~E1000_TXCW_ANE); ++ E1000_WRITE_REG(&adapter->shared, CTRL, ++ (ctrl | E1000_CTRL_SLU | E1000_CTRL_ILOS | ++ E1000_CTRL_FD)); ++ mdelay(20); ++ } ++ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) { ++ set_bit(E1000_BOARD_OPEN, &adapter->flags); ++ set_bit(E1000_DIAG_OPEN, &adapter->flags); ++ e1000_setup_tx_resources(adapter); ++ e1000_setup_rx_resources(adapter); ++ } ++ e1000_setup_rctl(adapter); ++ e1000_configure_rx(adapter); ++ e1000_alloc_rx_buffers((unsigned long) adapter); ++ e1000_configure_tx(adapter); ++} ++ ++void ++e1000_selective_hibernate_adapter(struct net_device *netdev) ++{ ++ struct e1000_adapter *adapter = netdev->priv; ++ uint32_t ctrl, txcw; ++ ++ if((adapter->link_active == FALSE) && ++ (adapter->shared.mac_type == e1000_82543)) { ++ ++ txcw = E1000_READ_REG(&adapter->shared, TXCW); ++ ctrl = E1000_READ_REG(&adapter->shared, CTRL); ++ ctrl &= ~E1000_CTRL_SLU & ~E1000_CTRL_ILOS; ++ E1000_WRITE_REG(&adapter->shared, TXCW, txcw | E1000_TXCW_ANE); ++ E1000_WRITE_REG(&adapter->shared, CTRL, ctrl); ++ mdelay(20); ++ } ++ /* clean out old buffers */ ++ e1000_clean_rx_ring(adapter); ++ e1000_clean_tx_ring(adapter); ++ if(test_and_clear_bit(E1000_DIAG_OPEN, &adapter->flags)) { ++ e1000_free_tx_resources(adapter); ++ e1000_free_rx_resources(adapter); ++ clear_bit(E1000_BOARD_OPEN, &adapter->flags); ++ } ++} ++ ++static int ++e1000_check_lbtest_frame(struct sk_buff *skb, ++ unsigned int frame_size) ++{ ++ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; ++ if(*(skb->data + 3) == 0xFF) { ++ if((*(skb->data + frame_size / 2 + 10) == 0xBE) && ++ (*(skb->data + frame_size / 2 + 12) == 0xAF)) { ++ return 1; ++ } ++ } ++ return 0; ++} ++#endif /* IDIAG */ ++ ++#ifdef SIOCETHTOOL ++/** ++ * e1000_ethtool_ioctl - Ethtool Ioctl Support ++ * @netdev: net device structure ++ * @ifr: interface request structure ++ **/ ++ ++static int ++e1000_ethtool_ioctl(struct net_device *netdev, ++ struct ifreq *ifr) ++{ ++ struct ethtool_cmd eth_cmd; ++ struct e1000_adapter *adapter = netdev->priv; ++ boolean_t re_initiate = FALSE; ++ ++#ifdef ETHTOOL_GLINK ++ struct ethtool_value eth_e1000_linkinfo; ++#endif ++#ifdef ETHTOOL_GDRVINFO ++ struct ethtool_drvinfo eth_e1000_info; ++#endif ++#ifdef ETHTOOL_GWOL ++ struct ethtool_wolinfo eth_e1000_wolinfo; ++#endif ++ ++ /* Get the data structure */ ++ if(copy_from_user(ð_cmd, ifr->ifr_data, sizeof(eth_cmd))) ++ return -EFAULT; ++ ++ switch (eth_cmd.cmd) { ++ /* Get the information */ ++ case ETHTOOL_GSET: ++ if(adapter->shared.media_type == e1000_media_type_copper) { ++ eth_cmd.supported = E1000_ETHTOOL_COPPER_INTERFACE_SUPPORTS; ++ eth_cmd.advertising = E1000_ETHTOOL_COPPER_INTERFACE_ADVERTISE; ++ eth_cmd.port = PORT_MII; ++ eth_cmd.phy_address = adapter->shared.phy_addr; ++ eth_cmd.transceiver = ++ (adapter->shared.mac_type > ++ e1000_82543) ? XCVR_INTERNAL : XCVR_EXTERNAL; ++ } else { ++ eth_cmd.supported = E1000_ETHTOOL_FIBER_INTERFACE_SUPPORTS; ++ eth_cmd.advertising = E1000_ETHTOOL_FIBER_INTERFACE_ADVERTISE; ++ eth_cmd.port = PORT_FIBRE; ++ } ++ ++ if(adapter->link_active == TRUE) { ++ e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, ++ &adapter->link_duplex); ++ eth_cmd.speed = adapter->link_speed; ++ eth_cmd.duplex = ++ (adapter->link_duplex == ++ FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; ++ } else { ++ eth_cmd.speed = 0; ++ eth_cmd.duplex = 0; ++ } ++ ++ if(adapter->shared.autoneg) ++ eth_cmd.autoneg = AUTONEG_ENABLE; ++ else ++ eth_cmd.autoneg = AUTONEG_DISABLE; ++ ++ if(copy_to_user(ifr->ifr_data, ð_cmd, sizeof(eth_cmd))) ++ return -EFAULT; ++ ++ break; ++ ++ /* set information */ ++ case ETHTOOL_SSET: ++ /* need proper permission to do set */ ++ if(!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ /* Cannot Force speed/duplex and at the same time autoneg. ++ * Autoneg will override forcing. ++ * For example to force speed/duplex pass in ++ * 'speed 100 duplex half autoneg off' ++ * pass in 'autoneg on' to start autoneg. ++ */ ++ printk("e1000: Requested link to be forced to %d Speed, %s Duplex " ++ "%s\n", eth_cmd.speed, (eth_cmd.duplex ? "Full" : "Half"), ++ (eth_cmd.autoneg ? "and Autonegotiate" : ".")); ++ ++ if(eth_cmd.autoneg && eth_cmd.speed) ++ printk("e1000: Autoneg request will over-ride speed forcing\n"); ++ ++ /* if not in autoneg mode and have been asked to enable autoneg */ ++ if(eth_cmd.autoneg) { ++ if(adapter->shared.autoneg && ++ adapter->shared.autoneg_advertised == AUTONEG_ADV_DEFAULT) ++ /* If already in Autoneg */ ++ return 0; ++ else { ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; ++ re_initiate = TRUE; ++ } ++ } ++ /* Force link to whatever speed and duplex */ ++ /* Also turning off Autoneg in case of non-gig speeds */ ++ else if(eth_cmd.speed) { ++ /* Check for invalid request */ ++ if(((eth_cmd.speed != SPEED_10) && (eth_cmd.speed != SPEED_100) && ++ (eth_cmd.speed != SPEED_1000)) || ++ ((eth_cmd.duplex != DUPLEX_HALF) && ++ (eth_cmd.duplex != DUPLEX_FULL)) || ++ (adapter->shared.media_type == e1000_media_type_fiber)) ++ return -EINVAL; ++ ++ e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, ++ &adapter->link_duplex); ++ /* If we are already forced to requested speed and duplex ++ * Donot do anything, just return ++ */ ++ if(!adapter->shared.autoneg && ++ (adapter->link_speed == eth_cmd.speed) && ++ (adapter->link_duplex == (eth_cmd.duplex + 1))) ++ ++ return 0; ++ ++ adapter->shared.autoneg = 0; ++ adapter->shared.autoneg_advertised = 0; ++ re_initiate = TRUE; ++ switch (eth_cmd.speed + eth_cmd.duplex) { ++ case (SPEED_10 + DUPLEX_HALF): ++ adapter->shared.forced_speed_duplex = e1000_10_half; ++ break; ++ case (SPEED_100 + DUPLEX_HALF): ++ adapter->shared.forced_speed_duplex = e1000_100_half; ++ break; ++ case (SPEED_10 + DUPLEX_FULL): ++ adapter->shared.forced_speed_duplex = e1000_10_full; ++ break; ++ case (SPEED_100 + DUPLEX_FULL): ++ adapter->shared.forced_speed_duplex = e1000_100_full; ++ break; ++ case (SPEED_1000 + DUPLEX_HALF): ++ printk("Half Duplex is not supported at 1000 Mbps\n"); ++ case (SPEED_1000 + DUPLEX_FULL): ++ printk("Using Auto-neg at 1000 Mbps Full Duplex\n"); ++ default: ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; ++ break; ++ } ++ } ++ ++ /* End of force */ ++ /* Put the adapter to new settings */ ++ if(re_initiate == TRUE) { ++ e1000_hibernate_adapter(netdev); ++ e1000_wakeup_adapter(netdev); ++ } else if(!eth_cmd.autoneg && !eth_cmd.speed) { ++ printk("Cannot turn off autoneg without " ++ "knowing what speed to force the link\n"); ++ printk("Speed specified was %dMbps\n", eth_cmd.speed); ++ return -EINVAL; ++ } ++ /* We donot support setting of ++ * whatever else that was requested */ ++ else ++ return -EOPNOTSUPP; ++ ++ break; ++ ++#ifdef ETHTOOL_NWAY_RST ++ case ETHTOOL_NWAY_RST: ++ /* need proper permission to restart auto-negotiation */ ++ if(!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ adapter->shared.autoneg = 1; ++ adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; ++ e1000_hibernate_adapter(netdev); ++ e1000_wakeup_adapter(netdev); ++ ++ break; ++#endif ++ ++#ifdef ETHTOOL_GLINK ++ case ETHTOOL_GLINK: ++ eth_e1000_linkinfo.data = adapter->link_active; ++ if(copy_to_user(ifr->ifr_data, ð_e1000_linkinfo, sizeof(eth_e1000_linkinfo))) ++ return -EFAULT; ++ break; ++#endif ++ ++#ifdef ETHTOOL_GDRVINFO ++ case ETHTOOL_GDRVINFO: ++ strcpy(eth_e1000_info.driver, e1000_driver_name); ++ strcpy(eth_e1000_info.version, e1000_driver_version); ++ strcpy(eth_e1000_info.fw_version, "None"); ++ strcpy(eth_e1000_info.bus_info, adapter->pdev->slot_name); ++ if(copy_to_user(ifr->ifr_data, ð_e1000_info, sizeof(eth_e1000_info))) ++ return -EFAULT; ++ break; ++#endif ++ ++#ifdef ETHTOOL_GWOL ++ case ETHTOOL_GWOL: ++ eth_e1000_wolinfo.supported = eth_e1000_wolinfo.wolopts = WAKE_MAGIC; ++ if(copy_to_user ++ (ifr->ifr_data, ð_e1000_wolinfo, sizeof(eth_e1000_wolinfo))) ++ return -EFAULT; ++ break; ++#endif ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++ ++} ++#endif /* SIOCETHTOOL */ ++ ++/** ++ * e1000_enable_WOL - Wake On Lan Support (Magic Pkt) ++ * @adapter: Adapter structure ++ **/ ++ ++static void ++e1000_enable_WOL(struct e1000_adapter *adapter) ++{ ++ uint32_t wuc_val; ++ ++ if(adapter->shared.mac_type <= e1000_82543) ++ return; ++ ++ /* Set up Wake-Up Ctrl reg */ ++ wuc_val = E1000_READ_REG(&adapter->shared, WUC); ++ wuc_val &= ~(E1000_WUC_APME | E1000_WUC_APMPME); ++ wuc_val |= (E1000_WUC_PME_STATUS | E1000_WUC_PME_EN); ++ ++ E1000_WRITE_REG(&adapter->shared, WUC, wuc_val); ++ ++ /* Set up Wake-up Filter */ ++ E1000_WRITE_REG(&adapter->shared, WUFC, E1000_WUFC_MAG); ++ ++ return; ++} ++ ++/** ++ * e1000_write_pci_cg - ++ * @shared: ++ * @reg: ++ * @value: ++ **/ ++ ++void ++e1000_write_pci_cfg(struct e1000_shared_adapter *shared, ++ uint32_t reg, ++ uint16_t *value) ++{ ++ struct e1000_adapter *adapter = (struct e1000_adapter *) shared->back; ++ ++ pci_write_config_word(adapter->pdev, reg, *value); ++ return; ++} ++ ++/* e1000_main.c */ +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_osdep.h 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,138 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++ ++/* glue for the OS independant part of e1000 ++ * includes register access macros ++ */ ++ ++#ifndef _E1000_OSDEP_H_ ++#define _E1000_OSDEP_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define usec_delay(x) udelay(x) ++#define msec_delay(x) mdelay(x) ++ ++#define PCI_COMMAND_REGISTER PCI_COMMAND ++#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE ++ ++typedef enum { ++ FALSE = 0, ++ TRUE = 1 ++} boolean_t; ++ ++#if DBG ++#define ASSERT(x) if(!(x)) panic("E1000: x") ++#define DEBUGOUT(S) printk(S "\n") ++#define DEBUGOUT1(S,A) printk(S "\n",A) ++#define DEBUGOUT2(S,A,B) printk(S "\n",A,B) ++#define DEBUGOUT3(S,A,B,C) printk(S "\n",A,B,C) ++#define DEBUGOUT7(S,A,B,C,D,E,F,G) printk(S "\n",A,B,C,D,E,F,G) ++#else ++#define ASSERT(x) ++#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 MSGOUT(S, A, B) printk(S "\n", A, B) ++#define DEBUGFUNC(F) DEBUGOUT(F) ++ ++#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))) ++ ++#endif /* _E1000_OSDEP_H_ */ +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_phy.c 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,1576 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/* e1000_phy.c ++ * Shared functions for accessing and configuring the PHY ++ */ ++ ++#include "e1000_mac.h" ++#include "e1000_phy.h" ++ ++/****************************************************************************** ++* Raises the Management Data Clock ++* ++* shared - Struct containing variables accessed by shared code ++* ctrl_reg - Device control register's current value ++******************************************************************************/ ++static void ++e1000_raise_mdc(struct e1000_shared_adapter *shared, ++ uint32_t *ctrl_reg) ++{ ++ /* Raise the clock input to the Management Data Clock (by setting ++ * the MDC bit), and then delay 2 microseconds. ++ */ ++ E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC)); ++ usec_delay(2); ++ return; ++} ++ ++/****************************************************************************** ++* Lowers the Management Data Clock ++* ++* shared - Struct containing variables accessed by shared code ++* ctrl_reg - Device control register's current value ++******************************************************************************/ ++static void ++e1000_lower_mdc(struct e1000_shared_adapter *shared, ++ uint32_t *ctrl_reg) ++{ ++ /* Lower the clock input to the Management Data Clock (by clearing ++ * the MDC bit), and then delay 2 microseconds. ++ */ ++ E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC)); ++ usec_delay(2); ++ return; ++} ++ ++/****************************************************************************** ++* Shifts data bits out to the PHY ++* ++* shared - Struct containing variables accessed by shared code ++* data - Data to send out to the PHY ++* count - Number of bits to shift out ++* ++* Bits are shifted out in MSB to LSB order. ++******************************************************************************/ ++static void ++e1000_phy_shift_out(struct e1000_shared_adapter *shared, ++ uint32_t data, ++ uint16_t count) ++{ ++ uint32_t ctrl_reg; ++ uint32_t mask; ++ ++ ASSERT(count <= 32); ++ ++ /* We need to shift "count" number of bits out to the PHY. So, the ++ * value in the "Data" parameter will be shifted out to the PHY ++ * one bit at a time. In order to do this, "Data" must be broken ++ * down into bits, which is what the "while" logic does below. ++ */ ++ mask = 0x01; ++ mask <<= (count - 1); ++ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to ++ * be used as output pins. ++ */ ++ ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); ++ ++ while(mask) { ++ /* A "1" is shifted out to the PHY by setting the MDIO bit to ++ * "1" and then raising and lowering the Management Data Clock ++ * (MDC). A "0" is shifted out to the PHY by setting the MDIO ++ * bit to "0" and then raising and lowering the clock. ++ */ ++ if(data & mask) ++ ctrl_reg |= E1000_CTRL_MDIO; ++ else ++ ctrl_reg &= ~E1000_CTRL_MDIO; ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ usec_delay(2); ++ ++ e1000_raise_mdc(shared, &ctrl_reg); ++ e1000_lower_mdc(shared, &ctrl_reg); ++ ++ mask = mask >> 1; ++ } ++ ++ /* Clear the data bit just before leaving this routine. */ ++ ctrl_reg &= ~E1000_CTRL_MDIO; ++ return; ++} ++ ++/****************************************************************************** ++* Shifts data bits in from the PHY ++* ++* shared - Struct containing variables accessed by shared code ++* ++* Bits are shifted in in MSB to LSB order. ++******************************************************************************/ ++static uint16_t ++e1000_phy_shift_in(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ uint16_t data = 0; ++ uint8_t i; ++ ++ /* In order to read a register from the PHY, we need to shift in a ++ * total of 18 bits from the PHY. The first two bit (TurnAround) ++ * times are used to avoid contention on the MDIO pin when a read ++ * operation is performed. These two bits are ignored by us and ++ * thrown away. Bits are "shifted in" by raising the clock input ++ * to the Management Data Clock (setting the MDC bit), and then ++ * reading the value of the MDIO bit. ++ */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as ++ * input. ++ */ ++ ctrl_reg &= ~E1000_CTRL_MDIO_DIR; ++ ctrl_reg &= ~E1000_CTRL_MDIO; ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ /* Raise and Lower the clock before reading in the data. This ++ * accounts for the TurnAround bits. The first clock occurred ++ * when we clocked out the last bit of the Register Address. ++ */ ++ e1000_raise_mdc(shared, &ctrl_reg); ++ e1000_lower_mdc(shared, &ctrl_reg); ++ ++ for(data = 0, i = 0; i < 16; i++) { ++ data = data << 1; ++ e1000_raise_mdc(shared, &ctrl_reg); ++ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Check to see if we shifted in a "1". */ ++ if(ctrl_reg & E1000_CTRL_MDIO) ++ data |= 1; ++ ++ e1000_lower_mdc(shared, &ctrl_reg); ++ } ++ ++ e1000_raise_mdc(shared, &ctrl_reg); ++ e1000_lower_mdc(shared, &ctrl_reg); ++ ++ /* Clear the MDIO bit just before leaving this routine. */ ++ ctrl_reg &= ~E1000_CTRL_MDIO; ++ ++ return (data); ++} ++ ++/****************************************************************************** ++* Force PHY speed and duplex settings to shared->forced_speed_duplex ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++static void ++e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared) ++{ ++ uint32_t tctl_reg; ++ uint32_t ctrl_reg; ++ uint32_t shift; ++ uint16_t mii_ctrl_reg; ++ uint16_t mii_status_reg; ++ uint16_t phy_data; ++ uint16_t i; ++ ++ DEBUGFUNC("e1000_phy_force_speed_duplex"); ++ ++ /* Turn off Flow control if we are forcing speed and duplex. */ ++ shared->fc = e1000_fc_none; ++ ++ DEBUGOUT1("shared->fc = %d\n", shared->fc); ++ ++ /* Read the Device Control Register. */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ ++ ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ ctrl_reg &= ~(DEVICE_SPEED_MASK); ++ ++ /* Clear the Auto Speed Detect Enable bit. */ ++ ctrl_reg &= ~E1000_CTRL_ASDE; ++ ++ /* Read the MII Control Register. */ ++ mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); ++ ++ /* We need to disable autoneg in order to force link and duplex. */ ++ ++ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; ++ ++ /* Are we forcing Full or Half Duplex? */ ++ if(shared->forced_speed_duplex == e1000_100_full || ++ shared->forced_speed_duplex == e1000_10_full) { ++ ++ /* We want to force full duplex so we SET the full duplex bits ++ * in the Device and MII Control Registers. ++ */ ++ ctrl_reg |= E1000_CTRL_FD; ++ mii_ctrl_reg |= MII_CR_FULL_DUPLEX; ++ ++ DEBUGOUT("Full Duplex\n"); ++ } else { ++ ++ /* We want to force half duplex so we CLEAR the full duplex ++ * bits in the Device and MII Control Registers. ++ */ ++ ctrl_reg &= ~E1000_CTRL_FD; ++ mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */ ++ ++ DEBUGOUT("Half Duplex\n"); ++ } ++ ++ /* Are we forcing 100Mbps??? */ ++ if(shared->forced_speed_duplex == e1000_100_full || ++ shared->forced_speed_duplex == e1000_100_half) { ++ ++ /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ ++ ctrl_reg |= E1000_CTRL_SPD_100; ++ mii_ctrl_reg |= MII_CR_SPEED_100; ++ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); ++ ++ DEBUGOUT("Forcing 100mb "); ++ } else { /* Force 10MB Full or Half */ ++ ++ /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ ++ ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); ++ mii_ctrl_reg |= MII_CR_SPEED_10; ++ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); ++ ++ DEBUGOUT("Forcing 10mb "); ++ } ++ ++ /* Now we need to configure the Collision Distance. We need to read ++ * the Transmit Control Register to do this. ++ * Note: This must be done for both Half or Full Duplex. ++ */ ++ tctl_reg = E1000_READ_REG(shared, TCTL); ++ DEBUGOUT1("tctl_reg = %x\n", tctl_reg); ++ ++ if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) { ++ ++ /* We are in Half Duplex mode so we need to set up our collision ++ * distance for 10/100. ++ */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ shift = E1000_HDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } else { ++ /* We are in Full Duplex mode. We have the same collision ++ * distance regardless of speed. ++ */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ shift = E1000_FDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } ++ ++ /* Write the configured values back to the Transmit Control Reg. */ ++ E1000_WRITE_REG(shared, TCTL, tctl_reg); ++ ++ /* Write the configured values back to the Device Control Reg. */ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ /* Write the MII Control Register with the new PHY configuration. */ ++ phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ ++ /* Clear Auto-Crossover to force MDI manually. ++ * M88E1000 requires MDI forced whenever speed/duplex is forced ++ */ ++ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; ++ ++ e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); ++ ++ DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); ++ ++ /* Need to reset the PHY or these bits will get ignored. */ ++ mii_ctrl_reg |= MII_CR_RESET; ++ ++ e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); ++ ++ /* The wait_autoneg_complete flag may be a little misleading here. ++ * Since we are forcing speed and duplex, Auto-Neg is not enabled. ++ * But we do want to delay for a period while forcing only so we ++ * don't generate false No Link messages. So we will wait here ++ * only if the user has set wait_autoneg_complete to 1, which is ++ * the default. ++ */ ++ if(shared->wait_autoneg_complete) { ++ /* We will wait for autoneg to complete. */ ++ DEBUGOUT("Waiting for forced speed/duplex link.\n"); ++ mii_status_reg = 0; ++ ++ /* We will wait for autoneg to complete or 4.5 seconds to expire. */ ++ for(i = PHY_FORCE_TIME; i > 0; i--) { ++ /* Read the MII Status Register and wait for Auto-Neg ++ * Complete bit to be set. ++ */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ if(mii_status_reg & MII_SR_LINK_STATUS) ++ break; ++ ++ msec_delay(100); ++ } /* end for loop */ ++ ++ if(i == 0) { /* We didn't get link */ ++ ++ /* Reset the DSP and wait again for link. */ ++ e1000_phy_reset_dsp(shared); ++ } ++ ++ /* This loop will early-out if the link condition has been met. */ ++ for(i = PHY_FORCE_TIME; i > 0; i--) { ++ if(mii_status_reg & MII_SR_LINK_STATUS) ++ break; ++ ++ msec_delay(100); ++ /* Read the MII Status Register and wait for Auto-Neg ++ * Complete bit to be set. ++ */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ } /* end for loop */ ++ } /* end if wait_autoneg_complete */ ++ /* ++ * Because we reset the PHY above, we need to re-force TX_CLK in the ++ * Extended PHY Specific Control Register to 25MHz clock. This ++ * value defaults back to a 2.5MHz clock when the PHY is reset. ++ */ ++ phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); ++ ++ phy_data |= M88E1000_EPSCR_TX_CLK_25; ++ ++ e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); ++ ++ /* In addition, because of the s/w reset above, we need to enable ++ * CRS on TX. This must be set for both full and half duplex ++ * operation. ++ */ ++ phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ ++ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ++ ++ e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); ++ DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data); ++ ++ return; ++} ++ ++/***************************************************************************** ++* Reads the value from a PHY register ++* ++* shared - Struct containing variables accessed by shared code ++* reg_addr - address of the PHY register to read ++******************************************************************************/ ++uint16_t ++e1000_read_phy_reg(struct e1000_shared_adapter *shared, ++ uint32_t reg_addr) ++{ ++ uint32_t i; ++ uint32_t data = 0; ++ uint32_t command = 0; ++ ++ ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); ++ ++ if(shared->mac_type > e1000_82543) { ++ /* Set up Op-code, Phy Address, and ++ * register address in the MDI Control register. The MAC will ++ * take care of interfacing with the PHY to retrieve the ++ * desired data. ++ */ ++ command = ((reg_addr << E1000_MDIC_REG_SHIFT) | ++ (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | ++ (E1000_MDIC_OP_READ)); ++ ++ E1000_WRITE_REG(shared, MDIC, command); ++ ++ /* Check every 10 usec to see if the read completed. The read ++ * may take as long as 64 usecs (we'll wait 100 usecs max) ++ * from the CPU Write to the Ready bit assertion. ++ */ ++ for(i = 0; i < 64; i++) { ++ usec_delay(10); ++ ++ data = E1000_READ_REG(shared, MDIC); ++ ++ if(data & E1000_MDIC_READY) ++ break; ++ } ++ } else { ++ /* We must first send a preamble through the MDIO pin to signal the ++ * beginning of an MII instruction. This is done by sending 32 ++ * consecutive "1" bits. ++ */ ++ e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); ++ ++ /* Now combine the next few fields that are required for a read ++ * operation. We use this method instead of calling the ++ * e1000_phy_shift_out routine five different times. The format of ++ * a MII read instruction consists of a shift out of 14 bits and is ++ * defined as follows: ++ * ++ * followed by a shift in of 18 bits. This first two bits shifted ++ * in are TurnAround bits used to avoid contention on the MDIO pin ++ * when a READ operation is performed. These two bits are thrown ++ * away followed by a shift in of 16 bits which contains the ++ * desired data. ++ */ ++ command = ((reg_addr) | ++ (shared->phy_addr << 5) | ++ (PHY_OP_READ << 10) | (PHY_SOF << 12)); ++ ++ e1000_phy_shift_out(shared, command, 14); ++ ++ /* Now that we've shifted out the read command to the MII, we need ++ * to "shift in" the 16-bit value (18 total bits) of the requested ++ * PHY register address. ++ */ ++ data = (uint32_t) e1000_phy_shift_in(shared); ++ } ++ ++ ASSERT(!(data & E1000_MDIC_ERROR)); ++ ++ return ((uint16_t) data); ++} ++ ++/****************************************************************************** ++* Writes a value to a PHY register ++* ++* shared - Struct containing variables accessed by shared code ++* reg_addr - address of the PHY register to write ++* data - data to write to the PHY ++******************************************************************************/ ++void ++e1000_write_phy_reg(struct e1000_shared_adapter *shared, ++ uint32_t reg_addr, ++ uint16_t data) ++{ ++ uint32_t i; ++ uint32_t command = 0; ++ uint32_t mdic_reg; ++ ++ ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); ++ ++ if(shared->mac_type > e1000_82543) { ++ /* Set up Op-code, Phy Address, register ++ * address, and data intended for the PHY register in the MDI ++ * Control register. The MAC will take care of interfacing ++ * with the PHY to send the desired data. ++ */ ++ command = (((uint32_t) data) | ++ (reg_addr << E1000_MDIC_REG_SHIFT) | ++ (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | ++ (E1000_MDIC_OP_WRITE)); ++ ++ E1000_WRITE_REG(shared, MDIC, command); ++ ++ /* Check every 10 usec to see if the read completed. The read ++ * may take as long as 64 usecs (we'll wait 100 usecs max) ++ * from the CPU Write to the Ready bit assertion. ++ */ ++ for(i = 0; i < 10; i++) { ++ usec_delay(10); ++ ++ mdic_reg = E1000_READ_REG(shared, MDIC); ++ ++ if(mdic_reg & E1000_MDIC_READY) ++ break; ++ } ++ } else { ++ /* We'll need to use the SW defined pins to shift the write command ++ * out to the PHY. We first send a preamble to the PHY to signal the ++ * beginning of the MII instruction. This is done by sending 32 ++ * consecutive "1" bits. ++ */ ++ e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); ++ ++ /* Now combine the remaining required fields that will indicate ++ * a write operation. We use this method instead of calling the ++ * e1000_phy_shift_out routine for each field in the command. The ++ * format of a MII write instruction is as follows: ++ * . ++ */ ++ command = ((PHY_TURNAROUND) | ++ (reg_addr << 2) | ++ (shared->phy_addr << 7) | ++ (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); ++ command <<= 16; ++ command |= ((uint32_t) data); ++ ++ e1000_phy_shift_out(shared, command, 32); ++ } ++ return; ++} ++ ++/****************************************************************************** ++* Returns the PHY to the power-on reset state ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++void ++e1000_phy_hw_reset(struct e1000_shared_adapter *shared) ++{ ++ uint32_t ctrl_reg; ++ uint32_t ctrl_ext_reg; ++ ++ DEBUGFUNC("e1000_phy_hw_reset"); ++ ++ DEBUGOUT("Resetting Phy...\n"); ++ ++ if(shared->mac_type > e1000_82543) { ++ /* Read the device control register and assert the ++ * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out ++ * of reset. ++ */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ ctrl_reg |= E1000_CTRL_PHY_RST; ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ msec_delay(20); ++ ++ ctrl_reg &= ~E1000_CTRL_PHY_RST; ++ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ msec_delay(20); ++ } else { ++ /* Read the Extended Device Control Register, assert the ++ * PHY_RESET_DIR bit. Then clock it out to the PHY. ++ */ ++ ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); ++ ++ ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4; ++ ++ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); ++ ++ msec_delay(20); ++ ++ /* Set the reset bit in the device control register and clock ++ * it out to the PHY. ++ */ ++ ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); ++ ++ ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4; ++ ++ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); ++ ++ msec_delay(20); ++ ++ ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); ++ ++ ctrl_ext_reg |= E1000_CTRL_PHY_RESET4; ++ ++ E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); ++ ++ msec_delay(20); ++ } ++ return; ++} ++ ++/****************************************************************************** ++* Resets the PHY ++* ++* shared - Struct containing variables accessed by shared code ++* ++* Sets bit 15 of the MII Control regiser ++******************************************************************************/ ++boolean_t ++e1000_phy_reset(struct e1000_shared_adapter *shared) ++{ ++ uint16_t reg_data; ++ uint16_t i; ++ ++ DEBUGFUNC("e1000_phy_reset"); ++ ++ /* Read the MII control register, set the reset bit and write the ++ * value back by clocking it out to the PHY. ++ */ ++ reg_data = e1000_read_phy_reg(shared, PHY_CTRL); ++ ++ reg_data |= MII_CR_RESET; ++ ++ e1000_write_phy_reg(shared, PHY_CTRL, reg_data); ++ ++ /* Wait for bit 15 of the MII Control Register to be cleared ++ * indicating the PHY has been reset. ++ */ ++ i = 0; ++ while((reg_data & MII_CR_RESET) && i++ < 500) { ++ reg_data = e1000_read_phy_reg(shared, PHY_CTRL); ++ usec_delay(1); ++ } ++ ++ if(i >= 500) { ++ DEBUGOUT("Timeout waiting for PHY to reset.\n"); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/****************************************************************************** ++* Detects which PHY is present and the speed and duplex ++* ++* shared - Struct containing variables accessed by shared code ++* ctrl_reg - current value of the device control register ++******************************************************************************/ ++boolean_t ++e1000_phy_setup(struct e1000_shared_adapter *shared, ++ uint32_t ctrl_reg) ++{ ++ uint16_t mii_ctrl_reg; ++ uint16_t mii_status_reg; ++ uint16_t phy_specific_ctrl_reg; ++ uint16_t mii_autoneg_adv_reg; ++ uint16_t mii_1000t_ctrl_reg; ++ uint16_t i; ++ uint16_t data; ++ uint16_t autoneg_hw_setting; ++ uint16_t autoneg_fc_setting; ++ boolean_t restart_autoneg = FALSE; ++ boolean_t force_autoneg_restart = FALSE; ++ ++ DEBUGFUNC("e1000_phy_setup"); ++ ++ /* We want to enable the Auto-Speed Detection bit in the Device ++ * Control Register. When set to 1, the MAC automatically detects ++ * the resolved speed of the link and self-configures appropriately. ++ * The Set Link Up bit must also be set for this behavior work ++ * properly. ++ */ ++ /* Nothing but 82543 and newer */ ++ ASSERT(shared->mac_type >= e1000_82543); ++ ++ /* With 82543, we need to force speed/duplex ++ * on the MAC equal to what the PHY speed/duplex configuration is. ++ * In addition, on 82543, we need to perform a hardware reset ++ * on the PHY to take it out of reset. ++ */ ++ if(shared->mac_type >= e1000_82544) { ++ ctrl_reg |= E1000_CTRL_SLU; ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ } else { ++ ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ if(shared->mac_type == e1000_82543) ++ e1000_phy_hw_reset(shared); ++ } ++ ++ if(!e1000_detect_gig_phy(shared)) { ++ /* No PHY detected, return FALSE */ ++ DEBUGOUT("PhySetup failure, did not detect valid phy.\n"); ++ return (FALSE); ++ } ++ ++ DEBUGOUT1("Phy ID = %x \n", shared->phy_id); ++ ++ /* Read the MII Control Register. */ ++ mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); ++ ++ DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg); ++ ++ /* Check to see if the Auto Neg Enable bit is set in the MII Control ++ * Register. If not, we could be in a situation where a driver was ++ * loaded previously and was forcing speed and duplex. Then the ++ * driver was unloaded but a e1000_phy_hw_reset was not performed, so ++ * link was still being forced and link was still achieved. Then ++ * the driver was reloaded with the intention to auto-negotiate, but ++ * since link is already established we end up not restarting ++ * auto-neg. So if the auto-neg bit is not enabled and the driver ++ * is being loaded with the desire to auto-neg, we set this flag to ++ * to ensure the restart of the auto-neg engine later in the logic. ++ */ ++ if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN)) ++ force_autoneg_restart = TRUE; ++ ++ /* Clear the isolate bit for normal operation and write it back to ++ * the MII Control Reg. Although the spec says this doesn't need ++ * to be done when the PHY address is not equal to zero, we do it ++ * anyway just to be safe. ++ */ ++ mii_ctrl_reg &= ~(MII_CR_ISOLATE); ++ ++ e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); ++ ++ data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ ++ /* Enable CRS on TX. This must be set for half-duplex operation. */ ++ data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ++ ++ DEBUGOUT1("M88E1000 PSCR: %x \n", data); ++ ++ e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data); ++ ++ data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); ++ ++ /* Force TX_CLK in the Extended PHY Specific Control Register ++ * to 25MHz clock. ++ */ ++ data |= M88E1000_EPSCR_TX_CLK_25; ++ ++ e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data); ++ ++ /* Certain PHYs will set the default of MII register 4 differently. ++ * We need to check this against our fc value. If it is ++ * different, we need to setup up register 4 correctly and restart ++ * autonegotiation. ++ */ ++ /* Read the MII Auto-Neg Advertisement Register (Address 4). */ ++ mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); ++ ++ /* Shift right to put 10T-Half bit in bit 0 ++ * Isolate the four bits for 100/10 Full/Half. ++ */ ++ autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF; ++ ++ /* Get the 1000T settings. */ ++ mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); ++ ++ /* Isolate and OR in the 1000T settings. */ ++ autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4); ++ ++ /* mask all bits in the MII Auto-Neg Advertisement Register ++ * except for ASM_DIR and PAUSE and shift. This value ++ * will be used later to see if we need to restart Auto-Negotiation. ++ */ ++ autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10); ++ ++ /* Perform some bounds checking on the shared->autoneg_advertised ++ * parameter. If this variable is zero, then set it to the default. ++ */ ++ shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ ++ /* If autoneg_advertised is zero, we assume it was not defaulted ++ * by the calling code so we set to advertise full capability. ++ */ ++ if(shared->autoneg_advertised == 0) ++ shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; ++ ++ /* We could be in the situation where Auto-Neg has already completed ++ * and the user has not indicated any overrides. In this case we ++ * simply need to call e1000_get_speed_and_duplex to obtain the Auto- ++ * Negotiated speed and duplex, then return. ++ */ ++ if(!force_autoneg_restart && shared->autoneg && ++ (shared->autoneg_advertised == autoneg_hw_setting) && ++ (shared->fc == autoneg_fc_setting)) { ++ ++ DEBUGOUT("No overrides - Reading MII Status Reg..\n"); ++ ++ /* Read the MII Status Register. We read this twice because ++ * certain bits are "sticky" and need to be read twice. ++ */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg); ++ ++ /* Do we have link now? (if so, auto-neg has completed) */ ++ if(mii_status_reg & MII_SR_LINK_STATUS) { ++ data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); ++ DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); ++ ++ /* We have link, so we need to finish the config process: ++ * 1) Set up the MAC to the current PHY speed/duplex ++ * if we are on 82543. If we ++ * are on newer silicon, we only need to configure ++ * collision distance in the Transmit Control Register. ++ * 2) Set up flow control on the MAC to that established ++ * with the link partner. ++ */ ++ if(shared->mac_type >= e1000_82544) ++ e1000_config_collision_dist(shared); ++ else ++ e1000_config_mac_to_phy(shared, data); ++ ++ e1000_config_fc_after_link_up(shared); ++ ++ return (TRUE); ++ } ++ } ++ ++ /* Options: ++ * MDI/MDI-X = 0 (default) ++ * 0 - Auto for all speeds ++ * 1 - MDI mode ++ * 2 - MDI-X mode ++ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) ++ */ ++ phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ ++ phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE; ++ ++ switch (shared->mdix) { ++ case 1: ++ phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE; ++ break; ++ case 2: ++ phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE; ++ break; ++ case 3: ++ phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T; ++ break; ++ case 0: ++ default: ++ phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE; ++ break; ++ } ++ ++ e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); ++ ++ /* Options: ++ * disable_polarity_correction = 0 (default) ++ * Automatic Correction for Reversed Cable Polarity ++ * 0 - Disabled ++ * 1 - Enabled ++ */ ++ phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ ++ phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL; ++ ++ if(shared->disable_polarity_correction == 1) ++ phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL; ++ ++ e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); ++ ++ /* Options: ++ * autoneg = 1 (default) ++ * PHY will advertise value(s) parsed from ++ * autoneg_advertised and fc ++ * autoneg = 0 ++ * PHY will be set to 10H, 10F, 100H, or 100F ++ * depending on value parsed from forced_speed_duplex. ++ */ ++ ++ /* Is autoneg enabled? This is enabled by default or by software override. ++ * If so, call e1000_phy_setup_autoneg routine to parse the ++ * autoneg_advertised and fc options. If autoneg is NOT enabled, then the ++ * user should have provided a speed/duplex override. If so, then call ++ * e1000_phy_force_speed_duplex to parse and set this up. Otherwise, ++ * we are in an error situation and need to bail. ++ */ ++ if(shared->autoneg) { ++ DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); ++ restart_autoneg = e1000_phy_setup_autoneg(shared); ++ } else { ++ DEBUGOUT("Forcing speed and duplex\n"); ++ e1000_phy_force_speed_duplex(shared); ++ } ++ ++ /* Based on information parsed above, check the flag to indicate ++ * whether we need to restart Auto-Neg. ++ */ ++ if(restart_autoneg) { ++ DEBUGOUT("Restarting Auto-Neg\n"); ++ ++ /* Read the MII Control Register. */ ++ mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); ++ ++ /* Restart auto-negotiation by setting the Auto Neg Enable bit and ++ * the Auto Neg Restart bit. ++ */ ++ mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); ++ ++ e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); ++ ++ /* Does the user want to wait for Auto-Neg to complete here, or ++ * check at a later time (for example, callback routine). ++ */ ++ if(shared->wait_autoneg_complete) ++ e1000_wait_autoneg(shared); ++ } /* end if restart_autoneg */ ++ ++ /* Read the MII Status Register. */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n", ++ mii_status_reg); ++ ++ /* Check link status. Wait up to 100 microseconds for link to ++ * become valid. ++ */ ++ for(i = 0; i < 10; i++) { ++ if(mii_status_reg & MII_SR_LINK_STATUS) ++ break; ++ usec_delay(10); ++ DEBUGOUT(". "); ++ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ } ++ ++ if(mii_status_reg & MII_SR_LINK_STATUS) { ++ /* Yes, so configure MAC to PHY settings as well as flow control ++ * registers. ++ */ ++ data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); ++ ++ DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); ++ ++ /* We have link, so we need to finish the config process: ++ * 1) Set up the MAC to the current PHY speed/duplex ++ * if we are on 82543. If we ++ * are on newer silicon, we only need to configure ++ * collision distance in the Transmit Control Register. ++ * 2) Set up flow control on the MAC to that established with ++ * the link partner. ++ */ ++ if(shared->mac_type >= e1000_82544) ++ e1000_config_collision_dist(shared); ++ else ++ e1000_config_mac_to_phy(shared, data); ++ ++ e1000_config_fc_after_link_up(shared); ++ ++ DEBUGOUT("Valid link established!!!\n"); ++ } else { ++ DEBUGOUT("Unable to establish link!!!\n"); ++ } ++ ++ return (TRUE); ++} ++ ++/****************************************************************************** ++* Configures PHY autoneg and flow control advertisement settings ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++boolean_t ++e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared) ++{ ++ uint16_t mii_autoneg_adv_reg; ++ uint16_t mii_1000t_ctrl_reg; ++ ++ DEBUGFUNC("e1000_phy_setup_autoneg"); ++ ++ /* Read the MII Auto-Neg Advertisement Register (Address 4). */ ++ mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); ++ ++ /* Read the MII 1000Base-T Control Register (Address 9). */ ++ mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); ++ ++ /* Need to parse both autoneg_advertised and fc and set up ++ * the appropriate PHY registers. First we will parse for ++ * autoneg_advertised software override. Since we can advertise ++ * a plethora of combinations, we need to check each bit ++ * individually. ++ */ ++ ++ /* First we clear all the 10/100 mb speed bits in the Auto-Neg ++ * Advertisement Register (Address 4) and the 1000 mb speed bits in ++ * the 1000Base-T Control Register (Address 9). ++ */ ++ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; ++ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; ++ ++ DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised); ++ ++ /* Do we want to advertise 10 Mb Half Duplex? */ ++ if(shared->autoneg_advertised & ADVERTISE_10_HALF) { ++ DEBUGOUT("Advertise 10mb Half duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; ++ } ++ ++ /* Do we want to advertise 10 Mb Full Duplex? */ ++ if(shared->autoneg_advertised & ADVERTISE_10_FULL) { ++ DEBUGOUT("Advertise 10mb Full duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; ++ } ++ ++ /* Do we want to advertise 100 Mb Half Duplex? */ ++ if(shared->autoneg_advertised & ADVERTISE_100_HALF) { ++ DEBUGOUT("Advertise 100mb Half duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; ++ } ++ ++ /* Do we want to advertise 100 Mb Full Duplex? */ ++ if(shared->autoneg_advertised & ADVERTISE_100_FULL) { ++ DEBUGOUT("Advertise 100mb Full duplex\n"); ++ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; ++ } ++ ++ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ ++ if(shared->autoneg_advertised & ADVERTISE_1000_HALF) { ++ DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); ++ } ++ ++ /* Do we want to advertise 1000 Mb Full Duplex? */ ++ if(shared->autoneg_advertised & ADVERTISE_1000_FULL) { ++ DEBUGOUT("Advertise 1000mb Full duplex\n"); ++ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; ++ } ++ ++ /* Check for a software override of the flow control settings, and ++ * setup the PHY advertisement registers accordingly. If ++ * auto-negotiation is enabled, then software will have to set the ++ * "PAUSE" bits to the correct value in the Auto-Negotiation ++ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. ++ * ++ * The possible values of the "fc" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause frames ++ * but not send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames ++ * but we do not support receiving pause frames). ++ * 3: Both Rx and TX flow control (symmetric) are enabled. ++ * other: No software override. The flow control configuration ++ * in the EEPROM is used. ++ */ ++ switch (shared->fc) { ++ case e1000_fc_none: /* 0 */ ++ /* Flow control (RX & TX) is completely disabled by a ++ * software over-ride. ++ */ ++ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ case e1000_fc_rx_pause: /* 1 */ ++ /* RX Flow control is enabled, and TX Flow control is ++ * disabled, by a software over-ride. ++ */ ++ ++ /* Since there really isn't a way to advertise that we are ++ * capable of RX Pause ONLY, we will advertise that we ++ * support both symmetric and asymmetric RX PAUSE. Later ++ * (in e1000_config_fc_after_link_up) we will disable the ++ *shared's ability to send PAUSE frames. ++ */ ++ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ case e1000_fc_tx_pause: /* 2 */ ++ /* TX Flow control is enabled, and RX Flow control is ++ * disabled, by a software over-ride. ++ */ ++ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; ++ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; ++ break; ++ case e1000_fc_full: /* 3 */ ++ /* Flow control (both RX and TX) is enabled by a software ++ * over-ride. ++ */ ++ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); ++ break; ++ default: ++ /* We should never get here. The value should be 0-3. */ ++ DEBUGOUT("Flow control param set incorrectly\n"); ++ ASSERT(0); ++ break; ++ } ++ ++ /* Write the MII Auto-Neg Advertisement Register (Address 4). */ ++ e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); ++ ++ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); ++ ++ /* Write the MII 1000Base-T Control Register (Address 9). */ ++ e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg); ++ return (TRUE); ++} ++ ++/****************************************************************************** ++* Sets MAC speed and duplex settings to reflect the those in the PHY ++* ++* shared - Struct containing variables accessed by shared code ++* mii_reg - data to write to the MII control register ++* ++* The contents of the PHY register containing the needed information need to ++* be passed in. ++******************************************************************************/ ++void ++e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, ++ uint16_t mii_reg) ++{ ++ uint32_t ctrl_reg; ++ uint32_t tctl_reg; ++ uint32_t shift; ++ ++ DEBUGFUNC("e1000_config_mac_to_phy"); ++ ++ /* We need to read the Transmit Control register to configure the ++ * collision distance. ++ * Note: This must be done for both Half or Full Duplex. ++ */ ++ tctl_reg = E1000_READ_REG(shared, TCTL); ++ DEBUGOUT1("tctl_reg = %x\n", tctl_reg); ++ ++ /* Read the Device Control Register and set the bits to Force Speed ++ * and Duplex. ++ */ ++ ctrl_reg = E1000_READ_REG(shared, CTRL); ++ ++ ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ++ ctrl_reg &= ~(DEVICE_SPEED_MASK); ++ ++ DEBUGOUT1("MII Register Data = %x\r\n", mii_reg); ++ ++ /* Clear the ILOS bit. */ ++ ctrl_reg &= ~E1000_CTRL_ILOS; ++ ++ /* Set up duplex in the Device Control and Transmit Control ++ * registers depending on negotiated values. ++ */ ++ if(mii_reg & M88E1000_PSSR_DPLX) { ++ ctrl_reg |= E1000_CTRL_FD; ++ ++ /* We are in Full Duplex mode. We have the same collision ++ * distance regardless of speed. ++ */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ shift = E1000_FDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } else { ++ ctrl_reg &= ~E1000_CTRL_FD; ++ ++ /* We are in Half Duplex mode. Our Half Duplex collision ++ * distance is different for Gigabit than for 10/100 so we will ++ * set accordingly. ++ */ ++ if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { ++ /* 1000Mbs HDX */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ shift = E1000_GB_HDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ ++ } else { ++ /* 10/100Mbs HDX */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ shift = E1000_HDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } ++ } ++ ++ /* Set up speed in the Device Control register depending on ++ * negotiated values. ++ */ ++ if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) ++ ctrl_reg |= E1000_CTRL_SPD_1000; ++ else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) ++ ctrl_reg |= E1000_CTRL_SPD_100; ++ else ++ ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); ++ ++ /* Write the configured values back to the Transmit Control Reg. */ ++ E1000_WRITE_REG(shared, TCTL, tctl_reg); ++ ++ /* Write the configured values back to the Device Control Reg. */ ++ E1000_WRITE_REG(shared, CTRL, ctrl_reg); ++ ++ return; ++} ++ ++/****************************************************************************** ++* Sets the collision distance in the Transmit Control register ++* ++* shared - Struct containing variables accessed by shared code ++* ++* Link should have been established previously. Reads the speed and duplex ++* information from the Device Status register. ++******************************************************************************/ ++void ++e1000_config_collision_dist(struct e1000_shared_adapter *shared) ++{ ++ uint32_t tctl_reg; ++ uint16_t speed; ++ uint16_t duplex; ++ uint32_t shift; ++ ++ DEBUGFUNC("e1000_config_collision_dist"); ++ ++ /* Get our current speed and duplex from the Device Status Register. */ ++ e1000_get_speed_and_duplex(shared, &speed, &duplex); ++ ++ /* We need to configure the Collision Distance for both Full or ++ * Half Duplex. ++ */ ++ tctl_reg = E1000_READ_REG(shared, TCTL); ++ DEBUGOUT1("tctl_reg = %x\n", tctl_reg); ++ ++ /* mask the Collision Distance bits in the Transmit Control Reg. */ ++ tctl_reg &= ~E1000_TCTL_COLD; ++ ++ if(duplex == FULL_DUPLEX) { ++ /* We are in Full Duplex mode. Therefore, the collision distance ++ * is the same regardless of speed. ++ */ ++ shift = E1000_FDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } else { ++ /* We are in Half Duplex mode. Half Duplex collision distance is ++ * different for Gigabit vs. 10/100, so we will set accordingly. ++ */ ++ if(speed == SPEED_1000) { /* 1000Mbs HDX */ ++ shift = E1000_GB_HDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ ++ } else { /* 10/100Mbs HDX */ ++ shift = E1000_HDX_COLLISION_DISTANCE; ++ shift <<= E1000_COLD_SHIFT; ++ tctl_reg |= shift; ++ } ++ } ++ ++ /* Write the configured values back to the Transmit Control Reg. */ ++ E1000_WRITE_REG(shared, TCTL, tctl_reg); ++ ++ return; ++} ++ ++#if DBG ++/****************************************************************************** ++* Displays the contents of all of the MII registers ++* ++* shared - Struct containing variables accessed by shared code ++* ++* For debugging. ++******************************************************************************/ ++void ++e1000_display_mii(struct e1000_shared_adapter *shared) ++{ ++ uint16_t data; ++ uint16_t phy_id_high; ++ uint16_t phy_id_low; ++ uint32_t phy_id; ++ ++ DEBUGFUNC("e1000_display_mii"); ++ ++ DEBUGOUT1("adapter Base Address = %x\n", shared->hw_addr); ++ ++ /* This will read each PHY Reg address and display its contents. */ ++ ++ data = e1000_read_phy_reg(shared, PHY_CTRL); ++ DEBUGOUT1("MII Ctrl Reg contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_STATUS); ++ data = e1000_read_phy_reg(shared, PHY_STATUS); ++ DEBUGOUT1("MII Status Reg contents = %x\n", data); ++ ++ phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); ++ usec_delay(2); ++ phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); ++ phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; ++ DEBUGOUT1("Phy ID = %x \n", phy_id); ++ ++ data = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); ++ DEBUGOUT1("Reg 4 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_LP_ABILITY); ++ DEBUGOUT1("Reg 5 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_AUTONEG_EXP); ++ DEBUGOUT1("Reg 6 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_NEXT_PAGE_TX); ++ DEBUGOUT1("Reg 7 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_LP_NEXT_PAGE); ++ DEBUGOUT1("Reg 8 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_1000T_CTRL); ++ DEBUGOUT1("Reg 9 contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_1000T_STATUS); ++ DEBUGOUT1("Reg A contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, PHY_EXT_STATUS); ++ DEBUGOUT1("Reg F contents = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ DEBUGOUT1("M88E1000 Specific Control Reg (0x10) = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); ++ DEBUGOUT1("M88E1000 Specific Status Reg (0x11) = %x\n", data); ++ ++ /* ++ * data = e1000_read_phy_reg(shared, M88E1000_INT_ENABLE_REG); ++ * DEBUGOUT1("M88E1000 Interrupt Enable Reg (0x12) = %x\n", data); ++ */ ++ ++ /* ++ * data = e1000_read_phy_reg(shared, M88E1000_INT_STATUS_REG); ++ * DEBUGOUT1("M88E1000 Interrupt Status Reg (0x13) = %x\n", data); ++ */ ++ ++ data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); ++ DEBUGOUT1("M88E1000 Ext. Phy Specific Control (0x14) = %x\n", data); ++ ++ data = e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR); ++ DEBUGOUT1("M88E1000 Receive Error Counter (0x15) = %x\n", data); ++ ++ /* ++ * data = e1000_read_phy_reg(shared, M88E1000_LED_CTRL_REG); ++ * DEBUGOUT1("M88E1000 LED control reg (0x18) = %x\n", data); ++ */ ++ ++ return; ++} ++#endif // DBG ++ ++/****************************************************************************** ++* Probes the expected PHY address for known PHY IDs ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++boolean_t ++e1000_detect_gig_phy(struct e1000_shared_adapter *shared) ++{ ++ uint32_t phy_id_high; ++ uint16_t phy_id_low; ++ ++ DEBUGFUNC("e1000_detect_gig_phy"); ++ ++ /* Read the PHY ID Registers to identify which PHY is onboard. */ ++ shared->phy_addr = 1; ++ ++ phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); ++ ++ usec_delay(2); ++ ++ phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); ++ ++ shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; ++ ++ if(shared->phy_id == M88E1000_12_PHY_ID || ++ shared->phy_id == M88E1000_14_PHY_ID || ++ shared->phy_id == M88E1000_I_PHY_ID || ++ shared->phy_id == M88E1011_I_PHY_ID) { ++ ++ DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n", ++ shared->phy_id, shared->phy_addr); ++ return (TRUE); ++ } else { ++ DEBUGOUT("Could not auto-detect Phy!\n"); ++ return (FALSE); ++ } ++} ++ ++/****************************************************************************** ++* Resets the PHY's DSP ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++void ++e1000_phy_reset_dsp(struct e1000_shared_adapter *shared) ++{ ++ e1000_write_phy_reg(shared, 29, 0x1d); ++ e1000_write_phy_reg(shared, 30, 0xc1); ++ e1000_write_phy_reg(shared, 30, 0x00); ++ return; ++} ++ ++/****************************************************************************** ++* Blocks until autoneg completes or times out (~4.5 seconds) ++* ++* shared - Struct containing variables accessed by shared code ++******************************************************************************/ ++boolean_t ++e1000_wait_autoneg(struct e1000_shared_adapter *shared) ++{ ++ uint16_t i; ++ uint16_t mii_status_reg; ++ boolean_t autoneg_complete = FALSE; ++ ++ DEBUGFUNC("e1000_wait_autoneg"); ++ ++ /* We will wait for autoneg to complete. */ ++ DEBUGOUT("Waiting for Auto-Neg to complete.\n"); ++ mii_status_reg = 0; ++ ++ /* We will wait for autoneg to complete or 4.5 seconds to expire. */ ++ ++ for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { ++ /* Read the MII Status Register and wait for Auto-Neg ++ * Complete bit to be set. ++ */ ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ ++ if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { ++ autoneg_complete = TRUE; ++ break; ++ } ++ ++ msec_delay(100); ++ } ++ ++ return (autoneg_complete); ++} ++ ++/****************************************************************************** ++* Get PHY information from various PHY registers ++* ++* shared - Struct containing variables accessed by shared code ++* phy_status_info - PHY information structure ++******************************************************************************/ ++boolean_t ++e1000_phy_get_info(struct e1000_shared_adapter *shared, ++ struct e1000_phy_info *phy_status_info) ++{ ++ uint16_t phy_mii_status_reg; ++ uint16_t phy_specific_ctrl_reg; ++ uint16_t phy_specific_status_reg; ++ uint16_t phy_specific_ext_ctrl_reg; ++ uint16_t phy_1000t_stat_reg; ++ ++ phy_status_info->cable_length = e1000_cable_length_undefined; ++ phy_status_info->extended_10bt_distance = ++ e1000_10bt_ext_dist_enable_undefined; ++ phy_status_info->cable_polarity = e1000_rev_polarity_undefined; ++ phy_status_info->polarity_correction = e1000_polarity_reversal_undefined; ++ phy_status_info->link_reset = e1000_down_no_idle_undefined; ++ phy_status_info->mdix_mode = e1000_auto_x_mode_undefined; ++ phy_status_info->local_rx = e1000_1000t_rx_status_undefined; ++ phy_status_info->remote_rx = e1000_1000t_rx_status_undefined; ++ ++ /* PHY info only valid for copper media. */ ++ if(shared == NULL || shared->media_type != e1000_media_type_copper) ++ return FALSE; ++ ++ /* PHY info only valid for LINK UP. Read MII status reg ++ * back-to-back to get link status. ++ */ ++ phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); ++ if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) ++ return FALSE; ++ ++ /* Read various PHY registers to get the PHY info. */ ++ phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); ++ phy_specific_status_reg = ++ e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); ++ phy_specific_ext_ctrl_reg = ++ e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); ++ phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS); ++ ++ phy_status_info->cable_length = ++ ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >> ++ M88E1000_PSSR_CABLE_LENGTH_SHIFT); ++ ++ phy_status_info->extended_10bt_distance = ++ (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> ++ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; ++ ++ phy_status_info->cable_polarity = ++ (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >> ++ M88E1000_PSSR_REV_POLARITY_SHIFT; ++ ++ phy_status_info->polarity_correction = ++ (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >> ++ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; ++ ++ phy_status_info->link_reset = ++ (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >> ++ M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT; ++ ++ phy_status_info->mdix_mode = ++ (phy_specific_status_reg & M88E1000_PSSR_MDIX) >> ++ M88E1000_PSSR_MDIX_SHIFT; ++ ++ phy_status_info->local_rx = ++ (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >> ++ SR_1000T_LOCAL_RX_STATUS_SHIFT; ++ ++ phy_status_info->remote_rx = ++ (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >> ++ SR_1000T_REMOTE_RX_STATUS_SHIFT; ++ ++ return TRUE; ++} ++ ++boolean_t ++e1000_validate_mdi_setting(struct e1000_shared_adapter *shared) ++{ ++ if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) { ++ shared->mdix = 1; ++ return FALSE; ++ } ++ return TRUE; ++} +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_phy.h 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,424 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/* e1000_phy.h ++ * Structures, enums, and macros for the PHY ++ */ ++ ++#ifndef _E1000_PHY_H_ ++#define _E1000_PHY_H_ ++ ++#include "e1000_osdep.h" ++ ++/* PHY status info structure and supporting enums */ ++typedef enum { ++ e1000_cable_length_50 = 0, ++ e1000_cable_length_50_80, ++ e1000_cable_length_80_110, ++ e1000_cable_length_110_140, ++ e1000_cable_length_140, ++ e1000_cable_length_undefined = 0xFF ++} e1000_cable_length; ++ ++typedef enum { ++ e1000_10bt_ext_dist_enable_normal = 0, ++ e1000_10bt_ext_dist_enable_lower, ++ e1000_10bt_ext_dist_enable_undefined = 0xFF ++} e1000_10bt_ext_dist_enable; ++ ++typedef enum { ++ e1000_rev_polarity_normal = 0, ++ e1000_rev_polarity_reversed, ++ e1000_rev_polarity_undefined = 0xFF ++} e1000_rev_polarity; ++ ++typedef enum { ++ e1000_polarity_reversal_enabled = 0, ++ e1000_polarity_reversal_disabled, ++ e1000_polarity_reversal_undefined = 0xFF ++} e1000_polarity_reversal; ++ ++typedef enum { ++ e1000_down_no_idle_no_detect = 0, ++ e1000_down_no_idle_detect, ++ e1000_down_no_idle_undefined = 0xFF ++} e1000_down_no_idle; ++ ++typedef enum { ++ e1000_auto_x_mode_manual_mdi = 0, ++ e1000_auto_x_mode_manual_mdix, ++ e1000_auto_x_mode_auto1, ++ e1000_auto_x_mode_auto2, ++ e1000_auto_x_mode_undefined = 0xFF ++} e1000_auto_x_mode; ++ ++typedef enum { ++ e1000_1000t_rx_status_not_ok = 0, ++ e1000_1000t_rx_status_ok, ++ e1000_1000t_rx_status_undefined = 0xFF ++} e1000_1000t_rx_status; ++ ++struct e1000_phy_info { ++ e1000_cable_length cable_length; ++ e1000_10bt_ext_dist_enable extended_10bt_distance; ++ e1000_rev_polarity cable_polarity; ++ e1000_polarity_reversal polarity_correction; ++ e1000_down_no_idle link_reset; ++ e1000_auto_x_mode mdix_mode; ++ e1000_1000t_rx_status local_rx; ++ e1000_1000t_rx_status remote_rx; ++}; ++ ++struct e1000_phy_stats { ++ uint32_t idle_errors; ++ uint32_t receive_errors; ++}; ++ ++/* Function Prototypes */ ++uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr); ++void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data); ++void e1000_phy_hw_reset(struct e1000_shared_adapter *shared); ++boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared); ++boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg); ++boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared); ++void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg); ++void e1000_config_collision_dist(struct e1000_shared_adapter *shared); ++void e1000_display_mii(struct e1000_shared_adapter *shared); ++boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared); ++void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared); ++boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared); ++boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info); ++boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared); ++ ++/* Bit definitions for the Management Data IO (MDIO) and Management Data ++ * Clock (MDC) pins in the Device Control Register. ++ */ ++#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 ++#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 ++#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 ++#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 ++#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 ++#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 ++#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR ++#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA ++ ++/* PHY 1000 MII Register/Bit Definitions */ ++/* PHY Registers defined by IEEE */ ++#define PHY_CTRL 0x00 /* Control Register */ ++#define PHY_STATUS 0x01 /* Status Regiser */ ++#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ ++#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ ++#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ ++#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ ++#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ ++#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ ++#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ ++#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ ++#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ ++#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ ++ ++/* M88E1000 Specific Registers */ ++#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ ++#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ ++#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ ++#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ ++#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ ++#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ ++ ++#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ ++ ++/* PHY Control Register */ ++#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ ++#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ ++#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ ++#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ ++#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ ++#define MII_CR_POWER_DOWN 0x0800 /* Power down */ ++#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ ++#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ ++#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ ++#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ ++ ++/* PHY Status Register */ ++#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ ++#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ ++#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ ++#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ ++#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ ++#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ ++#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ ++#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ ++#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ ++#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ ++#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ ++#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ ++#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ ++#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ ++#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ ++ ++/* Autoneg Advertisement Register */ ++#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ ++#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ ++#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ ++#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ ++#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ ++#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ ++#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ ++#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ ++#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ ++#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ ++ ++/* Link Partner Ability Register (Base Page) */ ++#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ ++#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ ++#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ ++#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ ++#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ ++#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ ++#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ ++#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ ++#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ ++#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ ++#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ ++ ++/* Autoneg Expansion Register */ ++#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ ++#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ ++#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ ++#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ ++#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ ++ ++/* Next Page TX Register */ ++#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ ++#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges ++ * of different NP ++ */ ++#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg ++ * 0 = cannot comply with msg ++ */ ++#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ ++#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow ++ * 0 = sending last NP ++ */ ++ ++/* Link Partner Next Page Register */ ++#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ ++#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges ++ * of different NP ++ */ ++#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg ++ * 0 = cannot comply with msg ++ */ ++#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ ++#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ ++#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow ++ * 0 = sending last NP ++ */ ++ ++/* 1000BASE-T Control Register */ ++#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ ++#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ ++#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ ++#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ ++ /* 0=DTE device */ ++#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ ++ /* 0=Configure PHY as Slave */ ++#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ ++ /* 0=Automatic Master/Slave config */ ++#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ ++#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ ++#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ ++#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ ++#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ ++ ++/* 1000BASE-T Status Register */ ++#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ ++#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ ++#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ ++#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ ++#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ ++#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ ++#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ ++#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ ++#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 ++#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 ++ ++/* Extended Status Register */ ++#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ ++#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ ++#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ ++#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ ++ ++#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ ++#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ ++ ++#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ ++ /* (0=enable, 1=disable) */ ++ ++/* M88E1000 PHY Specific Control Register */ ++#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ ++#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ ++#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ ++#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, ++ * 0=CLK125 toggling ++ */ ++#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ ++ /* Manual MDI configuration */ ++#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ ++#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, ++ * 100BASE-TX/10BASE-T: ++ * MDI Mode ++ */ ++#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled ++ * all speeds. ++ */ ++#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 ++ /* 1=Enable Extended 10BASE-T distance ++ * (Lower 10BASE-T RX Threshold) ++ * 0=Normal 10BASE-T RX Threshold */ ++#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 ++ /* 1=5-Bit interface in 100BASE-TX ++ * 0=MII interface in 100BASE-TX */ ++#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ ++#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ ++#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ ++ ++#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1 ++#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5 ++#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 ++ ++/* M88E1000 PHY Specific Status Register */ ++#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ ++#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ ++#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ ++#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; ++ * 3=110-140M;4=>140M */ ++#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ ++#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ ++#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ ++#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ ++#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ ++#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ ++#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ ++#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ ++ ++#define M88E1000_PSSR_REV_POLARITY_SHIFT 1 ++#define M88E1000_PSSR_MDIX_SHIFT 6 ++#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 ++ ++/* M88E1000 Extended PHY Specific Control Register */ ++#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ ++#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. ++ * Will assert lost lock and bring ++ * link down if idle not seen ++ * within 1ms in 1000BASE-T ++ */ ++#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ ++#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ ++#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ ++ ++#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15 ++ ++/* Bit definitions for valid PHY IDs. */ ++#define M88E1000_12_PHY_ID 0x01410C50 ++#define M88E1000_14_PHY_ID 0x01410C40 ++#define M88E1000_I_PHY_ID 0x01410C30 ++#define M88E1011_I_PHY_ID 0x01410C20 ++ ++/* Miscellaneous PHY bit definitions. */ ++#define PHY_PREAMBLE 0xFFFFFFFF ++#define PHY_SOF 0x01 ++#define PHY_OP_READ 0x02 ++#define PHY_OP_WRITE 0x01 ++#define PHY_TURNAROUND 0x02 ++#define PHY_PREAMBLE_SIZE 32 ++#define MII_CR_SPEED_1000 0x0040 ++#define MII_CR_SPEED_100 0x2000 ++#define MII_CR_SPEED_10 0x0000 ++#define E1000_PHY_ADDRESS 0x01 ++#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ ++#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ ++#define PHY_REVISION_MASK 0xFFFFFFF0 ++#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */ ++#define REG4_SPEED_MASK 0x01E0 ++#define REG9_SPEED_MASK 0x0300 ++#define ADVERTISE_10_HALF 0x0001 ++#define ADVERTISE_10_FULL 0x0002 ++#define ADVERTISE_100_HALF 0x0004 ++#define ADVERTISE_100_FULL 0x0008 ++#define ADVERTISE_1000_HALF 0x0010 ++#define ADVERTISE_1000_FULL 0x0020 ++#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ ++ ++#endif /* _E1000_PHY_H_ */ +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_proc.c 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,1437 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/***************************************************************************/ ++/* /proc File System Interaface Support Functions */ ++/***************************************************************************/ ++ ++#include "e1000.h" ++extern char e1000_driver_name[]; ++extern char e1000_driver_version[]; ++#include "e1000_proc.h" ++#include ++ ++struct proc_dir_entry *e1000_proc_dir; ++ ++#define CABLE_LENGTH_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.cable_length == e1000_cable_length_50) ? "0-50 Meters (+/- 20 Meters)" : \ ++ (adapter->phy_info.cable_length == e1000_cable_length_50_80) ? "50-80 Meters (+/- 20 Meters)" : \ ++ (adapter->phy_info.cable_length == e1000_cable_length_80_110) ? "80-110 Meters (+/- 20 Meters)" : \ ++ (adapter->phy_info.cable_length == e1000_cable_length_110_140) ? "110-140 Meters (+/- 20 Meters)" : \ ++ (adapter->phy_info.cable_length == e1000_cable_length_140) ? "> 140 Meters (+/- 20 Meters)" : \ ++ "Unknown"; ++ ++#define EXTENDED_10BASE_T_DISTANCE_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.extended_10bt_distance == \ ++ e1000_10bt_ext_dist_enable_normal) ? "Disabled" : \ ++ (adapter->phy_info.extended_10bt_distance == \ ++ e1000_10bt_ext_dist_enable_lower) ? "Enabled" : "Unknown"; ++ ++#define CABLE_POLARITY_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.cable_polarity == e1000_rev_polarity_normal) ? "Normal" : \ ++ (adapter->phy_info.cable_polarity == e1000_rev_polarity_reversed) ? \ ++ "Reversed" : "Unknown"; ++ ++#define POLARITY_CORRECTION_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.polarity_correction == \ ++ e1000_polarity_reversal_enabled) ? "Disabled" : \ ++ (adapter->phy_info.polarity_correction == \ ++ e1000_polarity_reversal_disabled) ? "Enabled" : "Undefined"; ++ ++#define LINK_RESET_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.link_reset == e1000_down_no_idle_no_detect) ? "Disabled" : \ ++ (adapter->phy_info.link_reset == e1000_down_no_idle_detect) ? "Enabled" : \ ++ "Unknown"; ++ ++#define MDI_X_MODE_TO_STRING() \ ++ msg = (adapter->phy_info.mdix_mode == 0) ? "MDI" : "MDI-X"; ++ ++#define LOCAL_RECEIVER_STATUS_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.local_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \ ++ (adapter->phy_info.local_rx == e1000_1000t_rx_status_ok) ? "OK" : \ ++ "Unknown"; ++ ++#define REMOTE_RECEIVER_STATUS_TO_STRING() \ ++ msg = \ ++ (adapter->phy_info.remote_rx == e1000_1000t_rx_status_not_ok) ? "NOT_OK" : \ ++ (adapter->phy_info.remote_rx == e1000_1000t_rx_status_ok) ? "OK" : \ ++ "Unknown"; ++ ++static void e1000_link_update(struct e1000_adapter * adapter) { ++ ++ e1000_check_for_link(&adapter->shared); ++ if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) ++ adapter->link_active = 1; ++ else ++ adapter->link_active = 0; ++ ++ if (adapter->link_active) { ++ e1000_get_speed_and_duplex(&adapter->shared, &adapter->link_speed, &adapter->link_duplex); ++ } else { ++ adapter->link_speed = 0; ++ adapter->link_duplex = 0; ++ } ++ return; ++} ++ ++static int e1000_generic_read(char *page, char **start, off_t off, ++ int count, int *eof) ++{ ++ int len; ++ ++ len = strlen(page); ++ page[len++] = '\n'; ++ ++ if (len <= off + count) ++ *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ return len; ++} ++ ++static int e1000_read_ulong(char *page, char **start, off_t off, ++ int count, int *eof, unsigned long l) ++{ ++ sprintf(page, "%lu", l); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_ulong_hex(char *page, char **start, off_t off, ++ int count, int *eof, unsigned long l) ++{ ++ sprintf(page, "0x%04lx", l); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_ullong(char *page, char **start, off_t off, ++ int count, int *eof, unsigned long long l) ++{ ++ sprintf(page, "%Lu", l); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_hwaddr(char *page, char **start, off_t off, ++ int count, int *eof, unsigned char *hwaddr) ++{ ++ sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X", ++ hwaddr[0], hwaddr[1], hwaddr[2], ++ hwaddr[3], hwaddr[4], hwaddr[5]); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++/* need to check page boundaries !!! */ ++static int e1000_read_info(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ struct net_device_stats *stats = &adapter->net_stats; ++ unsigned char *hwaddr; ++ char *pagep = page; ++ char *msg; ++ ++ page += sprintf(page, "%-32s %s\n", DESCRIPTION_TAG, adapter->id_string); ++ page += sprintf(page, "%-32s %06lx-%03x\n", ++ PART_NUMBER_TAG, ++ (unsigned long )adapter->part_num >> 8, ++ adapter->part_num & 0x000000FF); ++ ++ page += sprintf(page, "%-32s %s\n", DRVR_NAME_TAG, e1000_driver_name); ++ ++ page += sprintf(page, "%-32s %s\n", DRVR_VERSION_TAG, e1000_driver_version); ++ ++ page += sprintf(page, "%-32s 0x%04lx\n", ++ PCI_VENDOR_TAG, (unsigned long) adapter->vendor_id); ++ page += sprintf(page, "%-32s 0x%04lx\n", ++ PCI_DEVICE_ID_TAG, (unsigned long) adapter->device_id); ++ page += sprintf(page, "%-32s 0x%04lx\n", ++ PCI_SUBSYSTEM_VENDOR_TAG, ++ (unsigned long) adapter->subven_id); ++ page += sprintf(page, "%-32s 0x%04lx\n", ++ PCI_SUBSYSTEM_ID_TAG, ++ (unsigned long) adapter->subsys_id); ++ page += sprintf(page, "%-32s 0x%02lx\n", ++ PCI_REVISION_ID_TAG, ++ (unsigned long) adapter->rev_id); ++ ++ page += sprintf(page, "%-32s %lu\n", ++ PCI_BUS_TAG, ++ (unsigned long) (adapter->pdev->bus->number)); ++ page += sprintf(page, "%-32s %lu\n", ++ PCI_SLOT_TAG, ++ (unsigned ++ long) (PCI_SLOT((adapter->pdev->devfn)))); ++ ++ if(adapter->shared.mac_type >= e1000_82543) { ++ page += sprintf(page, "%-32s %s\n", ++ PCI_BUS_TYPE_TAG, ++ (adapter->shared.bus_type == e1000_bus_type_pci) ? "PCI" : ++ (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" : ++ "UNKNOWN"); ++ ++ page += sprintf(page, "%-32s %s\n", ++ PCI_BUS_SPEED_TAG, ++ (adapter->shared.bus_speed == e1000_bus_speed_33) ? "33MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_66) ? "66MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" : ++ "UNKNOWN"); ++ ++ page += sprintf(page, "%-32s %s\n", ++ PCI_BUS_WIDTH_TAG, ++ (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" : ++ (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" : ++ "UNKNOWN"); ++ } ++ ++ page += ++ sprintf(page, "%-32s %lu\n", IRQ_TAG, ++ (unsigned long) (adapter->pdev->irq)); ++ page += ++ sprintf(page, "%-32s %s\n", SYSTEM_DEVICE_NAME_TAG, ++ adapter->netdev->name); ++ ++ hwaddr = adapter->netdev->dev_addr; ++ page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n", ++ CURRENT_HWADDR_TAG, ++ hwaddr[0], hwaddr[1], hwaddr[2], ++ hwaddr[3], hwaddr[4], hwaddr[5]); ++ ++ hwaddr = adapter->perm_net_addr; ++ page += sprintf(page, "%-32s %02X:%02X:%02X:%02X:%02X:%02X\n", ++ PERMANENT_HWADDR_TAG, ++ hwaddr[0], hwaddr[1], hwaddr[2], ++ hwaddr[3], hwaddr[4], hwaddr[5]); ++ ++ page += sprintf(page, "\n"); ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ if (adapter->link_active == 1) ++ msg = "up"; ++ else ++ msg = "down"; ++ page += sprintf(page, "%-32s %s\n", LINK_TAG, msg); ++ ++ if (adapter->link_speed) ++ page += sprintf(page, "%-32s %lu\n", ++ SPEED_TAG, ++ (unsigned long) (adapter->link_speed)); ++ else ++ page += sprintf(page, "%-32s %s\n", SPEED_TAG, "N/A"); ++ ++ msg = adapter->link_duplex == FULL_DUPLEX ? "full" : ++ ((adapter->link_duplex == 0) ? "N/A" : "half"); ++ page += sprintf(page, "%-32s %s\n", DUPLEX_TAG, msg); ++ ++ if (adapter->netdev->flags & IFF_UP) ++ msg = "up"; ++ else ++ msg = "down"; ++ page += sprintf(page, "%-32s %s\n", STATE_TAG, msg); ++ ++ page += sprintf(page, "\n"); ++ ++ page += sprintf(page, "%-32s %lu\n", ++ RX_PACKETS_TAG, (unsigned long) stats->rx_packets); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_PACKETS_TAG, (unsigned long) stats->tx_packets); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_BYTES_TAG, (unsigned long) stats->rx_bytes); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_BYTES_TAG, (unsigned long) stats->tx_bytes); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_ERRORS_TAG, (unsigned long) stats->rx_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_ERRORS_TAG, (unsigned long) stats->tx_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_DROPPED_TAG, (unsigned long) stats->rx_dropped); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_DROPPED_TAG, (unsigned long) stats->tx_dropped); ++ page += sprintf(page, "%-32s %lu\n", ++ MULTICAST_TAG, (unsigned long) stats->multicast); ++ page += sprintf(page, "%-32s %lu\n", ++ COLLISIONS_TAG, (unsigned long) stats->collisions); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_LENGTH_ERRORS_TAG, ++ (unsigned long) stats->rx_length_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_OVER_ERRORS_TAG, ++ (unsigned long) stats->rx_over_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_CRC_ERRORS_TAG, ++ (unsigned long) stats->rx_crc_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_FRAME_ERRORS_TAG, ++ (unsigned long) stats->rx_frame_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_FIFO_ERRORS_TAG, ++ (unsigned long) stats->rx_fifo_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ RX_MISSED_ERRORS_TAG, ++ (unsigned long) stats->rx_missed_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_ABORTED_ERRORS_TAG, ++ (unsigned long) stats->tx_aborted_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_CARRIER_ERRORS_TAG, ++ (unsigned long) stats->tx_carrier_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_FIFO_ERRORS_TAG, ++ (unsigned long) stats->tx_fifo_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_HEARTBEAT_ERRORS_TAG, ++ (unsigned long) stats->tx_heartbeat_errors); ++ page += sprintf(page, "%-32s %lu\n", ++ TX_WINDOW_ERRORS_TAG, ++ (unsigned long) stats->tx_window_errors); ++ ++ page += sprintf(page, "\n"); ++ ++ /* 8254x specific stats */ ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_LATE_COLL_TAG, ++ (unsigned long long)adapter->stats.latecol); ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_DEFERRED_TAG, ++ (unsigned long long)adapter->stats.dc); ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_SINGLE_COLL_TAG, ++ (unsigned long long)adapter->stats.scc); ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_MULTI_COLL_TAG, ++ (unsigned long long)adapter->stats.mcc); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_LONG_ERRORS_TAG, ++ (unsigned long long)adapter->stats.roc); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_SHORT_ERRORS_TAG, ++ (unsigned long long)adapter->stats.ruc); ++ /* The 82542 does not have an alignment error count register */ ++ /* ALGNERRC is only valid in MII mode at 10 or 100 Mbps */ ++ if(adapter->shared.mac_type >= e1000_82543) ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_ALIGN_ERRORS_TAG, ++ (unsigned long long)adapter->stats.algnerrc); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_XON_TAG, ++ (unsigned long long)adapter->stats.xonrxc); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_XOFF_TAG, ++ (unsigned long long)adapter->stats.xoffrxc); ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_XON_TAG, ++ (unsigned long long)adapter->stats.xontxc); ++ page += sprintf(page, "%-32s %Lu\n", ++ TX_XOFF_TAG, ++ (unsigned long long)adapter->stats.xofftxc); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_CSUM_GOOD_TAG, ++ (unsigned long long)adapter->XsumRXGood); ++ page += sprintf(page, "%-32s %Lu\n", ++ RX_CSUM_ERROR_TAG, ++ (unsigned long long)adapter->XsumRXError); ++ ++ if (adapter->shared.media_type == e1000_media_type_copper) ++ msg = "Copper"; ++ else ++ msg = "Fiber"; ++ page += sprintf(page, "\n%-32s %s\n", MEDIA_TYPE_TAG, msg); ++ ++ if (adapter->shared.media_type == e1000_media_type_copper) { ++ CABLE_LENGTH_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", CABLE_LENGTH_TAG, msg); ++ ++ EXTENDED_10BASE_T_DISTANCE_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", EXTENDED_10BASE_T_DISTANCE_TAG, msg); ++ ++ CABLE_POLARITY_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", CABLE_POLARITY_TAG, msg); ++ ++ POLARITY_CORRECTION_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", CABLE_POLARITY_CORRECTION_TAG, msg); ++ ++ page += sprintf(page, "%-32s %lu\n", IDLE_ERRORS_TAG, (unsigned long)adapter->phy_stats.idle_errors ); ++ ++ LINK_RESET_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", LINK_RESET_ENABLED_TAG, msg); ++ ++ page += sprintf(page, "%-32s %lu\n", RECEIVE_ERRORS_TAG, (unsigned long)adapter->phy_stats.receive_errors); ++ ++ MDI_X_MODE_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", MDI_X_ENABLED_TAG, msg); ++ ++ LOCAL_RECEIVER_STATUS_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", LOCAL_RECEIVER_STATUS_TAG, msg); ++ ++ REMOTE_RECEIVER_STATUS_TO_STRING(); ++ page += sprintf(page, "%-32s %s\n", REMOTE_RECEIVER_STATUS_TAG, msg); ++ } ++ ++ *page = 0; ++ return e1000_generic_read(pagep, start, off, count, eof); ++} ++ ++static int e1000_read_descr(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ strncpy(page, adapter->id_string, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_partnum(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ sprintf(page, "%06lx-%03x", ++ (unsigned long)adapter->part_num >> 8, ++ adapter->part_num & 0x000000FF); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_drvr_name(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ strncpy(page, e1000_driver_name, PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_drvr_ver(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ strncpy(page, e1000_driver_version, PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_pci_vendor(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong_hex(page, start, off, count, eof, ++ (unsigned long) adapter->vendor_id); ++} ++ ++static int e1000_read_pci_device(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong_hex(page, start, off, count, eof, ++ (unsigned long) adapter->device_id); ++} ++ ++static int e1000_read_pci_sub_vendor(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong_hex(page, start, off, count, eof, ++ (unsigned long) adapter->subven_id); ++} ++ ++static int e1000_read_pci_sub_device(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong_hex(page, start, off, count, eof, ++ (unsigned long) adapter->subsys_id); ++} ++ ++static int e1000_read_pci_revision(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong_hex(page, start, off, count, eof, ++ (unsigned long) adapter->rev_id); ++} ++ ++static int e1000_read_dev_name(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ strncpy(page, adapter->netdev->name, PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_pci_bus(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) (adapter->pdev->bus->number)); ++} ++ ++static int e1000_read_pci_slot(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned ++ long) (PCI_SLOT((adapter->pdev->devfn)))); ++} ++ ++static int e1000_read_pci_bus_type(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ strncpy(page, ++ (adapter->shared.bus_type == e1000_bus_type_pci) ? "PCI" : ++ (adapter->shared.bus_type == e1000_bus_type_pcix) ? "PCI-X" : ++ "UNKNOWN", PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_pci_bus_speed(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ strncpy(page, ++ (adapter->shared.bus_speed == e1000_bus_speed_33) ? "33MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_66) ? "66MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_100) ? "100MHz" : ++ (adapter->shared.bus_speed == e1000_bus_speed_133) ? "133MHz" : ++ "UNKNOWN", PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_pci_bus_width(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ strncpy(page, ++ (adapter->shared.bus_width == e1000_bus_width_32) ? "32-bit" : ++ (adapter->shared.bus_width == e1000_bus_width_64) ? "64-bit" : ++ "UNKNOWN", PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_irq(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) (adapter->pdev->irq)); ++} ++ ++static int e1000_read_current_hwaddr(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ unsigned char *hwaddr = adapter->netdev->dev_addr; ++ ++ return e1000_read_hwaddr(page, start, off, count, eof, hwaddr); ++} ++ ++static int e1000_read_permanent_hwaddr(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ unsigned char *hwaddr = adapter->perm_net_addr; ++ ++ return e1000_read_hwaddr(page, start, off, count, eof, hwaddr); ++} ++ ++static int e1000_read_link_status(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ if (adapter->link_active == 1) ++ strncpy(page, "up", PAGE_SIZE); ++ else ++ strncpy(page, "down", PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_speed(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ if (adapter->link_speed) ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) (adapter->link_speed)); ++ strncpy(page, "N/A", PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_dplx_mode(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ char *dplx_mode; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ dplx_mode = adapter->link_duplex == FULL_DUPLEX ? "full" : ++ ((adapter->link_duplex == 0) ? "N/A" : "half"); ++ strncpy(page, dplx_mode, PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_state(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ if (adapter->netdev->flags & IFF_UP) ++ strncpy(page, "up", PAGE_SIZE); ++ else ++ strncpy(page, "down", PAGE_SIZE); ++ ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_rx_packets(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_packets); ++} ++ ++static int e1000_read_tx_packets(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_packets); ++} ++ ++static int e1000_read_rx_bytes(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_bytes); ++} ++ ++static int e1000_read_tx_bytes(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_bytes); ++} ++ ++static int e1000_read_rx_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_errors); ++} ++ ++static int e1000_read_tx_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_errors); ++} ++ ++static int e1000_read_rx_dropped(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_dropped); ++} ++ ++static int e1000_read_tx_dropped(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_dropped); ++} ++ ++static int e1000_read_rx_multicast_packets(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.multicast); ++} ++ ++static int e1000_read_collisions(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.collisions); ++} ++ ++static int e1000_read_rx_length_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_length_errors); ++} ++ ++static int e1000_read_rx_over_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_over_errors); ++} ++ ++static int e1000_read_rx_crc_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_crc_errors); ++} ++ ++static int e1000_read_rx_frame_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_frame_errors); ++} ++ ++static int e1000_read_rx_fifo_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_fifo_errors); ++} ++ ++static int e1000_read_rx_missed_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.rx_missed_errors); ++} ++ ++static int e1000_read_tx_aborted_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_aborted_errors); ++} ++ ++static int e1000_read_tx_carrier_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_carrier_errors); ++} ++ ++static int e1000_read_tx_fifo_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_fifo_errors); ++} ++ ++static int e1000_read_tx_heartbeat_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_heartbeat_errors); ++} ++ ++static int e1000_read_tx_window_errors(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ return e1000_read_ulong(page, start, off, count, eof, ++ (unsigned long) adapter->net_stats.tx_window_errors); ++} ++ ++/* 8254x specific stats */ ++static int e1000_read_tx_late_coll(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.latecol); ++} ++ ++static int e1000_read_tx_defer_events(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.dc); ++} ++static int e1000_read_tx_single_coll(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.scc); ++} ++static int e1000_read_tx_multi_coll(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.mcc); ++} ++static int e1000_read_rx_oversize(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.roc); ++} ++static int e1000_read_rx_undersize(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.ruc); ++} ++static int e1000_read_rx_align_err(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.algnerrc); ++} ++static int e1000_read_rx_xon(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xonrxc); ++} ++static int e1000_read_rx_xoff(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xoffrxc); ++} ++static int e1000_read_tx_xon(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xontxc); ++} ++static int e1000_read_tx_xoff(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ return e1000_read_ullong(page, start, off, count, eof, adapter->stats.xofftxc); ++} ++ ++static struct proc_dir_entry *e1000_create_proc_read(char *name, ++ struct e1000_adapter * adapter, ++ struct proc_dir_entry *parent, ++ read_proc_t * read_proc) ++{ ++ struct proc_dir_entry *pdep; ++ ++ if (!(pdep = create_proc_entry(name, S_IFREG, parent))) ++ return NULL; ++ pdep->read_proc = read_proc; ++ pdep->data = adapter; ++ return pdep; ++} ++ ++static int e1000_read_cable_length (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ CABLE_LENGTH_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_media_type (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ switch (adapter->shared.media_type) { ++ case e1000_media_type_copper: strncpy(page,"Copper", PAGE_SIZE); break; ++ case e1000_media_type_fiber: strncpy(page, "Fiber", PAGE_SIZE); break; ++ default: strncpy(page, "Unknown", PAGE_SIZE); ++ } ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_extended_10base_t_distance (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ EXTENDED_10BASE_T_DISTANCE_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_cable_polarity (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ CABLE_POLARITY_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_cable_polarity_correction (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ POLARITY_CORRECTION_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_idle_errors (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.idle_errors); ++} ++ ++static int e1000_read_link_reset_enabled (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ LINK_RESET_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_receive_errors (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ return e1000_read_ulong(page, start, off, count, eof, adapter->phy_stats.receive_errors); ++} ++ ++static int e1000_read_mdi_x_enabled (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ MDI_X_MODE_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_local_receiver_status (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ LOCAL_RECEIVER_STATUS_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++static int e1000_read_remote_receiver_status (char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ char *msg; ++ struct e1000_adapter * adapter = (struct e1000_adapter *) data; ++ ++ /* If board is not open yet, */ ++ if(!test_bit(E1000_BOARD_OPEN, &adapter->flags)) ++ e1000_link_update(adapter); ++ ++ REMOTE_RECEIVER_STATUS_TO_STRING(); ++ strncpy (page, msg, PAGE_SIZE); ++ return e1000_generic_read(page, start, off, count, eof); ++} ++ ++int e1000_create_proc_dev(struct e1000_adapter * adapter) ++{ ++ struct proc_dir_entry *dev_dir; ++ char info[256]; ++ int len; ++ ++ dev_dir = create_proc_entry(adapter->netdev->name, S_IFDIR, e1000_proc_dir); ++ ++ strncpy(info, adapter->netdev->name, sizeof(info)); ++ len = strlen(info); ++ strncat(info + len, ".info", sizeof(info) - len); ++ ++ /* info */ ++ if (!(e1000_create_proc_read(info, adapter, e1000_proc_dir, e1000_read_info))) ++ return -1; ++ ++ /* description */ ++ if (!(e1000_create_proc_read(DESCRIPTION_TAG, adapter, dev_dir, e1000_read_descr))) ++ return -1; ++ /* part number */ ++ if (!(e1000_create_proc_read(PART_NUMBER_TAG, adapter, dev_dir, e1000_read_partnum))) ++ return -1; ++ /* driver name */ ++ if (!(e1000_create_proc_read(DRVR_NAME_TAG, adapter, dev_dir, e1000_read_drvr_name))) ++ return -1; ++ /* driver version */ ++ if (!(e1000_create_proc_read(DRVR_VERSION_TAG, adapter, dev_dir, e1000_read_drvr_ver))) ++ return -1; ++ /* pci vendor */ ++ if (!(e1000_create_proc_read(PCI_VENDOR_TAG, adapter, dev_dir, e1000_read_pci_vendor))) ++ return -1; ++ /* pci device id */ ++ if (!(e1000_create_proc_read(PCI_DEVICE_ID_TAG, adapter, dev_dir, ++ e1000_read_pci_device))) return -1; ++ /* pci sub vendor */ ++ if (!(e1000_create_proc_read(PCI_SUBSYSTEM_VENDOR_TAG, adapter, dev_dir, ++ e1000_read_pci_sub_vendor))) return -1; ++ /* pci sub device id */ ++ if (!(e1000_create_proc_read(PCI_SUBSYSTEM_ID_TAG, adapter, dev_dir, ++ e1000_read_pci_sub_device))) return -1; ++ /* pci revision id */ ++ if (!(e1000_create_proc_read(PCI_REVISION_ID_TAG, adapter, dev_dir, ++ e1000_read_pci_revision))) return -1; ++ /* device name */ ++ if (!(e1000_create_proc_read(SYSTEM_DEVICE_NAME_TAG, adapter, dev_dir, ++ e1000_read_dev_name))) return -1; ++ /* pci bus */ ++ if (!(e1000_create_proc_read(PCI_BUS_TAG, adapter, dev_dir, e1000_read_pci_bus))) ++ return -1; ++ /* pci slot */ ++ if (!(e1000_create_proc_read(PCI_SLOT_TAG, adapter, dev_dir, e1000_read_pci_slot))) ++ return -1; ++ /* pci bus type */ ++ if (!(e1000_create_proc_read(PCI_BUS_TYPE_TAG, adapter, dev_dir, ++ e1000_read_pci_bus_type))) return -1; ++ /* pci bus speed */ ++ if (!(e1000_create_proc_read(PCI_BUS_SPEED_TAG, adapter, dev_dir, ++ e1000_read_pci_bus_speed))) return -1; ++ /* pci bus width */ ++ if (!(e1000_create_proc_read(PCI_BUS_WIDTH_TAG, adapter, dev_dir, ++ e1000_read_pci_bus_width))) return -1; ++ /* irq */ ++ if (!(e1000_create_proc_read(IRQ_TAG, adapter, dev_dir, e1000_read_irq))) ++ return -1; ++ /* current hwaddr */ ++ if (!(e1000_create_proc_read(CURRENT_HWADDR_TAG, adapter, dev_dir, ++ e1000_read_current_hwaddr))) return -1; ++ /* permanent hwaddr */ ++ if (!(e1000_create_proc_read(PERMANENT_HWADDR_TAG, adapter, dev_dir, ++ e1000_read_permanent_hwaddr))) return -1; ++ ++ /* link status */ ++ if (!(e1000_create_proc_read(LINK_TAG, adapter, dev_dir, e1000_read_link_status))) ++ return -1; ++ /* speed */ ++ if (!(e1000_create_proc_read(SPEED_TAG, adapter, dev_dir, e1000_read_speed))) ++ return -1; ++ /* duplex mode */ ++ if (!(e1000_create_proc_read(DUPLEX_TAG, adapter, dev_dir, e1000_read_dplx_mode))) ++ return -1; ++ /* state */ ++ if (!(e1000_create_proc_read(STATE_TAG, adapter, dev_dir, e1000_read_state))) ++ return -1; ++ /* rx packets */ ++ if (!(e1000_create_proc_read(RX_PACKETS_TAG, adapter, dev_dir, e1000_read_rx_packets))) ++ return -1; ++ /* tx packets */ ++ if (!(e1000_create_proc_read(TX_PACKETS_TAG, adapter, dev_dir, e1000_read_tx_packets))) ++ return -1; ++ /* rx bytes */ ++ if (!(e1000_create_proc_read(RX_BYTES_TAG, adapter, dev_dir, e1000_read_rx_bytes))) ++ return -1; ++ /* tx bytes */ ++ if (!(e1000_create_proc_read(TX_BYTES_TAG, adapter, dev_dir, e1000_read_tx_bytes))) ++ return -1; ++ /* rx errors */ ++ if (!(e1000_create_proc_read(RX_ERRORS_TAG, adapter, dev_dir, e1000_read_rx_errors))) ++ return -1; ++ /* tx errors */ ++ if (!(e1000_create_proc_read(TX_ERRORS_TAG, adapter, dev_dir, e1000_read_tx_errors))) ++ return -1; ++ /* rx dropped */ ++ if (!(e1000_create_proc_read(RX_DROPPED_TAG, adapter, dev_dir, e1000_read_rx_dropped))) ++ return -1; ++ /* tx dropped */ ++ if (!(e1000_create_proc_read(TX_DROPPED_TAG, adapter, dev_dir, e1000_read_tx_dropped))) ++ return -1; ++ /* multicast packets */ ++ if (!(e1000_create_proc_read(MULTICAST_TAG, adapter, dev_dir, ++ e1000_read_rx_multicast_packets))) ++ return -1; ++ ++ /* collisions */ ++ if (!(e1000_create_proc_read (COLLISIONS_TAG, adapter, dev_dir, e1000_read_collisions))) ++ return -1; ++ ++ /* rx length errors */ ++ if (!(e1000_create_proc_read(RX_LENGTH_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_length_errors))) return -1; ++ /* rx over errors */ ++ if (!(e1000_create_proc_read(RX_OVER_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_over_errors))) return -1; ++ /* rx crc errors */ ++ if (!(e1000_create_proc_read(RX_CRC_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_crc_errors))) return -1; ++ /* rx frame errors */ ++ if (!(e1000_create_proc_read(RX_FRAME_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_frame_errors))) return -1; ++ /* rx fifo errors */ ++ if (!(e1000_create_proc_read(RX_FIFO_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_fifo_errors))) return -1; ++ /* rx missed errors */ ++ if (!(e1000_create_proc_read(RX_MISSED_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_missed_errors))) return -1; ++ /* tx aborted errors */ ++ if (!(e1000_create_proc_read(TX_ABORTED_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_tx_aborted_errors))) return -1; ++ /* tx carrier errors */ ++ if (!(e1000_create_proc_read(TX_CARRIER_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_tx_carrier_errors))) return -1; ++ /* tx fifo errors */ ++ if (!(e1000_create_proc_read(TX_FIFO_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_tx_fifo_errors))) return -1; ++ /* tx heartbeat errors */ ++ if (!(e1000_create_proc_read(TX_HEARTBEAT_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_tx_heartbeat_errors))) return -1; ++ /* tx window errors */ ++ if (!(e1000_create_proc_read(TX_WINDOW_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_tx_window_errors))) return -1; ++ ++ if (!(e1000_create_proc_read(TX_LATE_COLL_TAG, adapter, dev_dir, ++ e1000_read_tx_late_coll))) return -1; ++ if (!(e1000_create_proc_read(TX_DEFERRED_TAG, adapter, dev_dir, ++ e1000_read_tx_defer_events))) return -1; ++ if (!(e1000_create_proc_read(TX_SINGLE_COLL_TAG, adapter, dev_dir, ++ e1000_read_tx_single_coll))) return -1; ++ if (!(e1000_create_proc_read(TX_MULTI_COLL_TAG, adapter, dev_dir, ++ e1000_read_tx_multi_coll))) return -1; ++ if (!(e1000_create_proc_read(RX_LONG_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_oversize))) return -1; ++ if (!(e1000_create_proc_read(RX_SHORT_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_undersize))) return -1; ++ if(adapter->shared.mac_type >= e1000_82543) ++ if (!(e1000_create_proc_read(RX_ALIGN_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_rx_align_err))) return -1; ++ if (!(e1000_create_proc_read(RX_XON_TAG, adapter, dev_dir, ++ e1000_read_rx_xon))) return -1; ++ if (!(e1000_create_proc_read(RX_XOFF_TAG, adapter, dev_dir, ++ e1000_read_rx_xoff))) return -1; ++ if (!(e1000_create_proc_read(TX_XON_TAG, adapter, dev_dir, ++ e1000_read_tx_xon))) return -1; ++ if (!(e1000_create_proc_read(TX_XOFF_TAG, adapter, dev_dir, ++ e1000_read_tx_xoff))) return -1; ++ ++ if (!(e1000_create_proc_read(MEDIA_TYPE_TAG, adapter, dev_dir, ++ e1000_read_media_type))) return -1; ++ ++ if (adapter->shared.media_type == e1000_media_type_copper) { ++ if (!(e1000_create_proc_read(CABLE_LENGTH_TAG, adapter, dev_dir, ++ e1000_read_cable_length))) return -1; ++ ++ if (!(e1000_create_proc_read(EXTENDED_10BASE_T_DISTANCE_TAG, ++ adapter, dev_dir, ++ e1000_read_extended_10base_t_distance))) return -1; ++ ++ if (!(e1000_create_proc_read(CABLE_POLARITY_TAG, adapter, dev_dir, ++ e1000_read_cable_polarity))) return -1; ++ ++ if (!(e1000_create_proc_read(CABLE_POLARITY_CORRECTION_TAG, adapter, dev_dir, ++ e1000_read_cable_polarity_correction))) return -1; ++ ++ if (!(e1000_create_proc_read(IDLE_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_idle_errors))) return -1; ++ ++ if (!(e1000_create_proc_read(LINK_RESET_ENABLED_TAG, adapter, dev_dir, ++ e1000_read_link_reset_enabled))) return -1; ++ ++ if (!(e1000_create_proc_read(RECEIVE_ERRORS_TAG, adapter, dev_dir, ++ e1000_read_receive_errors))) return -1; ++ ++ if (!(e1000_create_proc_read(MDI_X_ENABLED_TAG, adapter, dev_dir, ++ e1000_read_mdi_x_enabled))) return -1; ++ ++ if (!(e1000_create_proc_read(LOCAL_RECEIVER_STATUS_TAG, adapter, dev_dir, ++ e1000_read_local_receiver_status))) return -1; ++ ++ if (!(e1000_create_proc_read(REMOTE_RECEIVER_STATUS_TAG, adapter, dev_dir, ++ e1000_read_remote_receiver_status))) return -1; ++ } ++ ++ return 0; ++} ++ ++void e1000_remove_proc_dev(struct net_device *dev) ++{ ++ struct proc_dir_entry *de; ++ struct e1000_adapter * adapter = dev->priv; ++ char info[256]; ++ int len; ++ ++ len = strlen(dev->name); ++ strncpy(info, dev->name, sizeof(info)); ++ strncat(info + len, ".info", sizeof(info) - len); ++ ++ for (de = e1000_proc_dir->subdir; de; de = de->next) { ++ if ((de->namelen == len) && (!memcmp(de->name, dev->name, len))) ++ break; ++ } ++ if (de) { ++ remove_proc_entry(DESCRIPTION_TAG, de); ++ remove_proc_entry(PART_NUMBER_TAG, de); ++ remove_proc_entry(DRVR_NAME_TAG, de); ++ remove_proc_entry(DRVR_VERSION_TAG, de); ++ remove_proc_entry(PCI_VENDOR_TAG, de); ++ remove_proc_entry(PCI_DEVICE_ID_TAG, de); ++ remove_proc_entry(PCI_SUBSYSTEM_VENDOR_TAG, de); ++ remove_proc_entry(PCI_SUBSYSTEM_ID_TAG, de); ++ remove_proc_entry(PCI_REVISION_ID_TAG, de); ++ remove_proc_entry(SYSTEM_DEVICE_NAME_TAG, de); ++ remove_proc_entry(PCI_BUS_TAG, de); ++ remove_proc_entry(PCI_SLOT_TAG, de); ++ remove_proc_entry(PCI_BUS_TYPE_TAG, de); ++ remove_proc_entry(PCI_BUS_SPEED_TAG, de); ++ remove_proc_entry(PCI_BUS_WIDTH_TAG, de); ++ remove_proc_entry(IRQ_TAG, de); ++ remove_proc_entry(CURRENT_HWADDR_TAG, de); ++ remove_proc_entry(PERMANENT_HWADDR_TAG, de); ++ ++ remove_proc_entry(LINK_TAG, de); ++ remove_proc_entry(SPEED_TAG, de); ++ remove_proc_entry(DUPLEX_TAG, de); ++ remove_proc_entry(STATE_TAG, de); ++ ++ remove_proc_entry(RX_PACKETS_TAG, de); ++ remove_proc_entry(TX_PACKETS_TAG, de); ++ remove_proc_entry(RX_BYTES_TAG, de); ++ remove_proc_entry(TX_BYTES_TAG, de); ++ remove_proc_entry(RX_ERRORS_TAG, de); ++ remove_proc_entry(TX_ERRORS_TAG, de); ++ remove_proc_entry(RX_DROPPED_TAG, de); ++ remove_proc_entry(TX_DROPPED_TAG, de); ++ remove_proc_entry(MULTICAST_TAG, de); ++ remove_proc_entry(COLLISIONS_TAG, de); ++ remove_proc_entry(RX_LENGTH_ERRORS_TAG, de); ++ remove_proc_entry(RX_OVER_ERRORS_TAG, de); ++ remove_proc_entry(RX_CRC_ERRORS_TAG, de); ++ remove_proc_entry(RX_FRAME_ERRORS_TAG, de); ++ remove_proc_entry(RX_FIFO_ERRORS_TAG, de); ++ remove_proc_entry(RX_MISSED_ERRORS_TAG, de); ++ remove_proc_entry(TX_ABORTED_ERRORS_TAG, de); ++ remove_proc_entry(TX_CARRIER_ERRORS_TAG, de); ++ remove_proc_entry(TX_FIFO_ERRORS_TAG, de); ++ remove_proc_entry(TX_HEARTBEAT_ERRORS_TAG, de); ++ remove_proc_entry(TX_WINDOW_ERRORS_TAG, de); ++ remove_proc_entry(TX_LATE_COLL_TAG, de); ++ remove_proc_entry(TX_DEFERRED_TAG, de); ++ remove_proc_entry(TX_SINGLE_COLL_TAG, de); ++ remove_proc_entry(TX_MULTI_COLL_TAG, de); ++ remove_proc_entry(RX_LONG_ERRORS_TAG, de); ++ remove_proc_entry(RX_SHORT_ERRORS_TAG, de); ++ remove_proc_entry(RX_XON_TAG, de); ++ remove_proc_entry(RX_XOFF_TAG, de); ++ remove_proc_entry(TX_XON_TAG, de); ++ remove_proc_entry(TX_XOFF_TAG, de); ++ ++ remove_proc_entry(MEDIA_TYPE_TAG, de); ++ if (adapter->shared.media_type == e1000_media_type_copper) { ++ remove_proc_entry(CABLE_LENGTH_TAG, de); ++ remove_proc_entry(EXTENDED_10BASE_T_DISTANCE_TAG, de); ++ remove_proc_entry(CABLE_POLARITY_TAG, de); ++ remove_proc_entry(CABLE_POLARITY_CORRECTION_TAG, de); ++ remove_proc_entry(IDLE_ERRORS_TAG, de); ++ remove_proc_entry(LINK_RESET_ENABLED_TAG, de); ++ remove_proc_entry(RECEIVE_ERRORS_TAG, de); ++ remove_proc_entry(MDI_X_ENABLED_TAG, de); ++ remove_proc_entry(LOCAL_RECEIVER_STATUS_TAG, de); ++ remove_proc_entry(REMOTE_RECEIVER_STATUS_TAG, de); ++ } ++ } ++ ++ remove_proc_entry(info, e1000_proc_dir); ++ remove_proc_entry(dev->name, e1000_proc_dir); ++} +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/e1000_proc.h 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,181 @@ ++/******************************************************************************* ++ ++ This software program is available to you under a choice of one of two ++ licenses. You may choose to be licensed under either the GNU General Public ++ License (GPL) Version 2, June 1991, available at ++ http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++ text of which follows: ++ ++ Recipient has requested a license and Intel Corporation ("Intel") is willing ++ to grant a license for the software entitled Linux Base Driver for the ++ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++ by Intel Corporation. The following definitions apply to this license: ++ ++ "Licensed Patents" means patent claims licensable by Intel Corporation which ++ are necessarily infringed by the use of sale of the Software alone or when ++ combined with the operating system referred to below. ++ ++ "Recipient" means the party to whom Intel delivers this Software. ++ ++ "Licensee" means Recipient and those third parties that receive a license to ++ any operating system available under the GNU Public License version 2.0 or ++ later. ++ ++ Copyright (c) 1999 - 2002 Intel Corporation. ++ All rights reserved. ++ ++ The license is provided to Recipient and Recipient's Licensees under the ++ following terms. ++ ++ Redistribution and use in source and binary forms of the Software, with or ++ without modification, are permitted provided that the following conditions ++ are met: ++ ++ Redistributions of source code of the Software may retain the above ++ copyright notice, this list of conditions and the following disclaimer. ++ ++ Redistributions in binary form of the Software may reproduce the above ++ copyright notice, this list of conditions and the following disclaimer in ++ the documentation and/or materials provided with the distribution. ++ ++ Neither the name of Intel Corporation nor the names of its contributors ++ shall be used to endorse or promote products derived from this Software ++ without specific prior written permission. ++ ++ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++ royalty-free patent license under Licensed Patents to make, use, sell, offer ++ to sell, import and otherwise transfer the Software, if any, in source code ++ and object code form. This license shall include changes to the Software ++ that are error corrections or other minor changes to the Software that do ++ not add functionality or features when the Software is incorporated in any ++ version of an operating system that has been distributed under the GNU ++ General Public License 2.0 or later. This patent license shall apply to the ++ combination of the Software and any operating system licensed under the GNU ++ Public License version 2.0 or later if, at the time Intel provides the ++ Software to Recipient, such addition of the Software to the then publicly ++ available versions of such operating systems available under the GNU Public ++ License version 2.0 or later (whether in gold, beta or alpha form) causes ++ such combination to be covered by the Licensed Patents. The patent license ++ shall not apply to any other combinations which include the Software. NO ++ hardware per se is licensed hereunder. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++*******************************************************************************/ ++ ++/* /proc definitions */ ++#include ++ ++#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" ++ ++#define DESCRIPTION_TAG "Description" ++#define PART_NUMBER_TAG "Part_Number" ++#define DRVR_NAME_TAG "Driver_Name" ++#define DRVR_VERSION_TAG "Driver_Version" ++#define PCI_VENDOR_TAG "PCI_Vendor" ++#define PCI_DEVICE_ID_TAG "PCI_Device_ID" ++#define PCI_SUBSYSTEM_VENDOR_TAG "PCI_Subsystem_Vendor" ++#define PCI_SUBSYSTEM_ID_TAG "PCI_Subsystem_ID" ++#define PCI_REVISION_ID_TAG "PCI_Revision_ID" ++#define PCI_BUS_TAG "PCI_Bus" ++#define PCI_SLOT_TAG "PCI_Slot" ++#define PCI_BUS_TYPE_TAG "PCI_Bus_Type" ++#define PCI_BUS_SPEED_TAG "PCI_Bus_Speed" ++#define PCI_BUS_WIDTH_TAG "PCI_Bus_Width" ++#define IRQ_TAG "IRQ" ++#define SYSTEM_DEVICE_NAME_TAG "System_Device_Name" ++#define CURRENT_HWADDR_TAG "Current_HWaddr" ++#define PERMANENT_HWADDR_TAG "Permanent_HWaddr" ++ ++#define LINK_TAG "Link" ++#define SPEED_TAG "Speed" ++#define DUPLEX_TAG "Duplex" ++#define STATE_TAG "State" ++ ++#define RX_PACKETS_TAG "Rx_Packets" ++#define TX_PACKETS_TAG "Tx_Packets" ++#define RX_BYTES_TAG "Rx_Bytes" ++#define TX_BYTES_TAG "Tx_Bytes" ++#define RX_ERRORS_TAG "Rx_Errors" ++#define TX_ERRORS_TAG "Tx_Errors" ++#define RX_DROPPED_TAG "Rx_Dropped" ++#define TX_DROPPED_TAG "Tx_Dropped" ++#define MULTICAST_TAG "Multicast" ++#define COLLISIONS_TAG "Collisions" ++#define RX_LENGTH_ERRORS_TAG "Rx_Length_Errors" ++#define RX_OVER_ERRORS_TAG "Rx_Over_Errors" ++#define RX_CRC_ERRORS_TAG "Rx_CRC_Errors" ++#define RX_FRAME_ERRORS_TAG "Rx_Frame_Errors" ++#define RX_FIFO_ERRORS_TAG "Rx_FIFO_Errors" ++#define RX_MISSED_ERRORS_TAG "Rx_Missed_Errors" ++#define TX_ABORTED_ERRORS_TAG "Tx_Aborted_Errors" ++#define TX_CARRIER_ERRORS_TAG "Tx_Carrier_Errors" ++#define TX_FIFO_ERRORS_TAG "Tx_FIFO_Errors" ++#define TX_HEARTBEAT_ERRORS_TAG "Tx_Heartbeat_Errors" ++#define TX_WINDOW_ERRORS_TAG "Tx_Window_Errors" ++ ++#define RX_TCP_CHECKSUM_GOOD_TAG "Rx_TCP_Checksum_Good" ++#define RX_TCP_CHECKSUM_BAD_TAG "Rx_TCP_Checksum_Bad" ++#define TX_TCP_CHECKSUM_GOOD_TAG "Tx_TCP_Checksum_Good" ++#define TX_TCP_CHECKSUM_BAD_TAG "Tx_TCP_Checksum_Bad" ++ ++#define TX_LATE_COLL_TAG "Tx_Abort_Late_Coll" ++#define TX_DEFERRED_TAG "Tx_Deferred_Ok" ++#define TX_SINGLE_COLL_TAG "Tx_Single_Coll_Ok" ++#define TX_MULTI_COLL_TAG "Tx_Multi_Coll_Ok" ++#define RX_LONG_ERRORS_TAG "Rx_Long_Length_Errors" ++#define RX_SHORT_ERRORS_TAG "Rx_Short_Length_Errors" ++#define RX_ALIGN_ERRORS_TAG "Rx_Align_Errors" ++#define RX_XON_TAG "Rx_Flow_Control_XON" ++#define RX_XOFF_TAG "Rx_Flow_Control_XOFF" ++#define TX_XON_TAG "Tx_Flow_Control_XON" ++#define TX_XOFF_TAG "Tx_Flow_Control_XOFF" ++#define RX_CSUM_GOOD_TAG "Rx_Csum_Offload_Good" ++#define RX_CSUM_ERROR_TAG "Rx_Csum_Offload_Errors" ++ ++/* what is the cable length (only for 100/1000 modes)? - 50, 50-80, 80-110, 110-140 and > 140 meters */ ++#define CABLE_LENGTH_TAG "PHY_Cable_Length" ++ ++/* Media Type Copper/Fiber */ ++#define MEDIA_TYPE_TAG "PHY_Media_Type" ++ ++/* Is extended 10 Base-T distance feature enabled? This is done by lowering the receive threshold - enabled/disabled */ ++#define EXTENDED_10BASE_T_DISTANCE_TAG "PHY_Extended_10Base_T_Distance" ++ ++/* Cable polarity Normal/Reversed */ ++#define CABLE_POLARITY_TAG "PHY_Cable_Polarity" ++ ++/* Is Polarity reversal enabled? Enabled/Disabled */ ++#define CABLE_POLARITY_CORRECTION_TAG "PHY_Disable_Polarity_Correction" ++ ++/* Number of IDLE Errors */ ++#define IDLE_ERRORS_TAG "PHY_Idle_Errors" ++ ++/* Should the link be brought down if an IDLE is not seen within 1 msec while in 1000mbps mode? Enabled/Disabled */ ++#define LINK_RESET_ENABLED_TAG "PHY_Link_Reset_Enabled" ++ ++/* Number of receive errors */ ++#define RECEIVE_ERRORS_TAG "PHY_Receive_Errors" ++ ++/* MDI-X Support Enabled? Auto, Manual(MDI) or Manual(MDI-X) */ ++#define MDI_X_ENABLED_TAG "PHY_MDI_X_Enabled" ++ ++/* Local Receiver OK? OK/NOT_OK */ ++#define LOCAL_RECEIVER_STATUS_TAG "PHY_Local_Receiver_Status" ++ ++/* Remote Receiver OK? OK/NOT_OK */ ++#define REMOTE_RECEIVER_STATUS_TAG "PHY_Remote_Receiver_Status" ++ ++/* symbols exported to e1000_main */ ++extern struct proc_dir_entry *e1000_proc_dir; ++extern int e1000_create_proc_dev(struct e1000_adapter * Adapter); ++extern void e1000_remove_proc_dev(struct net_device *dev); +--- /dev/null 2002-08-30 16:31:37.000000000 -0700 ++++ linux-2.4.18-14-root/drivers/e1000/Makefile 2003-01-02 16:22:31.000000000 -0800 +@@ -0,0 +1,92 @@ ++################################################################################ ++# ++# This software program is available to you under a choice of one of two ++# licenses. You may choose to be licensed under either the GNU General Public ++# License (GPL) Version 2, June 1991, available at ++# http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the ++# text of which follows: ++# ++# Recipient has requested a license and Intel Corporation ("Intel") is willing ++# to grant a license for the software entitled Linux Base Driver for the ++# Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided ++# by Intel Corporation. The following definitions apply to this license: ++# ++# "Licensed Patents" means patent claims licensable by Intel Corporation which ++# are necessarily infringed by the use of sale of the Software alone or when ++# combined with the operating system referred to below. ++# ++# "Recipient" means the party to whom Intel delivers this Software. ++# ++# "Licensee" means Recipient and those third parties that receive a license to ++# any operating system available under the GNU Public License version 2.0 or ++# later. ++# ++# Copyright (c) 1999 - 2002 Intel Corporation. ++# All rights reserved. ++# ++# The license is provided to Recipient and Recipient's Licensees under the ++# following terms. ++# ++# Redistribution and use in source and binary forms of the Software, with or ++# without modification, are permitted provided that the following conditions ++# are met: ++# ++# Redistributions of source code of the Software may retain the above ++# copyright notice, this list of conditions and the following disclaimer. ++# ++# Redistributions in binary form of the Software may reproduce the above ++# copyright notice, this list of conditions and the following disclaimer in ++# the documentation and/or materials provided with the distribution. ++# ++# Neither the name of Intel Corporation nor the names of its contributors ++# shall be used to endorse or promote products derived from this Software ++# without specific prior written permission. ++# ++# Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, ++# royalty-free patent license under Licensed Patents to make, use, sell, offer ++# to sell, import and otherwise transfer the Software, if any, in source code ++# and object code form. This license shall include changes to the Software ++# that are error corrections or other minor changes to the Software that do ++# not add functionality or features when the Software is incorporated in any ++# version of an operating system that has been distributed under the GNU ++# General Public License 2.0 or later. This patent license shall apply to the ++# combination of the Software and any operating system licensed under the GNU ++# Public License version 2.0 or later if, at the time Intel provides the ++# Software to Recipient, such addition of the Software to the then publicly ++# available versions of such operating systems available under the GNU Public ++# License version 2.0 or later (whether in gold, beta or alpha form) causes ++# such combination to be covered by the Licensed Patents. The patent license ++# shall not apply to any other combinations which include the Software. NO ++# hardware per se is licensed hereunder. ++# ++# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++# IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++# ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY ++# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++# (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++# ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED ++# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR ++# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++# ++################################################################################ ++ ++########################################################################### ++# Configuration Section ++ ++# Optional features - set to 'y' for on, anything else for off ++# Intel(R) Advanced Network Services ++IANS := n ++# Intel(R) PRO Diagnostics ++IDIAG := n ++ ++########################################################################### ++# Driver files ++ ++# core driver files ++O_TARGET := e1000.o ++obj-y := e1000_main.o e1000_mac.o e1000_phy.o e1000_proc.o ++obj-m := $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- linux-2.4.18-14/drivers/Makefile~e1000 2003-01-02 16:20:41.000000000 -0800 ++++ linux-2.4.18-14-root/drivers/Makefile 2003-01-02 16:22:31.000000000 -0800 +@@ -6,14 +6,15 @@ + # + + +-mod-subdirs := addon dio mtd sbus video macintosh usb input telephony sgi ide \ ++mod-subdirs := e1000 addon dio mtd sbus video macintosh usb input telephony sgi ide \ + message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ + fc4 net/hamradio i2c acpi bluetooth sensors + +-subdir-y := addon parport char block net sound misc media cdrom hotplug ++subdir-y := e1000 addon parport char block net sound misc media cdrom hotplug + subdir-m := $(subdir-y) + + ++subdir-$(CONFIG_E1000) += e1000 + subdir-$(CONFIG_DIO) += dio + subdir-$(CONFIG_PCI) += pci + subdir-$(CONFIG_PCMCIA) += pcmcia +--- linux-2.4.18-14/Makefile~e1000 2003-01-02 16:20:51.000000000 -0800 ++++ linux-2.4.18-14-root/Makefile 2003-01-02 16:22:31.000000000 -0800 +@@ -178,6 +178,7 @@ DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmc + DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o + DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o + DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o ++DRIVERS-$(CONFIG_E1000) += drivers/e1000/e1000.o + DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a + DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o + DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o + +_ diff --git a/lustre/kernel_patches/patches/tcp_zero.patch b/lustre/kernel_patches/patches/tcp_zero.patch new file mode 100644 index 0000000..27b2ab7 --- /dev/null +++ b/lustre/kernel_patches/patches/tcp_zero.patch @@ -0,0 +1,468 @@ + +Zero-copy tcp patch. An initial implementation +we use for performance analysis. May render tree unstable. +Use at your own risk. + + + 0 files changed + +--- linux-2.4.18-14/include/linux/skbuff.h~tcp_zero 2003-01-02 16:33:52.000000000 -0800 ++++ linux-2.4.18-14-root/include/linux/skbuff.h 2003-01-02 16:36:14.000000000 -0800 +@@ -116,6 +116,30 @@ struct skb_frag_struct + __u16 size; + }; + ++/* Support for callback when skb data has been released */ ++typedef struct zccd /* Zero Copy Callback Descriptor */ ++{ /* (embed as first member of custom struct) */ ++ atomic_t zccd_count; /* reference count */ ++ void (*zccd_destructor)(struct zccd *); /* callback when refcount reaches zero */ ++} zccd_t; ++ ++static inline void zccd_init (zccd_t *d, void (*callback)(zccd_t *)) ++{ ++ atomic_set (&d->zccd_count, 1); ++ d->zccd_destructor = callback; ++} ++ ++static inline void zccd_get (zccd_t *d) /* take a reference */ ++{ ++ atomic_inc (&d->zccd_count); ++} ++ ++static inline void zccd_put (zccd_t *d) /* release a reference */ ++{ ++ if (atomic_dec_and_test (&d->zccd_count)) ++ (d->zccd_destructor)(d); ++} ++ + /* This data is invariant across clones and lives at + * the end of the header data, ie. at skb->end. + */ +@@ -123,6 +147,12 @@ struct skb_shared_info { + atomic_t dataref; + unsigned int nr_frags; + struct sk_buff *frag_list; ++ zccd_t *zccd; /* zero copy descriptor */ ++ zccd_t *zccd2; /* 2nd zero copy descriptor */ ++ /* NB we expect zero-copy data to be at least 1 packet, so ++ * having 2 zccds means we don't unneccessarily split the packet ++ * where consecutive zero-copy sends abutt. ++ */ + skb_frag_t frags[MAX_SKB_FRAGS]; + }; + +--- linux-2.4.18-14/include/net/tcp.h~tcp_zero 2003-01-02 16:34:14.000000000 -0800 ++++ linux-2.4.18-14-root/include/net/tcp.h 2003-01-02 16:36:14.000000000 -0800 +@@ -639,6 +639,8 @@ extern int tcp_v4_tw_remember_stam + + extern int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size); + extern ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); ++extern ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, ++ int flags, zccd_t *zccd); + + extern int tcp_ioctl(struct sock *sk, + int cmd, +@@ -732,6 +734,9 @@ extern int tcp_recvmsg(struct sock *sk + struct msghdr *msg, + int len, int nonblock, + int flags, int *addr_len); ++extern int tcp_recvpackets(struct sock *sk, ++ struct sk_buff_head *packets, ++ int len, int nonblock); + + extern int tcp_listen_start(struct sock *sk); + +--- linux-2.4.18-14/net/netsyms.c~tcp_zero 2003-01-02 16:34:39.000000000 -0800 ++++ linux-2.4.18-14-root/net/netsyms.c 2003-01-02 16:36:14.000000000 -0800 +@@ -395,6 +395,8 @@ EXPORT_SYMBOL(sysctl_tcp_wmem); + EXPORT_SYMBOL(sysctl_tcp_ecn); + EXPORT_SYMBOL(tcp_cwnd_application_limited); + EXPORT_SYMBOL(tcp_sendpage); ++EXPORT_SYMBOL(tcp_sendpage_zccd); ++EXPORT_SYMBOL(tcp_recvpackets); + + EXPORT_SYMBOL(tcp_write_xmit); + +@@ -415,6 +417,7 @@ EXPORT_SYMBOL(secure_ipv6_id); + #endif + + EXPORT_SYMBOL(tcp_read_sock); ++EXPORT_SYMBOL(tcp_sendpage_zccd); + + EXPORT_SYMBOL(netlink_set_err); + EXPORT_SYMBOL(netlink_broadcast); +--- linux-2.4.18-14/net/core/skbuff.c~tcp_zero 2003-01-02 16:34:50.000000000 -0800 ++++ linux-2.4.18-14-root/net/core/skbuff.c 2003-01-02 16:36:14.000000000 -0800 +@@ -208,6 +208,8 @@ struct sk_buff *alloc_skb(unsigned int s + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; ++ skb_shinfo(skb)->zccd = NULL; /* skbuffs kick off with NO user zero copy descriptors */ ++ skb_shinfo(skb)->zccd2 = NULL; + return skb; + + nodata: +@@ -276,6 +278,10 @@ static void skb_release_data(struct sk_b + { + if (!skb->cloned || + atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { ++ if (skb_shinfo(skb)->zccd != NULL) /* zero copy callback descriptor? */ ++ zccd_put (skb_shinfo(skb)->zccd); /* release hold */ ++ if (skb_shinfo(skb)->zccd2 != NULL) /* 2nd zero copy callback descriptor? */ ++ zccd_put (skb_shinfo(skb)->zccd2); /* release hold */ + if (skb_shinfo(skb)->nr_frags) { + int i; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +@@ -532,6 +538,8 @@ int skb_linearize(struct sk_buff *skb, i + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; ++ skb_shinfo(skb)->zccd = NULL; /* copied data => no user zero copy descriptor */ ++ skb_shinfo(skb)->zccd2 = NULL; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; +@@ -577,6 +585,14 @@ struct sk_buff *pskb_copy(struct sk_buff + + n->data_len = skb->data_len; + n->len = skb->len; ++ ++ if (skb_shinfo(skb)->zccd != NULL) /* user zero copy descriptor? */ ++ zccd_get (skb_shinfo(skb)->zccd); /* 1 more ref (pages are shared) */ ++ skb_shinfo(n)->zccd = skb_shinfo(skb)->zccd; ++ ++ if (skb_shinfo(skb)->zccd2 != NULL) /* 2nd user zero copy descriptor? */ ++ zccd_get (skb_shinfo(skb)->zccd2); /* 1 more ref (pages are shared) */ ++ skb_shinfo(n)->zccd2 = skb_shinfo(skb)->zccd2; + + if (skb_shinfo(skb)->nr_frags) { + int i; +@@ -620,6 +636,8 @@ int pskb_expand_head(struct sk_buff *skb + u8 *data; + int size = nhead + (skb->end - skb->head) + ntail; + long off; ++ zccd_t *zccd = skb_shinfo(skb)->zccd; /* stash user zero copy descriptor */ ++ zccd_t *zccd2 = skb_shinfo(skb)->zccd2; /* stash 2nd user zero copy descriptor */ + + if (skb_shared(skb)) + BUG(); +@@ -641,6 +659,11 @@ int pskb_expand_head(struct sk_buff *skb + if (skb_shinfo(skb)->frag_list) + skb_clone_fraglist(skb); + ++ if (zccd != NULL) /* user zero copy descriptor? */ ++ zccd_get (zccd); /* extra ref (pages are shared) */ ++ if (zccd2 != NULL) /* 2nd user zero copy descriptor? */ ++ zccd_get (zccd2); /* extra ref (pages are shared) */ ++ + skb_release_data(skb); + + off = (data+nhead) - skb->head; +@@ -655,6 +678,8 @@ int pskb_expand_head(struct sk_buff *skb + skb->nh.raw += off; + skb->cloned = 0; + atomic_set(&skb_shinfo(skb)->dataref, 1); ++ skb_shinfo(skb)->zccd = zccd; ++ skb_shinfo(skb)->zccd2 = zccd2; + return 0; + + nodata: +--- linux-2.4.18-14/net/ipv4/tcp.c~tcp_zero 2003-01-02 16:35:02.000000000 -0800 ++++ linux-2.4.18-14-root/net/ipv4/tcp.c 2003-01-02 16:36:14.000000000 -0800 +@@ -745,7 +745,7 @@ do_interrupted: + goto out; + } + +-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags); ++ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags, zccd_t *zccd); + + static inline int + can_coalesce(struct sk_buff *skb, int i, struct page *page, int off) +@@ -824,7 +824,8 @@ static int tcp_error(struct sock *sk, in + return err; + } + +-ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags) ++/* Extra parameter: user zero copy descriptor (or NULL if not doing that) */ ++ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags, zccd_t *zccd) + { + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int mss_now; +@@ -872,6 +873,17 @@ new_segment: + copy = size; + + i = skb_shinfo(skb)->nr_frags; ++ ++ if (zccd != NULL && /* this is a zcc I/O */ ++ skb_shinfo(skb)->zccd != NULL && /* skb is part of a zcc I/O */ ++ skb_shinfo(skb)->zccd2 != NULL && ++ skb_shinfo(skb)->zccd != zccd && /* not the same one */ ++ skb_shinfo(skb)->zccd2 != zccd) ++ { ++ tcp_mark_push (tp, skb); ++ goto new_segment; ++ } ++ + if (can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else if (i < MAX_SKB_FRAGS) { +@@ -881,6 +893,20 @@ new_segment: + tcp_mark_push(tp, skb); + goto new_segment; + } ++ ++ if (zccd != NULL && /* this is a zcc I/O */ ++ skb_shinfo(skb)->zccd != zccd && /* not already referencing this zccd */ ++ skb_shinfo(skb)->zccd2 != zccd) ++ { ++ zccd_get (zccd); /* bump ref count */ ++ ++ BUG_TRAP (skb_shinfo(skb)->zccd2 == NULL); ++ ++ if (skb_shinfo(skb)->zccd == NULL) /* reference this zccd */ ++ skb_shinfo(skb)->zccd = zccd; ++ else ++ skb_shinfo(skb)->zccd2 = zccd; ++ } + + skb->len += copy; + skb->data_len += copy; +@@ -945,7 +971,31 @@ ssize_t tcp_sendpage(struct socket *sock + + lock_sock(sk); + TCP_CHECK_TIMER(sk); +- res = do_tcp_sendpages(sk, &page, offset, size, flags); ++ res = do_tcp_sendpages(sk, &page, offset, size, flags, NULL); ++ TCP_CHECK_TIMER(sk); ++ release_sock(sk); ++ return res; ++} ++ ++ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, ++ int flags, zccd_t *zccd) ++{ ++ ssize_t res; ++ struct sock *sk = sock->sk; ++ ++#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) ++ ++ if (!(sk->route_caps & NETIF_F_SG) || /* caller shouldn't waste her time */ ++ !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) /* on double mapping */ ++ BUG (); ++ ++#undef TCP_ZC_CSUM_FLAGS ++ ++ lock_sock(sk); ++ TCP_CHECK_TIMER(sk); ++ ++ res = do_tcp_sendpages(sk, &page, offset, size, flags, zccd); ++ + TCP_CHECK_TIMER(sk); + release_sock(sk); + return res; +@@ -1769,6 +1819,202 @@ recv_urg: + goto out; + } + ++int tcp_recvpackets (struct sock *sk, struct sk_buff_head *packets, ++ int len, int nonblock) ++{ ++ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); ++ int copied; ++ long timeo; ++ ++ BUG_TRAP (len > 0); ++// BUG_TRAP ((flags & (MSG_OOB | MSG_PEEK | MSG_TRUNC)) == 0); ++ ++ lock_sock(sk); ++ ++ TCP_CHECK_TIMER(sk); ++ ++ copied = -ENOTCONN; ++ if (sk->state == TCP_LISTEN) ++ goto out; ++ ++ copied = 0; ++ timeo = sock_rcvtimeo(sk, nonblock); ++ ++ do { ++ struct sk_buff * skb; ++ u32 offset; ++ unsigned long used; ++ int exhausted; ++ int eaten; ++ ++ /* Are we at urgent data? Stop if we have read anything. */ ++ if (copied && tp->urg_data && tp->urg_seq == tp->copied_seq) ++ break; ++ ++ /* We need to check signals first, to get correct SIGURG ++ * handling. FIXME: Need to check this doesnt impact 1003.1g ++ * and move it down to the bottom of the loop ++ */ ++ if (signal_pending(current)) { ++ if (copied) ++ break; ++ copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; ++ break; ++ } ++ ++ /* Next get a buffer. */ ++ ++ skb = skb_peek(&sk->receive_queue); ++ ++ if (skb == NULL) /* nothing ready */ ++ { ++ if (copied) { ++ if (sk->err || ++ sk->state == TCP_CLOSE || ++ (sk->shutdown & RCV_SHUTDOWN) || ++ !timeo || ++ (0)) ++ break; ++ } else { ++ if (sk->done) ++ break; ++ ++ if (sk->err) { ++ copied = sock_error(sk); ++ break; ++ } ++ ++ if (sk->shutdown & RCV_SHUTDOWN) ++ break; ++ ++ if (sk->state == TCP_CLOSE) { ++ if (!sk->done) { ++ /* This occurs when user tries to read ++ * from never connected socket. ++ */ ++ copied = -ENOTCONN; ++ break; ++ } ++ break; ++ } ++ ++ if (!timeo) { ++ copied = -EAGAIN; ++ break; ++ } ++ } ++ ++ cleanup_rbuf(sk, copied); ++ timeo = tcp_data_wait(sk, timeo); ++ continue; ++ } ++ ++ BUG_TRAP (atomic_read (&skb->users) == 1); ++ ++ exhausted = eaten = 0; ++ ++ offset = tp->copied_seq - TCP_SKB_CB(skb)->seq; ++ if (skb->h.th->syn) ++ offset--; ++ ++ used = skb->len - offset; ++ ++ if (tp->urg_data) { ++ u32 urg_offset = tp->urg_seq - tp->copied_seq; ++ if (urg_offset < used) { ++ if (!urg_offset) { /* at urgent date */ ++ if (!sk->urginline) { ++ tp->copied_seq++; /* discard the single byte of urgent data */ ++ offset++; ++ used--; ++ } ++ } else /* truncate read */ ++ used = urg_offset; ++ } ++ } ++ ++ BUG_TRAP (used >= 0); ++ if (len < used) ++ used = len; ++ ++ if (used == 0) ++ exhausted = 1; ++ else ++ { ++ if (skb_is_nonlinear (skb)) ++ { ++ int rc = skb_linearize (skb, GFP_KERNEL); ++ ++ printk ("tcp_recvpackets(): linearising: %d\n", rc); ++ ++ if (rc) ++ { ++ if (!copied) ++ copied = rc; ++ break; ++ } ++ } ++ ++ if ((offset + used) == skb->len) /* consuming the whole packet */ ++ { ++ __skb_unlink (skb, &sk->receive_queue); ++ dst_release (skb->dst); ++ skb_orphan (skb); ++ __skb_pull (skb, offset); ++ __skb_queue_tail (packets, skb); ++ exhausted = eaten = 1; ++ } ++ else /* consuming only part of the packet */ ++ { ++ struct sk_buff *skb2 = skb_clone (skb, GFP_KERNEL); ++ ++ if (skb2 == NULL) ++ { ++ if (!copied) ++ copied = -ENOMEM; ++ break; ++ } ++ ++ dst_release (skb2->dst); ++ __skb_pull (skb2, offset); ++ __skb_trim (skb2, used); ++ __skb_queue_tail (packets, skb2); ++ } ++ ++ tp->copied_seq += used; ++ copied += used; ++ len -= used; ++ } ++ ++ if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) { ++ tp->urg_data = 0; ++ tcp_fast_path_check(sk, tp); ++ } ++ ++ if (!exhausted) ++ continue; ++ ++ if (skb->h.th->fin) ++ { ++ tp->copied_seq++; ++ if (!eaten) ++ tcp_eat_skb (sk, skb); ++ break; ++ } ++ ++ if (!eaten) ++ tcp_eat_skb (sk, skb); ++ ++ } while (len > 0); ++ ++ out: ++ /* Clean up data we have read: This will do ACK frames. */ ++ cleanup_rbuf(sk, copied); ++ TCP_CHECK_TIMER(sk); ++ release_sock(sk); ++ return copied; ++} ++ + /* + * State processing on a close. This implements the state shift for + * sending our FIN frame. Note that we only send a FIN for some + +_ diff --git a/lustre/kernel_patches/pc/e1000.pc b/lustre/kernel_patches/pc/e1000.pc new file mode 100644 index 0000000..8d804d9 --- /dev/null +++ b/lustre/kernel_patches/pc/e1000.pc @@ -0,0 +1,12 @@ +drivers/e1000/e1000.h +drivers/e1000/e1000_mac.c +drivers/e1000/e1000_mac.h +drivers/e1000/e1000_main.c +drivers/e1000/e1000_osdep.h +drivers/e1000/e1000_phy.c +drivers/e1000/e1000_phy.h +drivers/e1000/e1000_proc.c +drivers/e1000/e1000_proc.h +drivers/e1000/Makefile +drivers/Makefile +Makefile diff --git a/lustre/kernel_patches/pc/tcp_zero.pc b/lustre/kernel_patches/pc/tcp_zero.pc new file mode 100644 index 0000000..02877c0 --- /dev/null +++ b/lustre/kernel_patches/pc/tcp_zero.pc @@ -0,0 +1,5 @@ +include/linux/skbuff.h +include/net/tcp.h +net/netsyms.c +net/core/skbuff.c +net/ipv4/tcp.c diff --git a/lustre/kernel_patches/series/rh-8.0-intel b/lustre/kernel_patches/series/rh-8.0-intel new file mode 100644 index 0000000..4fceef5 --- /dev/null +++ b/lustre/kernel_patches/series/rh-8.0-intel @@ -0,0 +1,10 @@ +dev_read_only.patch +exports.patch +kmem_cache_validate.patch +lustre_version.patch +uml_check_get_page.patch +uml_no_panic.patch +vfs_intent.patch +uml_compile_fixes.patch +e1000.patch +tcp_zero.patch diff --git a/lustre/kernel_patches/txt/e1000.txt b/lustre/kernel_patches/txt/e1000.txt new file mode 100644 index 0000000..c0c1d89 --- /dev/null +++ b/lustre/kernel_patches/txt/e1000.txt @@ -0,0 +1,4 @@ +This patch creates the necessary drivers +for the e1000 card that are not included with +the standard RH distribution. This is used for the +GigE e1000 cards. diff --git a/lustre/kernel_patches/txt/tcp_zero.txt b/lustre/kernel_patches/txt/tcp_zero.txt new file mode 100644 index 0000000..abc85b5 --- /dev/null +++ b/lustre/kernel_patches/txt/tcp_zero.txt @@ -0,0 +1,3 @@ +Zero-copy tcp patch. An initial implementation +we use for performance analysis. May render tree unstable. +Use at your own risk.