diff -urN linux-2.4.35/drivers/net/e100/Makefile linux-2.4.35-e100-3.5.17/drivers/net/e100/Makefile --- linux-2.4.35/drivers/net/e100/Makefile 2003-06-13 16:51:34 +0200 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/Makefile 2007-08-13 10:07:17 +0200 @@ -4,8 +4,7 @@ O_TARGET := e100.o -obj-y := e100_main.o e100_config.o e100_phy.o \ - e100_eeprom.o e100_test.o +obj-y := e100_main.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -urN linux-2.4.35/drivers/net/e100/README linux-2.4.35-e100-3.5.17/drivers/net/e100/README --- linux-2.4.35/drivers/net/e100/README 1970-01-01 01:00:00 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/README 2007-08-13 10:16:46 +0200 @@ -0,0 +1,303 @@ +Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters +============================================================== + +May 3, 2006 + +Contents +======== + +- In This Release +- Identifying Your Adapter +- Building and Installation +- Driver Configuration Parameters +- Additional Configurations +- Known Issues +- Support + + +In This Release +=============== + +This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family +of Adapters. This driver supports 2.4.x and 2.6.x kernels. This driver +includes support for Itanium(R)2-based systems. + +For questions related to hardware requirements, refer to the documentation +supplied with your Intel PRO/100 adapter. + +The following features are now available in supported kernels: + - Native VLANs + - Channel Bonding (teaming) + - SNMP + +Channel Bonding documentation can be found in the Linux kernel source: +/Documentation/networking/bonding.txt + + +NOTE: If you have the Intel® 82562v 10/100 Network Connection, you must +install the e1000 driver. + +Identifying Your Adapter +======================== + +For more information on how to identify your adapter, go to the Adapter & +Driver ID Guide at: + + http://support.intel.com/support/network/adapter/pro100/21397.htm + +For the latest Intel network drivers for Linux, refer to the following +website. In the search field, enter your adapter name or type, or use the +networking link on the left to search for your adapter: + + http://downloadfinder.intel.com/scripts-df/support_intel.asp + + +Building and Installation +========================= + +To build a binary RPM* package of this driver run 'rpmbuild -tb +'. Replace with the specific file name +of he driver. + +NOTES: For the build to work properly it is important that the currently + running kernel MATCH the version and configuration of the installed + kernel source. If you have just recompiled your kernel, reboot the + system and choose the correct kernel to boot. + + RPM functionality has only been tested in Red Hat distributions. + +1. Move the base driver tar file to the directory of your choice. For + example, use: /home/username/e100 or /usr/local/src/e100. + +2. Untar/unzip the archive by entering the following, where is the + version number for the driver tar: + + tar xfz e100-.tar.gz + +3. Change to the driver src directory by entering the following, where + is the version number for the driver tar: + + cd e100-/src/ + +4. Compile the driver module: + + make install + + The binary will be installed as below: + + /lib/modules//kernel/drivers/net/e100/e100.[k]o + + The install location listed above is the default locations. It may + not be correct for certain Linux distributions. For more information, + see the ldistrib.txt file included in the driver tar. + +5. Install the module: + + modprobe e100 + +6. Assign an IP address to the interface by entering the following, where + is the interface number: + + ifconfig eth + +7. Verify that the interface works. Enter the following, where + is the IP address for another machine on the same subnet as the interface + that is being tested: + + ping + + +Driver Configuration Parameters +=============================== + +The default value for each parameter is generally the recommended setting, +unless otherwise noted. + +Rx Descriptors: Number of receive descriptors. A receive descriptor is a + data structure that describes a receive buffer and its attributes to + the network controller. The data in the descriptor is used by the + controller to write data from the controller to host memory. In the + 3.x.x driver the valid range for this parameter is 64-256. The default + value is 64. This parameter can be changed using the command: + + ethtool -G eth? rx n, where n is the number of desired rx descriptors. + +Tx Descriptors: Number of transmit descriptors. A transmit descriptor is + a data structure that describes a transmit buffer and its attributes + to the network controller. The data in the descriptor is used by the + controller to read data from the host memory to the controller. In the + 3.x.x driver the valid range for this parameter is 64-256. The default + value is 64. This parameter can be changed using the command: + + ethtool -G eth? tx n, where n is the number of desired tx descriptors. + +Speed/Duplex: The driver auto-negotiates the link speed and duplex settings + by default. Ethtool can be used as follows to force speed/duplex. + + ethtool -s eth? autoneg off speed {10|100} duplex {full|half} + + NOTE: setting the speed/duplex to incorrect values will cause the link + to fail. + +Event Log Message Level: The driver uses the message level flag to log + events to syslog. The message level can be set at driver load time. It + can also be set using the command: + + ethtool -s eth? msglvl n + + +Additional Configurations +========================= + + Configuring the Driver on Different Distributions + ------------------------------------------------- + + Configuring a network driver to load properly when the system is started + is distribution dependent. Typically, the configuration process involves + adding an alias line to /etc/modules.conf or /etc/modprobe.conf as well + as editing other system startup scripts and/or configuration files. + Many popular Linux distributions ship with tools to make these changes + for you. To learn the proper way to configure a network device for your + system, refer to your distribution documentation. If during this process + you are asked for the driver or module name, the name for the Linux Base + Driver for the Intel PRO/100 Family of Adapters is e100. + + As an example, if you install the e100 driver for two PRO/100 adapters + (eth0 and eth1), add the following to modules.conf or modprobe.conf: + + alias eth0 e100 + alias eth1 e100 + + Viewing Link Messages + --------------------- + In order to see link messages and other Intel driver information on your + console, you must set the dmesg level up to six. This can be done by + entering the following on the command line before loading the e100 driver: + + dmesg -n 8 + + If you wish to see all messages issued by the driver, including debug + messages, set the dmesg level to eight. + + NOTE: This setting is not saved across reboots. + + + Ethtool + ------- + + The driver utilizes the ethtool interface for driver configuration and + diagnostics, as well as displaying statistical information. Ethtool + version 1.6 or later is required for this functionality. + + The latest release of ethtool can be found from + http://sourceforge.net/projects/gkernel. + + NOTE: Ethtool 1.6 only supports a limited set of ethtool options. Support + for a more complete ethtool feature set can be enabled by upgrading + ethtool to ethtool-1.8.1. + + + Enabling Wake on LAN* (WoL) + --------------------------- + WoL is provided through the Ethtool* utility. Ethtool is included with + Red Hat* 8.0. For other Linux distributions, download and install Ethtool + from the following website: http://sourceforge.net/projects/gkernel. + + For instructions on enabling WoL with Ethtool, refer to the Ethtool man + page. + + WoL will be enabled on the system during the next shut down or reboot. + For this driver version, in order to enable WoL, the e100 driver must be + loaded when shutting down or rebooting the system. + + + NAPI + ---- + + NAPI (Rx polling mode) is supported in the e100 driver. NAPI is enabled + or disabled based on the configuration of the kernel. To override + the default, use the following compile-time flags. + + To enable NAPI, compile the driver module, passing in a configuration + option: + + make CFLAGS_EXTRA=-DE100_NAPI install + + To disable NAPI, compile the driver module, passing in a configuration + option: + + make CFLAGS_EXTRA=-DE100_NO_NAPI install + + See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI. + + +Known Issues +============ + +NOTE: For distribution-specific information, refer to the ldistrib.txt + file included in the driver tar. + + + Driver Compilation + ------------------ + + When trying to compile the driver by running make install, the following + error may occur: + + "Linux kernel source not configured - missing version.h" + + To solve this issue, create the version.h file by going to the Linux + source tree and entering: + + make include/linux/version.h. + + + Multiple Interfaces on Same Ethernet Broadcast Network + ------------------------------------------------------ + + Due to the default ARP behavior on Linux, it is not possible to have + one system on two IP networks in the same Ethernet broadcast domain + (non-partitioned switch) behave as expected. All Ethernet interfaces + will respond to IP traffic for any IP address assigned to the system. + This results in unbalanced receive traffic. + + If you have multiple interfaces in a server, either turn on ARP + filtering by + + (1) entering: echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter + (this only works if your kernel's version is higher than 2.4.5), or + + (2) installing the interfaces in separate broadcast domains (either + in different switches or in a switch partitioned to VLANs). + + +Support +======= + +For general information, go to the Intel support website at: + + http://support.intel.com + +If an issue is identified with the released source code on the supported +kernel with a supported adapter, email the specific information related +to the issue to linux.nics@intel.com. + +License +======= + +This software program is released under the terms of a license agreement +between you ('Licensee') and Intel. Do not use or load this software or any +associated materials (collectively, the 'Software') until you have carefully +read the full terms and conditions of the LICENSE located in this software +package. By loading or using the Software, you agree to the terms of this +Agreement. If you do not agree with the terms of this Agreement, do not +install or use the Software. + +Trademarks +========== + +Intel, Itanium, and Pentium are trademarks or registered trademarks of +Intel Corporation or its subsidiaries in the United States and other +countries. + +* Other names and brands may be claimed as the property of others. diff -urN linux-2.4.35/drivers/net/e100/e100.h linux-2.4.35-e100-3.5.17/drivers/net/e100/e100.h --- linux-2.4.35/drivers/net/e100/e100.h 2007-08-07 17:00:38 +0200 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100.h 1970-01-01 01:00:00 +0100 @@ -1,1001 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_INC_ -#define _E100_INC_ - -#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 -#include - -#define E100_CABLE_UNKNOWN 0 -#define E100_CABLE_OK 1 -#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ -#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ -#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ -#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ - -#define E100_REGS_LEN 2 -/* - * Configure parameters for buffers per controller. - * If the machine this is being used on is a faster machine (i.e. > 150MHz) - * and running on a 10MBS network then more queueing of data occurs. This - * may indicate the some of the numbers below should be adjusted. Here are - * some typical numbers: - * MAX_TCB 64 - * MAX_RFD 64 - * The default numbers give work well on most systems tests so no real - * adjustments really need to take place. Also, if the machine is connected - * to a 100MBS network the numbers described above can be lowered from the - * defaults as considerably less data will be queued. - */ - -#define TX_FRAME_CNT 8 /* consecutive transmit frames per interrupt */ -/* TX_FRAME_CNT must be less than MAX_TCB */ - -#define E100_DEFAULT_TCB 64 -#define E100_MIN_TCB 2*TX_FRAME_CNT + 3 /* make room for at least 2 interrupts */ -#define E100_MAX_TCB 1024 - -#define E100_DEFAULT_RFD 64 -#define E100_MIN_RFD 8 -#define E100_MAX_RFD 1024 - -#define E100_DEFAULT_XSUM true -#define E100_DEFAULT_BER ZLOCK_MAX_ERRORS -#define E100_DEFAULT_SPEED_DUPLEX 0 -#define E100_DEFAULT_FC 0 -#define E100_DEFAULT_IFS true -#define E100_DEFAULT_UCODE true - -#define TX_THRSHLD 8 - -/* IFS parameters */ -#define MIN_NUMBER_OF_TRANSMITS_100 1000 -#define MIN_NUMBER_OF_TRANSMITS_10 100 - -#define E100_MAX_NIC 16 - -#define E100_MAX_SCB_WAIT 100 /* Max udelays in wait_scb */ -#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ - -/* HWI feature related constant */ -#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ -#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ - -/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled. - * In some situations, such as the TCP windowing algorithm, it may be - * better to limit the growth of the bundle size than let it go as - * high as it can, because that could cause too much added latency. - * The default is six, because this is the number of packets in the - * default TCP window size. A value of 1 would make CPUSaver indicate - * an interrupt for every frame received. If you do not want to put - * a limit on the bundle size, set this value to xFFFF. - */ -#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX 6 -#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY 0x600 -#define E100_DEFAULT_BUNDLE_SMALL_FR false - -/* end of configurables */ - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/* timeout for command completion */ -#define E100_CMD_WAIT 100 /* iterations */ - -struct driver_stats { - struct net_device_stats net_stats; - - unsigned long tx_late_col; - unsigned long tx_ok_defrd; - unsigned long tx_one_retry; - unsigned long tx_mt_one_retry; - unsigned long rcv_cdt_frames; - unsigned long xmt_fc_pkts; - unsigned long rcv_fc_pkts; - unsigned long rcv_fc_unsupported; - unsigned long xmt_tco_pkts; - unsigned long rcv_tco_pkts; - unsigned long rx_intr_pkts; -}; - -/* TODO: kill me when we can do C99 */ -#define false (0) -#define true (1) - -/* Changed for 82558 and 82559 enhancements */ -/* defines for 82558/9 flow control CSR values */ -#define DFLT_FC_THLD 0x00 /* Rx FIFO threshold of 0.5KB free */ -#define DFLT_FC_CMD 0x00 /* FC Command in CSR */ - -/* ====================================================================== */ -/* equates */ -/* ====================================================================== */ - -/* - * These are general purpose defines - */ - -/* Bit Mask definitions */ -#define BIT_0 0x0001 -#define BIT_1 0x0002 -#define BIT_2 0x0004 -#define BIT_3 0x0008 -#define BIT_4 0x0010 -#define BIT_5 0x0020 -#define BIT_6 0x0040 -#define BIT_7 0x0080 -#define BIT_8 0x0100 -#define BIT_9 0x0200 -#define BIT_10 0x0400 -#define BIT_11 0x0800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_28 0x10000000 - -#define BIT_0_2 0x0007 -#define BIT_0_3 0x000F -#define BIT_0_4 0x001F -#define BIT_0_5 0x003F -#define BIT_0_6 0x007F -#define BIT_0_7 0x00FF -#define BIT_0_8 0x01FF -#define BIT_0_13 0x3FFF -#define BIT_0_15 0xFFFF -#define BIT_1_2 0x0006 -#define BIT_1_3 0x000E -#define BIT_2_5 0x003C -#define BIT_3_4 0x0018 -#define BIT_4_5 0x0030 -#define BIT_4_6 0x0070 -#define BIT_4_7 0x00F0 -#define BIT_5_7 0x00E0 -#define BIT_5_12 0x1FE0 -#define BIT_5_15 0xFFE0 -#define BIT_6_7 0x00c0 -#define BIT_7_11 0x0F80 -#define BIT_8_10 0x0700 -#define BIT_9_13 0x3E00 -#define BIT_12_15 0xF000 -#define BIT_8_15 0xFF00 - -#define BIT_16_20 0x001F0000 -#define BIT_21_25 0x03E00000 -#define BIT_26_27 0x0C000000 - -/* Transmit Threshold related constants */ -#define DEFAULT_TX_PER_UNDERRUN 20000 - -#define MAX_MULTICAST_ADDRS 64 -#define MAX_FILTER 16 - -#define FULL_DUPLEX 2 -#define HALF_DUPLEX 1 - -/* - * These defines are specific to the 82557 - */ - -/* E100 PORT functions -- lower 4 bits */ -#define PORT_SOFTWARE_RESET 0 -#define PORT_SELFTEST 1 -#define PORT_SELECTIVE_RESET 2 -#define PORT_DUMP 3 - -/* SCB Status Word bit definitions */ -/* Interrupt status/ack fields */ -/* ER and FCP interrupts for 82558 masks */ -#define SCB_STATUS_ACK_MASK BIT_8_15 /* Status Mask */ -#define SCB_STATUS_ACK_CX BIT_15 /* CU Completed Action Cmd */ -#define SCB_STATUS_ACK_FR BIT_14 /* RU Received A Frame */ -#define SCB_STATUS_ACK_CNA BIT_13 /* CU Became Inactive (IDLE) */ -#define SCB_STATUS_ACK_RNR BIT_12 /* RU Became Not Ready */ -#define SCB_STATUS_ACK_MDI BIT_11 /* MDI read or write done */ -#define SCB_STATUS_ACK_SWI BIT_10 /* S/W generated interrupt */ -#define SCB_STATUS_ACK_ER BIT_9 /* Early Receive */ -#define SCB_STATUS_ACK_FCP BIT_8 /* Flow Control Pause */ - -/*- CUS Fields */ -#define SCB_CUS_MASK (BIT_6 | BIT_7) /* CUS 2-bit Mask */ -#define SCB_CUS_IDLE 0 /* CU Idle */ -#define SCB_CUS_SUSPEND BIT_6 /* CU Suspended */ -#define SCB_CUS_ACTIVE BIT_7 /* CU Active */ - -/*- RUS Fields */ -#define SCB_RUS_IDLE 0 /* RU Idle */ -#define SCB_RUS_MASK BIT_2_5 /* RUS 3-bit Mask */ -#define SCB_RUS_SUSPEND BIT_2 /* RU Suspended */ -#define SCB_RUS_NO_RESOURCES BIT_3 /* RU Out Of Resources */ -#define SCB_RUS_READY BIT_4 /* RU Ready */ -#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) /* RU No More RBDs */ -#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) /* RU Ready, No RBDs */ - -/* SCB Command Word bit definitions */ -/*- CUC fields */ -/* Changing mask to 4 bits */ -#define SCB_CUC_MASK BIT_4_7 /* CUC 4-bit Mask */ -#define SCB_CUC_NOOP 0 -#define SCB_CUC_START BIT_4 /* CU Start */ -#define SCB_CUC_RESUME BIT_5 /* CU Resume */ -#define SCB_CUC_UNKNOWN BIT_7 /* CU unknown command */ -/* Changed for 82558 enhancements */ -#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */ -#define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */ -#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) /* CU Dump stat. counters */ -#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) /* Load the CU base */ -/* Below was defined as BIT_4_7 */ -#define SCB_CUC_DUMP_RST_STAT BIT_4_6 /* CU Dump & reset statistics cntrs */ - -/*- RUC fields */ -#define SCB_RUC_MASK BIT_0_2 /* RUC 3-bit Mask */ -#define SCB_RUC_START BIT_0 /* RU Start */ -#define SCB_RUC_RESUME BIT_1 /* RU Resume */ -#define SCB_RUC_ABORT BIT_2 /* RU Abort */ -#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) /* Load RFD Header Data Size */ -#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) /* Load the RU base */ -#define SCB_RUC_RBD_RESUME BIT_0_2 /* RBD resume */ - -/* Interrupt fields (assuming byte addressing) */ -#define SCB_INT_MASK BIT_0 /* Mask interrupts */ -#define SCB_SOFT_INT BIT_1 /* Generate a S/W interrupt */ -/* Specific Interrupt Mask Bits (upper byte of SCB Command word) */ -#define SCB_FCP_INT_MASK BIT_2 /* Flow Control Pause */ -#define SCB_ER_INT_MASK BIT_3 /* Early Receive */ -#define SCB_RNR_INT_MASK BIT_4 /* RU Not Ready */ -#define SCB_CNA_INT_MASK BIT_5 /* CU Not Active */ -#define SCB_FR_INT_MASK BIT_6 /* Frame Received */ -#define SCB_CX_INT_MASK BIT_7 /* CU eXecution w/ I-bit done */ -#define SCB_BACHELOR_INT_MASK BIT_2_7 /* 82558 interrupt mask bits */ - -#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7 - -/* EEPROM bit definitions */ -/*- EEPROM control register bits */ -#define EEPROM_FLAG_ASF 0x8000 -#define EEPROM_FLAG_GCL 0x4000 - -#define EN_TRNF 0x10 /* Enable turnoff */ -#define EEDO 0x08 /* EEPROM data out */ -#define EEDI 0x04 /* EEPROM data in (set for writing data) */ -#define EECS 0x02 /* EEPROM chip select (1=hi, 0=lo) */ -#define EESK 0x01 /* EEPROM shift clock (1=hi, 0=lo) */ - -/*- EEPROM opcodes */ -#define EEPROM_READ_OPCODE 06 -#define EEPROM_WRITE_OPCODE 05 -#define EEPROM_ERASE_OPCODE 07 -#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ -#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ - -/*- EEPROM data locations */ -#define EEPROM_NODE_ADDRESS_BYTE_0 0 -#define EEPROM_COMPATIBILITY_WORD 3 -#define EEPROM_PWA_NO 8 -#define EEPROM_ID_WORD 0x0A -#define EEPROM_CONFIG_ASF 0x0D -#define EEPROM_SMBUS_ADDR 0x90 - -#define EEPROM_SUM 0xbaba - -// Zero Locking Algorithm definitions: -#define ZLOCK_ZERO_MASK 0x00F0 -#define ZLOCK_MAX_READS 50 -#define ZLOCK_SET_ZERO 0x2010 -#define ZLOCK_MAX_SLEEP 300 * HZ -#define ZLOCK_MAX_ERRORS 300 - -/* E100 Action Commands */ -#define CB_IA_ADDRESS 1 -#define CB_CONFIGURE 2 -#define CB_MULTICAST 3 -#define CB_TRANSMIT 4 -#define CB_LOAD_MICROCODE 5 -#define CB_LOAD_FILTER 8 -#define CB_MAX_NONTX_CMD 9 -#define CB_IPCB_TRANSMIT 9 - -/* Pre-defined Filter Bits */ -#define CB_FILTER_EL 0x80000000 -#define CB_FILTER_FIX 0x40000000 -#define CB_FILTER_ARP 0x08000000 -#define CB_FILTER_IA_MATCH 0x02000000 - -/* Command Block (CB) Field Definitions */ -/*- CB Command Word */ -#define CB_EL_BIT BIT_15 /* CB EL Bit */ -#define CB_S_BIT BIT_14 /* CB Suspend Bit */ -#define CB_I_BIT BIT_13 /* CB Interrupt Bit */ -#define CB_TX_SF_BIT BIT_3 /* TX CB Flexible Mode */ -#define CB_CMD_MASK BIT_0_3 /* CB 4-bit CMD Mask */ -#define CB_CID_DEFAULT (0x1f << 8) /* CB 5-bit CID (max value) */ - -/*- CB Status Word */ -#define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ -#define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ -#define CB_STATUS_OK BIT_13 /* CB OK Bit */ -#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */ -#define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ - -/*misc command bits */ -#define CB_TX_EOF_BIT BIT_15 /* TX CB/TBD EOF Bit */ - -/* Config params */ -#define CB_CFIG_BYTE_COUNT 22 /* 22 config bytes */ -#define CB_CFIG_D102_BYTE_COUNT 10 - -/* Receive Frame Descriptor Fields */ - -/*- RFD Status Bits */ -#define RFD_RECEIVE_COLLISION BIT_0 /* Collision detected on Receive */ -#define RFD_IA_MATCH BIT_1 /* Indv Address Match Bit */ -#define RFD_RX_ERR BIT_4 /* RX_ERR pin on Phy was set */ -#define RFD_FRAME_TOO_SHORT BIT_7 /* Receive Frame Short */ -#define RFD_DMA_OVERRUN BIT_8 /* Receive DMA Overrun */ -#define RFD_NO_RESOURCES BIT_9 /* No Buffer Space */ -#define RFD_ALIGNMENT_ERROR BIT_10 /* Alignment Error */ -#define RFD_CRC_ERROR BIT_11 /* CRC Error */ -#define RFD_STATUS_OK BIT_13 /* RFD OK Bit */ -#define RFD_STATUS_COMPLETE BIT_15 /* RFD Complete Bit */ - -/*- RFD Command Bits*/ -#define RFD_EL_BIT BIT_15 /* RFD EL Bit */ -#define RFD_S_BIT BIT_14 /* RFD Suspend Bit */ -#define RFD_H_BIT BIT_4 /* Header RFD Bit */ -#define RFD_SF_BIT BIT_3 /* RFD Flexible Mode */ - -/*- RFD misc bits*/ -#define RFD_EOF_BIT BIT_15 /* RFD End-Of-Frame Bit */ -#define RFD_F_BIT BIT_14 /* RFD Buffer Fetch Bit */ -#define RFD_ACT_COUNT_MASK BIT_0_13 /* RFD Actual Count Mask */ - -/* Receive Buffer Descriptor Fields*/ -#define RBD_EOF_BIT BIT_15 /* RBD End-Of-Frame Bit */ -#define RBD_F_BIT BIT_14 /* RBD Buffer Fetch Bit */ -#define RBD_ACT_COUNT_MASK BIT_0_13 /* RBD Actual Count Mask */ - -#define SIZE_FIELD_MASK BIT_0_13 /* Size of the associated buffer */ -#define RBD_EL_BIT BIT_15 /* RBD EL Bit */ - -/* Self Test Results*/ -#define CB_SELFTEST_FAIL_BIT BIT_12 -#define CB_SELFTEST_DIAG_BIT BIT_5 -#define CB_SELFTEST_REGISTER_BIT BIT_3 -#define CB_SELFTEST_ROM_BIT BIT_2 - -#define CB_SELFTEST_ERROR_MASK ( \ - CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \ - CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT) - -/* adapter vendor & device ids */ -#define PCI_OHIO_BOARD 0x10f0 /* subdevice ID, Ohio dual port nic */ - -/* Values for PCI_REV_ID_REGISTER values */ -#define D101A4_REV_ID 4 /* 82558 A4 stepping */ -#define D101B0_REV_ID 5 /* 82558 B0 stepping */ -#define D101MA_REV_ID 8 /* 82559 A0 stepping */ -#define D101S_REV_ID 9 /* 82559S A-step */ -#define D102_REV_ID 12 -#define D102C_REV_ID 13 /* 82550 step C */ -#define D102E_REV_ID 15 -#define D102E_A1_REV_ID 16 - -/* ############Start of 82555 specific defines################## */ - -#define PHY_82555_LED_SWITCH_CONTROL 0x1b /* 82555 led switch control register */ - -/* 82555 led switch control reg. opcodes */ -#define PHY_82555_LED_NORMAL_CONTROL 0 // control back to the 8255X -#define PHY_82555_LED_DRIVER_CONTROL BIT_2 // the driver is in control -#define PHY_82555_LED_OFF BIT_2 // activity LED is off -#define PHY_82555_LED_ON_559 (BIT_0 | BIT_2) // activity LED is on for 559 and later -#define PHY_82555_LED_ON_PRE_559 (BIT_0 | BIT_1 | BIT_2) // activity LED is on for 558 and before - -// Describe the state of the phy led. -// needed for the function : 'e100_blink_timer' -enum led_state_e { - LED_OFF = 0, - LED_ON, -}; - -/* ############End of 82555 specific defines##################### */ - -#define RFD_PARSE_BIT BIT_3 -#define RFD_TCP_PACKET 0x00 -#define RFD_UDP_PACKET 0x01 -#define TCPUDP_CHECKSUM_BIT_VALID BIT_4 -#define TCPUDP_CHECKSUM_VALID BIT_5 -#define CHECKSUM_PROTOCOL_MASK 0x03 - -#define VLAN_SIZE 4 -#define CHKSUM_SIZE 2 -#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE) - -/* Bits for bdp->flags */ -#define DF_LINK_FC_CAP 0x00000001 /* Link is flow control capable */ -#define DF_CSUM_OFFLOAD 0x00000002 -#define DF_UCODE_LOADED 0x00000004 -#define USE_IPCB 0x00000008 /* set if using ipcb for transmits */ -#define IS_BACHELOR 0x00000010 /* set if 82558 or newer board */ -#define IS_ICH 0x00000020 -#define DF_SPEED_FORCED 0x00000040 /* set if speed is forced */ -#define LED_IS_ON 0x00000080 /* LED is turned ON by the driver */ -#define DF_LINK_FC_TX_ONLY 0x00000100 /* Received PAUSE frames are honored*/ - -typedef struct net_device_stats net_dev_stats_t; - -/* needed macros */ -/* These macros use the bdp pointer. If you use them it better be defined */ -#define PREV_TCB_USED(X) ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1) -#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1) -#define TCB_TO_USE(X) ((X).tail) -#define TCBS_AVAIL(X) (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head) - -#define RFD_POINTER(skb,bdp) ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size))) -#define SKB_RFD_STATUS(skb,bdp) ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status) - -/* ====================================================================== */ -/* 82557 */ -/* ====================================================================== */ - -/* Changed for 82558 enhancement */ -typedef struct _d101_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ -} __attribute__ ((__packed__)) d101_scb_ext; - -/* Changed for 82559 enhancement */ -typedef struct _d101m_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u16 scb_reserved; /* Reserved */ - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} __attribute__ ((__packed__)) d101m_scb_ext; - -/* Changed for 82550 enhancement */ -typedef struct _d102_scb_ext_t { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - u8 scb_early_rx_int; /* Early Rx DMA byte count */ - u8 scb_fc_thld; /* Flow Control threshold */ - u8 scb_fc_xon_xoff; /* Flow Control XON/XOFF values */ - u8 scb_pmdr; /* Power Mgmt. Driver Reg */ - u8 scb_gen_ctrl; /* General Control */ - u8 scb_gen_stat; /* General Status */ - u8 scb_gen_ctrl2; - u8 scb_reserved; /* Reserved */ - u32 scb_scheduling_reg; - u32 scb_reserved2; - u32 scb_function_event; /* Cardbus Function Event */ - u32 scb_function_event_mask; /* Cardbus Function Mask */ - u32 scb_function_present_state; /* Cardbus Function state */ - u32 scb_force_event; /* Cardbus Force Event */ -} __attribute__ ((__packed__)) d102_scb_ext; - -/* - * 82557 status control block. this will be memory mapped & will hang of the - * the bdp, which hangs of the bdp. This is the brain of it. - */ -typedef struct _scb_t { - u16 scb_status; /* SCB Status register */ - u8 scb_cmd_low; /* SCB Command register (low byte) */ - u8 scb_cmd_hi; /* SCB Command register (high byte) */ - u32 scb_gen_ptr; /* SCB General pointer */ - u32 scb_port; /* PORT register */ - u16 scb_flsh_cntrl; /* Flash Control register */ - u16 scb_eprm_cntrl; /* EEPROM control register */ - u32 scb_mdi_cntrl; /* MDI Control Register */ - /* Changed for 82558 enhancement */ - union { - u32 scb_rx_dma_cnt; /* Rx DMA byte count */ - d101_scb_ext d101_scb; /* 82558/9 specific fields */ - d101m_scb_ext d101m_scb; /* 82559 specific fields */ - d102_scb_ext d102_scb; - } scb_ext; -} __attribute__ ((__packed__)) scb_t; - -/* Self test - * This is used to dump results of the self test - */ -typedef struct _self_test_t { - u32 st_sign; /* Self Test Signature */ - u32 st_result; /* Self Test Results */ -} __attribute__ ((__packed__)) self_test_t; - -/* - * Statistical Counters - */ -/* 82557 counters */ -typedef struct _basic_cntr_t { - u32 xmt_gd_frames; /* Good frames transmitted */ - u32 xmt_max_coll; /* Fatal frames -- had max collisions */ - u32 xmt_late_coll; /* Fatal frames -- had a late coll. */ - u32 xmt_uruns; /* Xmit underruns (fatal or re-transmit) */ - u32 xmt_lost_crs; /* Frames transmitted without CRS */ - u32 xmt_deferred; /* Deferred transmits */ - u32 xmt_sngl_coll; /* Transmits that had 1 and only 1 coll. */ - u32 xmt_mlt_coll; /* Transmits that had multiple coll. */ - u32 xmt_ttl_coll; /* Transmits that had 1+ collisions. */ - u32 rcv_gd_frames; /* Good frames received */ - u32 rcv_crc_errs; /* Aligned frames that had a CRC error */ - u32 rcv_algn_errs; /* Receives that had alignment errors */ - u32 rcv_rsrc_err; /* Good frame dropped cuz no resources */ - u32 rcv_oruns; /* Overrun errors - bus was busy */ - u32 rcv_err_coll; /* Received frms. that encountered coll. */ - u32 rcv_shrt_frames; /* Received frames that were to short */ -} basic_cntr_t; - -/* 82558 extended statistic counters */ -typedef struct _ext_cntr_t { - u32 xmt_fc_frames; - u32 rcv_fc_frames; - u32 rcv_fc_unsupported; -} ext_cntr_t; - -/* 82559 TCO statistic counters */ -typedef struct _tco_cntr_t { - u16 xmt_tco_frames; - u16 rcv_tco_frames; -} tco_cntr_t; - -/* Structures to access thet physical dump area */ -/* Use one of these types, according to the statisitcal counters mode, - to cast the pointer to the physical dump area and access the cmd_complete - DWORD. */ - -/* 557-mode : only basic counters + cmd_complete */ -typedef struct _err_cntr_557_t { - basic_cntr_t basic_stats; - u32 cmd_complete; -} err_cntr_557_t; - -/* 558-mode : basic + extended counters + cmd_complete */ -typedef struct _err_cntr_558_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - u32 cmd_complete; -} err_cntr_558_t; - -/* 559-mode : basic + extended + TCO counters + cmd_complete */ -typedef struct _err_cntr_559_t { - basic_cntr_t basic_stats; - ext_cntr_t extended_stats; - tco_cntr_t tco_stats; - u32 cmd_complete; -} err_cntr_559_t; - -/* This typedef defines the struct needed to hold the largest number of counters */ -typedef err_cntr_559_t max_counters_t; - -/* Different statistical-counters mode the controller may be in */ -typedef enum _stat_mode_t { - E100_BASIC_STATS = 0, /* 82557 stats : 16 counters / 16 dw */ - E100_EXTENDED_STATS, /* 82558 stats : 19 counters / 19 dw */ - E100_TCO_STATS /* 82559 stats : 21 counters / 20 dw */ -} stat_mode_t; - -/* dump statistical counters complete codes */ -#define DUMP_STAT_COMPLETED 0xA005 -#define DUMP_RST_STAT_COMPLETED 0xA007 - -/* Command Block (CB) Generic Header Structure*/ -typedef struct _cb_header_t { - u16 cb_status; /* Command Block Status */ - u16 cb_cmd; /* Command Block Command */ - u32 cb_lnk_ptr; /* Link To Next CB */ -} __attribute__ ((__packed__)) cb_header_t; - -//* Individual Address Command Block (IA_CB)*/ -typedef struct _ia_cb_t { - cb_header_t ia_cb_hdr; - u8 ia_addr[ETH_ALEN]; -} __attribute__ ((__packed__)) ia_cb_t; - -/* Configure Command Block (CONFIG_CB)*/ -typedef struct _config_cb_t { - cb_header_t cfg_cbhdr; - u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; -} __attribute__ ((__packed__)) config_cb_t; - -/* MultiCast Command Block (MULTICAST_CB)*/ -typedef struct _multicast_cb_t { - cb_header_t mc_cbhdr; - u16 mc_count; /* Number of multicast addresses */ - u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)]; -} __attribute__ ((__packed__)) mltcst_cb_t; - -#define UCODE_MAX_DWORDS 134 -/* Load Microcode Command Block (LOAD_UCODE_CB)*/ -typedef struct _load_ucode_cb_t { - cb_header_t load_ucode_cbhdr; - u32 ucode_dword[UCODE_MAX_DWORDS]; -} __attribute__ ((__packed__)) load_ucode_cb_t; - -/* Load Programmable Filter Data*/ -typedef struct _filter_cb_t { - cb_header_t filter_cb_hdr; - u32 filter_data[MAX_FILTER]; -} __attribute__ ((__packed__)) filter_cb_t; - -/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block - */ -typedef struct _nxmit_cb_t { - union { - config_cb_t config; - ia_cb_t setup; - load_ucode_cb_t load_ucode; - mltcst_cb_t multicast; - filter_cb_t filter; - } ntcb; -} __attribute__ ((__packed__)) nxmit_cb_t; - -/*Block for queuing for postponed execution of the non-transmit commands*/ -typedef struct _nxmit_cb_entry_t { - struct list_head list_elem; - nxmit_cb_t *non_tx_cmd; - dma_addr_t dma_addr; - unsigned long expiration_time; -} nxmit_cb_entry_t; - -/* States for postponed non tx commands execution */ -typedef enum _non_tx_cmd_state_t { - E100_NON_TX_IDLE = 0, /* No queued NON-TX commands */ - E100_WAIT_TX_FINISH, /* Wait for completion of the TX activities */ - E100_WAIT_NON_TX_FINISH /* Wait for completion of the non TX command */ -} non_tx_cmd_state_t; - -/* some defines for the ipcb */ -#define IPCB_IP_CHECKSUM_ENABLE BIT_4 -#define IPCB_TCPUDP_CHECKSUM_ENABLE BIT_5 -#define IPCB_TCP_PACKET BIT_6 -#define IPCB_LARGESEND_ENABLE BIT_7 -#define IPCB_HARDWAREPARSING_ENABLE BIT_0 -#define IPCB_INSERTVLAN_ENABLE BIT_1 -#define IPCB_IP_ACTIVATION_DEFAULT IPCB_HARDWAREPARSING_ENABLE - -/* Transmit Buffer Descriptor (TBD)*/ -typedef struct _tbd_t { - u32 tbd_buf_addr; /* Physical Transmit Buffer Address */ - u16 tbd_buf_cnt; /* Actual Count Of Bytes */ - u16 padd; -} __attribute__ ((__packed__)) tbd_t; - -/* d102 specific fields */ -typedef struct _tcb_ipcb_t { - u16 schedule_low; - u8 ip_schedule; - u8 ip_activation_high; - u16 vlan; - u8 ip_header_offset; - u8 tcp_header_offset; - union { - u32 sec_rec_phys_addr; - u32 tbd_zero_address; - } tbd_sec_addr; - union { - u16 sec_rec_size; - u16 tbd_zero_size; - } tbd_sec_size; - u16 total_tcp_payload; -} __attribute__ ((__packed__)) tcb_ipcb_t; - -#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS) - -/* Transmit Command Block (TCB)*/ -struct _tcb_t { - cb_header_t tcb_hdr; - u32 tcb_tbd_ptr; /* TBD address */ - u16 tcb_cnt; /* Data Bytes In TCB past header */ - u8 tcb_thrshld; /* TX Threshold for FIFO Extender */ - u8 tcb_tbd_num; - - union { - tcb_ipcb_t ipcb; /* d102 ipcb fields */ - tbd_t tbd_array[E100_TBD_ARRAY_SIZE]; - } tcbu; - - /* From here onward we can dump anything we want as long as the - * size of the total structure is a multiple of a paragraph - * boundary ( i.e. -16 bit aligned ). - */ - tbd_t *tbd_ptr; - - u32 tcb_tbd_dflt_ptr; /* TBD address for non-segmented packet */ - u32 tcb_tbd_expand_ptr; /* TBD address for segmented packet */ - - struct sk_buff *tcb_skb; /* the associated socket buffer */ - dma_addr_t tcb_phys; /* phys addr of the TCB */ -} __attribute__ ((__packed__)); - -#define _TCB_T_ -typedef struct _tcb_t tcb_t; - -/* Receive Frame Descriptor (RFD) - will be using the simple model*/ -struct _rfd_t { - /* 8255x */ - cb_header_t rfd_header; - u32 rfd_rbd_ptr; /* Receive Buffer Descriptor Addr */ - u16 rfd_act_cnt; /* Number Of Bytes Received */ - u16 rfd_sz; /* Number Of Bytes In RFD */ - /* D102 aka Gamla */ - u16 vlanid; - u8 rcvparserstatus; - u8 reserved; - u16 securitystatus; - u8 checksumstatus; - u8 zerocopystatus; - u8 pad[8]; /* data should be 16 byte aligned */ - u8 data[RFD_DATA_SIZE]; - -} __attribute__ ((__packed__)); - -#define _RFD_T_ -typedef struct _rfd_t rfd_t; - -/* Receive Buffer Descriptor (RBD)*/ -typedef struct _rbd_t { - u16 rbd_act_cnt; /* Number Of Bytes Received */ - u16 rbd_filler; - u32 rbd_lnk_addr; /* Link To Next RBD */ - u32 rbd_rcb_addr; /* Receive Buffer Address */ - u16 rbd_sz; /* Receive Buffer Size */ - u16 rbd_filler1; -} __attribute__ ((__packed__)) rbd_t; - -/* - * This structure is used to maintain a FIFO access to a resource that is - * maintained as a circular queue. The resource to be maintained is pointed - * to by the "data" field in the structure below. In this driver the TCBs', - * TBDs' & RFDs' are maintained as a circular queue & are managed thru this - * structure. - */ -typedef struct _buf_pool_t { - unsigned int head; /* index to first used resource */ - unsigned int tail; /* index to last used resource */ - void *data; /* points to resource pool */ -} buf_pool_t; - -/*Rx skb holding structure*/ -struct rx_list_elem { - struct list_head list_elem; - dma_addr_t dma_addr; - struct sk_buff *skb; -}; - -enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT }; -enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING }; -enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP }; - -/* 64 bit aligned size */ -#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7) - -typedef struct _bd_dma_able_t { - char selftest[E100_SIZE_64A(self_test_t)]; - char stats_counters[E100_SIZE_64A(max_counters_t)]; -} bd_dma_able_t; - -/* bit masks for bool parameters */ -#define PRM_XSUMRX 0x00000001 -#define PRM_UCODE 0x00000002 -#define PRM_FC 0x00000004 -#define PRM_IFS 0x00000008 -#define PRM_BUNDLE_SMALL 0x00000010 - -struct cfg_params { - int e100_speed_duplex; - int RxDescriptors; - int TxDescriptors; - int IntDelay; - int BundleMax; - int ber; - u32 b_params; -}; -struct ethtool_lpbk_data{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - -}; - -struct e100_private { - struct vlan_group *vlgrp; - u32 flags; /* board management flags */ - u32 tx_per_underrun; /* number of good tx frames per underrun */ - unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ - u8 tx_thld; /* stores transmit threshold */ - u16 eeprom_size; - u32 pwa_no; /* PWA: xxxxxx-0xx */ - u8 perm_node_address[ETH_ALEN]; - struct list_head active_rx_list; /* list of rx buffers */ - struct list_head rx_struct_pool; /* pool of rx buffer struct headers */ - u16 rfd_size; /* size of the adapter's RFD struct */ - int skb_req; /* number of skbs neede by the adapter */ - u8 intr_mask; /* mask for interrupt status */ - - void *dma_able; /* dma allocated structs */ - dma_addr_t dma_able_phys; - self_test_t *selftest; /* pointer to self test area */ - dma_addr_t selftest_phys; /* phys addr of selftest */ - max_counters_t *stats_counters; /* pointer to stats table */ - dma_addr_t stat_cnt_phys; /* phys addr of stat counter area */ - - stat_mode_t stat_mode; /* statistics mode: extended, TCO, basic */ - scb_t *scb; /* memory mapped ptr to 82557 scb */ - - tcb_t *last_tcb; /* pointer to last tcb sent */ - buf_pool_t tcb_pool; /* adapter's TCB array */ - dma_addr_t tcb_phys; /* phys addr of start of TCBs */ - - u16 cur_line_speed; - u16 cur_dplx_mode; - - struct net_device *device; - struct pci_dev *pdev; - struct driver_stats drv_stats; - - u8 rev_id; /* adapter PCI revision ID */ - - unsigned int phy_addr; /* address of PHY component */ - unsigned int PhyId; /* ID of PHY component */ - unsigned int PhyState; /* state for the fix squelch algorithm */ - unsigned int PhyDelay; /* delay for the fix squelch algorithm */ - - /* Lock defintions for the driver */ - spinlock_t bd_lock; /* board lock */ - spinlock_t bd_non_tx_lock; /* Non transmit command lock */ - spinlock_t config_lock; /* config block lock */ - spinlock_t mdi_access_lock; /* mdi lock */ - - struct timer_list watchdog_timer; /* watchdog timer id */ - - /* non-tx commands parameters */ - struct timer_list nontx_timer_id; /* non-tx timer id */ - struct list_head non_tx_cmd_list; - non_tx_cmd_state_t non_tx_command_state; - nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD]; - - enum next_cu_cmd_e next_cu_cmd; - - /* Zero Locking Algorithm data members */ - enum zlock_state_e zlock_state; - u8 zlock_read_data[16]; /* number of times each value 0-15 was read */ - u16 zlock_read_cnt; /* counts number of reads */ - ulong zlock_sleep_cnt; /* keeps track of "sleep" time */ - - u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT]; - - /* IFS params */ - u8 ifs_state; - u8 ifs_value; - - struct cfg_params params; /* adapter's command line parameters */ - - u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */ - - /* WOL params for ethtool */ - u32 wolsupported; - u32 wolopts; - u16 ip_lbytes; - struct ethtool_lpbk_data loopback; - struct timer_list blink_timer; /* led blink timer id */ - -#ifdef CONFIG_PM - u32 pci_state[16]; -#endif -#ifdef E100_CU_DEBUG - u8 last_cmd; - u8 last_sub_cmd; -#endif -}; - -#define E100_AUTONEG 0 -#define E100_SPEED_10_HALF 1 -#define E100_SPEED_10_FULL 2 -#define E100_SPEED_100_HALF 3 -#define E100_SPEED_100_FULL 4 - -/********* function prototypes *************/ -extern int e100_open(struct net_device *); -extern int e100_close(struct net_device *); -extern void e100_isolate_driver(struct e100_private *bdp); -extern unsigned char e100_hw_init(struct e100_private *); -extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); -extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); -extern void e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd); -extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp); -extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *cmd); -extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout, - u32 *st_result); -extern unsigned char e100_get_link_state(struct e100_private *bdp); -extern unsigned char e100_wait_scb(struct e100_private *bdp); - -extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset); -extern unsigned char e100_configure_device(struct e100_private *bdp); -#ifdef E100_CU_DEBUG -extern unsigned char e100_cu_unknown_state(struct e100_private *bdp); -#endif - -#define ROM_TEST_FAIL 0x01 -#define REGISTER_TEST_FAIL 0x02 -#define SELF_TEST_FAIL 0x04 -#define TEST_TIMEOUT 0x08 - -enum test_offsets { - test_link, - test_eeprom, - test_self_test, - test_loopback_mac, - test_loopback_phy, - cable_diag, - max_test_res, /* must be last */ -}; - -#endif diff -urN linux-2.4.35/drivers/net/e100/e100_config.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_config.c --- linux-2.4.35/drivers/net/e100/e100_config.c 2004-02-18 14:36:31 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_config.c 1970-01-01 01:00:00 +0100 @@ -1,639 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_config.c * -* * -* Abstract: Functions for configuring the network adapter. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100_config.h" - -static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable); - -static const u8 def_config[] = { - CB_CFIG_BYTE_COUNT, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01, - 0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00, - 0x40, 0xf2, 0x80, 0x3f, 0x05 -}; - -/** - * e100_config_init_82557 - config the 82557 adapter - * @bdp: atapter's private data struct - * - * This routine will initialize the 82557 configure block. - * All other init functions will only set values that are - * different from the 82557 default. - */ -void -e100_config_init_82557(struct e100_private *bdp) -{ - /* initialize config block */ - memcpy(bdp->config, def_config, sizeof (def_config)); - bdp->config[0] = CB_CFIG_BYTE_COUNT; /* just in case */ - - e100_config_ifs(bdp); - - /* - * Enable extended statistical counters (82558 and up) and TCO counters - * (82559 and up) and set the statistical counters' mode in bdp - * - * stat. mode | TCO stat. bit (2) | Extended stat. bit (5) - * ------------------------------------------------------------------ - * Basic (557) | 0 | 1 - * ------------------------------------------------------------------ - * Extended (558) | 0 | 0 - * ------------------------------------------------------------------ - * TCO (559) | 1 | 1 - * ------------------------------------------------------------------ - * Reserved | 1 | 0 - * ------------------------------------------------------------------ - */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_BASIC_STATS; - - /* Setup for MII or 503 operation. The CRS+CDT bit should only be set */ - /* when operating in 503 mode. */ - if (bdp->phy_addr == 32) { - bdp->config[8] &= ~CB_CFIG_503_MII; - bdp->config[15] |= CB_CFIG_CRS_OR_CDT; - } else { - bdp->config[8] |= CB_CFIG_503_MII; - bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT; - } - - e100_config_fc(bdp); - e100_config_force_dplx(bdp); - e100_config_promisc(bdp, false); - e100_config_mulcast_enbl(bdp, false); -} - -static void -e100_config_init_82558(struct e100_private *bdp) -{ - /* MWI enable. This should be turned on only if the adapter is a 82558/9 - * and if the PCI command reg. has enabled the MWI bit. */ - bdp->config[3] |= CB_CFIG_MWI_EN; - - bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS; - - if (bdp->rev_id >= D101MA_REV_ID) { - /* this is 82559 and up - enable TCO counters */ - bdp->config[6] |= CB_CFIG_TCO_STAT; - bdp->config[6] |= CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_TCO_STATS; - - if ((bdp->rev_id < D102_REV_ID) && - (bdp->params.b_params & PRM_XSUMRX) && - (bdp->pdev->device != 0x1209)) { - - bdp->flags |= DF_CSUM_OFFLOAD; - bdp->config[9] |= 1; - } - } else { - /* this is 82558 */ - bdp->config[6] &= ~CB_CFIG_TCO_STAT; - bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS; - bdp->stat_mode = E100_EXTENDED_STATS; - } - - e100_config_long_rx(bdp, true); -} - -static void -e100_config_init_82550(struct e100_private *bdp) -{ - /* The D102 chip allows for 32 config bytes. This value is - * supposed to be in Byte 0. Just add the extra bytes to - * what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - - /* now we need to enable the extended RFD. When this is - * enabled, the immediated receive data buffer starts at offset - * 32 from the RFD base address, instead of at offset 16. */ - bdp->config[7] |= CB_CFIG_EXTENDED_RFD; - - /* put the chip into D102 receive mode. This is necessary - * for any parsing and offloading features. */ - bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE; - - /* set the flag if checksum offloading was enabled */ - if (bdp->params.b_params & PRM_XSUMRX) { - bdp->flags |= DF_CSUM_OFFLOAD; - } -} - -/* Initialize the adapter's configure block */ -void -e100_config_init(struct e100_private *bdp) -{ - e100_config_init_82557(bdp); - - if (bdp->flags & IS_BACHELOR) - e100_config_init_82558(bdp); - - if (bdp->rev_id >= D102_REV_ID) - e100_config_init_82550(bdp); -} - -/** - * e100_force_config - force a configure command - * @bdp: atapter's private data struct - * - * This routine will force a configure command to the adapter. - * The command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_force_config(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - bdp->config[0] = CB_CFIG_BYTE_COUNT; - if (bdp->rev_id >= D102_REV_ID) { - /* The D102 chip allows for 32 config bytes. This value is - supposed to be in Byte 0. Just add the extra bytes to - what was already setup in the block. */ - bdp->config[0] += CB_CFIG_D102_BYTE_COUNT; - } - - spin_unlock_bh(&(bdp->config_lock)); - - // although we call config outside the lock, there is no - // race condition because config byte count has maximum value - return e100_config(bdp); -} - -/** - * e100_config - issue a configure command - * @bdp: atapter's private data struct - * - * This routine will issue a configure command to the 82557. - * This command will be executed in polled mode as interrupts - * are _disabled_ at this time. - * - * Returns: - * true: if the configure command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_config(struct e100_private *bdp) -{ - cb_header_t *pntcb_hdr; - unsigned char res = true; - nxmit_cb_entry_t *cmd; - - if (bdp->config[0] == 0) { - goto exit; - } - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE); - - spin_lock_bh(&bdp->config_lock); - - if (bdp->config[0] < CB_CFIG_MIN_PARAMS) { - bdp->config[0] = CB_CFIG_MIN_PARAMS; - } - - /* Copy the device's config block to the device's memory */ - memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config, - bdp->config[0]); - /* reset number of bytes to config next time */ - bdp->config[0] = 0; - - spin_unlock_bh(&bdp->config_lock); - - res = e100_exec_non_cu_cmd(bdp, cmd); - -exit: - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - return res; -} - -/** - * e100_config_fc - config flow-control state - * @bdp: adapter's private data struct - * - * This routine will enable or disable flow control support in the adapter's - * config block. Flow control will be enable only if requested using the command - * line option, and if the link is flow-contorl capable (both us and the link - * partner). But, if link partner is capable of autoneg, but not capable of - * flow control, received PAUSE frames are still honored. - */ -void -e100_config_fc(struct e100_private *bdp) -{ - unsigned char enable = false; - /* 82557 doesn't support fc. Don't touch this option */ - if (!(bdp->flags & IS_BACHELOR)) - return; - - /* Enable fc if requested and if the link supports it */ - if ((bdp->params.b_params & PRM_FC) && (bdp->flags & - (DF_LINK_FC_CAP | DF_LINK_FC_TX_ONLY))) { - enable = true; - } - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->flags & DF_LINK_FC_TX_ONLY) { - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused by */ - /* incoming PAUSE frames */ - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~(CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART); - bdp->config[19] |= CB_CFIG_FC_REJECT; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } else { - bdp->config[16] = DFLT_FC_DELAY_LSB; - bdp->config[17] = DFLT_FC_DELAY_MSB; - bdp->config[19] |= CB_CFIG_FC_OPTS; - bdp->config[19] &= ~CB_CFIG_TX_FC_DIS; - } - } else { - bdp->config[16] = DFLT_NO_FC_DELAY_LSB; - bdp->config[17] = DFLT_NO_FC_DELAY_MSB; - bdp->config[19] &= ~CB_CFIG_FC_OPTS; - bdp->config[19] |= CB_CFIG_TX_FC_DIS; - } - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); - - return; -} - -/** - * e100_config_promisc - configure promiscuous mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable promiscuous mode - * in the adapter's config block. - */ -void -e100_config_promisc(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* if in promiscuous mode, save bad frames */ - if (enable) { - - if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) { - bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (bdp->config[7] & (u8) BIT_0) { - bdp->config[7] &= (u8) (~BIT_0); - E100_CONFIG(bdp, 7); - } - - if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) { - bdp->config[15] |= CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - - } else { /* not in promiscuous mode */ - - if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) { - bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES; - E100_CONFIG(bdp, 6); - } - - if (!(bdp->config[7] & (u8) BIT_0)) { - bdp->config[7] |= (u8) (BIT_0); - E100_CONFIG(bdp, 7); - } - - if (bdp->config[15] & CB_CFIG_PROMISCUOUS) { - bdp->config[15] &= ~CB_CFIG_PROMISCUOUS; - E100_CONFIG(bdp, 15); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_mulcast_enbl - configure allmulti mode - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of all multicast packets - * in the adapter's config block. - */ -void -e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* this flag is used to enable receiving all multicast packet */ - if (enable) { - if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) { - bdp->config[21] |= CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - - } else { - if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) { - bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL; - E100_CONFIG(bdp, 21); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_ifs - configure the IFS parameter - * @bdp: atapter's private data struct - * - * This routine will configure the adaptive IFS value - * in the adapter's config block. IFS values are only - * relevant in half duplex, so set to 0 in full duplex. - */ -void -e100_config_ifs(struct e100_private *bdp) -{ - u8 value = 0; - - spin_lock_bh(&(bdp->config_lock)); - - /* IFS value is only needed to be specified at half-duplex mode */ - if (bdp->cur_dplx_mode == HALF_DUPLEX) { - value = (u8) bdp->ifs_value; - } - - if (bdp->config[2] != value) { - bdp->config[2] = value; - E100_CONFIG(bdp, 2); - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_force_dplx - configure the forced full duplex mode - * @bdp: atapter's private data struct - * - * This routine will enable or disable force full duplex - * in the adapter's config block. If the PHY is 503, and - * the duplex is full, consider the adapter forced. - */ -void -e100_config_force_dplx(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - /* We must force full duplex on if we are using PHY 0, and we are */ - /* supposed to run in FDX mode. We do this because the e100 has only */ - /* one FDX# input pin, and that pin will be connected to PHY 1. */ - /* Changed the 'if' condition below to fix performance problem * at 10 - * full. The Phy was getting forced to full duplex while the MAC * was - * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. * - * This is how the condition was, initially. * This has been changed so - * that the MAC gets forced to full duplex * simply if the user has - * forced full duplex. * * if (( bdp->phy_addr == 0 ) && ( - * bdp->cur_dplx_mode == 2 )) */ - /* The rest of the fix is in the PhyDetect code. */ - if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) || - (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) || - ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) { - if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) { - bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX; - E100_CONFIG(bdp, 19); - } - - } else { - if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) { - bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX); - E100_CONFIG(bdp, 19); - } - } - - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_long_rx - * @bdp: atapter's private data struct - * @enable: should we enable this option or not - * - * This routine will enable or disable reception of larger packets. - * This is needed by VLAN implementations. - */ -static void -e100_config_long_rx(struct e100_private *bdp, unsigned char enable) -{ - if (enable) { - if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] |= CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - - } else { - if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) { - bdp->config[18] &= ~CB_CFIG_LONG_RX_OK; - E100_CONFIG(bdp, 18); - } - } -} - -/** - * e100_config_wol - * @bdp: atapter's private data struct - * - * This sets configuration options for PHY and Magic Packet WoL - */ -void -e100_config_wol(struct e100_private *bdp) -{ - spin_lock_bh(&(bdp->config_lock)); - - if (bdp->wolopts & WAKE_PHY) { - bdp->config[9] |= CB_LINK_STATUS_WOL; - } - else { - /* Disable PHY WoL */ - bdp->config[9] &= ~CB_LINK_STATUS_WOL; - } - - if (bdp->wolopts & WAKE_MAGIC) { - bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE; - } - else { - /* Disable Magic Packet WoL */ - bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE; - } - - E100_CONFIG(bdp, 19); - spin_unlock_bh(&(bdp->config_lock)); -} - -void -e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable) -{ - spin_lock_bh(&(bdp->config_lock)); - if (enable) { - if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - - } else { - if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { - bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE; - E100_CONFIG(bdp, 22); - } - } - spin_unlock_bh(&(bdp->config_lock)); -} - -/** - * e100_config_loopback_mode - * @bdp: atapter's private data struct - * @mode: loopback mode(phy/mac/none) - * - */ -unsigned char -e100_config_loopback_mode(struct e100_private *bdp, u8 mode) -{ - unsigned char bc_changed = false; - u8 config_byte; - - spin_lock_bh(&(bdp->config_lock)); - - switch (mode) { - case NO_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_NORMAL; - break; - case MAC_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_INTERNAL; - break; - case PHY_LOOPBACK: - config_byte = CB_CFIG_LOOPBACK_EXTERNAL; - break; - default: - printk(KERN_NOTICE "e100: e100_config_loopback_mode: " - "Invalid argument 'mode': %d\n", mode); - goto exit; - } - - if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) { - - bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE); - bdp->config[10] |= config_byte; - E100_CONFIG(bdp, 10); - bc_changed = true; - } - -exit: - spin_unlock_bh(&(bdp->config_lock)); - return bc_changed; -} -unsigned char -e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) { - - bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS); - E100_CONFIG(bdp, 6); - bc_changed = true; - } - - } else { - if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) { - - bdp->config[6] |= CB_CFIG_EXT_TCB_DIS; - E100_CONFIG(bdp, 6); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} -unsigned char -e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable) -{ - unsigned char bc_changed = false; - - spin_lock_bh(&(bdp->config_lock)); - - if (enable) { - if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) { - - bdp->config[7] |= CB_CFIG_DYNTBD_EN; - E100_CONFIG(bdp, 7); - bc_changed = true; - } - - } else { - if (bdp->config[7] & CB_CFIG_DYNTBD_EN) { - - bdp->config[7] &= (~CB_CFIG_DYNTBD_EN); - E100_CONFIG(bdp, 7); - bc_changed = true; - } - } - spin_unlock_bh(&(bdp->config_lock)); - - return bc_changed; -} - diff -urN linux-2.4.35/drivers/net/e100/e100_config.h linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_config.h --- linux-2.4.35/drivers/net/e100/e100_config.h 2007-08-07 17:00:38 +0200 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_config.h 1970-01-01 01:00:00 +0100 @@ -1,168 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_CONFIG_INC_ -#define _E100_CONFIG_INC_ - -#include "e100.h" - -#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1)) - -#define CB_CFIG_MIN_PARAMS 8 - -/* byte 0 bit definitions*/ -#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 /* Byte count occupies bit 5-0 */ - -/* byte 1 bit definitions*/ -#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 /* RxFifo limit mask */ -#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 /* TxFifo limit mask */ - -/* byte 2 bit definitions -- ADAPTIVE_IFS*/ - -/* word 3 bit definitions -- RESERVED*/ -/* Changed for 82558 enhancements */ -/* byte 3 bit definitions */ -#define CB_CFIG_MWI_EN BIT_0 /* Enable MWI on PCI bus */ -#define CB_CFIG_TYPE_EN BIT_1 /* Type Enable */ -#define CB_CFIG_READAL_EN BIT_2 /* Enable Read Align */ -#define CB_CFIG_TERMCL_EN BIT_3 /* Cache line write */ - -/* byte 4 bit definitions*/ -#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 /* Rx minimum DMA count mask */ - -/* byte 5 bit definitions*/ -#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 /* Tx minimum DMA count mask */ -#define CB_CFIG_DMBC_EN BIT_7 /* Enable Tx/Rx min. DMA counts */ - -/* Changed for 82558 enhancements */ -/* byte 6 bit definitions*/ -#define CB_CFIG_LATE_SCB BIT_0 /* Update SCB After New Tx Start */ -#define CB_CFIG_DIRECT_DMA_DIS BIT_1 /* Direct DMA mode */ -#define CB_CFIG_TNO_INT BIT_2 /* Tx Not OK Interrupt */ -#define CB_CFIG_TCO_STAT BIT_2 /* TCO statistics in 559 and above */ -#define CB_CFIG_CI_INT BIT_3 /* Command Complete Interrupt */ -#define CB_CFIG_EXT_TCB_DIS BIT_4 /* Extended TCB */ -#define CB_CFIG_EXT_STAT_DIS BIT_5 /* Extended Stats */ -#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 /* Save Bad Frames Enabled */ - -/* byte 7 bit definitions*/ -#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 /* Discard Short Frames */ -#define CB_CFIG_DYNTBD_EN BIT_7 /* Enable dynamic TBD */ -/* Enable extended RFD's on D102 */ -#define CB_CFIG_EXTENDED_RFD BIT_5 - -/* byte 8 bit definitions*/ -#define CB_CFIG_503_MII BIT_0 /* 503 vs. MII mode */ - -/* byte 9 bit definitions -- pre-defined all zeros*/ -#define CB_LINK_STATUS_WOL BIT_5 - -/* byte 10 bit definitions*/ -#define CB_CFIG_NO_SRCADR BIT_3 /* No Source Address Insertion */ -#define CB_CFIG_PREAMBLE_LEN BIT_4_5 /* Preamble Length */ -#define CB_CFIG_LOOPBACK_MODE BIT_6_7 /* Loopback Mode */ -#define CB_CFIG_LOOPBACK_NORMAL 0 -#define CB_CFIG_LOOPBACK_INTERNAL BIT_6 -#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7 - -/* byte 11 bit definitions*/ -#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 /* Linear Priority */ - -/* byte 12 bit definitions*/ -#define CB_CFIG_LINEAR_PRI_MODE BIT_0 /* Linear Priority mode */ -#define CB_CFIG_IFS_MASK BIT_4_7 /* Interframe Spacing mask */ - -/* byte 13 bit definitions -- pre-defined all zeros*/ - -/* byte 14 bit definitions -- pre-defined 0xf2*/ - -/* byte 15 bit definitions*/ -#define CB_CFIG_PROMISCUOUS BIT_0 /* Promiscuous Mode Enable */ -#define CB_CFIG_BROADCAST_DIS BIT_1 /* Broadcast Mode Disable */ -#define CB_CFIG_CRS_OR_CDT BIT_7 /* CRS Or CDT */ - -/* byte 16 bit definitions -- pre-defined all zeros*/ -#define DFLT_FC_DELAY_LSB 0x1f /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_LSB 0x00 /* no flow control default value */ - -/* byte 17 bit definitions -- pre-defined 0x40*/ -#define DFLT_FC_DELAY_MSB 0x01 /* Delay for outgoing Pause frames */ -#define DFLT_NO_FC_DELAY_MSB 0x40 /* no flow control default value */ - -/* byte 18 bit definitions*/ -#define CB_CFIG_STRIPPING BIT_0 /* Padding Disabled */ -#define CB_CFIG_PADDING BIT_1 /* Padding Disabled */ -#define CB_CFIG_CRC_IN_MEM BIT_2 /* Transfer CRC To Memory */ - -/* byte 19 bit definitions*/ -#define CB_CFIG_TX_ADDR_WAKE BIT_0 /* Address Wakeup */ -#define CB_DISABLE_MAGPAK_WAKE BIT_1 /* Magic Packet Wakeup disable */ -/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */ -#define CB_CFIG_TX_FC_DIS BIT_2 /* Tx Flow Control Disable */ -#define CB_CFIG_FC_RESTOP BIT_3 /* Rx Flow Control Restop */ -#define CB_CFIG_FC_RESTART BIT_4 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_REJECT BIT_5 /* Rx Flow Control Restart */ -#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT) - -/* end 82558/9 specifics */ - -#define CB_CFIG_FORCE_FDX BIT_6 /* Force Full Duplex */ -#define CB_CFIG_FDX_ENABLE BIT_7 /* Full Duplex Enabled */ - -/* byte 20 bit definitions*/ -#define CB_CFIG_MULTI_IA BIT_6 /* Multiple IA Addr */ - -/* byte 21 bit definitions*/ -#define CB_CFIG_MULTICAST_ALL BIT_3 /* Multicast All */ - -/* byte 22 bit defines */ -#define CB_CFIG_RECEIVE_GAMLA_MODE BIT_0 /* D102 receive mode */ -#define CB_CFIG_VLAN_DROP_ENABLE BIT_1 /* vlan stripping */ - -#define CB_CFIG_LONG_RX_OK BIT_3 - -#define NO_LOOPBACK 0 -#define MAC_LOOPBACK 0x01 -#define PHY_LOOPBACK 0x02 - -/* function prototypes */ -extern void e100_config_init(struct e100_private *bdp); -extern void e100_config_init_82557(struct e100_private *bdp); -extern unsigned char e100_force_config(struct e100_private *bdp); -extern unsigned char e100_config(struct e100_private *bdp); -extern void e100_config_fc(struct e100_private *bdp); -extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable); -extern void e100_config_brdcast_dsbl(struct e100_private *bdp); -extern void e100_config_mulcast_enbl(struct e100_private *bdp, - unsigned char enable); -extern void e100_config_ifs(struct e100_private *bdp); -extern void e100_config_force_dplx(struct e100_private *bdp); -extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); -extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); -extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); -extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable); -#endif /* _E100_CONFIG_INC_ */ diff -urN linux-2.4.35/drivers/net/e100/e100_eeprom.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_eeprom.c --- linux-2.4.35/drivers/net/e100/e100_eeprom.c 2004-02-18 14:36:31 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_eeprom.c 1970-01-01 01:00:00 +0100 @@ -1,565 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_eeprom.c * -* * -* Abstract: This module contains routines to read and write to a * -* serial EEPROM * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ -#include "e100.h" - -#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl) - -#define CSR_GENERAL_CONTROL2_FIELD(bdp) \ - ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2) - -#define EEPROM_STALL_TIME 4 -#define EEPROM_CHECKSUM ((u16) 0xBABA) -#define EEPROM_MAX_WORD_SIZE 256 - -void e100_eeprom_cleanup(struct e100_private *adapter); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); -static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg, - u16 data); -void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size); -u16 e100_eeprom_size(struct e100_private *adapter); -u16 e100_eeprom_read(struct e100_private *adapter, u16 reg); - -static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count); -static u16 shift_in_bits(struct e100_private *adapter); -static void raise_clock(struct e100_private *adapter, u16 *x); -static void lower_clock(struct e100_private *adapter, u16 *x); -static u16 eeprom_wait_cmd_done(struct e100_private *adapter); -static void eeprom_stand_by(struct e100_private *adapter); - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_set_semaphore -// -// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR). -// -// Arguments: -// Adapter - Adapter context -// -// Returns: true if success -// else return false -// -//---------------------------------------------------------------------------------------- - -inline u8 -eeprom_set_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - do { - // Get current value of General Control 2 - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Set bit 23 word 0x1C in the CSR. - data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE; - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); - - // Check to see if this bit set or not. - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - - if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) { - return true; - } - - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_reset_semaphore -// -// Description: This function reset (write 0) Gamla EEPROM semaphore bit -// (bit 23 word 0x1C in the CSR). -// -// Arguments: struct e100_private * adapter - Adapter context -//---------------------------------------------------------------------------------------- - -inline void -eeprom_reset_semaphore(struct e100_private *adapter) -{ - u16 data = 0; - - data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter)); - data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE); - writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_size -// -// Description: This routine determines the size of the EEPROM. This value should be -// checked for validity - ie. is it too big or too small. The size returned -// is then passed to the read/write functions. -// -// Returns: -// Size of the eeprom, or zero if an error occurred -//---------------------------------------------------------------------------------------- -u16 -e100_eeprom_size(struct e100_private *adapter) -{ - u16 x, size = 1; // must be one to accumulate a product - - // if we've already stored this data, read from memory - if (adapter->eeprom_size) { - return adapter->eeprom_size; - } - // otherwise, read from the eeprom - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // enable the eeprom by setting EECS. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - - // experiment to discover the size of the eeprom. request register zero - // and wait for the eeprom to tell us it has accepted the entire address. - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - do { - size *= 2; // each bit of address doubles eeprom size - x |= EEDO; // set bit to detect "dummy zero" - x &= ~EEDI; // address consists of all zeros - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - - // check for "dummy zero" - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (size > EEPROM_MAX_WORD_SIZE) { - size = 0; - break; - } - } while (x & EEDO); - - // read in the value requested - (void) shift_in_bits(adapter); - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return size; -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_address_size -// -// Description: determines the number of bits in an address for the eeprom acceptable -// values are 64, 128, and 256 -// Arguments: size of the eeprom -// Returns: bits in an address for that size eeprom -//---------------------------------------------------------------------------------------- - -static inline int -eeprom_address_size(u16 size) -{ - int isize = size; - - return (ffs(isize) - 1); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_read -// -// Description: This routine serially reads one word out of the EEPROM. -// -// Arguments: -// adapter - our adapter context -// reg - EEPROM word to read. -// -// Returns: -// Contents of EEPROM word (reg). -//---------------------------------------------------------------------------------------- - -u16 -e100_eeprom_read(struct e100_private *adapter, u16 reg) -{ - u16 x, data, bits; - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return 0; - } - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - bits = eeprom_address_size(adapter->eeprom_size); - - // select EEPROM, reset bits, set EECS - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EEDI | EEDO | EESK); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - // write the read opcode and register number in that order - // The opcode is 3bits in length, reg is 'bits' bits long - shift_out_bits(adapter, EEPROM_READ_OPCODE, 3); - shift_out_bits(adapter, reg, bits); - - // Now read the data (16 bits) in from the selected EEPROM word - data = shift_in_bits(adapter); - - e100_eeprom_cleanup(adapter); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } - - return data; -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_out_bits -// -// Description: This routine shifts data bits out to the EEPROM. -// -// Arguments: -// data - data to send to the EEPROM. -// count - number of data bits to shift out. -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -static void -shift_out_bits(struct e100_private *adapter, u16 data, u16 count) -{ - u16 x, mask; - - mask = 1 << (count - 1); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - - do { - x &= ~EEDI; - if (data & mask) - x |= EEDI; - - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - raise_clock(adapter, &x); - lower_clock(adapter, &x); - mask = mask >> 1; - } while (mask); - - x &= ~EEDI; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); -} - -//---------------------------------------------------------------------------------------- -// Procedure: raise_clock -// -// Description: This routine raises the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -raise_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x | EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: lower_clock -// -// Description: This routine lower's the EEPROM's clock input (EESK) -// -// Arguments: -// x - Ptr to the EEPROM control register's current value -// -// Returns: (none) -//---------------------------------------------------------------------------------------- - -void -lower_clock(struct e100_private *adapter, u16 *x) -{ - *x = *x & ~EESK; - writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} - -//---------------------------------------------------------------------------------------- -// Procedure: shift_in_bits -// -// Description: This routine shifts data bits in from the EEPROM. -// -// Arguments: -// -// Returns: -// The contents of that particular EEPROM word -//---------------------------------------------------------------------------------------- - -static u16 -shift_in_bits(struct e100_private *adapter) -{ - u16 x, d, i; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDO | EEDI); - d = 0; - - for (i = 0; i < 16; i++) { - d <<= 1; - raise_clock(adapter, &x); - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~EEDI; - if (x & EEDO) - d |= 1; - - lower_clock(adapter, &x); - } - - return d; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_cleanup -// -// Description: This routine returns the EEPROM to an idle state -//---------------------------------------------------------------------------------------- - -void -e100_eeprom_cleanup(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - - x &= ~(EECS | EEDI); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - raise_clock(adapter, &x); - lower_clock(adapter, &x); -} - -//********************************************************************************** -// Procedure: e100_eeprom_update_chksum -// -// Description: Calculates the checksum and writes it to the EEProm. -// It calculates the checksum accroding to the formula: -// Checksum = 0xBABA - (sum of first 63 words). -// -//----------------------------------------------------------------------------------- -u16 -e100_eeprom_calculate_chksum(struct e100_private *adapter) -{ - u16 idx, xsum_index, checksum = 0; - - // eeprom size is initialized to zero - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - xsum_index = adapter->eeprom_size - 1; - for (idx = 0; idx < xsum_index; idx++) - checksum += e100_eeprom_read(adapter, idx); - - checksum = EEPROM_CHECKSUM - checksum; - return checksum; -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_word -// -// Description: This routine writes a word to a specific EEPROM location without. -// taking EEPROM semaphore and updating checksum. -// Use e100_eeprom_write_block for the EEPROM update -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -static void -e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data) -{ - u16 x; - u16 bits; - - bits = eeprom_address_size(adapter->eeprom_size); - - /* select EEPROM, mask off ASIC and reset bits, set EECS */ - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EEDI | EEDO | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - - shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - /* write the new word to the EEPROM & send the write opcode the EEPORM */ - shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3); - - /* select which word in the EEPROM that we are writing to */ - shift_out_bits(adapter, reg, bits); - - /* write the data to the selected EEPROM word */ - shift_out_bits(adapter, data, 16); - if (!eeprom_wait_cmd_done(adapter)) - return; - - shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5); - shift_out_bits(adapter, reg, (u16) (bits - 2)); - if (!eeprom_wait_cmd_done(adapter)) - return; - - e100_eeprom_cleanup(adapter); -} - -//---------------------------------------------------------------------------------------- -// Procedure: e100_eeprom_write_block -// -// Description: This routine writes a block of words starting from specified EEPROM -// location and updates checksum -// Arguments: reg - The EEPROM word that we are going to write to. -// data - The data (word) that we are going to write to the EEPROM. -//---------------------------------------------------------------------------------------- -void -e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data, - u16 size) -{ - u16 checksum; - u16 i; - - if (!adapter->eeprom_size) - adapter->eeprom_size = e100_eeprom_size(adapter); - - // Set EEPROM semaphore. - if (adapter->rev_id >= D102_REV_ID) { - if (!eeprom_set_semaphore(adapter)) - return; - } - - for (i = 0; i < size; i++) { - e100_eeprom_write_word(adapter, start + i, data[i]); - } - //Update checksum - checksum = e100_eeprom_calculate_chksum(adapter); - e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum); - - // Clear EEPROM Semaphore. - if (adapter->rev_id >= D102_REV_ID) { - eeprom_reset_semaphore(adapter); - } -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_wait_cmd_done -// -// Description: This routine waits for the the EEPROM to finish its command. -// Specifically, it waits for EEDO (data out) to go high. -// Returns: true - If the command finished -// false - If the command never finished (EEDO stayed low) -//---------------------------------------------------------------------------------------- -static u16 -eeprom_wait_cmd_done(struct e100_private *adapter) -{ - u16 x; - unsigned long expiration_time = jiffies + HZ / 100 + 1; - - eeprom_stand_by(adapter); - - do { - rmb(); - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - if (x & EEDO) - return true; - if (time_before(jiffies, expiration_time)) - yield(); - else - return false; - } while (true); -} - -//---------------------------------------------------------------------------------------- -// Procedure: eeprom_stand_by -// -// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds. -//---------------------------------------------------------------------------------------- -static void -eeprom_stand_by(struct e100_private *adapter) -{ - u16 x; - - x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter)); - x &= ~(EECS | EESK); - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); - x |= EECS; - writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter)); - readw(&(adapter->scb->scb_status)); /* flush command to card */ - udelay(EEPROM_STALL_TIME); -} diff -urN linux-2.4.35/drivers/net/e100/e100_ethtool.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_ethtool.c --- linux-2.4.35/drivers/net/e100/e100_ethtool.c 1970-01-01 01:00:00 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_ethtool.c 2006-09-14 22:58:08 +0200 @@ -0,0 +1,849 @@ +/******************************************************************************* + + Intel PRO/100 Linux driver + Copyright(c) 1999 - 2006 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* + * net/core/ethtool.c - Ethtool ioctl handler + * Copyright (c) 2003 Matthew Wilcox + * + * This file is where we call all the ethtool_ops commands to get + * the information ethtool needs. We fall back to calling do_ioctl() + * for drivers which haven't been converted to ethtool_ops yet. + * + * It's GPL, stupid. + * + * Modification by sfeldma@pobox.com to work as backward compat + * solution for pre-ethtool_ops kernels. + * - copied struct ethtool_ops from ethtool.h + * - defined SET_ETHTOOL_OPS + * - put in some #ifndef NETIF_F_xxx wrappers + * - changes refs to dev->ethtool_ops to ethtool_ops + * - changed dev_ethtool to ethtool_ioctl + * - remove EXPORT_SYMBOL()s + * - added _kc_ prefix in built-in ethtool_op_xxx ops. + */ + +#include +#include +#include +#include +#include +#include + +#undef ethtool_ops +#define ethtool_ops _kc_ethtool_ops +struct _kc_ethtool_ops { + int (*get_settings)(struct net_device *, struct ethtool_cmd *); + int (*set_settings)(struct net_device *, struct ethtool_cmd *); + void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); + int (*get_regs_len)(struct net_device *); + void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); + void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); + int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); + u32 (*get_msglevel)(struct net_device *); + void (*set_msglevel)(struct net_device *, u32); + int (*nway_reset)(struct net_device *); + u32 (*get_link)(struct net_device *); + int (*get_eeprom_len)(struct net_device *); + int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); + int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *); + int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); + int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); + void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *); + int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *); + void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*); + int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*); + u32 (*get_rx_csum)(struct net_device *); + int (*set_rx_csum)(struct net_device *, u32); + u32 (*get_tx_csum)(struct net_device *); + int (*set_tx_csum)(struct net_device *, u32); + u32 (*get_sg)(struct net_device *); + int (*set_sg)(struct net_device *, u32); + u32 (*get_tso)(struct net_device *); + int (*set_tso)(struct net_device *, u32); + int (*self_test_count)(struct net_device *); + void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); + void (*get_strings)(struct net_device *, u32 stringset, u8 *); + int (*phys_id)(struct net_device *, u32); + int (*get_stats_count)(struct net_device *); + void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); +} *ethtool_ops = NULL; + +#undef SET_ETHTOOL_OPS +#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops)) + + +/* + * Some useful ethtool_ops methods that're device independent. + * If we find that all drivers want to do the same thing here, + * we can turn these into dev_() function calls. + */ + +#undef ethtool_op_get_link +#define ethtool_op_get_link _kc_ethtool_op_get_link +u32 _kc_ethtool_op_get_link(struct net_device *dev) +{ + return netif_carrier_ok(dev) ? 1 : 0; +} + +#undef ethtool_op_get_tx_csum +#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum +u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev) +{ +#ifdef NETIF_F_IP_CSUM + return (dev->features & NETIF_F_IP_CSUM) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_tx_csum +#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum +int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_IP_CSUM + if (data) + dev->features |= NETIF_F_IP_CSUM; + else + dev->features &= ~NETIF_F_IP_CSUM; +#endif + + return 0; +} + +#undef ethtool_op_get_sg +#define ethtool_op_get_sg _kc_ethtool_op_get_sg +u32 _kc_ethtool_op_get_sg(struct net_device *dev) +{ +#ifdef NETIF_F_SG + return (dev->features & NETIF_F_SG) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_sg +#define ethtool_op_set_sg _kc_ethtool_op_set_sg +int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_SG + if (data) + dev->features |= NETIF_F_SG; + else + dev->features &= ~NETIF_F_SG; +#endif + + return 0; +} + +#undef ethtool_op_get_tso +#define ethtool_op_get_tso _kc_ethtool_op_get_tso +u32 _kc_ethtool_op_get_tso(struct net_device *dev) +{ +#ifdef NETIF_F_TSO + return (dev->features & NETIF_F_TSO) != 0; +#else + return 0; +#endif +} + +#undef ethtool_op_set_tso +#define ethtool_op_set_tso _kc_ethtool_op_set_tso +int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data) +{ +#ifdef NETIF_F_TSO + if (data) + dev->features |= NETIF_F_TSO; + else + dev->features &= ~NETIF_F_TSO; +#endif + + return 0; +} + +/* Handlers for each ethtool command */ + +static int ethtool_get_settings(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd cmd = { ETHTOOL_GSET }; + int err; + + if (!ethtool_ops->get_settings) + return -EOPNOTSUPP; + + err = ethtool_ops->get_settings(dev, &cmd); + if (err < 0) + return err; + + if (copy_to_user(useraddr, &cmd, sizeof(cmd))) + return -EFAULT; + return 0; +} + +static int ethtool_set_settings(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd cmd; + + if (!ethtool_ops->set_settings) + return -EOPNOTSUPP; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + return ethtool_ops->set_settings(dev, &cmd); +} + +static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr) +{ + struct ethtool_drvinfo info; + struct ethtool_ops *ops = ethtool_ops; + + if (!ops->get_drvinfo) + return -EOPNOTSUPP; + + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ops->get_drvinfo(dev, &info); + + if (ops->self_test_count) + info.testinfo_len = ops->self_test_count(dev); + if (ops->get_stats_count) + info.n_stats = ops->get_stats_count(dev); + if (ops->get_regs_len) + info.regdump_len = ops->get_regs_len(dev); + if (ops->get_eeprom_len) + info.eedump_len = ops->get_eeprom_len(dev); + + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int ethtool_get_regs(struct net_device *dev, char *useraddr) +{ + struct ethtool_regs regs; + struct ethtool_ops *ops = ethtool_ops; + void *regbuf; + int reglen, ret; + + if (!ops->get_regs || !ops->get_regs_len) + return -EOPNOTSUPP; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + reglen = ops->get_regs_len(dev); + if (regs.len > reglen) + regs.len = reglen; + + regbuf = kmalloc(reglen, GFP_USER); + if (!regbuf) + return -ENOMEM; + + ops->get_regs(dev, ®s, regbuf); + + ret = -EFAULT; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + goto out; + useraddr += offsetof(struct ethtool_regs, data); + if (copy_to_user(useraddr, regbuf, reglen)) + goto out; + ret = 0; + + out: + kfree(regbuf); + return ret; +} + +static int ethtool_get_wol(struct net_device *dev, char *useraddr) +{ + struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; + + if (!ethtool_ops->get_wol) + return -EOPNOTSUPP; + + ethtool_ops->get_wol(dev, &wol); + + if (copy_to_user(useraddr, &wol, sizeof(wol))) + return -EFAULT; + return 0; +} + +static int ethtool_set_wol(struct net_device *dev, char *useraddr) +{ + struct ethtool_wolinfo wol; + + if (!ethtool_ops->set_wol) + return -EOPNOTSUPP; + + if (copy_from_user(&wol, useraddr, sizeof(wol))) + return -EFAULT; + + return ethtool_ops->set_wol(dev, &wol); +} + +static int ethtool_get_msglevel(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GMSGLVL }; + + if (!ethtool_ops->get_msglevel) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_msglevel(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_msglevel(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_msglevel) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + ethtool_ops->set_msglevel(dev, edata.data); + return 0; +} + +static int ethtool_nway_reset(struct net_device *dev) +{ + if (!ethtool_ops->nway_reset) + return -EOPNOTSUPP; + + return ethtool_ops->nway_reset(dev); +} + +static int ethtool_get_link(struct net_device *dev, void *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GLINK }; + + if (!ethtool_ops->get_link) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_link(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_get_eeprom(struct net_device *dev, void *useraddr) +{ + struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->get_eeprom || !ops->get_eeprom_len) + return -EOPNOTSUPP; + + if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + /* Check for wrap and zero */ + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) + return -EINVAL; + + data = kmalloc(eeprom.len, GFP_USER); + if (!data) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; + + ret = ops->get_eeprom(dev, &eeprom, data); + if (ret) + goto out; + + ret = -EFAULT; + if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) + goto out; + if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) + goto out; + ret = 0; + + out: + kfree(data); + return ret; +} + +static int ethtool_set_eeprom(struct net_device *dev, void *useraddr) +{ + struct ethtool_eeprom eeprom; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->set_eeprom || !ops->get_eeprom_len) + return -EOPNOTSUPP; + + if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + /* Check for wrap and zero */ + if (eeprom.offset + eeprom.len <= eeprom.offset) + return -EINVAL; + + /* Check for exceeding total eeprom len */ + if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) + return -EINVAL; + + data = kmalloc(eeprom.len, GFP_USER); + if (!data) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) + goto out; + + ret = ops->set_eeprom(dev, &eeprom, data); + if (ret) + goto out; + + if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) + ret = -EFAULT; + + out: + kfree(data); + return ret; +} + +static int ethtool_get_coalesce(struct net_device *dev, void *useraddr) +{ + struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; + + if (!ethtool_ops->get_coalesce) + return -EOPNOTSUPP; + + ethtool_ops->get_coalesce(dev, &coalesce); + + if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) + return -EFAULT; + return 0; +} + +static int ethtool_set_coalesce(struct net_device *dev, void *useraddr) +{ + struct ethtool_coalesce coalesce; + + if (!ethtool_ops->get_coalesce) + return -EOPNOTSUPP; + + if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) + return -EFAULT; + + return ethtool_ops->set_coalesce(dev, &coalesce); +} + +static int ethtool_get_ringparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; + + if (!ethtool_ops->get_ringparam) + return -EOPNOTSUPP; + + ethtool_ops->get_ringparam(dev, &ringparam); + + if (copy_to_user(useraddr, &ringparam, sizeof(ringparam))) + return -EFAULT; + return 0; +} + +static int ethtool_set_ringparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_ringparam ringparam; + + if (!ethtool_ops->get_ringparam) + return -EOPNOTSUPP; + + if (copy_from_user(&ringparam, useraddr, sizeof(ringparam))) + return -EFAULT; + + return ethtool_ops->set_ringparam(dev, &ringparam); +} + +static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; + + if (!ethtool_ops->get_pauseparam) + return -EOPNOTSUPP; + + ethtool_ops->get_pauseparam(dev, &pauseparam); + + if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam))) + return -EFAULT; + return 0; +} + +static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr) +{ + struct ethtool_pauseparam pauseparam; + + if (!ethtool_ops->get_pauseparam) + return -EOPNOTSUPP; + + if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam))) + return -EFAULT; + + return ethtool_ops->set_pauseparam(dev, &pauseparam); +} + +static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + if (!ethtool_ops->get_rx_csum) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_rx_csum(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_rx_csum) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + ethtool_ops->set_rx_csum(dev, edata.data); + return 0; +} + +static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + if (!ethtool_ops->get_tx_csum) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_tx_csum(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_tx_csum) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_tx_csum(dev, edata.data); +} + +static int ethtool_get_sg(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GSG }; + + if (!ethtool_ops->get_sg) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_sg(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_sg(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_sg) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_sg(dev, edata.data); +} + +static int ethtool_get_tso(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GTSO }; + + if (!ethtool_ops->get_tso) + return -EOPNOTSUPP; + + edata.data = ethtool_ops->get_tso(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_tso(struct net_device *dev, char *useraddr) +{ + struct ethtool_value edata; + + if (!ethtool_ops->set_tso) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + return ethtool_ops->set_tso(dev, edata.data); +} + +static int ethtool_self_test(struct net_device *dev, char *useraddr) +{ + struct ethtool_test test; + struct ethtool_ops *ops = ethtool_ops; + u64 *data; + int ret; + + if (!ops->self_test || !ops->self_test_count) + return -EOPNOTSUPP; + + if (copy_from_user(&test, useraddr, sizeof(test))) + return -EFAULT; + + test.len = ops->self_test_count(dev); + data = kmalloc(test.len * sizeof(u64), GFP_USER); + if (!data) + return -ENOMEM; + + ops->self_test(dev, &test, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &test, sizeof(test))) + goto out; + useraddr += sizeof(test); + if (copy_to_user(useraddr, data, test.len * sizeof(u64))) + goto out; + ret = 0; + + out: + kfree(data); + return ret; +} + +static int ethtool_get_strings(struct net_device *dev, void *useraddr) +{ + struct ethtool_gstrings gstrings; + struct ethtool_ops *ops = ethtool_ops; + u8 *data; + int ret; + + if (!ops->get_strings) + return -EOPNOTSUPP; + + if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) + return -EFAULT; + + switch (gstrings.string_set) { + case ETH_SS_TEST: + if (!ops->self_test_count) + return -EOPNOTSUPP; + gstrings.len = ops->self_test_count(dev); + break; + case ETH_SS_STATS: + if (!ops->get_stats_count) + return -EOPNOTSUPP; + gstrings.len = ops->get_stats_count(dev); + break; + default: + return -EINVAL; + } + + data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); + if (!data) + return -ENOMEM; + + ops->get_strings(dev, gstrings.string_set, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) + goto out; + useraddr += sizeof(gstrings); + if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) + goto out; + ret = 0; + + out: + kfree(data); + return ret; +} + +static int ethtool_phys_id(struct net_device *dev, void *useraddr) +{ + struct ethtool_value id; + + if (!ethtool_ops->phys_id) + return -EOPNOTSUPP; + + if (copy_from_user(&id, useraddr, sizeof(id))) + return -EFAULT; + + return ethtool_ops->phys_id(dev, id.data); +} + +static int ethtool_get_stats(struct net_device *dev, void *useraddr) +{ + struct ethtool_stats stats; + struct ethtool_ops *ops = ethtool_ops; + u64 *data; + int ret; + + if (!ops->get_ethtool_stats || !ops->get_stats_count) + return -EOPNOTSUPP; + + if (copy_from_user(&stats, useraddr, sizeof(stats))) + return -EFAULT; + + stats.n_stats = ops->get_stats_count(dev); + data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER); + if (!data) + return -ENOMEM; + + ops->get_ethtool_stats(dev, &stats, data); + + ret = -EFAULT; + if (copy_to_user(useraddr, &stats, sizeof(stats))) + goto out; + useraddr += sizeof(stats); + if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) + goto out; + ret = 0; + + out: + kfree(data); + return ret; +} + +/* The main entry point in this file. Called from net/core/dev.c */ + +#define ETHTOOL_OPS_COMPAT +int ethtool_ioctl(struct ifreq *ifr) +{ + struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + void *useraddr = (void *) ifr->ifr_data; + u32 ethcmd; + + /* + * XXX: This can be pushed down into the ethtool_* handlers that + * need it. Keep existing behaviour for the moment. + */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (!dev || !netif_device_present(dev)) + return -ENODEV; + + if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GSET: + return ethtool_get_settings(dev, useraddr); + case ETHTOOL_SSET: + return ethtool_set_settings(dev, useraddr); + case ETHTOOL_GDRVINFO: + return ethtool_get_drvinfo(dev, useraddr); + case ETHTOOL_GREGS: + return ethtool_get_regs(dev, useraddr); + case ETHTOOL_GWOL: + return ethtool_get_wol(dev, useraddr); + case ETHTOOL_SWOL: + return ethtool_set_wol(dev, useraddr); + case ETHTOOL_GMSGLVL: + return ethtool_get_msglevel(dev, useraddr); + case ETHTOOL_SMSGLVL: + return ethtool_set_msglevel(dev, useraddr); + case ETHTOOL_NWAY_RST: + return ethtool_nway_reset(dev); + case ETHTOOL_GLINK: + return ethtool_get_link(dev, useraddr); + case ETHTOOL_GEEPROM: + return ethtool_get_eeprom(dev, useraddr); + case ETHTOOL_SEEPROM: + return ethtool_set_eeprom(dev, useraddr); + case ETHTOOL_GCOALESCE: + return ethtool_get_coalesce(dev, useraddr); + case ETHTOOL_SCOALESCE: + return ethtool_set_coalesce(dev, useraddr); + case ETHTOOL_GRINGPARAM: + return ethtool_get_ringparam(dev, useraddr); + case ETHTOOL_SRINGPARAM: + return ethtool_set_ringparam(dev, useraddr); + case ETHTOOL_GPAUSEPARAM: + return ethtool_get_pauseparam(dev, useraddr); + case ETHTOOL_SPAUSEPARAM: + return ethtool_set_pauseparam(dev, useraddr); + case ETHTOOL_GRXCSUM: + return ethtool_get_rx_csum(dev, useraddr); + case ETHTOOL_SRXCSUM: + return ethtool_set_rx_csum(dev, useraddr); + case ETHTOOL_GTXCSUM: + return ethtool_get_tx_csum(dev, useraddr); + case ETHTOOL_STXCSUM: + return ethtool_set_tx_csum(dev, useraddr); + case ETHTOOL_GSG: + return ethtool_get_sg(dev, useraddr); + case ETHTOOL_SSG: + return ethtool_set_sg(dev, useraddr); + case ETHTOOL_GTSO: + return ethtool_get_tso(dev, useraddr); + case ETHTOOL_STSO: + return ethtool_set_tso(dev, useraddr); + case ETHTOOL_TEST: + return ethtool_self_test(dev, useraddr); + case ETHTOOL_GSTRINGS: + return ethtool_get_strings(dev, useraddr); + case ETHTOOL_PHYS_ID: + return ethtool_phys_id(dev, useraddr); + case ETHTOOL_GSTATS: + return ethtool_get_stats(dev, useraddr); + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} diff -urN linux-2.4.35/drivers/net/e100/e100_main.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_main.c --- linux-2.4.35/drivers/net/e100/e100_main.c 2007-01-05 23:49:43 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_main.c 2007-08-13 10:09:17 +0200 @@ -1,4402 +1,2956 @@ /******************************************************************************* - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + Intel PRO/100 Linux driver + Copyright(c) 1999 - 2006 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + Contact Information: Linux NICS + e1000-devel Mailing List Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *******************************************************************************/ -/********************************************************************** -* * -* INTEL CORPORATION * -* * -* This software is supplied under the terms of the license included * -* above. All use of this driver must be in accordance with the terms * -* of that license. * -* * -* Module Name: e100_main.c * -* * -* Abstract: Functions for the driver entry points like load, * -* unload, open and close. All board specific calls made * -* by the network interface section of the driver. * -* * -* Environment: This file is intended to be specific to the Linux * -* operating system. * -* * -**********************************************************************/ - -/* Change Log - * - * 2.3.40 2/13/04 - * o Updated microcode for D102 rev 15 and rev 16 to include fix - * for TCO issue. NFS packets would be misinterpreted as TCO packets - * and incorrectly routed to the BMC over SMBus. The microcode fix - * checks the fragmented IP bit in the NFS/UDP header to distinguish - * between NFS and TCO. - * o Bug fix: don't strip MAC header count from Rx byte count. - * Ben Greear (greear@candeltech.com). +/* + * e100.c: Intel(R) PRO/100 ethernet driver * - * 2.3.38 12/14/03 - * o Added netpoll support. - * o Added ICH6 device ID support - * o Moved to 2.6 APIs: pci_name() and free_netdev(). - * o Removed some __devinit from some functions that shouldn't be marked - * as such (Anton Blanchard [anton@samba.org]). - * - * 2.3.33 10/21/03 + * (Re)written 2003 by scott.feldman@intel.com. Based loosely on + * original e100 driver, but better described as a munging of + * e100, e1000, eepro100, tg3, 8139cp, and other drivers. + * + * References: + * Intel 8255x 10/100 Mbps Ethernet Controller Family, + * Open Source Software Developers Manual, + * http://sourceforge.net/projects/e1000 + * + * + * Theory of Operation + * + * I. General + * + * The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet + * controller family, which includes the 82557, 82558, 82559, 82550, + * 82551, and 82562 devices. 82558 and greater controllers + * integrate the Intel 82555 PHY. The controllers are used in + * server and client network interface cards, as well as in + * LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx + * configurations. 8255x supports a 32-bit linear addressing + * mode and operates at 33Mhz PCI clock rate. + * + * II. Driver Operation + * + * Memory-mapped mode is used exclusively to access the device's + * shared-memory structure, the Control/Status Registers (CSR). All + * setup, configuration, and control of the device, including queuing + * of Tx, Rx, and configuration commands is through the CSR. + * cmd_lock serializes accesses to the CSR command register. cb_lock + * protects the shared Command Block List (CBL). + * + * 8255x is highly MII-compliant and all access to the PHY go + * through the Management Data Interface (MDI). Consequently, the + * driver leverages the mii.c library shared with other MII-compliant + * devices. + * + * Big- and Little-Endian byte order as well as 32- and 64-bit + * archs are supported. Weak-ordered memory and non-cache-coherent + * archs are supported. + * + * III. Transmit + * + * A Tx skb is mapped and hangs off of a TCB. TCBs are linked + * together in a fixed-size ring (CBL) thus forming the flexible mode + * memory structure. A TCB marked with the suspend-bit indicates + * the end of the ring. The last TCB processed suspends the + * controller, and the controller can be restarted by issue a CU + * resume command to continue from the suspend point, or a CU start + * command to start at a given position in the ring. + * + * Non-Tx commands (config, multicast setup, etc) are linked + * into the CBL ring along with Tx commands. The common structure + * used for both Tx and non-Tx commands is the Command Block (CB). + * + * cb_to_use is the next CB to use for queuing a command; cb_to_clean + * is the next CB to check for completion; cb_to_send is the first + * CB to start on in case of a previous failure to resume. CB clean + * up happens in interrupt context in response to a CU interrupt. + * cbs_avail keeps track of number of free CB resources available. + * + * Hardware padding of short packets to minimum packet size is + * enabled. 82557 pads with 7Eh, while the later controllers pad + * with 00h. + * + * IV. Recieve + * + * The Receive Frame Area (RFA) comprises a ring of Receive Frame + * Descriptors (RFD) + data buffer, thus forming the simplified mode + * memory structure. Rx skbs are allocated to contain both the RFD + * and the data buffer, but the RFD is pulled off before the skb is + * indicated. The data buffer is aligned such that encapsulated + * protocol headers are u32-aligned. Since the RFD is part of the + * mapped shared memory, and completion status is contained within + * the RFD, the RFD must be dma_sync'ed to maintain a consistent + * view from software and hardware. + * + * Under typical operation, the receive unit (RU) is start once, + * and the controller happily fills RFDs as frames arrive. If + * replacement RFDs cannot be allocated, or the RU goes non-active, + * the RU must be restarted. Frame arrival generates an interrupt, + * and Rx indication and re-allocation happen in the same context, + * therefore no locking is required. A software-generated interrupt + * is generated from the watchdog to recover from a failed allocation + * senario where all Rx resources have been indicated and none re- + * placed. + * + * V. Miscellaneous + * + * VLAN offloading of tagging, stripping and filtering is not + * supported, but driver will accommodate the extra 4-byte VLAN tag + * for processing by upper layers. Tx/Rx Checksum offloading is not + * supported. Tx Scatter/Gather is not supported. Jumbo Frames is + * not supported (hardware limitation). + * + * MagicPacket(tm) WoL support is enabled/disabled via ethtool. + * + * Thanks to JC (jchapman@katalix.com) for helping with + * testing/troubleshooting the development driver. + * + * TODO: + * o several entry points race with dev->close + * o check for tx-no-resources/stop Q races with tx clean/wake Q + * + * FIXES: + * 2005/12/02 - Michael O'Donnell + * - Stratus87247: protect MDI control register manipulations */ - -#include -#include -#include -#include -#include "e100.h" -#include "e100_ucode.h" -#include "e100_config.h" -#include "e100_phy.h" -extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp); +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NETIF_F_HW_VLAN_TX +#include +#endif +#include +#include +#include +#include -static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", - /* device-specific stats */ - "tx_late_collision_errors", "tx_deferred", - "tx_single_collisions", "tx_multi_collisions", - "rx_collision_detected_errors", "tx_flow_control_pause", - "rx_flow_control_pause", "rx_flow_control_unsupported", - "tx_tco_packets", "rx_tco_packets", -}; -#define E100_NET_STATS_LEN 21 -#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN +#include "kcompat.h" -static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *); -static void e100_get_speed_duplex_caps(struct e100_private *); -static int e100_ethtool_get_settings(struct net_device *, struct ifreq *); -static int e100_ethtool_set_settings(struct net_device *, struct ifreq *); - -static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *); -static int e100_ethtool_eeprom(struct net_device *, struct ifreq *); - -#define E100_EEPROM_MAGIC 0x1234 -static int e100_ethtool_glink(struct net_device *, struct ifreq *); -static int e100_ethtool_gregs(struct net_device *, struct ifreq *); -static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *); -static int e100_ethtool_wol(struct net_device *, struct ifreq *); -#ifdef CONFIG_PM -static unsigned char e100_setup_filter(struct e100_private *bdp); -static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp); +#ifdef E100_USE_REBOOT_NOTIFIER +#include +#endif +#ifdef ETHTOOL_OPS_COMPAT +#include "e100_ethtool.c" #endif -static u16 e100_get_ip_lbytes(struct net_device *dev); -extern void e100_config_wol(struct e100_private *bdp); -extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); -static int e100_ethtool_test(struct net_device *, struct ifreq *); -static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char test_strings[][ETH_GSTRING_LEN] = { - "Link test (on/offline)", - "Eeprom test (on/offline)", - "Self test (offline)", - "Mac loopback (offline)", - "Phy loopback (offline)", - "Cable diagnostic (offline)" -}; - -static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); -static int e100_mii_ioctl(struct net_device *, struct ifreq *, int); +#define DRV_NAME "e100" +#ifndef CONFIG_E100_NAPI +#define DRV_EXT +#else +#define DRV_EXT "-NAPI" +#endif +#define DRV_VERSION "3.5.17"DRV_EXT +#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" +#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" +#define PFX DRV_NAME ": " -static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, - nxmit_cb_entry_t *); -static void e100_free_nontx_list(struct e100_private *); -static void e100_non_tx_background(unsigned long); -static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); -/* Global Data structures and variables */ -char e100_copyright[] __devinitdata = "Copyright (c) 2004 Intel Corporation"; -char e100_driver_version[]="2.3.43-k1"; -const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; -char e100_short_driver_name[] = "e100"; -static int e100nics = 0; -static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group - *grp); -static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid); -static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); +#define E100_WATCHDOG_PERIOD (2 * HZ) +#define E100_NAPI_WEIGHT 16 -#ifdef CONFIG_NET_POLL_CONTROLLER -/* for netdump / net console */ -static void e100_netpoll (struct net_device *dev); -#endif +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); -#ifdef CONFIG_PM -static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); -static int e100_suspend(struct pci_dev *pcid, u32 state); -static int e100_resume(struct pci_dev *pcid); -static unsigned char e100_asf_enabled(struct e100_private *bdp); -struct notifier_block e100_notifier_reboot = { - .notifier_call = e100_notify_reboot, - .next = NULL, - .priority = 0 +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +#define DPRINTK(nlevel, klevel, fmt, args...) \ + (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ + printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ + __FUNCTION__ , ## args)) + +#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\ + PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \ + PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich } +static struct pci_device_id e100_id_table[] = { + INTEL_8255X_ETHERNET_DEVICE(0x1029, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1030, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1031, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1032, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1033, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1034, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1038, 3), + INTEL_8255X_ETHERNET_DEVICE(0x1039, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103A, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103B, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103C, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103D, 4), + INTEL_8255X_ETHERNET_DEVICE(0x103E, 4), + INTEL_8255X_ETHERNET_DEVICE(0x1050, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1051, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1052, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1053, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1054, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1055, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1056, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1057, 5), + INTEL_8255X_ETHERNET_DEVICE(0x1059, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1064, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1065, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1066, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1067, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1068, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1069, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106A, 6), + INTEL_8255X_ETHERNET_DEVICE(0x106B, 6), + INTEL_8255X_ETHERNET_DEVICE(0x1091, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1092, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1093, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1094, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1095, 7), + INTEL_8255X_ETHERNET_DEVICE(0x1209, 0), + INTEL_8255X_ETHERNET_DEVICE(0x1229, 0), + INTEL_8255X_ETHERNET_DEVICE(0x2449, 2), + INTEL_8255X_ETHERNET_DEVICE(0x2459, 2), + INTEL_8255X_ETHERNET_DEVICE(0x245D, 2), + INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7), + { 0, } }; -#endif +MODULE_DEVICE_TABLE(pci, e100_id_table); -/*********************************************************************/ -/*! 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 E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 } - -/* All parameters are treated the same, as an integer array of values. - * This macro just reduces the need to repeat the same declaration code - * over and over (plus this helps to avoid typo bugs). - */ -#define E100_PARAM(X, S) \ - static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \ - MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \ - MODULE_PARM_DESC(X, S); - -/* ====================================================================== */ -static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); -static u8 e100_D102_check_checksum(rfd_t *); -static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_change_mtu(struct net_device *, int); -static int e100_xmit_frame(struct sk_buff *, struct net_device *); -static unsigned char e100_init(struct e100_private *); -static int e100_set_mac(struct net_device *, void *); -struct net_device_stats *e100_get_stats(struct net_device *); - -static irqreturn_t e100intr(int, void *, struct pt_regs *); -static void e100_print_brd_conf(struct e100_private *); -static void e100_set_multi(struct net_device *); - -static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); -static u8 e100_sw_init(struct e100_private *); -static void e100_tco_workaround(struct e100_private *); -static unsigned char e100_alloc_space(struct e100_private *); -static void e100_dealloc_space(struct e100_private *); -static int e100_alloc_tcb_pool(struct e100_private *); -static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *); -static void e100_free_tcb_pool(struct e100_private *); -static int e100_alloc_rfd_pool(struct e100_private *); -static void e100_free_rfd_pool(struct e100_private *); - -static void e100_rd_eaddr(struct e100_private *); -static void e100_rd_pwa_no(struct e100_private *); -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16); -extern u16 e100_eeprom_size(struct e100_private *); -u16 e100_eeprom_calculate_chksum(struct e100_private *adapter); - -static unsigned char e100_clr_cntrs(struct e100_private *); -static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); -static unsigned char e100_update_stats(struct e100_private *bdp); - -static void e100_start_ru(struct e100_private *); -static void e100_dump_stats_cntrs(struct e100_private *); - -static void e100_check_options(int board, struct e100_private *bdp); -static void e100_set_int_option(int *, int, int, int, int, char *); -static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, - char *); -unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); -void e100_exec_cmplx(struct e100_private *, u32, u8); +enum mac { + mac_82557_D100_A = 0, + mac_82557_D100_B = 1, + mac_82557_D100_C = 2, + mac_82558_D101_A4 = 4, + mac_82558_D101_B0 = 5, + mac_82559_D101M = 8, + mac_82559_D101S = 9, + mac_82550_D102 = 12, + mac_82550_D102_C = 13, + mac_82551_E = 14, + mac_82551_F = 15, + mac_82551_10 = 16, + mac_unknown = 0xFF, +}; -/** - * e100_get_rx_struct - retrieve cell to hold skb buff from the pool - * @bdp: atapter's private data struct - * - * Returns the new cell to hold sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_get_rx_struct(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct = NULL; +enum phy { + phy_100a = 0x000003E0, + phy_100c = 0x035002A8, + phy_82555_tx = 0x015002A8, + phy_nsc_tx = 0x5C002000, + phy_82562_et = 0x033002A8, + phy_82562_em = 0x032002A8, + phy_82562_ek = 0x031002A8, + phy_82562_eh = 0x017002A8, + phy_unknown = 0xFFFFFFFF, +}; - if (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - } +/* CSR (Control/Status Registers) */ +struct csr { + struct { + u8 status; + u8 stat_ack; + u8 cmd_lo; + u8 cmd_hi; + u32 gen_ptr; + } scb; + u32 port; + u16 flash_ctrl; + u8 eeprom_ctrl_lo; + u8 eeprom_ctrl_hi; + u32 mdi_ctrl; + u32 rx_dma_count; +}; - return rx_struct; -} +enum scb_status { + rus_ready = 0x10, + rus_mask = 0x3C, +}; -/** - * e100_alloc_skb - allocate an skb for the adapter - * @bdp: atapter's private data struct - * - * Allocates skb with enough room for rfd, and data, and reserve non-data space. - * Returns the new cell with sk_buff or %NULL. - */ -static inline struct rx_list_elem * -e100_alloc_skb(struct e100_private *bdp) -{ - struct sk_buff *new_skb; - u32 skb_size = sizeof (rfd_t); - struct rx_list_elem *rx_struct; - - new_skb = (struct sk_buff *) dev_alloc_skb(skb_size); - if (new_skb) { - /* The IP data should be - DWORD aligned. since the ethernet header is 14 bytes long, - we need to reserve 2 extra bytes so that the TCP/IP headers - will be DWORD aligned. */ - skb_reserve(new_skb, 2); - if ((rx_struct = e100_get_rx_struct(bdp)) == NULL) - goto err; - rx_struct->skb = new_skb; - rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data, - sizeof (rfd_t), - PCI_DMA_FROMDEVICE); - if (!rx_struct->dma_addr) - goto err; - skb_reserve(new_skb, bdp->rfd_size); - return rx_struct; - } else { - return NULL; - } +enum ru_state { + RU_SUSPENDED = 0, + RU_RUNNING = 1, + RU_UNINITIALIZED = -1, +}; -err: - dev_kfree_skb_irq(new_skb); - return NULL; -} +enum scb_stat_ack { + stat_ack_not_ours = 0x00, + stat_ack_sw_gen = 0x04, + stat_ack_rnr = 0x10, + stat_ack_cu_idle = 0x20, + stat_ack_frame_rx = 0x40, + stat_ack_cu_cmd_done = 0x80, + stat_ack_not_present = 0xFF, + stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), + stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done), +}; -/** - * e100_add_skb_to_end - add an skb to the end of our rfd list - * @bdp: atapter's private data struct - * @rx_struct: rx_list_elem with the new skb - * - * Adds a newly allocated skb to the end of our rfd list. - */ -inline void -e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct) -{ - rfd_t *rfdn; /* The new rfd */ - rfd_t *rfd; /* The old rfd */ - struct rx_list_elem *rx_struct_last; +enum scb_cmd_hi { + irq_mask_none = 0x00, + irq_mask_all = 0x01, + irq_sw_gen = 0x02, +}; - (rx_struct->skb)->dev = bdp->device; - rfdn = RFD_POINTER(rx_struct->skb, bdp); - rfdn->rfd_header.cb_status = 0; - rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT); - rfdn->rfd_act_cnt = 0; - rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE); +enum scb_cmd_lo { + cuc_nop = 0x00, + ruc_start = 0x01, + ruc_load_base = 0x06, + cuc_start = 0x10, + cuc_resume = 0x20, + cuc_dump_addr = 0x40, + cuc_dump_stats = 0x50, + cuc_load_base = 0x60, + cuc_dump_reset = 0x70, +}; - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size, - PCI_DMA_TODEVICE); +enum cuc_dump { + cuc_dump_complete = 0x0000A005, + cuc_dump_reset_complete = 0x0000A007, +}; - if (!list_empty(&(bdp->active_rx_list))) { - rx_struct_last = list_entry(bdp->active_rx_list.prev, - struct rx_list_elem, list_elem); - rfd = RFD_POINTER(rx_struct_last->skb, bdp); - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_FROMDEVICE); - put_unaligned(cpu_to_le32(rx_struct->dma_addr), - ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr)))); +enum port { + software_reset = 0x0000, + selftest = 0x0001, + selective_reset = 0x0002, +}; - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 8, PCI_DMA_TODEVICE); - rfd->rfd_header.cb_cmd &= - __constant_cpu_to_le16((u16) ~RFD_EL_BIT); +enum eeprom_ctrl_lo { + eesk = 0x01, + eecs = 0x02, + eedi = 0x04, + eedo = 0x08, +}; - pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr, - 4, PCI_DMA_TODEVICE); - } +enum mdi_ctrl { + mdi_write = 0x04000000, + mdi_read = 0x08000000, + mdi_ready = 0x10000000, +}; - list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list)); -} +enum eeprom_op { + op_write = 0x05, + op_read = 0x06, + op_ewds = 0x10, + op_ewen = 0x13, +}; -static inline void -e100_alloc_skbs(struct e100_private *bdp) -{ - for (; bdp->skb_req > 0; bdp->skb_req--) { - struct rx_list_elem *rx_struct; +enum eeprom_offsets { + eeprom_cnfg_mdix = 0x03, + eeprom_id = 0x0A, + eeprom_config_asf = 0x0D, + eeprom_smbus_addr = 0x90, +}; - if ((rx_struct = e100_alloc_skb(bdp)) == NULL) - return; +enum eeprom_cnfg_mdix { + eeprom_mdix_enabled = 0x0080, +}; - e100_add_skb_to_end(bdp, rx_struct); - } -} +enum eeprom_id { + eeprom_id_wol = 0x0020, +}; -void e100_tx_srv(struct e100_private *); -u32 e100_rx_srv(struct e100_private *); +enum eeprom_config_asf { + eeprom_asf = 0x8000, + eeprom_gcl = 0x4000, +}; -void e100_watchdog(struct net_device *); -void e100_refresh_txthld(struct e100_private *); -void e100_manage_adaptive_ifs(struct e100_private *); -void e100_clear_pools(struct e100_private *); -static void e100_clear_structs(struct net_device *); -static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *, - struct sk_buff *); -static void e100_set_multi_exec(struct net_device *dev); +enum cb_status { + cb_complete = 0x8000, + cb_ok = 0x2000, +}; -MODULE_AUTHOR("Intel Corporation, "); -MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver"); -MODULE_LICENSE("GPL"); +enum cb_command { + cb_nop = 0x0000, + cb_iaaddr = 0x0001, + cb_config = 0x0002, + cb_multi = 0x0003, + cb_tx = 0x0004, + cb_ucode = 0x0005, + cb_dump = 0x0006, + cb_tx_sf = 0x0008, + cb_cid = 0x1f00, + cb_i = 0x2000, + cb_s = 0x4000, + cb_el = 0x8000, +}; -E100_PARAM(TxDescriptors, "Number of transmit descriptors"); -E100_PARAM(RxDescriptors, "Number of receive descriptors"); -E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); -E100_PARAM(e100_speed_duplex, "Speed and Duplex settings"); -E100_PARAM(ucode, "Disable or enable microcode loading"); -E100_PARAM(ber, "Value for the BER correction algorithm"); -E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing"); -E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay"); -E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames"); -E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling"); -E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm"); +struct rfd { + u16 status; + u16 command; + u32 link; + u32 rbd; + u16 actual_size; + u16 size; +}; -/** - * e100_exec_cmd - issue a comand - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100. - */ -static inline void -e100_exec_cmd(struct e100_private *bdp, u8 cmd_low) -{ - writeb(cmd_low, &(bdp->scb->scb_cmd_low)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} +struct rx { + struct rx *next, *prev; + struct sk_buff *skb; + dma_addr_t dma_addr; +}; -/** - * e100_wait_scb - wait for SCB to clear - * @bdp: atapter's private data struct - * - * This routine checks to see if the e100 has accepted a command. - * It does so by checking the command field in the SCB, which will - * be zeroed by the e100 upon accepting a command. The loop waits - * for up to 1 millisecond for command acceptance. - * - * Returns: - * true if the SCB cleared within 1 millisecond. - * false if it didn't clear within 1 millisecond - */ -unsigned char -e100_wait_scb(struct e100_private *bdp) -{ - int i; +#if defined(__BIG_ENDIAN_BITFIELD) +#define X(a,b) b,a +#else +#define X(a,b) a,b +#endif +struct config { +/*0*/ u8 X(byte_count:6, pad0:2); +/*1*/ u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1); +/*2*/ u8 adaptive_ifs; +/*3*/ u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1), + term_write_cache_line:1), pad3:4); +/*4*/ u8 X(rx_dma_max_count:7, pad4:1); +/*5*/ u8 X(tx_dma_max_count:7, dma_max_count_enable:1); +/*6*/ u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1), + tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1), + rx_discard_overruns:1), rx_save_bad_frames:1); +/*7*/ u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2), + pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1), + tx_dynamic_tbd:1); +/*8*/ u8 X(X(mii_mode:1, pad8:6), csma_disabled:1); +/*9*/ u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1), + link_status_wake:1), arp_wake:1), mcmatch_wake:1); +/*10*/ u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2), + loopback:2); +/*11*/ u8 X(linear_priority:3, pad11:5); +/*12*/ u8 X(X(linear_priority_mode:1, pad12:3), ifs:4); +/*13*/ u8 ip_addr_lo; +/*14*/ u8 ip_addr_hi; +/*15*/ u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1), + wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1), + pad15_2:1), crs_or_cdt:1); +/*16*/ u8 fc_delay_lo; +/*17*/ u8 fc_delay_hi; +/*18*/ u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1), + rx_long_ok:1), fc_priority_threshold:3), pad18:1); +/*19*/ u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1), + fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1), + full_duplex_force:1), full_duplex_pin:1); +/*20*/ u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1); +/*21*/ u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4); +/*22*/ u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6); + u8 pad_d102[9]; +}; - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - } +#define E100_MAX_MULTICAST_ADDRS 64 +struct multi { + u16 count; + u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/]; +}; - /* it didn't work. do it the slow way using udelay()s */ - for (i = 0; i < E100_MAX_SCB_WAIT; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - return true; - cpu_relax(); - udelay(1); - } +/* Important: keep total struct u32-aligned */ +#define UCODE_SIZE 134 +struct cb { + u16 status; + u16 command; + u32 link; + union { + u8 iaaddr[ETH_ALEN]; + u32 ucode[UCODE_SIZE]; + struct config config; + struct multi multi; + struct { + u32 tbd_array; + u16 tcb_byte_count; + u8 threshold; + u8 tbd_count; + struct { + u32 buf_addr; + u16 size; + u16 eol; + } tbd; + } tcb; + u32 dump_buffer_addr; + } u; + struct cb *next, *prev; + dma_addr_t dma_addr; + struct sk_buff *skb; +}; - return false; -} +enum loopback { + lb_none = 0, lb_mac = 1, lb_phy = 3, +}; -/** - * e100_wait_exec_simple - issue a command - * @bdp: atapter's private data struct - * @scb_cmd_low: the command that is to be issued - * - * This general routine will issue a command to the e100 after waiting for - * the previous command to finish. - * - * Returns: - * true if the command was issued to the chip successfully - * false if the command was not issued to the chip - */ -inline unsigned char -e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low) -{ - if (!e100_wait_scb(bdp)) { - printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n", - bdp->device->name); -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current simple command (%x) " - "can't be executed\n", - bdp->device->name, scb_cmd_low); -#endif - return false; - } - e100_exec_cmd(bdp, scb_cmd_low); -#ifdef E100_CU_DEBUG - bdp->last_cmd = scb_cmd_low; - bdp->last_sub_cmd = 0; -#endif - return true; -} - -void -e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) -{ - writel(phys_addr, &(bdp->scb->scb_gen_ptr)); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - e100_exec_cmd(bdp, cmd); -} - -unsigned char -e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd) -{ - if (!e100_wait_scb(bdp)) { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: Last command (%x/%x) " - "timeout\n", bdp->device->name, - bdp->last_cmd, bdp->last_sub_cmd); - printk(KERN_ERR "e100: %s: Current complex command " - "(%x/%x) can't be executed\n", - bdp->device->name, cmd, sub_cmd); -#endif - return false; - } - e100_exec_cmplx(bdp, phys_addr, cmd); -#ifdef E100_CU_DEBUG - bdp->last_cmd = cmd; - bdp->last_sub_cmd = sub_cmd; -#endif - return true; -} +struct stats { + u32 tx_good_frames, tx_max_collisions, tx_late_collisions, + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; + u32 rx_good_frames, rx_crc_errors, rx_alignment_errors, + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; + u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + u16 xmt_tco_frames, rcv_tco_frames; + u32 complete; +}; -inline u8 -e100_wait_cus_idle(struct e100_private *bdp) -{ - int i; +struct mem { + struct { + u32 signature; + u32 result; + } selftest; + struct stats stats; + u8 dump_buf[596]; +}; - /* loop on the scb for a few times */ - for (i = 0; i < 100; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - } +struct param_range { + u32 min; + u32 max; + u32 count; +}; - for (i = 0; i < E100_MAX_CU_IDLE_WAIT; i++) { - if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) != - SCB_CUS_ACTIVE)) { - return true; - } - cpu_relax(); - udelay(1); - } +struct params { + struct param_range rfds; + struct param_range cbs; +}; - return false; -} +struct nic { + /* Begin: frequently used values: keep adjacent for cache effect */ + u32 msg_enable ____cacheline_aligned; + struct net_device *netdev; + struct pci_dev *pdev; + + struct rx *rxs ____cacheline_aligned; + struct rx *rx_to_use; + struct rx *rx_to_clean; + struct rfd blank_rfd; + enum ru_state ru_running; + + spinlock_t cb_lock ____cacheline_aligned; + spinlock_t cmd_lock; + struct csr __iomem *csr; + enum scb_cmd_lo cuc_cmd; + unsigned int cbs_avail; + struct cb *cbs; + struct cb *cb_to_use; + struct cb *cb_to_send; + struct cb *cb_to_clean; + u16 tx_command; + /* End: frequently used values: keep adjacent for cache effect */ + + enum { + ich = (1 << 0), + promiscuous = (1 << 1), + multicast_all = (1 << 2), + wol_magic = (1 << 3), + ich_10h_workaround = (1 << 4), + } flags ____cacheline_aligned; + + enum mac mac; + enum phy phy; + struct params params; + struct net_device_stats net_stats; + struct timer_list watchdog; + struct timer_list blink_timer; + struct mii_if_info mii; + struct work_struct tx_timeout_task; + enum loopback loopback; + + struct mem *mem; + dma_addr_t dma_addr; + + dma_addr_t cbs_dma_addr; + u8 adaptive_ifs; + u8 tx_threshold; + u32 tx_frames; + u32 tx_collisions; + u32 tx_deferred; + u32 tx_single_collisions; + u32 tx_multiple_collisions; + u32 tx_fc_pause; + u32 tx_tco_frames; + + u32 rx_fc_pause; + u32 rx_fc_unsupported; + u32 rx_tco_frames; + u32 rx_over_length_errors; + + u8 rev_id; + u16 leds; + u16 eeprom_wc; + u16 eeprom[256]; + spinlock_t mdio_lock; + u32 pm_state[16]; +}; -/** - * e100_disable_clear_intr - disable and clear/ack interrupts - * @bdp: atapter's private data struct - * - * This routine disables interrupts at the hardware, by setting - * the M (mask) bit in the adapter's CSR SCB command word. - * It also clear/ack interrupts. - */ -static inline void -e100_disable_clear_intr(struct e100_private *bdp) +static inline void e100_write_flush(struct nic *nic) { - u16 intr_status; - /* Disable interrupts on our PCI board by setting the mask bit */ - writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi); - intr_status = readw(&bdp->scb->scb_status); - /* ack and clear intrs */ - writew(intr_status, &bdp->scb->scb_status); - readw(&bdp->scb->scb_status); + /* Flush previous PCI writes through intermediate bridges + * by doing a benign read */ + (void)readb(&nic->csr->scb.status); } -/** - * e100_set_intr_mask - set interrupts - * @bdp: atapter's private data struct - * - * This routine sets interrupts at the hardware, by resetting - * the M (mask) bit in the adapter's CSR SCB command word - */ -static inline void -e100_set_intr_mask(struct e100_private *bdp) +static void e100_enable_irq(struct nic *nic) { - writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ -} + unsigned long flags; -static inline void -e100_trigger_SWI(struct e100_private *bdp) -{ - /* Trigger interrupt on our PCI board by asserting SWI bit */ - writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ + spin_lock_irqsave(&nic->cmd_lock, flags); + writeb(irq_mask_none, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); } -static int __devinit -e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) +static void e100_disable_irq(struct nic *nic) { - static int first_time = true; - struct net_device *dev = NULL; - struct e100_private *bdp = NULL; - int rc = 0; - u16 cal_checksum, read_checksum; - - dev = alloc_etherdev(sizeof (struct e100_private)); - if (dev == NULL) { - printk(KERN_ERR "e100: Not able to alloc etherdev struct\n"); - rc = -ENODEV; - goto out; - } - - SET_MODULE_OWNER(dev); - - if (first_time) { - first_time = false; - printk(KERN_NOTICE "%s - version %s\n", - e100_full_driver_name, e100_driver_version); - printk(KERN_NOTICE "%s\n", e100_copyright); - printk(KERN_NOTICE "\n"); - } - - bdp = dev->priv; - bdp->pdev = pcid; - bdp->device = dev; - - pci_set_drvdata(pcid, dev); - SET_NETDEV_DEV(dev, &pcid->dev); - - bdp->flags = 0; - bdp->ifs_state = 0; - bdp->ifs_value = 0; - bdp->scb = 0; - - init_timer(&bdp->nontx_timer_id); - bdp->nontx_timer_id.data = (unsigned long) bdp; - bdp->nontx_timer_id.function = (void *) &e100_non_tx_background; - INIT_LIST_HEAD(&(bdp->non_tx_cmd_list)); - bdp->non_tx_command_state = E100_NON_TX_IDLE; - - init_timer(&bdp->watchdog_timer); - bdp->watchdog_timer.data = (unsigned long) dev; - bdp->watchdog_timer.function = (void *) &e100_watchdog; - - if ((rc = e100_pci_setup(pcid, bdp)) != 0) { - goto err_dev; - } - - if ((rc = e100_alloc_space(bdp)) != 0) { - goto err_pci; - } - - if (((bdp->pdev->device > 0x1030) - && (bdp->pdev->device < 0x103F)) - || ((bdp->pdev->device >= 0x1050) - && (bdp->pdev->device <= 0x1057)) - || ((bdp->pdev->device >= 0x1064) - && (bdp->pdev->device <= 0x106B)) - || (bdp->pdev->device == 0x2449) - || (bdp->pdev->device == 0x2459) - || (bdp->pdev->device == 0x245D)) { - bdp->rev_id = D101MA_REV_ID; /* workaround for ICH3 */ - bdp->flags |= IS_ICH; - } - - if (bdp->rev_id == 0xff) - bdp->rev_id = 1; - - if ((u8) bdp->rev_id >= D101A4_REV_ID) - bdp->flags |= IS_BACHELOR; - - if ((u8) bdp->rev_id >= D102_REV_ID) { - bdp->flags |= USE_IPCB; - bdp->rfd_size = 32; - } else { - bdp->rfd_size = 16; - } - - dev->vlan_rx_register = e100_vlan_rx_register; - dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; - dev->irq = pcid->irq; - dev->open = &e100_open; - dev->hard_start_xmit = &e100_xmit_frame; - dev->stop = &e100_close; - dev->change_mtu = &e100_change_mtu; - dev->get_stats = &e100_get_stats; - dev->set_multicast_list = &e100_set_multi; - dev->set_mac_address = &e100_set_mac; - dev->do_ioctl = &e100_ioctl; - -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = e100_netpoll; -#endif + unsigned long flags; - if (bdp->flags & USE_IPCB) - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - if ((rc = register_netdev(dev)) != 0) { - goto err_dealloc; - } - - e100_check_options(e100nics, bdp); - - if (!e100_init(bdp)) { - printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - /* Check if checksum is valid */ - cal_checksum = e100_eeprom_calculate_chksum(bdp); - read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1)); - if (cal_checksum != read_checksum) { - printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", - e100nics); - rc = -ENODEV; - goto err_unregister_netdev; - } - - e100nics++; - - e100_get_speed_duplex_caps(bdp); - - printk(KERN_NOTICE - "e100: %s: %s\n", - bdp->device->name, "Intel(R) PRO/100 Network Connection"); - e100_print_brd_conf(bdp); - - bdp->wolsupported = 0; - bdp->wolopts = 0; - if (bdp->rev_id >= D101A4_REV_ID) - bdp->wolsupported = WAKE_PHY | WAKE_MAGIC; - if (bdp->rev_id >= D101MA_REV_ID) - bdp->wolsupported |= WAKE_UCAST | WAKE_ARP; - - /* Check if WoL is enabled on EEPROM */ - if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) { - /* Magic Packet WoL is enabled on device by default */ - /* if EEPROM WoL bit is TRUE */ - bdp->wolopts = WAKE_MAGIC; - } - - printk(KERN_NOTICE "\n"); - - goto out; - -err_unregister_netdev: - unregister_netdev(dev); -err_dealloc: - e100_dealloc_space(bdp); -err_pci: - iounmap(bdp->scb); - pci_release_regions(pcid); - pci_disable_device(pcid); -err_dev: - pci_set_drvdata(pcid, NULL); - free_netdev(dev); -out: - return rc; + spin_lock_irqsave(&nic->cmd_lock, flags); + writeb(irq_mask_all, &nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); } -/** - * e100_clear_structs - free resources - * @dev: adapter's net_device struct - * - * Free all device specific structs, unmap i/o address, etc. - */ -static void __devexit -e100_clear_structs(struct net_device *dev) +static void e100_hw_reset(struct nic *nic) { - struct e100_private *bdp = dev->priv; + /* Put CU and RU into idle with a selective reset to get + * device off of PCI bus */ + writel(selective_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); - iounmap(bdp->scb); - pci_release_regions(bdp->pdev); - pci_disable_device(bdp->pdev); + /* Now fully reset device */ + writel(software_reset, &nic->csr->port); + e100_write_flush(nic); udelay(20); - e100_dealloc_space(bdp); - pci_set_drvdata(bdp->pdev, NULL); - free_netdev(dev); + /* Mask off our interrupt line - it's unmasked after reset */ + e100_disable_irq(nic); } -static void __devexit -e100_remove1(struct pci_dev *pcid) +static int e100_self_test(struct nic *nic) { - struct net_device *dev; - struct e100_private *bdp; + u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest); - if (!(dev = (struct net_device *) pci_get_drvdata(pcid))) - return; + /* Passing the self-test is a pretty good indication + * that the device can DMA to/from host memory */ - bdp = dev->priv; + nic->mem->selftest.signature = 0; + nic->mem->selftest.result = 0xFFFFFFFF; - unregister_netdev(dev); + writel(selftest | dma_addr, &nic->csr->port); + e100_write_flush(nic); + /* Wait 10 msec for self-test to complete */ + msleep(10); - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); + /* Interrupts are enabled after self-test */ + e100_disable_irq(nic); - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - del_timer_sync(&bdp->nontx_timer_id); - e100_free_nontx_list(bdp); - bdp->non_tx_command_state = E100_NON_TX_IDLE; + /* Check results of self-test */ + if(nic->mem->selftest.result != 0) { + DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n", + nic->mem->selftest.result); + return -ETIMEDOUT; } - - e100_clear_structs(dev); - - --e100nics; -} - -static struct pci_device_id e100_id_table[] = { - {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1066, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1067, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x1069, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x106A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x106B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, - {0,} /* This has to be the last entry*/ -}; -MODULE_DEVICE_TABLE(pci, e100_id_table); - -static struct pci_driver e100_driver = { - .name = "e100", - .id_table = e100_id_table, - .probe = e100_found1, - .remove = __devexit_p(e100_remove1), -#ifdef CONFIG_PM - .suspend = e100_suspend, - .resume = e100_resume, -#endif -}; - -static int __init -e100_init_module(void) -{ - int ret; - ret = pci_module_init(&e100_driver); - - if(ret >= 0) { -#ifdef CONFIG_PM - register_reboot_notifier(&e100_notifier_reboot); -#endif + if(nic->mem->selftest.signature == 0) { + DPRINTK(HW, ERR, "Self-test failed: timed out\n"); + return -ETIMEDOUT; } - return ret; -} - -static void __exit -e100_cleanup_module(void) -{ -#ifdef CONFIG_PM - unregister_reboot_notifier(&e100_notifier_reboot); -#endif - - pci_unregister_driver(&e100_driver); + return 0; } -module_init(e100_init_module); -module_exit(e100_cleanup_module); - -/** - * e100_check_options - check command line options - * @board: board number - * @bdp: atapter's private data struct - * - * This routine does range checking on command-line options - */ -void __devinit -e100_check_options(int board, struct e100_private *bdp) +static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) { - if (board >= E100_MAX_NIC) { - printk(KERN_NOTICE - "e100: No configuration available for board #%d\n", - board); - printk(KERN_NOTICE "e100: Using defaults for all values\n"); - board = E100_MAX_NIC; - } - - e100_set_int_option(&(bdp->params.TxDescriptors), TxDescriptors[board], - E100_MIN_TCB, E100_MAX_TCB, E100_DEFAULT_TCB, - "TxDescriptor count"); - - e100_set_int_option(&(bdp->params.RxDescriptors), RxDescriptors[board], - E100_MIN_RFD, E100_MAX_RFD, E100_DEFAULT_RFD, - "RxDescriptor count"); - - e100_set_int_option(&(bdp->params.e100_speed_duplex), - e100_speed_duplex[board], 0, 4, - E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode"); - - e100_set_int_option(&(bdp->params.ber), ber[board], 0, ZLOCK_MAX_ERRORS, - E100_DEFAULT_BER, "Bit Error Rate count"); - - e100_set_bool_option(bdp, XsumRX[board], PRM_XSUMRX, E100_DEFAULT_XSUM, - "XsumRX value"); - - /* Default ucode value depended on controller revision */ - if (bdp->rev_id >= D101MA_REV_ID) { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, - E100_DEFAULT_UCODE, "ucode value"); - } else { - e100_set_bool_option(bdp, ucode[board], PRM_UCODE, false, - "ucode value"); - } - - e100_set_bool_option(bdp, flow_control[board], PRM_FC, E100_DEFAULT_FC, - "flow control value"); - - e100_set_bool_option(bdp, IFS[board], PRM_IFS, E100_DEFAULT_IFS, - "IFS value"); - - e100_set_bool_option(bdp, BundleSmallFr[board], PRM_BUNDLE_SMALL, - E100_DEFAULT_BUNDLE_SMALL_FR, - "CPU saver bundle small frames value"); - - e100_set_int_option(&(bdp->params.IntDelay), IntDelay[board], 0x0, - 0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, - "CPU saver interrupt delay value"); - - e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1, - 0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX, - "CPU saver bundle max value"); - -} - -/** - * e100_set_int_option - check and set an integer option - * @option: a pointer to the relevant option field - * @val: the value specified - * @min: the minimum valid value - * @max: the maximum valid value - * @default_val: the default value - * @name: the name of the option - * - * This routine does range checking on a command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid, change it to the default. - */ -void __devinit -e100_set_int_option(int *option, int val, int min, int max, int default_val, - char *name) -{ - if (val == -1) { /* no value specified. use default */ - *option = default_val; - - } else if ((val < min) || (val > max)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid range is %i-%i\n", - name, val, min, max); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - *option = default_val; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - *option = val; - } -} - -/** - * e100_set_bool_option - check and set a boolean option - * @bdp: atapter's private data struct - * @val: the value specified - * @mask: the mask for the relevant option - * @default_val: the default value - * @name: the name of the option - * - * This routine checks a boolean command-line option. - * If the option's value is '-1' use the specified default. - * Otherwise, if the value is invalid (not 0 or 1), - * change it to the default. - */ -void __devinit -e100_set_bool_option(struct e100_private *bdp, int val, u32 mask, - int default_val, char *name) -{ - if (val == -1) { - if (default_val) - bdp->params.b_params |= mask; - - } else if ((val != true) && (val != false)) { - printk(KERN_NOTICE - "e100: Invalid %s specified (%i). " - "Valid values are %i/%i\n", - name, val, false, true); - printk(KERN_NOTICE "e100: Using default %s of %i\n", name, - default_val); - - if (default_val) - bdp->params.b_params |= mask; - } else { - printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); - if (val) - bdp->params.b_params |= mask; + u32 cmd_addr_data[3]; + u8 ctrl; + int i, j; + + /* Three cmds: write/erase enable, write data, write/erase disable */ + cmd_addr_data[0] = op_ewen << (addr_len - 2); + cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | + cpu_to_le16(data); + cmd_addr_data[2] = op_ewds << (addr_len - 2); + + /* Bit-bang cmds to write word to eeprom */ + for(j = 0; j < 3; j++) { + + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data[j] & (1 << i)) ? + eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); + } + /* Wait 10 msec for cmd to complete */ + msleep(10); + + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); } -} +}; -int -e100_open(struct net_device *dev) +/* General technique stolen from the eepro100 driver - very clever */ +static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) { - struct e100_private *bdp; - int rc = 0; - - bdp = dev->priv; - - /* setup the tcb pool */ - if (!e100_alloc_tcb_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } - bdp->last_tcb = NULL; - - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - - e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data, - bdp->params.TxDescriptors, bdp); + u32 cmd_addr_data; + u16 data = 0; + u8 ctrl; + int i; - if (!e100_alloc_rfd_pool(bdp)) { - rc = -ENOMEM; - goto err_exit; - } + cmd_addr_data = ((op_read << *addr_len) | addr) << 16; - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } + /* Chip select */ + writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) { - rc = -EAGAIN; - goto err_exit; - } + /* Bit-bang to read word from eeprom */ + for(i = 31; i >= 0; i--) { + ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; + writeb(ctrl, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); + writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); - if (dev->flags & IFF_UP) - /* Otherwise process may sleep forever */ - netif_wake_queue(dev); - else - netif_start_queue(dev); + /* Eeprom drives a dummy zero to EEDO after receiving + * complete address. Use this to adjust addr_len. */ + ctrl = readb(&nic->csr->eeprom_ctrl_lo); + if(!(ctrl & eedo) && i > 16) { + *addr_len -= (i - 16); + i = 17; + } - e100_start_ru(bdp); - if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, - dev->name, dev)) != 0) { - del_timer_sync(&bdp->watchdog_timer); - goto err_exit; + data = (data << 1) | (ctrl & eedo ? 1 : 0); } - bdp->intr_mask = 0; - e100_set_intr_mask(bdp); - e100_force_config(bdp); + /* Chip deselect */ + writeb(0, &nic->csr->eeprom_ctrl_lo); + e100_write_flush(nic); udelay(4); - goto exit; - -err_exit: - e100_clear_pools(bdp); -exit: - return rc; -} + return le16_to_cpu(data); +}; -int -e100_close(struct net_device *dev) +/* Load entire EEPROM image into driver cache and validate checksum */ +static int e100_eeprom_load(struct nic *nic) { - struct e100_private *bdp = dev->priv; - - e100_disable_clear_intr(bdp); - free_irq(dev->irq, dev); - bdp->intr_mask = SCB_INT_MASK; - e100_isolate_driver(bdp); - - netif_carrier_off(bdp->device); - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - e100_clear_pools(bdp); - - return 0; -} + u16 addr, addr_len = 8, checksum = 0; -static int -e100_change_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) - return -EINVAL; + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; + + for(addr = 0; addr < nic->eeprom_wc; addr++) { + nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr); + if(addr < nic->eeprom_wc - 1) + checksum += cpu_to_le16(nic->eeprom[addr]); + } + + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + checksum = le16_to_cpu(0xBABA - checksum); + if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); + return -EAGAIN; + } - dev->mtu = new_mtu; return 0; } -/** - * e100_prepare_xmit_buff - prepare a buffer for transmission - * @bdp: atapter's private data struct - * @skb: skb to send - * - * This routine prepare a buffer for transmission. It checks - * the message length for the appropiate size. It picks up a - * free tcb from the TCB pool and sets up the corresponding - * TBD's. If the number of fragments are more than the number - * of TBD/TCB it copies all the fragments in a coalesce buffer. - * It returns a pointer to the prepared TCB. - */ -static inline tcb_t * -e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) +/* Save (portion of) driver EEPROM cache to device and update checksum */ +static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) { - tcb_t *tcb, *prev_tcb; - - tcb = bdp->tcb_pool.data; - tcb += TCB_TO_USE(bdp->tcb_pool); - - if (bdp->flags & USE_IPCB) { - tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET; - tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; - } - - if(bdp->vlgrp && vlan_tx_tag_present(skb)) { - (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; - (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); - } - - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); - - /* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */ - if (!(++bdp->tx_count % TX_FRAME_CNT)) - tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT); - else - /* Clear I bit on other packets */ - tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT); - - tcb->tcb_skb = skb; + u16 addr, addr_len = 8, checksum = 0; - if (skb->ip_summed == CHECKSUM_HW) { - const struct iphdr *ip = skb->nh.iph; + /* Try reading with an 8-bit addr len to discover actual addr len */ + e100_eeprom_read(nic, &addr_len, 0); + nic->eeprom_wc = 1 << addr_len; - if ((ip->protocol == IPPROTO_TCP) || - (ip->protocol == IPPROTO_UDP)) { - - tcb->tcbu.ipcb.ip_activation_high |= - IPCB_HARDWAREPARSING_ENABLE; - tcb->tcbu.ipcb.ip_schedule |= - IPCB_TCPUDP_CHECKSUM_ENABLE; - - if (ip->protocol == IPPROTO_TCP) - tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET; - } - } - - if (!skb_shinfo(skb)->nr_frags) { - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len); - tcb->tcb_tbd_num = 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr; - } else { - int i; - void *addr; - tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]); - skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; - - (tcb->tbd_ptr)->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, skb->data, - skb_headlen(skb), - PCI_DMA_TODEVICE)); - (tcb->tbd_ptr)->tbd_buf_cnt = - cpu_to_le16(skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; - i++, tbd_arr_ptr++, frag++) { - - addr = ((void *) page_address(frag->page) + - frag->page_offset); - - tbd_arr_ptr->tbd_buf_addr = - cpu_to_le32(pci_map_single(bdp->pdev, - addr, frag->size, - PCI_DMA_TODEVICE)); - tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size); - } - tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1; - tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr; - } - - /* clear the S-BIT on the previous tcb */ - prev_tcb = bdp->tcb_pool.data; - prev_tcb += PREV_TCB_USED(bdp->tcb_pool); - prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT); - - bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail); - - wmb(); - - e100_start_cu(bdp, tcb); - - return tcb; -} - -static int -e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) -{ - int rc = 0; - int notify_stop = false; - struct e100_private *bdp = dev->priv; - - if (!spin_trylock(&bdp->bd_non_tx_lock)) { - notify_stop = true; - rc = 1; - goto exit2; - } - - /* tcb list may be empty temporarily during releasing resources */ - if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || - (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { - notify_stop = true; - rc = 1; - goto exit1; - } - - bdp->drv_stats.net_stats.tx_bytes += skb->len; - - e100_prepare_xmit_buff(bdp, skb); - - dev->trans_start = jiffies; - -exit1: - spin_unlock(&bdp->bd_non_tx_lock); -exit2: - if (notify_stop) { - netif_stop_queue(dev); - } - - return rc; -} - -/** - * e100_get_stats - get driver statistics - * @dev: adapter's net_device struct - * - * This routine is called when the OS wants the adapter's stats returned. - * It returns the address of the net_device_stats stucture for the device. - * If the statistics are currently being updated, then they might be incorrect - * for a short while. However, since this cannot actually cause damage, no - * locking is used. - */ -struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - - bdp->drv_stats.net_stats.tx_errors = - bdp->drv_stats.net_stats.tx_carrier_errors + - bdp->drv_stats.net_stats.tx_aborted_errors; - - bdp->drv_stats.net_stats.rx_errors = - bdp->drv_stats.net_stats.rx_crc_errors + - bdp->drv_stats.net_stats.rx_frame_errors + - bdp->drv_stats.net_stats.rx_length_errors + - bdp->drv_stats.rcv_cdt_frames; - - return &(bdp->drv_stats.net_stats); -} - -/** - * e100_set_mac - set the MAC address - * @dev: adapter's net_device struct - * @addr: the new address - * - * This routine sets the ethernet address of the board - * Returns: - * 0 - if successful - * -1 - otherwise - */ -static int -e100_set_mac(struct net_device *dev, void *addr) -{ - struct e100_private *bdp; - int rc = -1; - struct sockaddr *p_sockaddr = (struct sockaddr *) addr; - - if (!is_valid_ether_addr(p_sockaddr->sa_data)) - return -EADDRNOTAVAIL; - bdp = dev->priv; - - if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { - memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN); - rc = 0; - } - - return rc; -} - -static void -e100_set_multi_exec(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - mltcst_cb_t *mcast_buff; - cb_header_t *cb_hdr; - struct dev_mc_list *mc_list; - unsigned int i; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast); - cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr); - } else { - return; - } - - /* initialize the multi cast command */ - cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST); - - /* now fill in the rest of the multicast command */ - *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6); - for (i = 0, mc_list = dev->mc_list; - (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS); - i++, mc_list = mc_list->next) { - /* copy into the command */ - memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]), - (u8 *) &(mc_list->dmi_addr), ETH_ALEN); - } - - if (!e100_exec_non_cu_cmd(bdp, cmd)) { - printk(KERN_WARNING "e100: %s: Multicast setup failed\n", - dev->name); - } -} - -/** - * e100_set_multi - set multicast status - * @dev: adapter's net_device struct - * - * This routine is called to add or remove multicast addresses, and/or to - * change the adapter's promiscuous state. - */ -static void -e100_set_multi(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - unsigned char promisc_enbl; - unsigned char mulcast_enbl; - - promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); - mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > MAX_MULTICAST_ADDRS)); - - e100_config_promisc(bdp, promisc_enbl); - e100_config_mulcast_enbl(bdp, mulcast_enbl); - - /* reconfigure the chip if something has changed in its config space */ - e100_config(bdp); - - if (promisc_enbl || mulcast_enbl) { - return; /* no need for Multicast Cmd */ - } - - /* get the multicast CB */ - e100_set_multi_exec(dev); -} - -static int -e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - - switch (cmd) { - - case SIOCETHTOOL: - return e100_do_ethtool_ioctl(dev, ifr); - break; - - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCSMIIREG: /* Write to MII PHY register. */ - return e100_mii_ioctl(dev, ifr, cmd); - break; - - default: - return -EOPNOTSUPP; - } - return 0; - -} - -/** - * e100init - initialize the adapter - * @bdp: atapter's private data struct - * - * This routine is called when this driver is loaded. This is the initialization - * routine which allocates memory, configures the adapter and determines the - * system resources. - * - * Returns: - * true: if successful - * false: otherwise - */ -static unsigned char __devinit -e100_init(struct e100_private *bdp) -{ - u32 st_timeout = 0; - u32 st_result = 0; - e100_sw_init(bdp); - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (st_timeout) { - printk(KERN_ERR "e100: selftest timeout\n"); - } else { - printk(KERN_ERR "e100: selftest failed. Results: %x\n", - st_result); - } - return false; - } - else - printk(KERN_DEBUG "e100: selftest OK.\n"); - - /* read the MAC address from the eprom */ - e100_rd_eaddr(bdp); - if (!is_valid_ether_addr(bdp->device->dev_addr)) { - printk(KERN_ERR "e100: Invalid Ethernet address\n"); - return false; - } - /* read NIC's part number */ - e100_rd_pwa_no(bdp); - - if (!e100_hw_init(bdp)) - return false; - /* Interrupts are enabled after device reset */ - e100_disable_clear_intr(bdp); - - return true; -} - -/** - * e100_sw_init - initialize software structs - * @bdp: atapter's private data struct - * - * This routine initializes all software structures. Sets up the - * circular structures for the RFD's & TCB's. Allocates the per board - * structure for storing adapter information. The CSR is also memory - * mapped in this routine. - * - * Returns : - * true: if S/W was successfully initialized - * false: otherwise - */ -static unsigned char __devinit -e100_sw_init(struct e100_private *bdp) -{ - bdp->next_cu_cmd = START_WAIT; // init the next cu state - - /* - * Set the value for # of good xmits per underrun. the value assigned - * here is an intelligent suggested default. Nothing magical about it. - */ - bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; - - /* get the default transmit threshold value */ - bdp->tx_thld = TX_THRSHLD; - - /* get the EPROM size */ - bdp->eeprom_size = e100_eeprom_size(bdp); - - /* Initialize our spinlocks */ - spin_lock_init(&(bdp->bd_lock)); - spin_lock_init(&(bdp->bd_non_tx_lock)); - spin_lock_init(&(bdp->config_lock)); - spin_lock_init(&(bdp->mdi_access_lock)); - /* Initialize configuration data */ - e100_config_init(bdp); - - return 1; -} - -static void -e100_tco_workaround(struct e100_private *bdp) -{ - int i; - - /* Do software reset */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - - /* Do a dummy LOAD CU BASE command. */ - /* This gets us out of pre-driver to post-driver. */ - e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE); - - /* Wait 20 msec for reset to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 50 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset */ - e100_disable_clear_intr(bdp); - - /* Wait for command to be cleared up to 1 sec */ - for (i=0; i<100; i++) { - if (!readb(&bdp->scb->scb_cmd_low)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } - - /* Wait for TCO request bit in PMDR register to be clear */ - for (i=0; i<50; i++) { - if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1)) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - } -} - -/** - * e100_hw_init - initialized tthe hardware - * @bdp: atapter's private data struct - * - * This routine performs a reset on the adapter, and configures the adapter. - * This includes configuring the 82557 LAN controller, validating and setting - * the node address, detecting and configuring the Phy chip on the adapter, - * and initializing all of the on chip counters. - * - * Returns: - * true - If the adapter was initialized - * false - If the adapter failed initialization - */ -unsigned char -e100_hw_init(struct e100_private *bdp) -{ - if (!e100_phy_init(bdp)) - goto err; - - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); - - /* Only 82559 or above needs TCO workaround */ - if (bdp->rev_id >= D101MA_REV_ID) - e100_tco_workaround(bdp); - - /* Load the CU BASE (set to 0, because we use linear mode) */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - goto err; - - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - goto err; - - /* Load interrupt microcode */ - if (e100_load_microcode(bdp)) { - bdp->flags |= DF_UCODE_LOADED; - } - - if ((u8) bdp->rev_id < D101A4_REV_ID) - e100_config_init_82557(bdp); - - if (!e100_config(bdp)) - goto err; - - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - goto err; - - /* Clear the internal counters */ - if (!e100_clr_cntrs(bdp)) - goto err; - - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up the - * Flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } - - return true; -err: - printk(KERN_ERR "e100: hw init failed\n"); - return false; -} - -/** - * e100_setup_tcb_pool - setup TCB circular list - * @head: Pointer to head of the allocated TCBs - * @qlen: Number of elements in the queue - * @bdp: atapter's private data struct - * - * This routine arranges the contigiously allocated TCB's in a circular list. - * Also does the one time initialization of the TCBs. - */ -static void -e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp) -{ - int ele_no; - tcb_t *pcurr_tcb; /* point to current tcb */ - u32 next_phys; /* the next phys addr */ - u16 txcommand = CB_S_BIT | CB_TX_SF_BIT; - - bdp->tx_count = 0; - if (bdp->flags & USE_IPCB) { - txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT; - } else if (bdp->flags & IS_BACHELOR) { - txcommand |= CB_TRANSMIT | CB_CID_DEFAULT; - } else { - txcommand |= CB_TRANSMIT; - } - - for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head; - ele_no < qlen; ele_no++, pcurr_tcb++) { - - /* set the phys addr for this TCB, next_phys has not incr. yet */ - pcurr_tcb->tcb_phys = next_phys; - next_phys += sizeof (tcb_t); - - /* set the link to next tcb */ - if (ele_no == (qlen - 1)) - pcurr_tcb->tcb_hdr.cb_lnk_ptr = - cpu_to_le32(bdp->tcb_phys); - else - pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys); - - pcurr_tcb->tcb_hdr.cb_status = 0; - pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand); - pcurr_tcb->tcb_cnt = 0; - pcurr_tcb->tcb_thrshld = bdp->tx_thld; - if (ele_no < 2) { - pcurr_tcb->tcb_hdr.cb_status = - cpu_to_le16(CB_STATUS_COMPLETE); - } - pcurr_tcb->tcb_tbd_num = 1; - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_ptr = - __constant_cpu_to_le32(0xFFFFFFFF); - } else { - pcurr_tcb->tcb_tbd_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - - if (bdp->flags & IS_BACHELOR) { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x20); - } else { - pcurr_tcb->tcb_tbd_expand_ptr = - cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); - } - pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr; - - if (bdp->flags & USE_IPCB) { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]); - pcurr_tcb->tcbu.ipcb.ip_activation_high = - IPCB_IP_ACTIVATION_DEFAULT; - pcurr_tcb->tcbu.ipcb.vlan = 0; - } else { - pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]); - } - - pcurr_tcb->tcb_skb = NULL; - } - - wmb(); -} - -/***************************************************************************/ -/***************************************************************************/ -/* Memory Management Routines */ -/***************************************************************************/ - -/** - * e100_alloc_space - allocate private driver data - * @bdp: atapter's private data struct - * - * This routine allocates memory for the driver. Memory allocated is for the - * selftest and statistics structures. - * - * Returns: - * 0: if the operation was successful - * %-ENOMEM: if memory allocation failed - */ -unsigned char __devinit -e100_alloc_space(struct e100_private *bdp) -{ - unsigned long off; - - /* allocate all the dma-able structures in one call: - * selftest results, adapter stats, and non-tx cb commands */ - if (!(bdp->dma_able = - pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t), - &(bdp->dma_able_phys)))) { - goto err; - } - - /* now assign the various pointers into the struct we've just allocated */ - off = offsetof(bd_dma_able_t, selftest); - - bdp->selftest = (self_test_t *) (bdp->dma_able + off); - bdp->selftest_phys = bdp->dma_able_phys + off; - - off = offsetof(bd_dma_able_t, stats_counters); - - bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off); - bdp->stat_cnt_phys = bdp->dma_able_phys + off; - - return 0; - -err: - printk(KERN_ERR - "e100: Failed to allocate memory\n"); - return -ENOMEM; -} - -/** - * e100_alloc_tcb_pool - allocate TCB circular list - * @bdp: atapter's private data struct - * - * This routine allocates memory for the circular list of transmit descriptors. - * - * Returns: - * 0: if allocation has failed. - * 1: Otherwise. - */ -int -e100_alloc_tcb_pool(struct e100_private *bdp) -{ - int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors; - - /* allocate space for the TCBs */ - if (!(bdp->tcb_pool.data = - pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys))) - return 0; - - memset(bdp->tcb_pool.data, 0x00, stcb); - - return 1; -} - -/** - * e100_tx_skb_free - free TX skbs resources - * @bdp: atapter's private data struct - * @tcb: associated tcb of the freed skb - * - * This routine frees resources of TX skbs. - */ -static inline void -e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb) -{ - if (tcb->tcb_skb) { - int i; - tbd_t *tbd_arr = tcb->tbd_ptr; - int frags = skb_shinfo(tcb->tcb_skb)->nr_frags; - - for (i = 0; i <= frags; i++, tbd_arr++) { - pci_unmap_single(bdp->pdev, - le32_to_cpu(tbd_arr->tbd_buf_addr), - le16_to_cpu(tbd_arr->tbd_buf_cnt), - PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(tcb->tcb_skb); - tcb->tcb_skb = NULL; - } -} - -void -e100_free_tcb_pool(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - /* Return tx skbs */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - e100_tx_skb_free(bdp, tcb); - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) - break; - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) * bdp->params.TxDescriptors, - bdp->tcb_pool.data, bdp->tcb_phys); - bdp->tcb_pool.head = 0; - bdp->tcb_pool.tail = 1; - bdp->tcb_phys = 0; -} - -static void -e100_dealloc_space(struct e100_private *bdp) -{ - if (bdp->dma_able) { - pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t), - bdp->dma_able, bdp->dma_able_phys); - } - - bdp->selftest_phys = 0; - bdp->stat_cnt_phys = 0; - bdp->dma_able_phys = 0; - bdp->dma_able = 0; -} - -static void -e100_free_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - - while (!list_empty(&(bdp->active_rx_list))) { - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_TODEVICE); - dev_kfree_skb(rx_struct->skb); - kfree(rx_struct); - } - - while (!list_empty(&(bdp->rx_struct_pool))) { - rx_struct = list_entry(bdp->rx_struct_pool.next, - struct rx_list_elem, list_elem); - list_del(&(rx_struct->list_elem)); - kfree(rx_struct); - } -} - -/** - * e100_alloc_rfd_pool - allocate RFDs - * @bdp: atapter's private data struct - * - * Allocates initial pool of skb which holds both rfd and data, - * and return a pointer to the head of the list - */ -static int -e100_alloc_rfd_pool(struct e100_private *bdp) -{ - struct rx_list_elem *rx_struct; - int i; - - INIT_LIST_HEAD(&(bdp->active_rx_list)); - INIT_LIST_HEAD(&(bdp->rx_struct_pool)); - bdp->skb_req = bdp->params.RxDescriptors; - for (i = 0; i < bdp->skb_req; i++) { - rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC); - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - } - e100_alloc_skbs(bdp); - return !list_empty(&(bdp->active_rx_list)); - -} - -void -e100_clear_pools(struct e100_private *bdp) -{ - bdp->last_tcb = NULL; - e100_free_rfd_pool(bdp); - e100_free_tcb_pool(bdp); -} - -/*****************************************************************************/ -/*****************************************************************************/ -/* Run Time Functions */ -/*****************************************************************************/ - -/** - * e100_watchdog - * @dev: adapter's net_device struct - * - * This routine runs every 2 seconds and updates our statitics and link state, - * and refreshs txthld value. - */ -void -e100_watchdog(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - -#ifdef E100_CU_DEBUG - if (e100_cu_unknown_state(bdp)) { - printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n", - dev->name); - } -#endif - if (!netif_running(dev)) { - return; - } - - /* check if link state has changed */ - if (e100_phy_check(bdp)) { - if (netif_carrier_ok(dev)) { - printk(KERN_ERR - "e100: %s NIC Link is Up %d Mbps %s duplex\n", - bdp->device->name, bdp->cur_line_speed, - (bdp->cur_dplx_mode == HALF_DUPLEX) ? - "Half" : "Full"); - - e100_config_fc(bdp); - e100_config(bdp); - - } else { - printk(KERN_ERR "e100: %s NIC Link is Down\n", - bdp->device->name); - } - } - - // toggle the tx queue according to link status - // this also resolves a race condition between tx & non-cu cmd flows - if (netif_carrier_ok(dev)) { - if (netif_running(dev)) - netif_wake_queue(dev); - } else { - if (netif_running(dev)) - netif_stop_queue(dev); - /* When changing to non-autoneg, device may lose */ - /* link with some switches. e100 will try to */ - /* revover link by sending command to PHY layer */ - if (bdp->params.e100_speed_duplex != E100_AUTONEG) - e100_force_speed_duplex_to_phy(bdp); - } - - rmb(); - - if (e100_update_stats(bdp)) { - - /* Check if a change in the IFS parameter is needed, - and configure the device accordingly */ - if (bdp->params.b_params & PRM_IFS) - e100_manage_adaptive_ifs(bdp); - - /* Now adjust our dynamic tx threshold value */ - e100_refresh_txthld(bdp); - - /* Now if we are on a 557 and we havn't received any frames then we - * should issue a multicast command to reset the RU */ - if (bdp->rev_id < D101A4_REV_ID) { - if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) { - e100_set_multi(dev); - } - } - } - /* Issue command to dump statistics from device. */ - /* Check for command completion on next watchdog timer. */ - e100_dump_stats_cntrs(bdp); - - wmb(); - - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - - if (list_empty(&bdp->active_rx_list)) - e100_trigger_SWI(bdp); -} - -/** - * e100_manage_adaptive_ifs - * @bdp: atapter's private data struct - * - * This routine manages the adaptive Inter-Frame Spacing algorithm - * using a state machine. - */ -void -e100_manage_adaptive_ifs(struct e100_private *bdp) -{ - static u16 state_table[9][4] = { // rows are states - {2, 0, 0, 0}, // state0 // column0: next state if increasing - {2, 0, 5, 30}, // state1 // column1: next state if decreasing - {5, 1, 5, 30}, // state2 // column2: IFS value for 100 mbit - {5, 3, 0, 0}, // state3 // column3: IFS value for 10 mbit - {5, 3, 10, 60}, // state4 - {8, 4, 10, 60}, // state5 - {8, 6, 0, 0}, // state6 - {8, 6, 20, 60}, // state7 - {8, 7, 20, 60} // state8 - }; - - u32 transmits = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames); - u32 collisions = - le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll); - u32 state = bdp->ifs_state; - u32 old_value = bdp->ifs_value; - int next_col; - u32 min_transmits; - - if (bdp->cur_dplx_mode == FULL_DUPLEX) { - bdp->ifs_state = 0; - bdp->ifs_value = 0; - - } else { /* Half Duplex */ - /* Set speed specific parameters */ - if (bdp->cur_line_speed == 100) { - next_col = 2; - min_transmits = MIN_NUMBER_OF_TRANSMITS_100; - - } else { /* 10 Mbps */ - next_col = 3; - min_transmits = MIN_NUMBER_OF_TRANSMITS_10; - } - - if ((transmits / 32 < collisions) - && (transmits > min_transmits)) { - state = state_table[state][0]; /* increment */ - - } else if (transmits < min_transmits) { - state = state_table[state][1]; /* decrement */ - } - - bdp->ifs_value = state_table[state][next_col]; - bdp->ifs_state = state; - } - - /* If the IFS value has changed, configure the device */ - if (bdp->ifs_value != old_value) { - e100_config_ifs(bdp); - e100_config(bdp); - } -} - -/** - * e100intr - interrupt handler - * @irq: the IRQ number - * @dev_inst: the net_device struct - * @regs: registers (unused) - * - * This routine is the ISR for the e100 board. It services - * the RX & TX queues & starts the RU if it has stopped due - * to no resources. - */ -irqreturn_t -e100intr(int irq, void *dev_inst, struct pt_regs *regs) -{ - struct net_device *dev; - struct e100_private *bdp; - u16 intr_status; - - dev = dev_inst; - bdp = dev->priv; - - intr_status = readw(&bdp->scb->scb_status); - /* If not my interrupt, just return */ - if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) { - return IRQ_NONE; - } - - /* disable and ack intr */ - e100_disable_clear_intr(bdp); - - /* the device is closed, don't continue or else bad things may happen. */ - if (!netif_running(dev)) { - e100_set_intr_mask(bdp); - return IRQ_NONE; - } - - /* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */ - if (intr_status & SCB_STATUS_ACK_SWI) { - e100_alloc_skbs(bdp); - } - - /* do recv work if any */ - if (intr_status & - (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) - bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp); - - /* clean up after tx'ed packets */ - if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) - e100_tx_srv(bdp); - - e100_set_intr_mask(bdp); - return IRQ_HANDLED; -} - -/** - * e100_tx_srv - service TX queues - * @bdp: atapter's private data struct - * - * This routine services the TX queues. It reclaims the TCB's & TBD's & other - * resources used during the transmit of this buffer. It is called from the ISR. - * We don't need a tx_lock since we always access buffers which were already - * prepared. - */ -void -e100_tx_srv(struct e100_private *bdp) -{ - tcb_t *tcb; - int i; - - /* go over at most TxDescriptors buffers */ - for (i = 0; i < bdp->params.TxDescriptors; i++) { - tcb = bdp->tcb_pool.data; - tcb += bdp->tcb_pool.head; - - rmb(); - - /* if the buffer at 'head' is not complete, break */ - if (!(tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - break; - - /* service next buffer, clear the out of resource condition */ - e100_tx_skb_free(bdp, tcb); - - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); - - /* if we've caught up with 'tail', break */ - if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) { - break; - } - - bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); - } -} - -/** - * e100_rx_srv - service RX queue - * @bdp: atapter's private data struct - * @max_number_of_rfds: max number of RFDs to process - * @rx_congestion: flag pointer, to inform the calling function of congestion. - * - * This routine processes the RX interrupt & services the RX queues. - * For each successful RFD, it allocates a new msg block, links that - * into the RFD list, and sends the old msg upstream. - * The new RFD is then put at the end of the free list of RFD's. - * It returns the number of serviced RFDs. - */ -u32 -e100_rx_srv(struct e100_private *bdp) -{ - rfd_t *rfd; /* new rfd, received rfd */ - int i; - u16 rfd_status; - struct sk_buff *skb; - struct net_device *dev; - unsigned int data_sz; - struct rx_list_elem *rx_struct; - u32 rfd_cnt = 0; - - dev = bdp->device; - - /* current design of rx is as following: - * 1. socket buffer (skb) used to pass network packet to upper layer - * 2. all HW host memory structures (like RFDs, RBDs and data buffers) - * are placed in a skb's data room - * 3. when rx process is complete, we change skb internal pointers to exclude - * from data area all unrelated things (RFD, RDB) and to leave - * just rx'ed packet netto - * 4. for each skb passed to upper layer, new one is allocated instead. - * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made - * (watchdog trigger SWI intr and isr should allocate new skbs) - */ - for (i = 0; i < bdp->params.RxDescriptors; i++) { - if (list_empty(&(bdp->active_rx_list))) { - break; - } - - rx_struct = list_entry(bdp->active_rx_list.next, - struct rx_list_elem, list_elem); - skb = rx_struct->skb; - - rfd = RFD_POINTER(skb, bdp); /* locate RFD within skb */ - - // sync only the RFD header - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - rfd_status = le16_to_cpu(rfd->rfd_header.cb_status); /* get RFD's status */ - if (!(rfd_status & RFD_STATUS_COMPLETE)) /* does not contains data yet - exit */ - break; - - /* to allow manipulation with current skb we need to unlink it */ - list_del(&(rx_struct->list_elem)); - - /* do not free & unmap badly received packet. - * move it to the end of skb list for reuse */ - if (!(rfd_status & RFD_STATUS_OK)) { - e100_add_skb_to_end(bdp, rx_struct); - continue; - } - - data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff), - (sizeof (rfd_t) - bdp->rfd_size)); - - /* now sync all the data */ - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - (data_sz + bdp->rfd_size), - PCI_DMA_FROMDEVICE); - - pci_unmap_single(bdp->pdev, rx_struct->dma_addr, - sizeof (rfd_t), PCI_DMA_FROMDEVICE); - - list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); - - /* end of dma access to rfd */ - bdp->skb_req++; /* incr number of requested skbs */ - e100_alloc_skbs(bdp); /* and get them */ - - /* set packet size, excluding checksum (2 last bytes) if it is present */ - if ((bdp->flags & DF_CSUM_OFFLOAD) - && (bdp->rev_id < D102_REV_ID)) - skb_put(skb, (int) data_sz - 2); - else - skb_put(skb, (int) data_sz); - - bdp->drv_stats.net_stats.rx_bytes += skb->len; - - /* set the protocol */ - skb->protocol = eth_type_trans(skb, dev); - - /* set the checksum info */ - if (bdp->flags & DF_CSUM_OFFLOAD) { - if (bdp->rev_id >= D102_REV_ID) { - skb->ip_summed = e100_D102_check_checksum(rfd); - } else { - skb->ip_summed = e100_D101M_checksum(bdp, skb); - } - } else { - skb->ip_summed = CHECKSUM_NONE; - } - - if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) { - vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid)); - } else { - netif_rx(skb); - } - dev->last_rx = jiffies; - - rfd_cnt++; - } /* end of rfd loop */ - - /* restart the RU if it has stopped */ - if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) { - e100_start_ru(bdp); - } - - return rfd_cnt; -} - -void -e100_refresh_txthld(struct e100_private *bdp) -{ - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - /* as long as tx_per_underrun is not 0, we can go about dynamically * - * adjusting the xmit threshold. we stop doing that & resort to defaults - * * once the adjustments become meaningless. the value is adjusted by * - * dumping the error counters & checking the # of xmit underrun errors * - * we've had. */ - if (bdp->tx_per_underrun) { - /* We are going to last values dumped from the dump statistics - * command */ - if (le32_to_cpu(pstat->xmt_gd_frames)) { - if (le32_to_cpu(pstat->xmt_uruns)) { - /* - * if we have had more than one underrun per "DEFAULT # - * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the - * THRESHOLD. - */ - if ((le32_to_cpu(pstat->xmt_gd_frames) / - le32_to_cpu(pstat->xmt_uruns)) < - bdp->tx_per_underrun) { - bdp->tx_thld += 3; - } - } - - /* - * if we've had less than one underrun per the DEFAULT number of - * of good xmits allowed, lower the THOLD but not less than 0 - */ - if (le32_to_cpu(pstat->xmt_gd_frames) > - bdp->tx_per_underrun) { - bdp->tx_thld--; - - if (bdp->tx_thld < 6) - bdp->tx_thld = 6; - - } - } - - /* end good xmits */ - /* - * * if our adjustments are becoming unresonable, stop adjusting & - * resort * to defaults & pray. A THOLD value > 190 means that the - * adapter will * wait for 190*8=1520 bytes in TX FIFO before it - * starts xmit. Since * MTU is 1514, it doesn't make any sense for - * further increase. */ - if (bdp->tx_thld >= 190) { - bdp->tx_per_underrun = 0; - bdp->tx_thld = 189; - } - } /* end underrun check */ -} - -/* Changed for 82558 enhancement */ -/** - * e100_start_cu - start the adapter's CU - * @bdp: atapter's private data struct - * @tcb: TCB to be transmitted - * - * This routine issues a CU Start or CU Resume command to the 82558/9. - * This routine was added because the prepare_ext_xmit_buff takes advantage - * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as - * soon as the first TBD is ready. - * - * e100_start_cu must be called while holding the tx_lock ! - */ -u8 -e100_start_cu(struct e100_private *bdp, tcb_t *tcb) -{ - unsigned long lock_flag; - u8 ret = true; - - spin_lock_irqsave(&(bdp->bd_lock), lock_flag); - switch (bdp->next_cu_cmd) { - case RESUME_NO_WAIT: - /*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to - * wait for command word to clear, we reach here only if we are bachlor - */ - e100_exec_cmd(bdp, SCB_CUC_RESUME); - break; - - case RESUME_WAIT: - if ((bdp->flags & IS_ICH) && - (bdp->cur_line_speed == 10) && - (bdp->cur_dplx_mode == HALF_DUPLEX)) { - e100_wait_exec_simple(bdp, SCB_CUC_NOOP); - udelay(1); - } - if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) && - (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) { - bdp->next_cu_cmd = RESUME_NO_WAIT; - } - break; - - case START_WAIT: - // The last command was a non_tx CU command - if (!e100_wait_cus_idle(bdp)) - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for cu\n", - bdp->device->name); - if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START, CB_TRANSMIT)) { - printk(KERN_DEBUG - "e100: %s: cu_start: timeout waiting for scb\n", - bdp->device->name); - e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys), - SCB_CUC_START); - ret = false; - } - - bdp->next_cu_cmd = RESUME_WAIT; - - break; - } - - /* save the last tcb */ - bdp->last_tcb = tcb; - - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - return ret; -} - -/* ====================================================================== */ -/* hw */ -/* ====================================================================== */ - -/** - * e100_selftest - perform H/W self test - * @bdp: atapter's private data struct - * @st_timeout: address to return timeout value, if fails - * @st_result: address to return selftest result, if fails - * - * This routine will issue PORT Self-test command to test the e100. - * The self-test will fail if the adapter's master-enable bit is not - * set in the PCI Command Register, or if the adapter is not seated - * in a PCI master-enabled slot. we also disable interrupts when the - * command is completed. - * - * Returns: - * true: if adapter passes self_test - * false: otherwise - */ -unsigned char -e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result) -{ - u32 selftest_cmd; - - /* initialize the nic state before running test */ - e100_sw_reset(bdp, PORT_SOFTWARE_RESET); - /* Setup the address of the self_test area */ - selftest_cmd = bdp->selftest_phys; - - /* Setup SELF TEST Command Code in D3 - D0 */ - selftest_cmd |= PORT_SELFTEST; - - /* Initialize the self-test signature and results DWORDS */ - bdp->selftest->st_sign = 0; - bdp->selftest->st_result = 0xffffffff; - - /* Do the port command */ - writel(selftest_cmd, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* Wait at least 10 milliseconds for the self-test to complete */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100 + 1); - - /* disable interrupts since they are enabled */ - /* after device reset during selftest */ - e100_disable_clear_intr(bdp); - - /* if The First Self Test DWORD Still Zero, We've timed out. If the - * second DWORD is not zero then we have an error. */ - if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) { - - if (st_timeout) - *st_timeout = !(le32_to_cpu(bdp->selftest->st_sign)); - - if (st_result) - *st_result = le32_to_cpu(bdp->selftest->st_result); - - return false; - } - - return true; -} - -/** - * e100_setup_iaaddr - issue IA setup sommand - * @bdp: atapter's private data struct - * @eaddr: new ethernet address - * - * This routine will issue the IA setup command. This command - * will notify the 82557 (e100) of what its individual (node) - * address is. This command will be executed in polled mode. - * - * Returns: - * true: if the IA setup command was successfully issued and completed - * false: otherwise - */ -unsigned char -e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr) -{ - unsigned int i; - cb_header_t *ntcb_hdr; - unsigned char res; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - res = false; - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS); + if(start + count >= nic->eeprom_wc) + return -EINVAL; - for (i = 0; i < ETH_ALEN; i++) { - (cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i]; - } + for(addr = start; addr < start + count; addr++) + e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]); - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: IA setup failed\n", - bdp->device->name); + /* The checksum, stored in the last word, is calculated such that + * the sum of words should be 0xBABA */ + for(addr = 0; addr < nic->eeprom_wc - 1; addr++) + checksum += cpu_to_le16(nic->eeprom[addr]); + nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum); + e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, + nic->eeprom[nic->eeprom_wc - 1]); -exit: - return res; + return 0; } -/** - * e100_start_ru - start the RU if needed - * @bdp: atapter's private data struct - * - * This routine checks the status of the 82557's receive unit(RU), - * and starts the RU if it was not already active. However, - * before restarting the RU, the driver gives the RU the buffers - * it freed up during the servicing of the ISR. If there are - * no free buffers to give to the RU, (i.e. we have reached a - * no resource condition) the RU will not be started till the - * next ISR. - */ -void -e100_start_ru(struct e100_private *bdp) +#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */ +#define E100_WAIT_SCB_FAST 20 /* delay like the old code */ +static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) { - struct rx_list_elem *rx_struct = NULL; - int buffer_found = 0; - struct list_head *entry_ptr; - - list_for_each(entry_ptr, &(bdp->active_rx_list)) { - rx_struct = - list_entry(entry_ptr, struct rx_list_elem, list_elem); - pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, - bdp->rfd_size, PCI_DMA_FROMDEVICE); - if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) & - __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) { - buffer_found = 1; - break; - } - } - - /* No available buffers */ - if (!buffer_found) { - return; - } + unsigned long flags; + unsigned int i; + int err = 0; - spin_lock(&bdp->bd_lock); + spin_lock_irqsave(&nic->cmd_lock, flags); - if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) { - printk(KERN_DEBUG - "e100: %s: start_ru: wait_scb failed\n", - bdp->device->name); - e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START); + /* Previous command is accepted when SCB clears */ + for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { + if(likely(!readb(&nic->csr->scb.cmd_lo))) + break; + cpu_relax(); + if(unlikely(i > E100_WAIT_SCB_FAST)) + udelay(5); } - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; + if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) { + err = -EAGAIN; + goto err_unlock; } - spin_unlock(&bdp->bd_lock); -} - -/** - * e100_cmd_complete_location - * @bdp: atapter's private data struct - * - * This routine returns a pointer to the location of the command-complete - * DWord in the dump statistical counters area, according to the statistical - * counters mode (557 - basic, 558 - extended, or 559 - TCO mode). - * See e100_config_init() for the setting of the statistical counters mode. - */ -static u32 * -e100_cmd_complete_location(struct e100_private *bdp) -{ - u32 *cmd_complete; - max_counters_t *stats = bdp->stats_counters; - switch (bdp->stat_mode) { - case E100_EXTENDED_STATS: - cmd_complete = - (u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete); - break; - - case E100_TCO_STATS: - cmd_complete = - (u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete); - break; + if(unlikely(cmd != cuc_resume)) + writel(dma_addr, &nic->csr->scb.gen_ptr); + writeb(cmd, &nic->csr->scb.cmd_lo); - case E100_BASIC_STATS: - default: - cmd_complete = - (u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete); - break; - } +err_unlock: + spin_unlock_irqrestore(&nic->cmd_lock, flags); - return cmd_complete; + return err; } -/** - * e100_clr_cntrs - clear statistics counters - * @bdp: atapter's private data struct - * - * This routine will clear the adapter error statistic counters. - * - * Returns: - * true: if successfully cleared stat counters - * false: otherwise - */ -static unsigned char -e100_clr_cntrs(struct e100_private *bdp) +static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) { - volatile u32 *pcmd_complete; + struct cb *cb; + unsigned long flags; + int err = 0; - /* clear the dump counter complete word */ - pcmd_complete = e100_cmd_complete_location(bdp); - *pcmd_complete = 0; - wmb(); + spin_lock_irqsave(&nic->cb_lock, flags); - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; + if(unlikely(!nic->cbs_avail)) { + err = -ENOMEM; + goto err_unlock; + } - /* wait 10 microseconds for the command to complete */ - udelay(10); + cb = nic->cb_to_use; + nic->cb_to_use = cb->next; + nic->cbs_avail--; + cb->skb = skb; - if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) - return false; + if(unlikely(!nic->cbs_avail)) + err = -ENOSPC; - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } + cb_prepare(nic, cb, skb); - return true; -} + /* Order is important otherwise we'll be in a race with h/w: + * set S-bit in current first, then clear S-bit in previous. */ + cb->command |= cpu_to_le16(cb_s); + wmb(); + cb->prev->command &= cpu_to_le16(~cb_s); -static unsigned char -e100_update_stats(struct e100_private *bdp) -{ - u32 *pcmd_complete; - basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats); - - // check if last dump command completed - pcmd_complete = e100_cmd_complete_location(bdp); - if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && - *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { - *pcmd_complete = 0; - return false; - } - - /* increment the statistics */ - bdp->drv_stats.net_stats.rx_packets += - le32_to_cpu(pstat->rcv_gd_frames); - bdp->drv_stats.net_stats.tx_packets += - le32_to_cpu(pstat->xmt_gd_frames); - bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll); - bdp->drv_stats.net_stats.rx_length_errors += - le32_to_cpu(pstat->rcv_shrt_frames); - bdp->drv_stats.net_stats.rx_over_errors += - le32_to_cpu(pstat->rcv_rsrc_err); - bdp->drv_stats.net_stats.rx_crc_errors += - le32_to_cpu(pstat->rcv_crc_errs); - bdp->drv_stats.net_stats.rx_frame_errors += - le32_to_cpu(pstat->rcv_algn_errs); - bdp->drv_stats.net_stats.rx_fifo_errors += - le32_to_cpu(pstat->rcv_oruns); - bdp->drv_stats.net_stats.tx_aborted_errors += - le32_to_cpu(pstat->xmt_max_coll); - bdp->drv_stats.net_stats.tx_carrier_errors += - le32_to_cpu(pstat->xmt_lost_crs); - bdp->drv_stats.net_stats.tx_fifo_errors += - le32_to_cpu(pstat->xmt_uruns); - - bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll); - bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred); - bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll); - bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll); - bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll); - - if (bdp->stat_mode != E100_BASIC_STATS) { - ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats; - - bdp->drv_stats.xmt_fc_pkts += - le32_to_cpu(pex_stat->xmt_fc_frames); - bdp->drv_stats.rcv_fc_pkts += - le32_to_cpu(pex_stat->rcv_fc_frames); - bdp->drv_stats.rcv_fc_unsupported += - le32_to_cpu(pex_stat->rcv_fc_unsupported); - } - - if (bdp->stat_mode == E100_TCO_STATS) { - tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats; - - bdp->drv_stats.xmt_tco_pkts += - le16_to_cpu(ptco_stat->xmt_tco_frames); - bdp->drv_stats.rcv_tco_pkts += - le16_to_cpu(ptco_stat->rcv_tco_frames); + while(nic->cb_to_send != nic->cb_to_use) { + if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd, + nic->cb_to_send->dma_addr))) { + /* Ok, here's where things get sticky. It's + * possible that we can't schedule the command + * because the controller is too busy, so + * let's just queue the command and try again + * when another command is scheduled. */ + if(err == -ENOSPC) { + //request a reset + schedule_work(&nic->tx_timeout_task); + } + break; + } else { + nic->cuc_cmd = cuc_resume; + nic->cb_to_send = nic->cb_to_send->next; + } } - *pcmd_complete = 0; - return true; +err_unlock: + spin_unlock_irqrestore(&nic->cb_lock, flags); + + return err; } -/** - * e100_dump_stat_cntrs - * @bdp: atapter's private data struct - * - * This routine will dump the board statistical counters without waiting - * for stat_dump to complete. Any access to this stats should verify the completion - * of the command - */ -void -e100_dump_stats_cntrs(struct e100_private *bdp) +static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) { - unsigned long lock_flag_bd; + u32 data_out = 0; + unsigned int i; + unsigned long flags; - spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd); - /* dump h/w stats counters */ - if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) { - if (bdp->next_cu_cmd == RESUME_NO_WAIT) { - bdp->next_cu_cmd = RESUME_WAIT; - } + /* + * Stratus87247: we shouldn't be writing the MDI control + * register until the Ready bit shows True. Also, since + * manipulation of the MDI control registers is a multi-step + * procedure it should be done under lock. + */ + spin_lock_irqsave(&nic->mdio_lock, flags); + for (i = 100; i; --i) { + if (readl(&nic->csr->mdi_ctrl) & mdi_ready) + break; + udelay(20); } + if (unlikely(!i)) { + printk("e100.mdio_ctrl(%s) won't go Ready\n", + nic->netdev->name ); + spin_unlock_irqrestore(&nic->mdio_lock, flags); + return 0; /* No way to indicate timeout error */ + } + writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd); + for (i = 0; i < 100; i++) { + udelay(20); + if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) + break; + } + spin_unlock_irqrestore(&nic->mdio_lock, flags); + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out); + return (u16)data_out; } -/** - * e100_exec_non_cu_cmd - * @bdp: atapter's private data struct - * @command: the non-cu command to execute - * - * This routine will submit a command block to be executed, - */ -unsigned char -e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) +static int mdio_read(struct net_device *netdev, int addr, int reg) { - cb_header_t *ntcb_hdr; - unsigned long lock_flag; - unsigned long expiration_time; - unsigned char rc = true; - u8 sub_cmd; - - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */ - sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd); - - /* Set the Command Block to be the last command block */ - ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT); - ntcb_hdr->cb_status = 0; - ntcb_hdr->cb_lnk_ptr = 0; + return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0); +} - wmb(); - if (in_interrupt()) - return e100_delayed_exec_non_cu_cmd(bdp, command); +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); +} - if (netif_running(bdp->device) && netif_carrier_ok(bdp->device)) - return e100_delayed_exec_non_cu_cmd(bdp, command); +static void e100_get_defaults(struct nic *nic) +{ + struct param_range rfds = { .min = 16, .max = 256, .count = 256 }; + struct param_range cbs = { .min = 64, .max = 256, .count = 128 }; - spin_lock_bh(&(bdp->bd_non_tx_lock)); + pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id); + /* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */ + nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id; + if(nic->mac == mac_unknown) + nic->mac = mac_82557_D100_A; - if (bdp->non_tx_command_state != E100_NON_TX_IDLE) { - goto delayed_exec; - } + nic->params.rfds = rfds; + nic->params.cbs = cbs; - if (bdp->last_tcb) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto delayed_exec; - } + /* Quadwords to DMA into FIFO before starting frame transmit */ + nic->tx_threshold = 0xE0; - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) { - goto delayed_exec; - } + /* no interrupt for every tx completion, delay = 256us if not 557*/ + nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf | + ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); - spin_lock_irqsave(&bdp->bd_lock, lock_flag); + /* Template for a freshly allocated RFD */ + nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.rbd = 0xFFFFFFFF; + nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); - if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) { - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); - rc = false; - goto exit; - } + /* MII setup */ + nic->mii.phy_id_mask = 0x1F; + nic->mii.reg_num_mask = 0x1F; + nic->mii.dev = nic->netdev; + nic->mii.mdio_read = mdio_read; + nic->mii.mdio_write = mdio_write; +} - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); +static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct config *config = &cb->u.config; + u8 *c = (u8 *)config; - /* now wait for completion of non-cu CB up to 20 msec */ - expiration_time = jiffies + HZ / 50 + 1; - rmb(); - while (!(ntcb_hdr->cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE))) { + cb->command = cpu_to_le16(cb_config); - if (time_before(jiffies, expiration_time)) { - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - yield(); - spin_lock_bh(&(bdp->bd_non_tx_lock)); - } else { -#ifdef E100_CU_DEBUG - printk(KERN_ERR "e100: %s: non-TX command (%x) " - "timeout\n", bdp->device->name, sub_cmd); -#endif - rc = false; - goto exit; - } - rmb(); - } + memset(config, 0, sizeof(struct config)); -exit: - e100_free_non_tx_cmd(bdp, command); + config->byte_count = 0x16; /* bytes in this struct */ + config->rx_fifo_limit = 0x8; /* bytes in FIFO before DMA */ + config->direct_rx_dma = 0x1; /* reserved */ + config->standard_tcb = 0x1; /* 1=standard, 0=extended */ + config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ + config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ + config->tx_underrun_retry = 0x3; /* # of underrun retries */ + config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + config->pad10 = 0x6; + config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ + config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ + config->ifs = 0x6; /* x16 = inter frame spacing */ + config->ip_addr_hi = 0xF2; /* ARP IP filter - not used */ + config->pad15_1 = 0x1; + config->pad15_2 = 0x1; + config->crs_or_cdt = 0x0; /* 0=CRS only, 1=CRS or CDT */ + config->fc_delay_hi = 0x40; /* time delay for fc frame */ + config->tx_padding = 0x1; /* 1=pad short frames */ + config->fc_priority_threshold = 0x7; /* 7=priority fc disabled */ + config->pad18 = 0x1; + config->full_duplex_pin = 0x1; /* 1=examine FDX# pin */ + config->pad20_1 = 0x1F; + config->fc_priority_location = 0x1; /* 1=byte#31, 0=byte#19 */ + config->pad21_1 = 0x5; - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); + config->adaptive_ifs = nic->adaptive_ifs; + config->loopback = nic->loopback; - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return rc; + if(nic->mii.force_media && nic->mii.full_duplex) + config->full_duplex_force = 0x1; /* 1=force, 0=auto */ -delayed_exec: - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return e100_delayed_exec_non_cu_cmd(bdp, command); -} + if(nic->flags & promiscuous || nic->loopback) { + config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */ + config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */ + config->promiscuous_mode = 0x1; /* 1=on, 0=off */ + } -/** - * e100_sw_reset - * @bdp: atapter's private data struct - * @reset_cmd: s/w reset or selective reset - * - * This routine will issue a software reset to the adapter. It - * will also disable interrupts, as the are enabled after reset. - */ -void -e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) -{ - /* Do a selective reset first to avoid a potential PCI hang */ - writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port); - readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ - - /* wait for the reset to take effect */ - udelay(20); - if (reset_cmd == PORT_SOFTWARE_RESET) { - writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port); + if(nic->flags & multicast_all) + config->multicast_all = 0x1; /* 1=accept, 0=no */ - /* wait 20 micro seconds for the reset to take effect */ - udelay(20); + /* disable WoL when up */ + if(netif_running(nic->netdev) || !(nic->flags & wol_magic)) + config->magic_packet_disable = 0x1; /* 1=off, 0=on */ + + if(nic->mac >= mac_82558_D101_A4) { + config->fc_disable = 0x1; /* 1=Tx fc off, 0=Tx fc on */ + config->mwi_enable = 0x1; /* 1=enable, 0=disable */ + config->standard_tcb = 0x0; /* 1=standard, 0=extended */ + config->rx_long_ok = 0x1; /* 1=VLANs ok, 0=standard */ + if(nic->mac >= mac_82559_D101M) + config->tno_intr = 0x1; /* TCO stats enable */ + else + config->standard_stat_counter = 0x0; } - /* Mask off our interrupt line -- it is unmasked after reset */ - e100_disable_clear_intr(bdp); -#ifdef E100_CU_DEBUG - bdp->last_cmd = 0; - bdp->last_sub_cmd = 0; -#endif + DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); + DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); + DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); +} + +/********************************************************/ +/* Micro code for 8086:1229 Rev 8 */ +/********************************************************/ + +/* Parameter values for the D101M B-step */ +#define D101M_CPUSAVER_TIMER_DWORD 78 +#define D101M_CPUSAVER_BUNDLE_DWORD 65 +#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 + +#define D101M_B_RCVBUNDLE_UCODE \ +{\ +0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ +0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ +0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ +0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ +0x00380438, 0x00000000, 0x00140000, 0x00380555, \ +0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ +0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ +0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ +0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ +0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ +0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ +0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ +0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ +0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ +0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ +0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ +0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ +0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ +0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ +0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ +0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ +0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ +0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ +0x00380559, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ +0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ +0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ +} + +/********************************************************/ +/* Micro code for 8086:1229 Rev 9 */ +/********************************************************/ + +/* Parameter values for the D101S */ +#define D101S_CPUSAVER_TIMER_DWORD 78 +#define D101S_CPUSAVER_BUNDLE_DWORD 67 +#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 + +#define D101S_RCVBUNDLE_UCODE \ +{\ +0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ +0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ +0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ +0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ +0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ +0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ +0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ +0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ +0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ +0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ +0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ +0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ +0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ +0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ +0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ +0x00101313, 0x00380700, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ +0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ +0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ +0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ +0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ +0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ +0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ +0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ +0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ +0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00130831, \ +0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ +0x00041000, 0x00010004, 0x00380700 \ +} + +/********************************************************/ +/* Micro code for the 8086:1229 Rev F/10 */ +/********************************************************/ + +/* Parameter values for the D102 E-step */ +#define D102_E_CPUSAVER_TIMER_DWORD 42 +#define D102_E_CPUSAVER_BUNDLE_DWORD 54 +#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 + +#define D102_E_RCVBUNDLE_UCODE \ +{\ +0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \ +0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ +0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ +0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ +0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ +0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ +0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ +0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \ +0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ +0x00000000, 0x00000000, 0x00000000, 0x00000000, \ } -/** - * e100_load_microcode - Download microsocde to controller. - * @bdp: atapter's private data struct - * - * This routine downloads microcode on to the controller. This - * microcode is available for the 82558/9, 82550. Currently the - * microcode handles interrupt bundling and TCO workaround. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char -e100_load_microcode(struct e100_private *bdp) +static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) { +/* *INDENT-OFF* */ static struct { - u8 rev_id; - u32 ucode[UCODE_MAX_DWORDS + 1]; - int timer_dword; - int bundle_dword; - int min_size_dword; + u32 ucode[UCODE_SIZE + 1]; + u8 mac; + u8 timer_dword; + u8 bundle_dword; + u8 min_size_dword; } ucode_opts[] = { - { D101A4_REV_ID, - D101_A_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101B0_REV_ID, - D101_B0_RCVBUNDLE_UCODE, - D101_CPUSAVER_TIMER_DWORD, - D101_CPUSAVER_BUNDLE_DWORD, - D101_CPUSAVER_MIN_SIZE_DWORD }, - { D101MA_REV_ID, - D101M_B_RCVBUNDLE_UCODE, + { D101M_B_RCVBUNDLE_UCODE, + mac_82559_D101M, D101M_CPUSAVER_TIMER_DWORD, D101M_CPUSAVER_BUNDLE_DWORD, D101M_CPUSAVER_MIN_SIZE_DWORD }, - { D101S_REV_ID, - D101S_RCVBUNDLE_UCODE, + { D101S_RCVBUNDLE_UCODE, + mac_82559_D101S, D101S_CPUSAVER_TIMER_DWORD, D101S_CPUSAVER_BUNDLE_DWORD, D101S_CPUSAVER_MIN_SIZE_DWORD }, - { D102_REV_ID, - D102_B_RCVBUNDLE_UCODE, - D102_B_CPUSAVER_TIMER_DWORD, - D102_B_CPUSAVER_BUNDLE_DWORD, - D102_B_CPUSAVER_MIN_SIZE_DWORD }, - { D102C_REV_ID, - D102_C_RCVBUNDLE_UCODE, - D102_C_CPUSAVER_TIMER_DWORD, - D102_C_CPUSAVER_BUNDLE_DWORD, - D102_C_CPUSAVER_MIN_SIZE_DWORD }, - { D102E_REV_ID, - D102_E_RCVBUNDLE_UCODE, + { D102_E_RCVBUNDLE_UCODE, + mac_82551_F, D102_E_CPUSAVER_TIMER_DWORD, D102_E_CPUSAVER_BUNDLE_DWORD, D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { D102E_A1_REV_ID, - D102_E_RCVBUNDLE_UCODE, + { D102_E_RCVBUNDLE_UCODE, + mac_82551_10, D102_E_CPUSAVER_TIMER_DWORD, D102_E_CPUSAVER_BUNDLE_DWORD, D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { 0, {0}, 0, 0, 0} + { {0}, 0, 0, 0, 0} }, *opts; +/* *INDENT-ON* */ - opts = ucode_opts; - - /* User turned ucode loading off */ - if (!(bdp->params.b_params & PRM_UCODE)) - return false; - - /* These controllers do not need ucode */ - if (bdp->flags & IS_ICH) - return false; +/************************************************************************* +* CPUSaver parameters +* +* All CPUSaver parameters are 16-bit literals that are part of a +* "move immediate value" instruction. By changing the value of +* the literal in the instruction before the code is loaded, the +* driver can change the algorithm. +* +* INTDELAY - This loads the dead-man timer with its inital value. +* When this timer expires the interrupt is asserted, and the +* timer is reset each time a new packet is received. (see +* BUNDLEMAX below to set the limit on number of chained packets) +* The current default is 0x600 or 1536. Experiments show that +* the value should probably stay within the 0x200 - 0x1000. +* +* BUNDLEMAX - +* This sets the maximum number of frames that will be bundled. In +* some situations, such as the TCP windowing algorithm, it may be +* better to limit the growth of the bundle size than let it go as +* high as it can, because that could cause too much added latency. +* The default is six, because this is the number of packets in the +* default TCP window size. A value of 1 would make CPUSaver indicate +* an interrupt for every frame received. If you do not want to put +* a limit on the bundle size, set this value to xFFFF. +* +* BUNDLESMALL - +* This contains a bit-mask describing the minimum size frame that +* will be bundled. The default masks the lower 7 bits, which means +* that any frame less than 128 bytes in length will not be bundled, +* but will instead immediately generate an interrupt. This does +* not affect the current bundle in any way. Any frame that is 128 +* bytes or large will be bundled normally. This feature is meant +* to provide immediate indication of ACK frames in a TCP environment. +* Customers were seeing poor performance when a machine with CPUSaver +* enabled was sending but not receiving. The delay introduced when +* the ACKs were received was enough to reduce total throughput, because +* the sender would sit idle until the ACK was finally seen. +* +* The current default is 0xFF80, which masks out the lower 7 bits. +* This means that any frame which is x7F (127) bytes or smaller +* will cause an immediate interrupt. Because this value must be a +* bit mask, there are only a few valid values that can be used. To +* turn this feature off, the driver can write the value xFFFF to the +* lower word of this instruction (in the same way that the other +* parameters are used). Likewise, a value of 0xF800 (2047) would +* cause an interrupt to be generated for every frame, because all +* standard Ethernet frames are <= 2047 bytes in length. +*************************************************************************/ + +/* if you wish to disable the ucode functionality, while maintaining the + * workarounds it provides, set the following defines to: + * BUNDLESMALL 0 + * BUNDLEMAX 1 + * INTDELAY 1 + */ +#define BUNDLESMALL 1 +#define BUNDLEMAX (u16)6 +#define INTDELAY (u16)1536 /* 0x600 */ + + /* do not load u-code for ICH devices */ + if (nic->flags & ich) + goto noloaducode; /* Search for ucode match against h/w rev_id */ - while (opts->rev_id) { - if (bdp->rev_id == opts->rev_id) { - int i; - u32 *ucode_dword; - load_ucode_cb_t *ucode_cmd_ptr; - nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); - - if (cmd != NULL) { - ucode_cmd_ptr = - (load_ucode_cb_t *) cmd->non_tx_cmd; - ucode_dword = ucode_cmd_ptr->ucode_dword; - } else { - return false; - } + for (opts = ucode_opts; opts->mac; opts++) { + int i; + u32 *ucode = opts->ucode; + if (nic->mac != opts->mac) + continue; + + /* Insert user-tunable settings */ + ucode[opts->timer_dword] &= 0xFFFF0000; + ucode[opts->timer_dword] |= INTDELAY; + ucode[opts->bundle_dword] &= 0xFFFF0000; + ucode[opts->bundle_dword] |= BUNDLEMAX; + ucode[opts->min_size_dword] &= 0xFFFF0000; + ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80; + + for (i = 0; i < UCODE_SIZE; i++) + cb->u.ucode[i] = cpu_to_le32(ucode[i]); + cb->command = cpu_to_le16(cb_ucode | cb_el); + return; + } + +noloaducode: + cb->command = cpu_to_le16(cb_nop | cb_el); +} - memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode)); +static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, + void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) +{ + int err = 0, counter = 50; + struct cb *cb = nic->cb_to_clean; - /* Insert user-tunable settings */ - ucode_dword[opts->timer_dword] &= 0xFFFF0000; - ucode_dword[opts->timer_dword] |= - (u16) bdp->params.IntDelay; - ucode_dword[opts->bundle_dword] &= 0xFFFF0000; - ucode_dword[opts->bundle_dword] |= - (u16) bdp->params.BundleMax; - ucode_dword[opts->min_size_dword] &= 0xFFFF0000; - ucode_dword[opts->min_size_dword] |= - (bdp->params.b_params & PRM_BUNDLE_SMALL) ? - 0xFFFF : 0xFF80; + if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode))) + DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err); - for (i = 0; i < UCODE_MAX_DWORDS; i++) - cpu_to_le32s(&(ucode_dword[i])); + /* must restart cuc */ + nic->cuc_cmd = cuc_start; - ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd = - __constant_cpu_to_le16(CB_LOAD_MICROCODE); + /* wait for completion */ + e100_write_flush(nic); + udelay(10); - return e100_exec_non_cu_cmd(bdp, cmd); - } - opts++; + /* wait for possibly (ouch) 500ms */ + while (!(cb->status & cpu_to_le16(cb_complete))) { + msleep(10); + if (!--counter) break; } - return false; -} + /* ack any interupts, something could have been set */ + writeb(~0, &nic->csr->scb.stat_ack); -/***************************************************************************/ -/***************************************************************************/ -/* EEPROM Functions */ -/***************************************************************************/ + /* if the command failed, or is not OK, notify and return */ + if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { + DPRINTK(PROBE,ERR, "ucode load failed\n"); + err = -EPERM; + } -/* Read PWA (printed wired assembly) number */ -void __devinit -e100_rd_pwa_no(struct e100_private *bdp) + return err; +} +static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, + struct sk_buff *skb) { - bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO); - bdp->pwa_no <<= 16; - bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1); + cb->command = cpu_to_le16(cb_iaaddr); + memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); } -/* Read the permanent ethernet address from the eprom. */ -void __devinit -e100_rd_eaddr(struct e100_private *bdp) +static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) { - int i; - u16 eeprom_word; + cb->command = cpu_to_le16(cb_dump); + cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr + + offsetof(struct mem, dump_buf)); +} - for (i = 0; i < 6; i += 2) { - eeprom_word = - e100_eeprom_read(bdp, - EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2)); - - bdp->device->dev_addr[i] = - bdp->perm_node_address[i] = (u8) eeprom_word; - bdp->device->dev_addr[i + 1] = - bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8); +#define NCONFIG_AUTO_SWITCH 0x0080 +#define MII_NSC_CONG MII_RESV1 +#define NSC_CONG_ENABLE 0x0100 +#define NSC_CONG_TXREADY 0x0400 +#define ADVERTISE_FC_SUPPORTED 0x0400 +static int e100_phy_init(struct nic *nic) +{ + struct net_device *netdev = nic->netdev; + u32 addr; + u16 bmcr, stat, id_lo, id_hi, cong; + + /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ + for(addr = 0; addr < 32; addr++) { + nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; + bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR); + if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) + break; + } + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); + if(addr == 32) + return -EAGAIN; + + /* Selected the phy and isolate the rest */ + for(addr = 0; addr < 32; addr++) { + if(addr != nic->mii.phy_id) { + mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); + } else { + bmcr = mdio_read(netdev, addr, MII_BMCR); + mdio_write(netdev, addr, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } } -} -/* Check the D102 RFD flags to see if the checksum passed */ -static unsigned char -e100_D102_check_checksum(rfd_t *rfd) -{ - if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT) - && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_TCP_PACKET) - || ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) == - RFD_UDP_PACKET)) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID) - && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) { - return CHECKSUM_UNNECESSARY; + /* Get phy ID */ + id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); + id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2); + nic->phy = (u32)id_hi << 16 | (u32)id_lo; + DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy); + + /* Handle National tx phys */ +#define NCS_PHY_MODEL_MASK 0xFFF0FFFF + if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) { + /* Disable congestion control */ + cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG); + cong |= NSC_CONG_TXREADY; + cong &= ~NSC_CONG_ENABLE; + mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong); + } + + if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && + (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && + !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { + /* enable/disable MDI/MDI-X auto-switching. */ + mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, + nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); } - return CHECKSUM_NONE; + + return 0; } -/** - * e100_D101M_checksum - * @bdp: atapter's private data struct - * @skb: skb received - * - * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The - * D101M sums all words in frame excluding the ethernet II header (14 bytes) so - * in case the packet is ethernet II and the protocol is IP, all is need is to - * assign this value to skb->csum. - */ -static unsigned char -e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb) +static int e100_hw_init(struct nic *nic) { - unsigned short proto = (skb->protocol); + int err; - if (proto == __constant_htons(ETH_P_IP)) { + e100_hw_reset(nic); - skb->csum = get_unaligned((u16 *) (skb->tail)); - return CHECKSUM_HW; - } - return CHECKSUM_NONE; + DPRINTK(HW, ERR, "e100_hw_init\n"); + if(!in_interrupt() && (err = e100_self_test(nic))) + return err; + + if((err = e100_phy_init(nic))) + return err; + if((err = e100_exec_cmd(nic, cuc_load_base, 0))) + return err; + if((err = e100_exec_cmd(nic, ruc_load_base, 0))) + return err; + if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_configure))) + return err; + if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_addr, + nic->dma_addr + offsetof(struct mem, stats)))) + return err; + if((err = e100_exec_cmd(nic, cuc_dump_reset, 0))) + return err; + + e100_disable_irq(nic); + + return 0; +} + +static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +{ + struct net_device *netdev = nic->netdev; + struct dev_mc_list *list = netdev->mc_list; + u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS); + + cb->command = cpu_to_le16(cb_multi); + cb->u.multi.count = cpu_to_le16(count * ETH_ALEN); + for(i = 0; list && i < count; i++, list = list->next) + memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr, + ETH_ALEN); } -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/***************************************************************************/ -/* Auxilary Functions */ -/***************************************************************************/ +static void e100_set_multicast_list(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + + DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n", + netdev->mc_count, netdev->flags); + + if(netdev->flags & IFF_PROMISC) + nic->flags |= promiscuous; + else + nic->flags &= ~promiscuous; + + if(netdev->flags & IFF_ALLMULTI || + netdev->mc_count > E100_MAX_MULTICAST_ADDRS) + nic->flags |= multicast_all; + else + nic->flags &= ~multicast_all; + + e100_exec_cb(nic, NULL, e100_configure); + e100_exec_cb(nic, NULL, e100_multi); +} -/* Print the board's configuration */ -void __devinit -e100_print_brd_conf(struct e100_private *bdp) +static void e100_update_stats(struct nic *nic) { - /* Print the string if checksum Offloading was enabled */ - if (bdp->flags & DF_CSUM_OFFLOAD) - printk(KERN_NOTICE " Hardware receive checksums enabled\n"); - else { - if (bdp->rev_id >= D101MA_REV_ID) - printk(KERN_NOTICE " Hardware receive checksums disabled\n"); + struct net_device_stats *ns = &nic->net_stats; + struct stats *s = &nic->mem->stats; + u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : + (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : + &s->complete; + + /* Device's stats reporting may take several microseconds to + * complete, so where always waiting for results of the + * previous command. */ + + if(*complete == le32_to_cpu(cuc_dump_reset_complete)) { + *complete = 0; + nic->tx_frames = le32_to_cpu(s->tx_good_frames); + nic->tx_collisions = le32_to_cpu(s->tx_total_collisions); + ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions); + ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions); + ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs); + ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns); + ns->collisions += nic->tx_collisions; + ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + + le32_to_cpu(s->tx_lost_crs); + ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + + nic->rx_over_length_errors; + ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); + ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); + ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors); + ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + + le32_to_cpu(s->rx_alignment_errors) + + le32_to_cpu(s->rx_short_frame_errors) + + le32_to_cpu(s->rx_cdt_errors); + nic->tx_deferred += le32_to_cpu(s->tx_deferred); + nic->tx_single_collisions += + le32_to_cpu(s->tx_single_collisions); + nic->tx_multiple_collisions += + le32_to_cpu(s->tx_multiple_collisions); + if(nic->mac >= mac_82558_D101_A4) { + nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause); + nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause); + nic->rx_fc_unsupported += + le32_to_cpu(s->fc_rcv_unsupported); + if(nic->mac >= mac_82559_D101M) { + nic->tx_tco_frames += + le16_to_cpu(s->xmt_tco_frames); + nic->rx_tco_frames += + le16_to_cpu(s->rcv_tco_frames); + } + } } - if ((bdp->flags & DF_UCODE_LOADED)) - printk(KERN_NOTICE " cpu cycle saver enabled\n"); + if(e100_exec_cmd(nic, cuc_dump_reset, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n"); } -/** - * e100_pci_setup - setup the adapter's PCI information - * @pcid: adapter's pci_dev struct - * @bdp: atapter's private data struct - * - * This routine sets up all PCI information for the adapter. It enables the bus - * master bit (some BIOS don't do this), requests memory ans I/O regions, and - * calls ioremap() on the adapter's memory region. - * - * Returns: - * true: if successfull - * false: otherwise - */ -static unsigned char __devinit -e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp) +static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) { - struct net_device *dev = bdp->device; - int rc = 0; + /* Adjust inter-frame-spacing (IFS) between two transmits if + * we're getting collisions on a half-duplex connection. */ - if ((rc = pci_enable_device(pcid)) != 0) { - goto err; + if(duplex == DUPLEX_HALF) { + u32 prev = nic->adaptive_ifs; + u32 min_frames = (speed == SPEED_100) ? 1000 : 100; + + if((nic->tx_frames / 32 < nic->tx_collisions) && + (nic->tx_frames > min_frames)) { + if(nic->adaptive_ifs < 60) + nic->adaptive_ifs += 5; + } else if (nic->tx_frames < min_frames) { + if(nic->adaptive_ifs >= 5) + nic->adaptive_ifs -= 5; + } + if(nic->adaptive_ifs != prev) + e100_exec_cb(nic, NULL, e100_configure); } +} + +static void e100_watchdog(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + struct ethtool_cmd cmd; - /* dev and ven ID have already been checked so it is our device */ - pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id)); + DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies); - /* address #0 is a memory region */ - dev->mem_start = pci_resource_start(pcid, 0); - dev->mem_end = dev->mem_start + sizeof (scb_t); + /* mii library handles link maintenance tasks */ - /* address #1 is a IO region */ - dev->base_addr = pci_resource_start(pcid, 1); + mii_ethtool_gset(&nic->mii, &cmd); - if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) { - goto err_disable; + if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "full" : "half"); + } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { + DPRINTK(LINK, INFO, "link down\n"); } - pci_enable_wake(pcid, 0, 0); + mii_check_link(&nic->mii); - /* if Bus Mastering is off, turn it on! */ - pci_set_master(pcid); + /* Software generated interrupt to recover from (rare) Rx + * allocation failure. + * Unfortunately have to use a spinlock to not re-enable interrupts + * accidentally, due to hardware that shares a register between the + * interrupt mask bit and the SW Interrupt generation bit */ + spin_lock_irq(&nic->cmd_lock); + writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); + e100_write_flush(nic); + spin_unlock_irq(&nic->cmd_lock); - /* address #0 is a memory mapping */ - bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t)); + e100_update_stats(nic); + e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); - if (!bdp->scb) { - printk(KERN_ERR "e100: %s: Failed to map PCI address 0x%lX\n", - dev->name, pci_resource_start(pcid, 0)); - rc = -ENOMEM; - goto err_region; - } + if(nic->mac <= mac_82557_D100_C) + /* Issue a multicast command to workaround a 557 lock up */ + e100_set_multicast_list(nic->netdev); - return 0; + if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF) + /* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */ + nic->flags |= ich_10h_workaround; + else + nic->flags &= ~ich_10h_workaround; -err_region: - pci_release_regions(pcid); -err_disable: - pci_disable_device(pcid); -err: - return rc; -} - -void -e100_isolate_driver(struct e100_private *bdp) -{ - - /* Check if interface is up */ - /* NOTE: Can't use netif_running(bdp->device) because */ - /* dev_close clears __LINK_STATE_START before calling */ - /* e100_close (aka dev->stop) */ - if (bdp->device->flags & IFF_UP) { - e100_disable_clear_intr(bdp); - del_timer_sync(&bdp->watchdog_timer); - netif_carrier_off(bdp->device); - netif_stop_queue(bdp->device); - bdp->last_tcb = NULL; - } - e100_sw_reset(bdp, PORT_SELECTIVE_RESET); + mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); } -static void -e100_tcb_add_C_bit(struct e100_private *bdp) +static void e100_xmit_prepare(struct nic *nic, struct cb *cb, + struct sk_buff *skb) { - tcb_t *tcb = (tcb_t *) bdp->tcb_pool.data; - int i; + cb->command = nic->tx_command; + /* interrupt every 16 packets regardless of delay */ + if((nic->cbs_avail & ~15) == nic->cbs_avail) + cb->command |= cpu_to_le16(cb_i); + cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd); + cb->u.tcb.tcb_byte_count = 0; + cb->u.tcb.threshold = nic->tx_threshold; + cb->u.tcb.tbd_count = 1; + cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + /* check for mapping failure? */ + cb->u.tcb.tbd.size = cpu_to_le16(skb->len); +} + +static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + int err; + + if(nic->flags & ich_10h_workaround) { + /* SW workaround for ICH[x] 10Mbps/half duplex Tx hang. + Issue a NOP command followed by a 1us delay before + issuing the Tx command. */ + if(e100_exec_cmd(nic, cuc_nop, 0)) + DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n"); + udelay(1); + } + + err = e100_exec_cb(nic, skb, e100_xmit_prepare); - for (i = 0; i < bdp->params.TxDescriptors; i++, tcb++) { - tcb->tcb_hdr.cb_status |= cpu_to_le16(CB_STATUS_COMPLETE); + switch(err) { + case -ENOSPC: + /* We queued the skb, but now we're out of space. */ + DPRINTK(TX_ERR, DEBUG, "No space for CB\n"); + netif_stop_queue(netdev); + break; + case -ENOMEM: + /* This is a hard error - log it. */ + DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); + netif_stop_queue(netdev); + return 1; } + + netdev->trans_start = jiffies; + return 0; } -/* - * Procedure: e100_configure_device - * - * Description: This routine will configure device - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * true upon success - * false upon failure - */ -unsigned char -e100_configure_device(struct e100_private *bdp) +static int e100_tx_clean(struct nic *nic) { - /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; + struct cb *cb; + int tx_cleaned = 0; - if (e100_load_microcode(bdp)) - bdp->flags |= DF_UCODE_LOADED; + spin_lock(&nic->cb_lock); - if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; + /* Clean CBs marked complete */ + for(cb = nic->cb_to_clean; + cb->status & cpu_to_le16(cb_complete); + cb = nic->cb_to_clean = cb->next) { + DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n", + (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)), + cb->status); - /* Issue the load dump counters address command */ - if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0)) - return false; + if(likely(cb->skb != NULL)) { + nic->net_stats.tx_packets++; + nic->net_stats.tx_bytes += cb->skb->len; - if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) { - printk(KERN_ERR "e100: e100_configure_device: " - "setup iaaddr failed\n"); - return false; + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(cb->skb); + cb->skb = NULL; + tx_cleaned = 1; + } + cb->status = 0; + nic->cbs_avail++; } - e100_set_multi_exec(bdp->device); + spin_unlock(&nic->cb_lock); - /* Change for 82558 enhancement */ - /* If 82558/9 and if the user has enabled flow control, set up */ - /* flow Control Reg. in the CSR */ - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - writeb(DFLT_FC_THLD, - &bdp->scb->scb_ext.d101_scb.scb_fc_thld); - writeb(DFLT_FC_CMD, - &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); - } + /* Recover from running out of Tx resources in xmit_frame */ + if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev))) + netif_wake_queue(nic->netdev); - e100_force_config(bdp); + return tx_cleaned; +} - return true; +static void e100_clean_cbs(struct nic *nic) +{ + if(nic->cbs) { + while(nic->cbs_avail != nic->params.cbs.count) { + struct cb *cb = nic->cb_to_clean; + if(cb->skb) { + pci_unmap_single(nic->pdev, + le32_to_cpu(cb->u.tcb.tbd.buf_addr), + le16_to_cpu(cb->u.tcb.tbd.size), + PCI_DMA_TODEVICE); + dev_kfree_skb(cb->skb); + } + nic->cb_to_clean = nic->cb_to_clean->next; + nic->cbs_avail++; + } + pci_free_consistent(nic->pdev, + sizeof(struct cb) * nic->params.cbs.count, + nic->cbs, nic->cbs_dma_addr); + nic->cbs = NULL; + nic->cbs_avail = 0; + } + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = + nic->cbs; } -void -e100_deisolate_driver(struct e100_private *bdp, u8 full_reset) +static int e100_alloc_cbs(struct nic *nic) { - u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET; - e100_sw_reset(bdp, cmd); - if (cmd == PORT_SOFTWARE_RESET) { - if (!e100_configure_device(bdp)) - printk(KERN_ERR "e100: e100_deisolate_driver:" - " device configuration failed\n"); - } + struct cb *cb; + unsigned int i, count = nic->params.cbs.count; - if (netif_running(bdp->device)) { + nic->cuc_cmd = cuc_start; + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL; + nic->cbs_avail = 0; - bdp->next_cu_cmd = START_WAIT; - bdp->last_tcb = NULL; + nic->cbs = pci_alloc_consistent(nic->pdev, + sizeof(struct cb) * count, &nic->cbs_dma_addr); + if(!nic->cbs) + return -ENOMEM; - e100_start_ru(bdp); + for(cb = nic->cbs, i = 0; i < count; cb++, i++) { + cb->next = (i + 1 < count) ? cb + 1 : nic->cbs; + cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1; + + cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); + cb->link = cpu_to_le32(nic->cbs_dma_addr + + ((i+1) % count) * sizeof(struct cb)); + cb->skb = NULL; + } - /* relaunch watchdog timer in 2 sec */ - mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); + nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; + nic->cbs_avail = count; - // we must clear tcbs since we may have lost Tx intrrupt - // or have unsent frames on the tcb chain - e100_tcb_add_C_bit(bdp); - e100_tx_srv(bdp); - netif_wake_queue(bdp->device); - e100_set_intr_mask(bdp); - } + return 0; } -static int -e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) +static inline void e100_start_receiver(struct nic *nic, struct rx *rx) { - struct ethtool_cmd ecmd; - int rc = -EOPNOTSUPP; + if(!nic->rxs) return; + if(RU_SUSPENDED != nic->ru_running) return; - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd))) - return -EFAULT; + /* handle init time starts */ + if(!rx) rx = nic->rxs; - switch (ecmd.cmd) { - case ETHTOOL_GSET: - rc = e100_ethtool_get_settings(dev, ifr); - break; - case ETHTOOL_SSET: - rc = e100_ethtool_set_settings(dev, ifr); - break; - case ETHTOOL_GDRVINFO: - rc = e100_ethtool_get_drvinfo(dev, ifr); - break; - case ETHTOOL_GREGS: - rc = e100_ethtool_gregs(dev, ifr); - break; - case ETHTOOL_NWAY_RST: - rc = e100_ethtool_nway_rst(dev, ifr); - break; - case ETHTOOL_GLINK: - rc = e100_ethtool_glink(dev, ifr); - break; - case ETHTOOL_GEEPROM: - case ETHTOOL_SEEPROM: - rc = e100_ethtool_eeprom(dev, ifr); - break; - case ETHTOOL_GSTATS: { - struct { - struct ethtool_stats cmd; - uint64_t data[E100_STATS_LEN]; - } stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} }; - struct e100_private *bdp = dev->priv; - void *addr = ifr->ifr_data; - int i; + /* (Re)start RU if suspended or idle and RFA is non-NULL */ + if(rx->skb) { + e100_exec_cmd(nic, ruc_start, rx->dma_addr); + nic->ru_running = RU_RUNNING; + } +} - for(i = 0; i < E100_NET_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&bdp->drv_stats.net_stats)[i]; - stats.data[i++] = bdp->drv_stats.tx_late_col; - stats.data[i++] = bdp->drv_stats.tx_ok_defrd; - stats.data[i++] = bdp->drv_stats.tx_one_retry; - stats.data[i++] = bdp->drv_stats.tx_mt_one_retry; - stats.data[i++] = bdp->drv_stats.rcv_cdt_frames; - stats.data[i++] = bdp->drv_stats.xmt_fc_pkts; - stats.data[i++] = bdp->drv_stats.rcv_fc_pkts; - stats.data[i++] = bdp->drv_stats.rcv_fc_unsupported; - stats.data[i++] = bdp->drv_stats.xmt_tco_pkts; - stats.data[i++] = bdp->drv_stats.rcv_tco_pkts; - if(copy_to_user(addr, &stats, sizeof(stats))) - return -EFAULT; - return 0; +#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) +static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) +{ + if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + + NET_IP_ALIGN))) + return -ENOMEM; + + /* Align, init, and map the RFD. */ + skb_reserve(rx->skb, NET_IP_ALIGN); + memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd)); + rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, + RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); + + if(pci_dma_mapping_error(rx->dma_addr)) { + dev_kfree_skb_any(rx->skb); + rx->skb = NULL; + rx->dma_addr = 0; + return -ENOMEM; } - case ETHTOOL_GWOL: - case ETHTOOL_SWOL: - rc = e100_ethtool_wol(dev, ifr); - break; - case ETHTOOL_TEST: - rc = e100_ethtool_test(dev, ifr); - break; - case ETHTOOL_GSTRINGS: - rc = e100_ethtool_gstrings(dev,ifr); - break; - case ETHTOOL_PHYS_ID: - rc = e100_ethtool_led_blink(dev,ifr); - break; -#ifdef ETHTOOL_GRINGPARAM - case ETHTOOL_GRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - memset((void *) &ering, 0, sizeof(ering)); - ering.rx_max_pending = E100_MAX_RFD; - ering.tx_max_pending = E100_MAX_TCB; - ering.rx_pending = bdp->params.RxDescriptors; - ering.tx_pending = bdp->params.TxDescriptors; - rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) - ? -EFAULT : 0; - return rc; + + /* Link the RFD to end of RFA by linking previous RFD to + * this one, and clearing EL bit of previous. */ + if(rx->prev->skb) { + struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; + put_unaligned(cpu_to_le32(rx->dma_addr), + (u32 *)&prev_rfd->link); + wmb(); + prev_rfd->command &= ~cpu_to_le16(cb_el); + pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); } + + return 0; +} + +static int e100_rx_indicate(struct nic *nic, struct rx *rx, + unsigned int *work_done, unsigned int work_to_do) +{ + struct sk_buff *skb = rx->skb; + struct rfd *rfd = (struct rfd *)skb->data; + u16 rfd_status, actual_size; + + if(unlikely(work_done && *work_done >= work_to_do)) + return -EAGAIN; + + /* Need to sync before taking a peek at cb_complete bit */ + pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); + rfd_status = le16_to_cpu(rfd->status); + + DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); + + /* If data isn't ready, nothing to indicate */ + if(unlikely(!(rfd_status & cb_complete))) + return -ENODATA; + + /* Get actual data size */ + actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; + if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd))) + actual_size = RFD_BUF_LEN - sizeof(struct rfd); + + /* Get data */ + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + /* this allows for a fast restart without re-enabling interrupts */ + if(le16_to_cpu(rfd->command) & cb_el) + nic->ru_running = RU_SUSPENDED; + + /* Pull off the RFD and put the actual data (minus eth hdr) */ + skb_reserve(skb, sizeof(struct rfd)); + skb_put(skb, actual_size); + skb->protocol = eth_type_trans(skb, nic->netdev); + + if(unlikely(!(rfd_status & cb_ok))) { + /* Don't indicate if hardware indicates errors */ + dev_kfree_skb_any(skb); + } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) { + /* Don't indicate oversized frames */ + nic->rx_over_length_errors++; + dev_kfree_skb_any(skb); + } else { + nic->net_stats.rx_packets++; + nic->net_stats.rx_bytes += actual_size; + nic->netdev->last_rx = jiffies; +#ifdef CONFIG_E100_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); #endif -#ifdef ETHTOOL_SRINGPARAM - case ETHTOOL_SRINGPARAM: { - struct ethtool_ringparam ering; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) - return -EFAULT; - if (ering.rx_pending > E100_MAX_RFD - || ering.rx_pending < E100_MIN_RFD) - return -EINVAL; - if (ering.tx_pending > E100_MAX_TCB - || ering.tx_pending < E100_MIN_TCB) - return -EINVAL; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - /* Use new values to open interface */ - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - e100_hw_init(bdp); - e100_open(dev); - } - else { - bdp->params.RxDescriptors = ering.rx_pending; - bdp->params.TxDescriptors = ering.tx_pending; - } - return 0; + if(work_done) + (*work_done)++; } -#endif -#ifdef ETHTOOL_GPAUSEPARAM - case ETHTOOL_GPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - memset((void *) &epause, 0, sizeof(epause)); - if ((bdp->flags & IS_BACHELOR) - && (bdp->params.b_params & PRM_FC)) { - epause.autoneg = 1; - if (bdp->flags & DF_LINK_FC_CAP) { - epause.rx_pause = 1; - epause.tx_pause = 1; - } - if (bdp->flags & DF_LINK_FC_TX_ONLY) - epause.tx_pause = 1; - } - rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) - ? -EFAULT : 0; - return rc; + + rx->skb = NULL; + + return 0; +} + +static void e100_rx_clean(struct nic *nic, unsigned int *work_done, + unsigned int work_to_do) +{ + struct rx *rx; + int restart_required = 0; + struct rx *rx_to_start = NULL; + + /* are we already rnr? then pay attention!!! this ensures that + * the state machine progression never allows a start with a + * partially cleaned list, avoiding a race between hardware + * and rx_to_clean when in NAPI mode */ + if(RU_SUSPENDED == nic->ru_running) + restart_required = 1; + + /* Indicate newly arrived packets */ + for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { + int err = e100_rx_indicate(nic, rx, work_done, work_to_do); + if(-EAGAIN == err) { + /* hit quota so have more work to do, restart once + * cleanup is complete */ + restart_required = 0; + break; + } else if(-ENODATA == err) + break; /* No more to clean */ } -#endif -#ifdef ETHTOOL_SPAUSEPARAM - case ETHTOOL_SPAUSEPARAM: { - struct ethtool_pauseparam epause; - struct e100_private *bdp = dev->priv; - if (!(bdp->flags & IS_BACHELOR)) - return -EINVAL; - if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) - return -EFAULT; - if (epause.autoneg == 1) - bdp->params.b_params |= PRM_FC; - else - bdp->params.b_params &= ~PRM_FC; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - return 0; + + /* save our starting point as the place we'll restart the receiver */ + if(restart_required) + rx_to_start = nic->rx_to_clean; + + /* Alloc new skbs to refill list */ + for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { + if(unlikely(e100_rx_alloc_skb(nic, rx))) + break; /* Better luck next time (see watchdog) */ } -#endif -#ifdef ETHTOOL_GRXCSUM - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - memset((void *) &eval, 0, sizeof(eval)); - if ((ecmd.cmd == ETHTOOL_GRXCSUM) - && (bdp->params.b_params & PRM_XSUMRX)) - eval.data = 1; - else - eval.data = 0; - rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) - ? -EFAULT : 0; - return rc; + + if(restart_required) { + // ack the rnr? + writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); + e100_start_receiver(nic, rx_to_start); + if(work_done) + (*work_done)++; } -#endif -#ifdef ETHTOOL_SRXCSUM - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - case ETHTOOL_SSG: - { struct ethtool_value eval; - struct e100_private *bdp = dev->priv; - if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) - return -EFAULT; - if (ecmd.cmd == ETHTOOL_SRXCSUM) { - if (eval.data == 1) { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params |= PRM_XSUMRX; - else - return -EINVAL; - } else { - if (bdp->rev_id >= D101MA_REV_ID) - bdp->params.b_params &= ~PRM_XSUMRX; - else - return 0; +} + +static void e100_rx_clean_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + nic->ru_running = RU_UNINITIALIZED; + + if(nic->rxs) { + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + if(rx->skb) { + pci_unmap_single(nic->pdev, rx->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + dev_kfree_skb(rx->skb); } - } else { - if (eval.data == 1) - return -EINVAL; - else - return 0; } - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); + kfree(nic->rxs); + nic->rxs = NULL; + } + + nic->rx_to_use = nic->rx_to_clean = NULL; +} + +static int e100_rx_alloc_list(struct nic *nic) +{ + struct rx *rx; + unsigned int i, count = nic->params.rfds.count; + + nic->rx_to_use = nic->rx_to_clean = NULL; + nic->ru_running = RU_UNINITIALIZED; + + if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC))) + return -ENOMEM; + memset(nic->rxs, 0, sizeof(struct rx) * count); + + for(rx = nic->rxs, i = 0; i < count; rx++, i++) { + rx->next = (i + 1 < count) ? rx + 1 : nic->rxs; + rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1; + if(e100_rx_alloc_skb(nic, rx)) { + e100_rx_clean_list(nic); + return -ENOMEM; } - return 0; } -#endif - default: - break; - } //switch - return rc; + + nic->rx_to_use = nic->rx_to_clean = nic->rxs; + nic->ru_running = RU_SUSPENDED; + + return 0; } -static int -e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr) +static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs) { - struct e100_private *bdp; - struct ethtool_cmd ecmd; - u16 advert = 0; + struct net_device *netdev = dev_id; + struct nic *nic = netdev_priv(netdev); + u8 stat_ack = readb(&nic->csr->scb.stat_ack); - memset((void *) &ecmd, 0, sizeof (ecmd)); + DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); + + if(stat_ack == stat_ack_not_ours || /* Not our interrupt */ + stat_ack == stat_ack_not_present) /* Hardware is ejected */ + return IRQ_NONE; - bdp = dev->priv; + /* Ack interrupt(s) */ + writeb(stat_ack, &nic->csr->scb.stat_ack); - ecmd.supported = bdp->speed_duplex_caps; + /* We hit Receive No Resource (RNR); restart RU after cleaning */ + if(stat_ack & stat_ack_rnr) + nic->ru_running = RU_SUSPENDED; + +#ifdef CONFIG_E100_NAPI + if(likely(netif_rx_schedule_prep(netdev))) { + e100_disable_irq(nic); + __netif_rx_schedule(netdev); + } +#else + e100_rx_clean(nic, NULL, 0); + e100_tx_clean(nic); +#endif - ecmd.port = - (bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.phy_address = bdp->phy_addr; + return IRQ_HANDLED; +} - if (netif_carrier_ok(bdp->device)) { - ecmd.speed = bdp->cur_line_speed; - ecmd.duplex = - (bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL; - } - else { - ecmd.speed = -1; - ecmd.duplex = -1; +#ifdef CONFIG_E100_NAPI +static int e100_poll(struct net_device *netdev, int *budget) +{ + struct nic *nic = netdev_priv(netdev); + unsigned int work_to_do = min(netdev->quota, *budget); + unsigned int work_done = 0; + int tx_cleaned; + + e100_rx_clean(nic, &work_done, work_to_do); + tx_cleaned = e100_tx_clean(nic); + + /* If no Rx and Tx cleanup work was done, exit polling mode. */ + if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) { + netif_rx_complete(netdev); + e100_enable_irq(nic); + return 0; } - ecmd.advertising = ADVERTISED_TP; + *budget -= work_done; + netdev->quota -= work_done; - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - ecmd.autoneg = AUTONEG_ENABLE; - ecmd.advertising |= ADVERTISED_Autoneg; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - } + return 1; +} +#endif + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void e100_netpoll(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + + e100_disable_irq(nic); + e100_intr(nic->pdev->irq, netdev, NULL); + e100_tx_clean(nic); + e100_enable_irq(nic); +} +#endif + +static struct net_device_stats *e100_get_stats(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return &nic->net_stats; +} - if (bdp->speed_duplex_caps & SUPPORTED_MII) { - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert); +static int e100_set_mac_address(struct net_device *netdev, void *p) +{ + struct nic *nic = netdev_priv(netdev); + struct sockaddr *addr = p; - if (advert & ADVERTISE_10HALF) - ecmd.advertising |= ADVERTISED_10baseT_Half; - if (advert & ADVERTISE_10FULL) - ecmd.advertising |= ADVERTISED_10baseT_Full; - if (advert & ADVERTISE_100HALF) - ecmd.advertising |= ADVERTISED_100baseT_Half; - if (advert & ADVERTISE_100FULL) - ecmd.advertising |= ADVERTISED_100baseT_Full; - } else { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.advertising &= ~ADVERTISED_Autoneg; - } + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + e100_exec_cb(nic, NULL, e100_setup_iaaddr); return 0; } -static int -e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr) +static int e100_change_mtu(struct net_device *netdev, int new_mtu) { - struct e100_private *bdp; - int e100_new_speed_duplex; - int ethtool_new_speed_duplex; - struct ethtool_cmd ecmd; - - bdp = dev->priv; - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) { - return -EFAULT; - } - - if ((ecmd.autoneg == AUTONEG_ENABLE) - && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { - bdp->params.e100_speed_duplex = E100_AUTONEG; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - if (ecmd.speed == SPEED_10) { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_10_HALF; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_10_FULL; - ethtool_new_speed_duplex = - SUPPORTED_10baseT_Full; - } - } else { - if (ecmd.duplex == DUPLEX_HALF) { - e100_new_speed_duplex = - E100_SPEED_100_HALF; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Half; - } else { - e100_new_speed_duplex = - E100_SPEED_100_FULL; - ethtool_new_speed_duplex = - SUPPORTED_100baseT_Full; - } - } - - if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { - bdp->params.e100_speed_duplex = - e100_new_speed_duplex; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EOPNOTSUPP; - } - } - + if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN) + return -EINVAL; + netdev->mtu = new_mtu; return 0; } -static int -e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr) +#ifdef CONFIG_PM +static int e100_asf(struct nic *nic) { - struct e100_private *bdp; - struct ethtool_value info; - - memset((void *) &info, 0, sizeof (info)); + /* ASF can be enabled from eeprom */ + return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) && + (nic->eeprom[eeprom_config_asf] & eeprom_asf) && + !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) && + ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE)); +} +#endif - bdp = dev->priv; - info.cmd = ETHTOOL_GLINK; +static int e100_up(struct nic *nic) +{ + int err; - /* Consider both PHY link and netif_running */ - info.data = e100_update_link_state(bdp); + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_rx_clean_list; + if((err = e100_hw_init(nic))) + goto err_clean_cbs; + e100_set_multicast_list(nic->netdev); + e100_start_receiver(nic, NULL); + mod_timer(&nic->watchdog, jiffies); + if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, + nic->netdev->name, nic->netdev))) + goto err_no_irq; + netif_wake_queue(nic->netdev); +#ifdef CONFIG_E100_NAPI + netif_poll_enable(nic->netdev); + /* enable ints _after_ enabling poll, preventing a race between + * disable ints+schedule */ +#endif + e100_enable_irq(nic); + return 0; - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; +err_no_irq: + del_timer_sync(&nic->watchdog); +err_clean_cbs: + e100_clean_cbs(nic); +err_rx_clean_list: + e100_rx_clean_list(nic); + return err; +} - return 0; +static void e100_down(struct nic *nic) +{ +#ifdef CONFIG_E100_NAPI + /* wait here for poll to complete */ + netif_poll_disable(nic->netdev); +#endif + netif_stop_queue(nic->netdev); + e100_hw_reset(nic); + free_irq(nic->pdev->irq, nic->netdev); + del_timer_sync(&nic->watchdog); + netif_carrier_off(nic->netdev); + e100_clean_cbs(nic); + e100_rx_clean_list(nic); } -static int -e100_ethtool_test(struct net_device *dev, struct ifreq *ifr) +static void e100_tx_timeout(struct net_device *netdev) { - struct ethtool_test *info; - int rc = -EFAULT; + struct nic *nic = netdev_priv(netdev); - info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), - GFP_ATOMIC); + /* Reset outside of interrupt context, to avoid request_irq + * in interrupt context */ + schedule_work(&nic->tx_timeout_task); +} - if (!info) - return -ENOMEM; +static void e100_tx_timeout_task(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); - memset((void *) info, 0, sizeof(*info) + - max_test_res * sizeof(u64)); + DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", + readb(&nic->csr->scb.status)); + e100_down(netdev_priv(netdev)); + e100_up(netdev_priv(netdev)); +} - if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) - goto exit; +static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) +{ + int err; + struct sk_buff *skb; - info->flags = e100_run_diag(dev, info->data, info->flags); + /* Use driver resources to perform internal MAC or PHY + * loopback test. A single packet is prepared and transmitted + * in loopback mode, and the test passes if the received + * packet compares byte-for-byte to the transmitted packet. */ + + if((err = e100_rx_alloc_list(nic))) + return err; + if((err = e100_alloc_cbs(nic))) + goto err_clean_rx; + + /* ICH PHY loopback is broken so do MAC loopback instead */ + if(nic->flags & ich && loopback_mode == lb_phy) + loopback_mode = lb_mac; + + nic->loopback = loopback_mode; + if((err = e100_hw_init(nic))) + goto err_loopback_none; + + if(loopback_mode == lb_phy) + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, + BMCR_LOOPBACK); + + e100_start_receiver(nic, NULL); + + if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) { + err = -ENOMEM; + goto err_loopback_none; + } + skb_put(skb, ETH_DATA_LEN); + memset(skb->data, 0xFF, ETH_DATA_LEN); + e100_xmit_frame(skb, nic->netdev); + + msleep(10); + + pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + + if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd), + skb->data, ETH_DATA_LEN)) + err = -EAGAIN; + +err_loopback_none: + mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0); + nic->loopback = lb_none; + e100_clean_cbs(nic); + e100_hw_reset(nic); +err_clean_rx: + e100_rx_clean_list(nic); + return err; +} + +#define MII_LED_CONTROL 0x1B +static void e100_blink_led(unsigned long data) +{ + struct nic *nic = (struct nic *)data; + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; - if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + max_test_res * sizeof(u64))) - rc = 0; -exit: - kfree(info); - return rc; + nic->leds = (nic->leds & led_on) ? led_off : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds); + mod_timer(&nic->blink_timer, jiffies + HZ / 4); } -static int -e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr) +static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { - struct e100_private *bdp; - u32 regs_buff[E100_REGS_LEN]; - struct ethtool_regs regs = {ETHTOOL_GREGS}; - void *addr = ifr->ifr_data; - u16 mdi_reg; - - bdp = dev->priv; + struct nic *nic = netdev_priv(netdev); + return mii_ethtool_gset(&nic->mii, cmd); +} - if(copy_from_user(®s, addr, sizeof(regs))) - return -EFAULT; +static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct nic *nic = netdev_priv(netdev); + int err; - regs.version = (1 << 24) | bdp->rev_id; - regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | - readb(&(bdp->scb->scb_cmd_low)) << 16 | - readw(&(bdp->scb->scb_status)); - e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); - regs_buff[1] = mdi_reg; + mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET); + err = mii_ethtool_sset(&nic->mii, cmd); + e100_exec_cb(nic, NULL, e100_configure); - if(copy_to_user(addr, ®s, sizeof(regs))) - return -EFAULT; + return err; +} - addr += offsetof(struct ethtool_regs, data); - if(copy_to_user(addr, regs_buff, regs.len)) - return -EFAULT; +static void e100_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct nic *nic = netdev_priv(netdev); + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(nic->pdev)); +} - return 0; +static int e100_get_regs_len(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); +#define E100_PHY_REGS 0x1C +#define E100_REGS_LEN 1 + E100_PHY_REGS + \ + sizeof(nic->mem->dump_buf) / sizeof(u32) + return E100_REGS_LEN * sizeof(u32); } -static int -e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr) +static void e100_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) { - struct e100_private *bdp; + struct nic *nic = netdev_priv(netdev); + u32 *buff = p; + int i; - bdp = dev->priv; + regs->version = (1 << 24) | nic->rev_id; + buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | + readb(&nic->csr->scb.cmd_lo) << 16 | + readw(&nic->csr->scb.status); + for(i = E100_PHY_REGS; i >= 0; i--) + buff[1 + E100_PHY_REGS - i] = + mdio_read(netdev, nic->mii.phy_id, i); + memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf)); + e100_exec_cb(nic, NULL, e100_dump); + msleep(10); + memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf, + sizeof(nic->mem->dump_buf)); +} - if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && - (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } else { - return -EFAULT; - } - return 0; +static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct nic *nic = netdev_priv(netdev); + wol->supported = (nic->mac >= mac_82558_D101_A4) ? WAKE_MAGIC : 0; + wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0; } -static int -e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr) +static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { - struct e100_private *bdp; - struct ethtool_drvinfo info; + struct nic *nic = netdev_priv(netdev); + + if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + return -EOPNOTSUPP; - memset((void *) &info, 0, sizeof (info)); + if(wol->wolopts) + nic->flags |= wol_magic; + else + nic->flags &= ~wol_magic; - bdp = dev->priv; - - strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1); - strncpy(info.version, e100_driver_version, sizeof (info.version) - 1); - strncpy(info.fw_version, "N/A", - sizeof (info.fw_version) - 1); - strncpy(info.bus_info, pci_name(bdp->pdev), - sizeof (info.bus_info) - 1); - info.n_stats = E100_STATS_LEN; - info.regdump_len = E100_REGS_LEN * sizeof(u32); - info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = max_test_res; - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - return -EFAULT; + e100_exec_cb(nic, NULL, e100_configure); return 0; } -static int -e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) +static u32 e100_get_msglevel(struct net_device *netdev) { - struct e100_private *bdp; - struct ethtool_eeprom ecmd; - u16 eeprom_data[256]; - u16 *usr_eeprom_ptr; - u16 first_word, last_word; - int i, max_len; - void *ptr; - u8 *eeprom_data_bytes = (u8 *)eeprom_data; - - bdp = dev->priv; - - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; - - usr_eeprom_ptr = - (u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data)); - - max_len = bdp->eeprom_size * 2; - - if (ecmd.offset > ecmd.offset + ecmd.len) - return -EINVAL; - - if ((ecmd.offset + ecmd.len) > max_len) - ecmd.len = (max_len - ecmd.offset); - - first_word = ecmd.offset >> 1; - last_word = (ecmd.offset + ecmd.len - 1) >> 1; - - if (first_word >= bdp->eeprom_size) - return -EFAULT; - - if (ecmd.cmd == ETHTOOL_GEEPROM) { - for(i = 0; i <= (last_word - first_word); i++) - eeprom_data[i] = e100_eeprom_read(bdp, first_word + i); - - ecmd.magic = E100_EEPROM_MAGIC; - - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - - if(ecmd.offset & 1) - eeprom_data_bytes++; - if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len)) - return -EFAULT; - } else { - if (ecmd.magic != E100_EEPROM_MAGIC) - return -EFAULT; - - ptr = (void *)eeprom_data; - if(ecmd.offset & 1) { - /* need modification of first changed EEPROM word */ - /* only the second byte of the word is being modified */ - eeprom_data[0] = e100_eeprom_read(bdp, first_word); - ptr++; - } - if((ecmd.offset + ecmd.len) & 1) { - /* need modification of last changed EEPROM word */ - /* only the first byte of the word is being modified */ - eeprom_data[last_word - first_word] = - e100_eeprom_read(bdp, last_word); - } - if(copy_from_user(ptr, usr_eeprom_ptr, ecmd.len)) - return -EFAULT; + struct nic *nic = netdev_priv(netdev); + return nic->msg_enable; +} - e100_eeprom_write_block(bdp, first_word, eeprom_data, - last_word - first_word + 1); +static void e100_set_msglevel(struct net_device *netdev, u32 value) +{ + struct nic *nic = netdev_priv(netdev); + nic->msg_enable = value; +} - if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) - return -EFAULT; - } - return 0; +static int e100_nway_reset(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return mii_nway_restart(&nic->mii); } -#define E100_BLINK_INTERVAL (HZ/4) -/** - * e100_led_control - * @bdp: atapter's private data struct - * @led_mdi_op: led operation - * - * Software control over adapter's led. The possible operations are: - * TURN LED OFF, TURN LED ON and RETURN LED CONTROL TO HARDWARE. - */ -static void -e100_led_control(struct e100_private *bdp, u16 led_mdi_op) +static u32 e100_get_link(struct net_device *netdev) { - e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL, - bdp->phy_addr, led_mdi_op); + struct nic *nic = netdev_priv(netdev); + return mii_link_ok(&nic->mii); +} +static int e100_get_eeprom_len(struct net_device *netdev) +{ + struct nic *nic = netdev_priv(netdev); + return nic->eeprom_wc << 1; } -/** - * e100_led_blink_callback - * @data: pointer to atapter's private data struct - * - * Blink timer callback function. Toggles ON/OFF led status bit and calls - * led hardware access function. - */ -static void -e100_led_blink_callback(unsigned long data) + +#define E100_EEPROM_MAGIC 0x1234 +static int e100_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) { - struct e100_private *bdp = (struct e100_private *) data; + struct nic *nic = netdev_priv(netdev); - if(bdp->flags & LED_IS_ON) { - bdp->flags &= ~LED_IS_ON; - e100_led_control(bdp, PHY_82555_LED_OFF); - } else { - bdp->flags |= LED_IS_ON; - if (bdp->rev_id >= D101MA_REV_ID) - e100_led_control(bdp, PHY_82555_LED_ON_559); - else - e100_led_control(bdp, PHY_82555_LED_ON_PRE_559); - } + eeprom->magic = E100_EEPROM_MAGIC; + memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len); - mod_timer(&bdp->blink_timer, jiffies + E100_BLINK_INTERVAL); + return 0; } -/** - * e100_ethtool_led_blink - * @dev: pointer to atapter's net_device struct - * @ifr: pointer to ioctl request structure - * - * Blink led ioctl handler. Initialtes blink timer and sleeps until - * blink period expires. Than it kills timer and returns. The led control - * is returned back to hardware when blink timer is killed. - */ -static int -e100_ethtool_led_blink(struct net_device *dev, struct ifreq *ifr) -{ - struct e100_private *bdp; - struct ethtool_value ecmd; - bdp = dev->priv; +static int e100_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct nic *nic = netdev_priv(netdev); - if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) - return -EFAULT; + if(eeprom->magic != E100_EEPROM_MAGIC) + return -EINVAL; - if(!bdp->blink_timer.function) { - init_timer(&bdp->blink_timer); - bdp->blink_timer.function = e100_led_blink_callback; - bdp->blink_timer.data = (unsigned long) bdp; - } + memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len); - mod_timer(&bdp->blink_timer, jiffies); + return e100_eeprom_save(nic, eeprom->offset >> 1, + (eeprom->len >> 1) + 1); +} - set_current_state(TASK_INTERRUPTIBLE); +static void e100_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev_priv(netdev); + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; - if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) - ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + ring->rx_max_pending = rfds->max; + ring->tx_max_pending = cbs->max; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rfds->count; + ring->tx_pending = cbs->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} - schedule_timeout(ecmd.data * HZ); +static int e100_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct nic *nic = netdev_priv(netdev); + struct param_range *rfds = &nic->params.rfds; + struct param_range *cbs = &nic->params.cbs; - del_timer_sync(&bdp->blink_timer); + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; - e100_led_control(bdp, PHY_82555_LED_NORMAL_CONTROL); + if(netif_running(netdev)) + e100_down(nic); + rfds->count = max(ring->rx_pending, rfds->min); + rfds->count = min(rfds->count, rfds->max); + cbs->count = max(ring->tx_pending, cbs->min); + cbs->count = min(cbs->count, cbs->max); + DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n", + rfds->count, cbs->count); + if(netif_running(netdev)) + e100_up(nic); return 0; } -static inline int __devinit -e100_10BaseT_adapter(struct e100_private *bdp) +static const char e100_gstrings_test[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", +}; +#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN + +static int e100_diag_test_count(struct net_device *netdev) { - return ((bdp->pdev->device == 0x1229) && - (bdp->pdev->subsystem_vendor == 0x8086) && - (bdp->pdev->subsystem_device == 0x0003)); + return E100_TEST_LEN; } -static void __devinit -e100_get_speed_duplex_caps(struct e100_private *bdp) +static void e100_diag_test(struct net_device *netdev, + struct ethtool_test *test, u64 *data) { - u16 status; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - bdp->speed_duplex_caps = 0; + struct ethtool_cmd cmd; + struct nic *nic = netdev_priv(netdev); + int i, err; - bdp->speed_duplex_caps |= - (status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0; + memset(data, 0, E100_TEST_LEN * sizeof(u64)); + data[0] = !mii_link_ok(&nic->mii); + data[1] = e100_eeprom_load(nic); + if(test->flags & ETH_TEST_FL_OFFLINE) { - bdp->speed_duplex_caps |= - (status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0; + /* save speed, duplex & autoneg settings */ + err = mii_ethtool_gset(&nic->mii, &cmd); - bdp->speed_duplex_caps |= - (status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0; + if(netif_running(netdev)) + e100_down(nic); + data[2] = e100_self_test(nic); + data[3] = e100_loopback_test(nic, lb_mac); + data[4] = e100_loopback_test(nic, lb_phy); - bdp->speed_duplex_caps |= - (status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0; + /* restore speed, duplex & autoneg settings */ + err = mii_ethtool_sset(&nic->mii, &cmd); - bdp->speed_duplex_caps |= - (status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0; - - if (IS_NC3133(bdp)) - bdp->speed_duplex_caps = - (SUPPORTED_FIBRE | SUPPORTED_100baseT_Full); - else - bdp->speed_duplex_caps |= SUPPORTED_TP; - - if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) { - bdp->speed_duplex_caps = - (SUPPORTED_10baseT_Half | SUPPORTED_TP); - } else { - bdp->speed_duplex_caps |= SUPPORTED_MII; + if(netif_running(netdev)) + e100_up(nic); } + for(i = 0; i < E100_TEST_LEN; i++) + test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0; + msleep_interruptible(4 * 1000); } -#ifdef CONFIG_PM -static unsigned char -e100_setup_filter(struct e100_private *bdp) +static int e100_phys_id(struct net_device *netdev, u32 data) { - cb_header_t *ntcb_hdr; - unsigned char res = false; - nxmit_cb_entry_t *cmd; - - if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) { - goto exit; - } - - ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd; - ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER); - - /* Set EL and FIX bit */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] = - __constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX); - - if (bdp->wolopts & WAKE_UCAST) { - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - __constant_cpu_to_le32(CB_FILTER_IA_MATCH); - } - - if (bdp->wolopts & WAKE_ARP) { - /* Setup ARP bit and lower IP parts */ - /* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */ - (cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |= - cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes); - } - - res = e100_exec_non_cu_cmd(bdp, cmd); - if (!res) - printk(KERN_WARNING "e100: %s: Filter setup failed\n", - bdp->device->name); + struct nic *nic = netdev_priv(netdev); -exit: - return res; + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + mod_timer(&nic->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&nic->blink_timer); + mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0); + return 0; } -static void -e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp) -{ - e100_config_wol(bdp); - - if (e100_config(bdp)) { - if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) - if (!e100_setup_filter(bdp)) - printk(KERN_ERR - "e100: WOL options failed\n"); - } else { - printk(KERN_ERR "e100: config WOL failed\n"); - } -} -#endif +static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + /* device-specific stats */ + "tx_deferred", "tx_single_collisions", "tx_multi_collisions", + "tx_flow_control_pause", "rx_flow_control_pause", + "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", +}; +#define E100_NET_STATS_LEN 21 +#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN -static u16 -e100_get_ip_lbytes(struct net_device *dev) +static int e100_get_stats_count(struct net_device *netdev) { - struct in_ifaddr *ifa; - struct in_device *in_dev; - u32 res = 0; - - in_dev = (struct in_device *) dev->ip_ptr; - /* Check if any in_device bound to interface */ - if (in_dev) { - /* Check if any IP address is bound to interface */ - if ((ifa = in_dev->ifa_list) != NULL) { - res = __constant_ntohl(ifa->ifa_address); - res = __constant_htons(res & 0x0000ffff); - } - } - return res; + return E100_STATS_LEN; } -static int -e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr) +static void e100_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) { - struct e100_private *bdp; - struct ethtool_wolinfo wolinfo; - int res = 0; - - bdp = dev->priv; + struct nic *nic = netdev_priv(netdev); + int i; - if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) { - return -EFAULT; - } + for(i = 0; i < E100_NET_STATS_LEN; i++) + data[i] = ((unsigned long *)&nic->net_stats)[i]; - switch (wolinfo.cmd) { - case ETHTOOL_GWOL: - wolinfo.supported = bdp->wolsupported; - wolinfo.wolopts = bdp->wolopts; - if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo))) - res = -EFAULT; - break; - case ETHTOOL_SWOL: - /* If ALL requests are supported or request is DISABLE wol */ - if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts) - || (wolinfo.wolopts == 0)) { - bdp->wolopts = wolinfo.wolopts; - } else { - res = -EOPNOTSUPP; - } - if (wolinfo.wolopts & WAKE_ARP) - bdp->ip_lbytes = e100_get_ip_lbytes(dev); - break; - default: + data[i++] = nic->tx_deferred; + data[i++] = nic->tx_single_collisions; + data[i++] = nic->tx_multiple_collisions; + data[i++] = nic->tx_fc_pause; + data[i++] = nic->rx_fc_pause; + data[i++] = nic->rx_fc_unsupported; + data[i++] = nic->tx_tco_frames; + data[i++] = nic->rx_tco_frames; +} + +static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + switch(stringset) { + case ETH_SS_TEST: + memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test)); + break; + case ETH_SS_STATS: + memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats)); break; } - return res; } -static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) -{ - struct ethtool_gstrings info; - char *strings = NULL; - char *usr_strings; - int i; - - memset((void *) &info, 0, sizeof(info)); - - usr_strings = (u8 *) (ifr->ifr_data + - offsetof(struct ethtool_gstrings, data)); +static struct ethtool_ops e100_ethtool_ops = { + .get_settings = e100_get_settings, + .set_settings = e100_set_settings, + .get_drvinfo = e100_get_drvinfo, + .get_regs_len = e100_get_regs_len, + .get_regs = e100_get_regs, + .get_wol = e100_get_wol, + .set_wol = e100_set_wol, + .get_msglevel = e100_get_msglevel, + .set_msglevel = e100_set_msglevel, + .nway_reset = e100_nway_reset, + .get_link = e100_get_link, + .get_eeprom_len = e100_get_eeprom_len, + .get_eeprom = e100_get_eeprom, + .set_eeprom = e100_set_eeprom, + .get_ringparam = e100_get_ringparam, + .set_ringparam = e100_set_ringparam, + .self_test_count = e100_diag_test_count, + .self_test = e100_diag_test, + .get_strings = e100_get_strings, + .phys_id = e100_phys_id, + .get_stats_count = e100_get_stats_count, + .get_ethtool_stats = e100_get_ethtool_stats, +#ifdef ETHTOOL_GPERMADDR + .get_perm_addr = ethtool_op_get_perm_addr, +#endif +}; - if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) - return -EFAULT; +static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct nic *nic = netdev_priv(netdev); - switch (info.string_set) { - case ETH_SS_TEST: { - int ret = 0; - if (info.len > max_test_res) - info.len = max_test_res; - strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); - if (!strings) - return -ENOMEM; - memset(strings, 0, info.len * ETH_GSTRING_LEN); +#ifdef ETHTOOL_OPS_COMPAT + if(cmd == SIOCETHTOOL) + return ethtool_ioctl(ifr); - for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%s", - test_strings[i]); - } - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) - ret = -EFAULT; - if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) - ret = -EFAULT; - kfree(strings); - return ret; - } - case ETH_SS_STATS: { - char *strings = NULL; - void *addr = ifr->ifr_data; - info.len = E100_STATS_LEN; - strings = *e100_gstrings_stats; - if(copy_to_user(ifr->ifr_data, &info, sizeof(info))) - return -EFAULT; - addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, - info.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; - } - default: - return -EOPNOTSUPP; - } +#endif + return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL); } -static int -e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int e100_alloc(struct nic *nic) { - struct e100_private *bdp; - struct mii_ioctl_data *data_ptr = - (struct mii_ioctl_data *) &(ifr->ifr_data); - - bdp = dev->priv; - - switch (cmd) { - case SIOCGMIIPHY: - data_ptr->phy_id = bdp->phy_addr & 0x1f; - break; - - case SIOCGMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr, - &(data_ptr->val_out)); - break; - - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* If reg = 0 && change speed/duplex */ - if (data_ptr->reg_num == 0 && - (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */ - || data_ptr->val_in == (BMCR_RESET) /* reset cmd */ - || data_ptr->val_in & (BMCR_SPEED100 | BMCR_FULLDPLX) - || data_ptr->val_in == 0)) { - if (data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) - || data_ptr->val_in == (BMCR_RESET)) - bdp->params.e100_speed_duplex = E100_AUTONEG; - else if (data_ptr->val_in == (BMCR_SPEED100 | BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - else if (data_ptr->val_in == (BMCR_SPEED100)) - bdp->params.e100_speed_duplex = E100_SPEED_100_HALF; - else if (data_ptr->val_in == (BMCR_FULLDPLX)) - bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; - else - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - e100_hw_init(bdp); - e100_open(dev); - } - } - else - /* Only allows changing speed/duplex */ - return -EINVAL; - - break; + nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem), + &nic->dma_addr); + return nic->mem ? 0 : -ENOMEM; +} - default: - return -EOPNOTSUPP; +static void e100_free(struct nic *nic) +{ + if(nic->mem) { + pci_free_consistent(nic->pdev, sizeof(struct mem), + nic->mem, nic->dma_addr); + nic->mem = NULL; } - return 0; } -nxmit_cb_entry_t * -e100_alloc_non_tx_cmd(struct e100_private *bdp) +static int e100_open(struct net_device *netdev) { - nxmit_cb_entry_t *non_tx_cmd_elem; + struct nic *nic = netdev_priv(netdev); + int err = 0; - if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *) - kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) { - return NULL; - } - non_tx_cmd_elem->non_tx_cmd = - pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t), - &(non_tx_cmd_elem->dma_addr)); - if (non_tx_cmd_elem->non_tx_cmd == NULL) { - kfree(non_tx_cmd_elem); - return NULL; - } - return non_tx_cmd_elem; + netif_carrier_off(netdev); + if((err = e100_up(nic))) + DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n"); + return err; } -void -e100_free_non_tx_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *non_tx_cmd_elem) +static int e100_close(struct net_device *netdev) { - pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t), - non_tx_cmd_elem->non_tx_cmd, - non_tx_cmd_elem->dma_addr); - kfree(non_tx_cmd_elem); + e100_down(netdev_priv(netdev)); + return 0; } -static void -e100_free_nontx_list(struct e100_private *bdp) +static int __devinit e100_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - nxmit_cb_entry_t *command; - int i; - - while (!list_empty(&bdp->non_tx_cmd_list)) { - command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - list_del(&(command->list_elem)); - e100_free_non_tx_cmd(bdp, command); - } - - for (i = 0; i < CB_MAX_NONTX_CMD; i++) { - bdp->same_cmd_entry[i] = NULL; + struct net_device *netdev; + struct nic *nic; + int err; + + if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { + if(((1 << debug) - 1) & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n"); + return -ENOMEM; } -} -static unsigned char -e100_delayed_exec_non_cu_cmd(struct e100_private *bdp, - nxmit_cb_entry_t *command) -{ - nxmit_cb_entry_t *same_command; - cb_header_t *ntcb_hdr; - u16 cmd; + netdev->open = e100_open; + netdev->stop = e100_close; + netdev->hard_start_xmit = e100_xmit_frame; + netdev->get_stats = e100_get_stats; + netdev->set_multicast_list = e100_set_multicast_list; + netdev->set_mac_address = e100_set_mac_address; + netdev->change_mtu = e100_change_mtu; + netdev->do_ioctl = e100_do_ioctl; + SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); + netdev->tx_timeout = e100_tx_timeout; + netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; +#ifdef CONFIG_E100_NAPI + netdev->poll = e100_poll; + netdev->weight = E100_NAPI_WEIGHT; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e100_netpoll; +#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); - ntcb_hdr = (cb_header_t *) command->non_tx_cmd; + nic = netdev_priv(netdev); + nic->netdev = netdev; + nic->pdev = pdev; + nic->msg_enable = (1 << debug) - 1; + pci_set_drvdata(pdev, netdev); - cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd); + if((err = pci_enable_device(pdev))) { + DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n"); + goto err_out_free_dev; + } - spin_lock_bh(&(bdp->bd_non_tx_lock)); + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DPRINTK(PROBE, ERR, "Cannot find proper PCI device " + "base address, aborting.\n"); + err = -ENODEV; + goto err_out_disable_pdev; + } - same_command = bdp->same_cmd_entry[cmd]; + if((err = pci_request_regions(pdev, DRV_NAME))) { + DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n"); + goto err_out_disable_pdev; + } - if (same_command != NULL) { - memcpy((void *) (same_command->non_tx_cmd), - (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t)); - e100_free_non_tx_cmd(bdp, command); - } else { - list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list)); - bdp->same_cmd_entry[cmd] = command; + if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); + goto err_out_free_res; } - if (bdp->non_tx_command_state == E100_NON_TX_IDLE) { - bdp->non_tx_command_state = E100_WAIT_TX_FINISH; - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); + if(!nic->csr) { + DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); + err = -ENOMEM; + goto err_out_free_res; } - spin_unlock_bh(&(bdp->bd_non_tx_lock)); - return true; -} + if(ent->driver_data) + nic->flags |= ich; + else + nic->flags &= ~ich; -static void -e100_non_tx_background(unsigned long ptr) -{ - struct e100_private *bdp = (struct e100_private *) ptr; - nxmit_cb_entry_t *active_command; - int restart = true; - cb_header_t *non_tx_cmd; - u8 sub_cmd; + e100_get_defaults(nic); - spin_lock_bh(&(bdp->bd_non_tx_lock)); + /* locks must be initialized before calling hw_reset */ + spin_lock_init(&nic->cb_lock); + spin_lock_init(&nic->cmd_lock); + spin_lock_init(&nic->mdio_lock); - switch (bdp->non_tx_command_state) { - case E100_WAIT_TX_FINISH: - if (bdp->last_tcb != NULL) { - rmb(); - if ((bdp->last_tcb->tcb_hdr.cb_status & - __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - goto exit; - } - if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == - SCB_CUS_ACTIVE) { - goto exit; - } - break; + /* Reset the device before pci_set_master() in case device is in some + * funky state and has an interrupt pending - hint: we don't have the + * interrupt handler registered yet. */ + e100_hw_reset(nic); - case E100_WAIT_NON_TX_FINISH: - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - rmb(); - - if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0) - && time_before(jiffies, active_command->expiration_time)) { - goto exit; - } else { - non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd; - sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd); -#ifdef E100_CU_DEBUG - if (!(non_tx_cmd->cb_status - & __constant_cpu_to_le16(CB_STATUS_COMPLETE))) - printk(KERN_ERR "e100: %s: Queued " - "command (%x) timeout\n", - bdp->device->name, sub_cmd); -#endif - list_del(&(active_command->list_elem)); - e100_free_non_tx_cmd(bdp, active_command); - } - break; + pci_set_master(pdev); - default: - break; - } //switch + init_timer(&nic->watchdog); + nic->watchdog.function = e100_watchdog; + nic->watchdog.data = (unsigned long)nic; + init_timer(&nic->blink_timer); + nic->blink_timer.function = e100_blink_led; + nic->blink_timer.data = (unsigned long)nic; - if (list_empty(&bdp->non_tx_cmd_list)) { - bdp->non_tx_command_state = E100_NON_TX_IDLE; - spin_lock_irq(&(bdp->bd_lock)); - bdp->next_cu_cmd = START_WAIT; - spin_unlock_irq(&(bdp->bd_lock)); - restart = false; - goto exit; - } else { - u16 cmd_type; + INIT_WORK(&nic->tx_timeout_task, + (void (*)(void *))e100_tx_timeout_task, netdev); - bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH; - active_command = list_entry(bdp->non_tx_cmd_list.next, - nxmit_cb_entry_t, list_elem); - sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd; - spin_lock_irq(&(bdp->bd_lock)); - e100_wait_exec_cmplx(bdp, active_command->dma_addr, - SCB_CUC_START, sub_cmd); - spin_unlock_irq(&(bdp->bd_lock)); - active_command->expiration_time = jiffies + HZ; - cmd_type = CB_CMD_MASK & - le16_to_cpu(((cb_header_t *) - (active_command->non_tx_cmd))->cb_cmd); - bdp->same_cmd_entry[cmd_type] = NULL; - } - -exit: - if (restart) { - mod_timer(&(bdp->nontx_timer_id), jiffies + 1); - } else { - if (netif_running(bdp->device)) - netif_wake_queue(bdp->device); + if((err = e100_alloc(nic))) { + DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); + goto err_out_iounmap; } - spin_unlock_bh(&(bdp->bd_non_tx_lock)); -} -static void -e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) -{ - struct e100_private *bdp = netdev->priv; + if((err = e100_eeprom_load(nic))) + goto err_out_free; - e100_disable_clear_intr(bdp); - bdp->vlgrp = grp; + e100_phy_init(nic); - if(grp) { - /* enable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, true); + memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); +#ifdef ETHTOOL_GPERMADDR + memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); + if(!is_valid_ether_addr(netdev->perm_addr)) { +#else + if(!is_valid_ether_addr(netdev->dev_addr)) { +#endif + DPRINTK(PROBE, ERR, "Invalid MAC address from " + "EEPROM, aborting.\n"); + err = -EAGAIN; + goto err_out_free; + } + + /* Wol magic packet can be enabled from eeprom */ + if((nic->mac >= mac_82558_D101_A4) && + (nic->eeprom[eeprom_id] & eeprom_id_wol)) + nic->flags |= wol_magic; + + /* ack any pending wake events, disable PME */ + err = pci_enable_wake(pdev, 0, 0); + if (err) + DPRINTK(PROBE, ERR, "Error clearing wake event\n"); + + strcpy(netdev->name, "eth%d"); + if((err = register_netdev(netdev))) { + DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); + goto err_out_free; + } + + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " + "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", + (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); - } else { - /* disable VLAN tag insert/strip */ - e100_config_vlan_drop(bdp, false); - } + return 0; - e100_config(bdp); - e100_set_intr_mask(bdp); +err_out_free: + e100_free(nic); +err_out_iounmap: + iounmap(nic->csr); +err_out_free_res: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); +err_out_free_dev: + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); + return err; +} + +static void __devexit e100_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + if(netdev) { + struct nic *nic = netdev_priv(netdev); + unregister_netdev(netdev); + e100_free(nic); + iounmap(nic->csr); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } } -static void -e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid) -{ - /* We don't do Vlan filtering */ - return; -} +static int e100_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + if (netif_running(netdev)) + e100_down(nic); + e100_hw_reset(nic); + netif_device_detach(netdev); -static void -e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) -{ - struct e100_private *bdp = netdev->priv; +#ifdef CONFIG_PM + pci_save_state(pdev); + if (nic->flags & (wol_magic | e100_asf(nic))) +#else + if (nic->flags & (wol_magic)) +#endif + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + else + /* disable PME */ + pci_enable_wake(pdev, 0, 0); + + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); - if(bdp->vlgrp) - bdp->vlgrp->vlan_devices[vid] = NULL; - /* We don't do Vlan filtering */ - return; + return 0; } #ifdef CONFIG_PM -static int -e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) +static int e100_resume(struct pci_dev *pdev) { - struct pci_dev *pdev = NULL; - - switch(event) { - case SYS_DOWN: - case SYS_HALT: - case SYS_POWER_OFF: - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - if(pci_dev_driver(pdev) == &e100_driver) { - /* If net_device struct is allocated? */ - if (pci_get_drvdata(pdev)) - e100_suspend(pdev, 3); + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); - } - } - } - return NOTIFY_DONE; + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); + netif_device_attach(netdev); + if (netif_running(netdev)) + e100_up(nic); + + return 0; } +#endif /* CONFIG_PM */ -static int -e100_suspend(struct pci_dev *pcid, u32 state) +#ifdef E100_USE_SHUTDOWN_HANDLER +static void e100_shutdown(struct pci_dev *pdev) { - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; - - e100_isolate_driver(bdp); - pci_save_state(pcid, bdp->pci_state); - - /* Enable or disable WoL */ - e100_do_wol(pcid, bdp); - - /* If wol is enabled */ - if (bdp->wolopts || e100_asf_enabled(bdp)) { - pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ - pci_set_power_state(pcid, 3); /* Set power state to D3. */ - } else { - /* Disable bus mastering */ - pci_disable_device(pcid); - pci_set_power_state(pcid, state); - } - return 0; + e100_suspend(pdev, PMSG_SUSPEND); } +#endif /* E100_USE_SHUTDOWN_HANDLER */ -static int -e100_resume(struct pci_dev *pcid) +#ifdef E100_USE_PCI_ERS +/* ------------------ PCI Error Recovery infrastructure -------------- */ +/** + * e100_io_error_detected - called when PCI error is detected. + * @pdev: Pointer to PCI device + * @state: The current pci conneection state + */ +static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { - struct net_device *netdev = pci_get_drvdata(pcid); - struct e100_private *bdp = netdev->priv; + struct net_device *netdev = pci_get_drvdata(pdev); - pci_set_power_state(pcid, 0); - pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */ - pci_restore_state(pcid, bdp->pci_state); + /* Similar to calling e100_down(), but avoids adpater I/O. */ + netdev->stop(netdev); - /* Also do device full reset because device was in D3 state */ - e100_deisolate_driver(bdp, true); + /* Detach; put netif into state similar to hotplug unplug. */ + netif_poll_enable(netdev); + netif_device_detach(netdev); + pci_disable_device(pdev); - return 0; + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; } /** - * e100_asf_enabled - checks if ASF is configured on the current adaper - * by reading registers 0xD and 0x90 in the EEPROM - * @bdp: atapter's private data struct + * e100_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device * - * Returns: true if ASF is enabled + * Restart the card from scratch. */ -static unsigned char -e100_asf_enabled(struct e100_private *bdp) +static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev) { - u16 asf_reg; - u16 smbus_addr_reg; - if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) { - asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF); - if ((asf_reg & EEPROM_FLAG_ASF) - && !(asf_reg & EEPROM_FLAG_GCL)) { - smbus_addr_reg = - e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR); - if ((smbus_addr_reg & 0xFF) != 0xFE) - return true; - } + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; } - return false; + pci_set_master(pdev); + + /* Only one device per card can do a reset */ + if (0 != PCI_FUNC(pdev->devfn)) + return PCI_ERS_RESULT_RECOVERED; + e100_hw_reset(nic); + e100_phy_init(nic); + + return PCI_ERS_RESULT_RECOVERED; } -#endif /* CONFIG_PM */ -#ifdef E100_CU_DEBUG -unsigned char -e100_cu_unknown_state(struct e100_private *bdp) -{ - u8 scb_cmd_low; - u16 scb_status; - scb_cmd_low = bdp->scb->scb_cmd_low; - scb_status = le16_to_cpu(bdp->scb->scb_status); - /* If CU is active and executing unknown cmd */ - if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN) - return true; - else - return false; +/** + * e100_io_resume - resume normal operations + * @pdev: Pointer to PCI device + * + * Resume normal operations after an error recovery + * sequence has been completed. + */ +static void e100_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct nic *nic = netdev_priv(netdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, 0, 0); + + netif_device_attach(netdev); + if (netif_running(netdev)) { + e100_open(netdev); + mod_timer(&nic->watchdog, jiffies); + } } + +static struct pci_error_handlers e100_err_handler = { + .error_detected = e100_io_error_detected, + .slot_reset = e100_io_slot_reset, + .resume = e100_io_resume, +}; +#endif /* E100_USE_PCI_ERS */ + +static struct pci_driver e100_driver = { + .name = DRV_NAME, + .id_table = e100_id_table, + .probe = e100_probe, + .remove = __devexit_p(e100_remove), + /* Power Management hooks */ + .suspend = e100_suspend, +#ifdef CONFIG_PM + .resume = e100_resume, +#endif +#ifdef E100_USE_SHUTDOWN_HANDLER + .shutdown = e100_shutdown, +#endif +#ifdef E100_USE_PCI_ERS + .err_handler = &e100_err_handler, #endif +}; -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling 'interrupt' - used by things like netconsole to send skbs - * without having to re-enable interrupts. It's not called while - * the interrupt routine is executing. - */ +#ifdef E100_USE_REBOOT_NOTIFIER +static int e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *ptr) +{ + struct pci_dev *pdev = NULL; + + switch (event) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) { + if (pci_dev_driver(pdev) == &e100_driver) + e100_suspend(pdev, PMSG_SUSPEND); + } + } + return NOTIFY_DONE; +} + +struct notifier_block e100_notifier_reboot = { + .notifier_call = e100_notify_reboot, + .next = NULL, + .priority = 0 +}; +#endif /* E100_USE_REBOOT_NOTIFIER */ -static void e100_netpoll (struct net_device *dev) +static int __init e100_init_module(void) { - struct e100_private *adapter = dev->priv; - disable_irq(adapter->pdev->irq); - e100intr (adapter->pdev->irq, dev, NULL); - enable_irq(adapter->pdev->irq); +#ifdef E100_USE_REBOOT_NOTIFIER + int retval; +#endif + if(((1 << debug) - 1) & NETIF_MSG_DRV) { + printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); + printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); + } +#ifdef E100_USE_REBOOT_NOTIFIER + retval = pci_register_driver(&e100_driver); + if (retval >= 0) + register_reboot_notifier(&e100_notifier_reboot); + + return retval; +#else + return pci_register_driver(&e100_driver); +#endif } + +static void __exit e100_cleanup_module(void) +{ +#ifdef E100_USE_REBOOT_NOTIFIER + unregister_reboot_notifier(&e100_notifier_reboot); #endif + pci_unregister_driver(&e100_driver); +} + +module_init(e100_init_module); +module_exit(e100_cleanup_module); diff -urN linux-2.4.35/drivers/net/e100/e100_phy.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_phy.c --- linux-2.4.35/drivers/net/e100/e100_phy.c 2004-02-18 14:36:31 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_phy.c 1970-01-01 01:00:00 +0100 @@ -1,1163 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" - -void e100_handle_zlock(struct e100_private *bdp); - -/* - * Procedure: e100_mdi_write - * - * Description: This routine will write a value to the specified MII register - * of an external MDI compliant device (e.g. PHY 100). The - * command will execute in polled mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are writing to - * phy_addr - The MDI address of the Phy component. - * data - The value that we are writing to the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - temp_val = (((u32) data) | (reg_addr << 16) | - (phy_addr << 21) | (MDI_WRITE << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi write to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) - return 0; - else { - printk(KERN_ERR "e100: MDI write timeout\n"); - return 1; - } -} - -/* - * Procedure: e100_mdi_read - * - * Description: This routine will read a value from the specified MII register - * of an external MDI compliant device (e.g. PHY 100), and return - * it to the calling routine. The command will execute in polled - * mode. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * reg_addr - The MII register that we are reading from - * phy_addr - The MDI address of the Phy component. - * - * Results: - * data - The value that we read from the MII register. - * - * Returns: - * NOTHING - */ -int -e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data) -{ - int e100_retry; - u32 temp_val; - unsigned int mdi_cntrl; - - spin_lock_bh(&bdp->mdi_access_lock); - /* Issue the read command to the MDI control register. */ - temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26)); - writel(temp_val, &bdp->scb->scb_mdi_cntrl); - readw(&bdp->scb->scb_status); - - /* wait 20usec before checking status */ - udelay(20); - - /* poll for the mdi read to complete */ - e100_retry = E100_CMD_WAIT; - while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) { - - udelay(20); - e100_retry--; - } - - spin_unlock_bh(&bdp->mdi_access_lock); - if (mdi_cntrl & MDI_PHY_READY) { - /* return the lower word */ - *data = (u16) mdi_cntrl; - return 0; - } - else { - printk(KERN_ERR "e100: MDI read timeout\n"); - return 1; - } -} - -static unsigned char -e100_phy_valid(struct e100_private *bdp, unsigned int phy_address) -{ - u16 ctrl_reg, stat_reg; - - /* Read the MDI control register */ - e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg); - - /* Read the status register twice, bacause of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg); - - if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0))) - return false; - - return true; -} - -static void -e100_phy_address_detect(struct e100_private *bdp) -{ - unsigned int addr; - unsigned char valid_phy_found = false; - - if (IS_NC3133(bdp)) { - bdp->phy_addr = 0; - return; - } - - if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) { - bdp->phy_addr = PHY_DEFAULT_ADDRESS; - valid_phy_found = true; - - } else { - for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) { - if (e100_phy_valid(bdp, addr)) { - bdp->phy_addr = addr; - valid_phy_found = true; - break; - } - } - } - - if (!valid_phy_found) { - bdp->phy_addr = PHY_ADDRESS_503; - } -} - -static void -e100_phy_id_detect(struct e100_private *bdp) -{ - u16 low_id_reg, high_id_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - bdp->PhyId = PHY_503; - return; - } - if (!(bdp->flags & IS_ICH)) { - if (bdp->rev_id >= D102_REV_ID) { - bdp->PhyId = PHY_82562ET; - return; - } - } - - /* Read phy id from the MII register */ - e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg); - e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg); - - bdp->PhyId = ((unsigned int) low_id_reg | - ((unsigned int) high_id_reg << 16)); -} - -static void -e100_phy_isolate(struct e100_private *bdp) -{ - unsigned int phy_address; - u16 ctrl_reg; - - /* Go over all phy addresses. Deisolate the selected one, and isolate - * all the rest */ - for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) { - if (phy_address != bdp->phy_addr) { - e100_mdi_write(bdp, MII_BMCR, phy_address, - BMCR_ISOLATE); - - } else { - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg); - ctrl_reg &= ~BMCR_ISOLATE; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - } - - udelay(100); - } -} - -static unsigned char -e100_phy_specific_setup(struct e100_private *bdp) -{ - u16 misc_reg; - - if (bdp->phy_addr == PHY_ADDRESS_503) { - switch (bdp->params.e100_speed_duplex) { - case E100_AUTONEG: - /* The adapter can't autoneg. so set to 10/HALF */ - printk(KERN_INFO - "e100: 503 serial component detected which " - "cannot autonegotiate\n"); - printk(KERN_INFO - "e100: speed/duplex forced to " - "10Mbps / Half duplex\n"); - bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - break; - - case E100_SPEED_100_HALF: - case E100_SPEED_100_FULL: - printk(KERN_ERR - "e100: 503 serial component detected " - "which does not support 100Mbps\n"); - printk(KERN_ERR - "e100: Change the forced speed/duplex " - "to a supported setting\n"); - return false; - } - - return true; - } - - if (IS_NC3133(bdp)) { - u16 int_reg; - - /* enable 100BASE fiber interface */ - e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr, - MDI_NC3133_100FX_ENABLE); - - if ((bdp->params.e100_speed_duplex != E100_AUTONEG) && - (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) { - /* just inform user about 100 full */ - printk(KERN_ERR "e100: NC3133 NIC can only run " - "at 100Mbps full duplex\n"); - } - - bdp->params.e100_speed_duplex = E100_SPEED_100_FULL; - - /* enable interrupts */ - e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, &int_reg); - int_reg |= MDI_NC3133_INT_ENABLE; - e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG, - bdp->phy_addr, int_reg); - } - - /* Handle the National TX */ - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) { - e100_mdi_read(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, &misc_reg); - - misc_reg |= NSC_TX_CONG_TXREADY; - - /* disable the congestion control bit in the National Phy */ - misc_reg &= ~NSC_TX_CONG_ENABLE; - - e100_mdi_write(bdp, NSC_CONG_CONTROL_REG, - bdp->phy_addr, misc_reg); - } - - return true; -} - -/* - * Procedure: e100_phy_fix_squelch - * - * Description: - * Help find link on certain rare scenarios. - * NOTE: This routine must be called once per watchdog, - * and *after* setting the current link state. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_phy_fix_squelch(struct e100_private *bdp) -{ - if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED)) - return; - - if (netif_carrier_ok(bdp->device)) { - switch (bdp->PhyState) { - case 0: - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - break; - } - bdp->PhyState = 0; - bdp->PhyDelay = 0; - - } else if (!bdp->PhyDelay--) { - switch (bdp->PhyState) { - case 0: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, EXTENDED_SQUELCH_BIT); - bdp->PhyState = 1; - break; - case 1: - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, 0x0000); - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x2010); - bdp->PhyState = 2; - break; - case 2: - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0x3000); - bdp->PhyState = 0; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - bdp->PhyDelay = 3; - } -} - -/* - * Procedure: e100_fix_polarity - * - * Description: - * Fix for 82555 auto-polarity toggle problem. With a short cable - * connecting an 82555 with an 840A link partner, if the medium is noisy, - * the 82555 sometime thinks that the polarity might be wrong and so - * toggles polarity. This happens repeatedly and results in a high bit - * error rate. - * NOTE: This happens only at 10 Mbps - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_fix_polarity(struct e100_private *bdp) -{ - u16 status; - u16 errors; - u16 misc_reg; - int speed; - - if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) && - (bdp->PhyId != PHY_82562EM)) - return; - - /* If the user wants auto-polarity disabled, do only that and nothing * - * else. * e100_autopolarity == 0 means disable --- we do just the - * disabling * e100_autopolarity == 1 means enable --- we do nothing at - * all * e100_autopolarity >= 2 means we do the workaround code. */ - /* Change for 82558 enhancement */ - switch (E100_AUTOPOLARITY) { - case 0: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg | DISABLE_AUTO_POLARITY)); - break; - - case 1: - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr, - (u16) (misc_reg & ~DISABLE_AUTO_POLARITY)); - break; - - case 2: - /* we do this only if link is up */ - if (!netif_carrier_ok(bdp->device)) { - break; - } - - e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status); - speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10; - - /* we need to do this only if speed is 10 */ - if (speed != 10) { - break; - } - - /* see if we have any end of frame errors */ - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero, wait for 100 ms before reading again */ - if (errors) { - udelay(200); - e100_mdi_read(bdp, PHY_82555_EOF_COUNTER, - bdp->phy_addr, &errors); - - /* if non-zero again, we disable polarity */ - if (errors) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - - if (!errors) { - /* it is safe to read the polarity now */ - e100_mdi_read(bdp, PHY_82555_CSR, - bdp->phy_addr, &status); - - /* if polarity is normal, disable polarity */ - if (!(status & PHY_82555_POLARITY_BIT)) { - e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, &misc_reg); - e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, - bdp->phy_addr, - (u16) (misc_reg | - DISABLE_AUTO_POLARITY)); - } - } - break; - - default: - break; - } -} - -/* - * Procedure: e100_find_speed_duplex - * - * Description: This routine will figure out what line speed and duplex mode - * the PHY is currently using. - * - * Arguments: - * bdp - Ptr to this card's e100_bdconfig structure - * - * Returns: - * NOTHING - */ -static void -e100_find_speed_duplex(struct e100_private *bdp) -{ - unsigned int PhyId; - u16 stat_reg, misc_reg; - u16 ad_reg, lp_ad_reg; - - PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK; - - /* First we should check to see if we have link */ - /* If we don't have a link no reason to print a speed and duplex */ - if (!e100_update_link_state(bdp)) { - bdp->cur_line_speed = 0; - bdp->cur_dplx_mode = 0; - return; - } - - /* On the 82559 and later controllers, speed/duplex is part of the * - * SCB. So, we save an mdi_read and get these from the SCB. * */ - if (bdp->rev_id >= D101MA_REV_ID) { - /* Read speed */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Read duplex */ - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* If this is a Phy 100, then read bits 1 and 0 of extended register 0, - * to get the current speed and duplex settings. */ - if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || - (PhyId == PHY_82555_TX)) { - - /* Read Phy 100 extended register 0 */ - e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg); - - /* Get current speed setting */ - if (misc_reg & PHY_100_ER0_SPEED_INDIC) - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get current duplex setting -- FDX enabled if bit is set */ - if (misc_reg & PHY_100_ER0_FDX_INDIC) - bdp->cur_dplx_mode = FULL_DUPLEX; - else - bdp->cur_dplx_mode = HALF_DUPLEX; - - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg); - - /* See if Auto-Negotiation was complete (bit 5, reg 1) */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* If a True NWAY connection was made, then we can detect speed/dplx - * by ANDing our adapter's advertised abilities with our link partner's - * advertised ablilities, and then assuming that the highest common - * denominator was chosed by NWAY. */ - if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) { - - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - /* AND the two advertisement registers together, and get rid - * of any extraneous bits. */ - ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY); - - /* Get speed setting */ - if (ad_reg & - (ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_100BASE4)) - - bdp->cur_line_speed = 100; - else - bdp->cur_line_speed = 10; - - /* Get duplex setting -- use priority resolution algorithm */ - if (ad_reg & ADVERTISE_100BASE4) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_100FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else if (ad_reg & ADVERTISE_100HALF) { - bdp->cur_dplx_mode = HALF_DUPLEX; - } else if (ad_reg & ADVERTISE_10FULL) { - bdp->cur_dplx_mode = FULL_DUPLEX; - } else { - bdp->cur_dplx_mode = HALF_DUPLEX; - } - - return; - } - - /* If we are connected to a dumb (non-NWAY) repeater or hub, and the - * line speed was determined automatically by parallel detection, then - * we have no way of knowing exactly what speed the PHY is set to - * unless that PHY has a propietary register which indicates speed in - * this situation. The NSC TX PHY does have such a register. Also, - * since NWAY didn't establish the connection, the duplex setting - * should HALF duplex. */ - bdp->cur_dplx_mode = HALF_DUPLEX; - - if (PhyId == PHY_NSC_TX) { - /* Read register 25 to get the SPEED_10 bit */ - e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg); - - /* If bit 6 was set then we're at 10Mbps */ - if (misc_reg & NSC_TX_SPD_INDC_SPEED) - bdp->cur_line_speed = 10; - else - bdp->cur_line_speed = 100; - - } else { - /* If we don't know the line speed, default to 10Mbps */ - bdp->cur_line_speed = 10; - } -} - -/* - * Procedure: e100_force_speed_duplex - * - * Description: This routine forces line speed and duplex mode of the - * adapter based on the values the user has set in e100.c. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -void -e100_force_speed_duplex(struct e100_private *bdp) -{ - u16 control; - unsigned long expires; - - bdp->flags |= DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 10; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = HALF_DUPLEX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - bdp->cur_line_speed = 100; - bdp->cur_dplx_mode = FULL_DUPLEX; - break; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); - - /* loop must run at least once */ - expires = jiffies + 2 * HZ; - do { - if (e100_update_link_state(bdp) || - time_after(jiffies, expires)) { - break; - } else { - yield(); - } - - } while (true); -} - -void -e100_force_speed_duplex_to_phy(struct e100_private *bdp) -{ - u16 control; - - e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); - control &= ~BMCR_ANENABLE; - control &= ~BMCR_LOOPBACK; - - switch (bdp->params.e100_speed_duplex) { - case E100_SPEED_10_HALF: - control &= ~BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_10_FULL: - control &= ~BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - - case E100_SPEED_100_HALF: - control |= BMCR_SPEED100; - control &= ~BMCR_FULLDPLX; - break; - - case E100_SPEED_100_FULL: - control |= BMCR_SPEED100; - control |= BMCR_FULLDPLX; - break; - } - - /* Send speed/duplex command to PHY layer. */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); -} - -/* - * Procedure: e100_set_fc - * - * Description: Checks the link's capability for flow control. - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: void - * - */ -static void -e100_set_fc(struct e100_private *bdp) -{ - u16 ad_reg; - u16 lp_ad_reg; - u16 exp_reg; - - /* no flow control for 82557, forced links or half duplex */ - if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) || - (bdp->cur_dplx_mode == HALF_DUPLEX) || - !(bdp->flags & IS_BACHELOR)) { - - bdp->flags &= ~DF_LINK_FC_CAP; - return; - } - - /* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */ - e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg); - - if (exp_reg & EXPANSION_NWAY) { - /* Read our advertisement register */ - e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg); - - /* Read our link partner's advertisement register */ - e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg); - - ad_reg &= lp_ad_reg; /* AND the 2 ad registers */ - - if (ad_reg & NWAY_AD_FC_SUPPORTED) - bdp->flags |= DF_LINK_FC_CAP; - else - /* If link partner is capable of autoneg, but */ - /* not capable of flow control, Received PAUSE */ - /* frames are still honored, i.e., */ - /* transmitted frames would be paused */ - /* by incoming PAUSE frames */ - bdp->flags |= DF_LINK_FC_TX_ONLY; - - } else { - bdp->flags &= ~DF_LINK_FC_CAP; - } -} - -/* - * Procedure: e100_phy_check - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * Returns: true if link state was changed - * false otherwise - * - */ -unsigned char -e100_phy_check(struct e100_private *bdp) -{ - unsigned char old_link; - unsigned char changed = false; - - old_link = netif_carrier_ok(bdp->device) ? 1 : 0; - e100_find_speed_duplex(bdp); - - if (!old_link && netif_carrier_ok(bdp->device)) { - e100_set_fc(bdp); - changed = true; - } - - if (old_link && !netif_carrier_ok(bdp->device)) { - /* reset the zero lock state */ - bdp->zlock_state = ZLOCK_INITIAL; - - // set auto lock for phy auto-negotiation on link up - if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX) - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - changed = true; - } - - e100_phy_fix_squelch(bdp); - e100_handle_zlock(bdp); - - return changed; -} - -/* - * Procedure: e100_auto_neg - * - * Description: This routine will start autonegotiation and wait - * for it to complete - * - * Arguments: - * bdp - pointer to this card's e100_bdconfig structure - * force_restart - defines if autoneg should be restarted even if it - * has been completed before - * Returns: - * NOTHING - */ -static void -e100_auto_neg(struct e100_private *bdp, unsigned char force_restart) -{ - u16 stat_reg; - unsigned long expires; - - bdp->flags &= ~DF_SPEED_FORCED; - - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - /* if we are capable of performing autoneg then we restart if needed */ - if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) { - - if ((!force_restart) && - (stat_reg & BMSR_ANEGCOMPLETE)) { - goto exit; - } - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_ANENABLE | BMCR_ANRESTART); - - /* wait for autoneg to complete (up to 3 seconds) */ - expires = jiffies + HZ * 3; - do { - /* now re-read the value. Sticky so read twice */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg); - - if ((stat_reg & BMSR_ANEGCOMPLETE) || - time_after(jiffies, expires) ) { - goto exit; - } else { - yield(); - } - } while (true); - } - -exit: - e100_find_speed_duplex(bdp); -} - -void -e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart) -{ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) { - if (bdp->rev_id >= D102_REV_ID) - /* Enable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_AUTO_SWITCH_ENABLE); - e100_auto_neg(bdp, force_restart); - - } else { - if (bdp->rev_id >= D102_REV_ID) - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - e100_force_speed_duplex(bdp); - } - - e100_set_fc(bdp); -} - -void -e100_phy_autoneg(struct e100_private *bdp) -{ - u16 ctrl_reg; - - ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET; - - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - - udelay(100); -} - -void -e100_phy_set_loopback(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_LOOPBACK; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - udelay(100); -} - -void -e100_phy_reset(struct e100_private *bdp) -{ - u16 ctrl_reg; - ctrl_reg = BMCR_RESET; - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); - /* ieee 802.3 : The reset process shall be completed */ - /* within 0.5 seconds from the settting of PHY reset bit. */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); -} - -unsigned char -e100_phy_init(struct e100_private *bdp) -{ - e100_phy_reset(bdp); - e100_phy_address_detect(bdp); - e100_phy_isolate(bdp); - e100_phy_id_detect(bdp); - - if (!e100_phy_specific_setup(bdp)) - return false; - - bdp->PhyState = 0; - bdp->PhyDelay = 0; - bdp->zlock_state = ZLOCK_INITIAL; - - e100_phy_set_speed_duplex(bdp, false); - e100_fix_polarity(bdp); - - return true; -} - -/* - * Procedure: e100_get_link_state - * - * Description: This routine checks the link status of the adapter - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_get_link_state(struct e100_private *bdp) -{ - unsigned char link = false; - u16 status; - - /* Check link status */ - /* If the controller is a 82559 or later one, link status is available - * from the CSR. This avoids the mdi_read. */ - if (bdp->rev_id >= D101MA_REV_ID) { - if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) { - link = true; - } else { - link = false; - } - - } else { - /* Read the status register twice because of sticky bits */ - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status); - - if (status & BMSR_LSTATUS) { - link = true; - } else { - link = false; - } - } - - return link; -} - -/* - * Procedure: e100_update_link_state - * - * Description: This routine updates the link status of the adapter, - * also considering netif_running - * - * Arguments: bdp - Pointer to the e100_private structure for the board - * - * - * Returns: true - If a link is found - * false - If there is no link - * - */ -unsigned char -e100_update_link_state(struct e100_private *bdp) -{ - unsigned char link; - - /* Logical AND PHY link & netif_running */ - link = e100_get_link_state(bdp) && netif_running(bdp->device); - - if (link) { - if (!netif_carrier_ok(bdp->device)) - netif_carrier_on(bdp->device); - } else { - if (netif_carrier_ok(bdp->device)) - netif_carrier_off(bdp->device); - } - - return link; -} - -/**************************************************************************\ - ** - ** PROC NAME: e100_handle_zlock - ** This function manages a state machine that controls - ** the driver's zero locking algorithm. - ** This function is called by e100_watchdog() every ~2 second. - ** States: - ** The current link handling state is stored in - ** bdp->zlock_state, and is one of: - ** ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING - ** Detailed description of the states and the transitions - ** between states is found below. - ** Note that any time the link is down / there is a reset - ** state will be changed outside this function to ZLOCK_INITIAL - ** Algorithm: - ** 1. If link is up & 100 Mbps continue else stay in #1: - ** 2. Set 'auto lock' - ** 3. Read & Store 100 times 'Zero' locked in 1 sec interval - ** 4. If max zero read >= 0xB continue else goto 1 - ** 5. Set most popular 'Zero' read in #3 - ** 6. Sleep 5 minutes - ** 7. Read number of errors, if it is > 300 goto 2 else goto 6 - ** Data Structures (in DRIVER_DATA): - ** zlock_state - current state of the algorithm - ** zlock_read_cnt - counts number of reads (up to 100) - ** zlock_read_data[i] - counts number of times 'Zero' read was i, 0 <= i <= 15 - ** zlock_sleep_cnt - keeps track of "sleep" time (up to 300 secs = 5 minutes) - ** - ** Parameters: DRIVER_DATA *bdp - ** - ** bdp - Pointer to HSM's adapter data space - ** - ** Return Value: NONE - ** - ** See Also: e100_watchdog() - ** - \**************************************************************************/ -void -e100_handle_zlock(struct e100_private *bdp) -{ - u16 pos; - u16 eq_reg; - u16 err_cnt; - u8 mpz; /* Most Popular Zero */ - - switch (bdp->zlock_state) { - case ZLOCK_INITIAL: - - if (((u8) bdp->rev_id <= D102_REV_ID) || - !(bdp->cur_line_speed == 100) || - !netif_carrier_ok(bdp->device)) { - break; - } - - /* initialize hw and sw and start reading */ - e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, 0); - /* reset read counters: */ - bdp->zlock_read_cnt = 0; - for (pos = 0; pos < 16; pos++) - bdp->zlock_read_data[pos] = 0; - /* start reading in the next call back: */ - bdp->zlock_state = ZLOCK_READING; - - /* FALL THROUGH !! */ - - case ZLOCK_READING: - /* state: reading (100 times) zero locked in 1 sec interval - * prev states: ZLOCK_INITIAL - * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */ - - e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, &eq_reg); - pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4; - bdp->zlock_read_data[pos]++; - bdp->zlock_read_cnt++; - - if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) { - /* check if we read a 'Zero' value of 0xB or greater */ - if ((bdp->zlock_read_data[0xB]) || - (bdp->zlock_read_data[0xC]) || - (bdp->zlock_read_data[0xD]) || - (bdp->zlock_read_data[0xE]) || - (bdp->zlock_read_data[0xF])) { - - /* we've read 'Zero' value of 0xB or greater, - * find most popular 'Zero' value and lock it */ - mpz = 0; - /* this loop finds the most popular 'Zero': */ - for (pos = 1; pos < 16; pos++) { - if (bdp->zlock_read_data[pos] > - bdp->zlock_read_data[mpz]) - - mpz = pos; - } - /* now lock the most popular 'Zero': */ - eq_reg = (ZLOCK_SET_ZERO | mpz); - e100_mdi_write(bdp, - PHY_82555_MDI_EQUALIZER_CSR, - bdp->phy_addr, eq_reg); - - /* sleep for 5 minutes: */ - bdp->zlock_sleep_cnt = jiffies; - bdp->zlock_state = ZLOCK_SLEEPING; - /* we will be reading the # of errors after 5 - * minutes, so we need to reset the error - * counters - these registers are self clearing - * on read, so read them */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - - } else { - /* we did not read a 'Zero' value of 0xB or - * above. go back to the start */ - bdp->zlock_state = ZLOCK_INITIAL; - } - - } - break; - - case ZLOCK_SLEEPING: - /* state: sleeping for 5 minutes - * prev states: ZLOCK_READING - * next states: ZLOCK_READING, ZLOCK_SLEEPING */ - - /* if 5 minutes have passed: */ - if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) { - /* read and sum up the number of errors: */ - e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR, - bdp->phy_addr, &err_cnt); - /* if we've more than 300 errors (this number was - * calculated according to the spec max allowed errors - * (80 errors per 1 million frames) for 5 minutes in - * 100 Mbps (or the user specified max BER number) */ - if (err_cnt > bdp->params.ber) { - /* start again in the next callback: */ - bdp->zlock_state = ZLOCK_INITIAL; - } else { - /* we don't have more errors than allowed, - * sleep for 5 minutes */ - bdp->zlock_sleep_cnt = jiffies; - } - } - break; - - default: - break; - } -} diff -urN linux-2.4.35/drivers/net/e100/e100_phy.h linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_phy.h --- linux-2.4.35/drivers/net/e100/e100_phy.h 2007-08-07 17:00:38 +0200 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_phy.h 1970-01-01 01:00:00 +0100 @@ -1,158 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_PHY_INC_ -#define _E100_PHY_INC_ - -#include "e100.h" - -/* - * Auto-polarity enable/disable - * e100_autopolarity = 0 => disable auto-polarity - * e100_autopolarity = 1 => enable auto-polarity - * e100_autopolarity = 2 => let software determine - */ -#define E100_AUTOPOLARITY 2 - -#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \ - ((bdp)->pdev->subsystem_device == 0xB0E1)) - -#define PHY_503 0 -#define PHY_100_A 0x000003E0 -#define PHY_100_C 0x035002A8 -#define PHY_NSC_TX 0x5c002000 -#define PHY_82562ET 0x033002A8 -#define PHY_82562EM 0x032002A8 -#define PHY_82562EH 0x017002A8 -#define PHY_82555_TX 0x015002a8 /* added this for 82555 */ -#define PHY_OTHER 0xFFFF -#define MAX_PHY_ADDR 31 -#define MIN_PHY_ADDR 0 - -#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF - -#define PHY_DEFAULT_ADDRESS 1 -#define PHY_ADDRESS_503 32 - -/* MDI Control register bit definitions */ -#define MDI_PHY_READY BIT_28 /* PHY is ready for next MDI cycle */ - -#define MDI_NC3133_CONFIG_REG 0x19 -#define MDI_NC3133_100FX_ENABLE BIT_2 -#define MDI_NC3133_INT_ENABLE_REG 0x17 -#define MDI_NC3133_INT_ENABLE BIT_1 - -/* MDI Control register opcode definitions */ -#define MDI_WRITE 1 /* Phy Write */ -#define MDI_READ 2 /* Phy read */ - -/* MDI register set*/ -#define AUTO_NEG_NEXT_PAGE_REG 0x07 /* Auto-negotiation next page xmit */ -#define EXTENDED_REG_0 0x10 /* Extended reg 0 (Phy 100 modes) */ -#define EXTENDED_REG_1 0x14 /* Extended reg 1 (Phy 100 error indications) */ -#define NSC_CONG_CONTROL_REG 0x17 /* National (TX) congestion control */ -#define NSC_SPEED_IND_REG 0x19 /* National (TX) speed indication */ - -#define HWI_CONTROL_REG 0x1D /* HWI Control register */ -/* MDI/MDI-X Control Register bit definitions */ -#define MDI_MDIX_RES_TIMER BIT_0_3 /* minimum slot time for resolution timer */ -#define MDI_MDIX_CONFIG_IS_OK BIT_4 /* 1 = resolution algorithm completes OK */ -#define MDI_MDIX_STATUS BIT_5 /* 1 = MDIX (croos over), 0 = MDI (straight through) */ -#define MDI_MDIX_SWITCH BIT_6 /* 1 = Forces to MDIX, 0 = Forces to MDI */ -#define MDI_MDIX_AUTO_SWITCH_ENABLE BIT_7 /* 1 = MDI/MDI-X feature enabled */ -#define MDI_MDIX_CONCT_CONFIG BIT_8 /* Sets the MDI/MDI-X connectivity configuration (test prupose only) */ -#define MDI_MDIX_CONCT_TEST_ENABLE BIT_9 /* 1 = Enables connectivity testing */ -#define MDI_MDIX_RESET_ALL_MASK 0x0000 - -/* HWI Control Register bit definitions */ -#define HWI_TEST_DISTANCE BIT_0_8 /* distance to cable problem */ -#define HWI_TEST_HIGHZ_PROBLEM BIT_9 /* 1 = Open Circuit */ -#define HWI_TEST_LOWZ_PROBLEM BIT_10 /* 1 = Short Circuit */ -#define HWI_TEST_RESERVED (BIT_11 | BIT_12) /* reserved */ -#define HWI_TEST_EXECUTE BIT_13 /* 1 = Execute the HWI test on the PHY */ -#define HWI_TEST_ABILITY BIT_14 /* 1 = test passed */ -#define HWI_TEST_ENABLE BIT_15 /* 1 = Enables the HWI feature */ -#define HWI_RESET_ALL_MASK 0x0000 - -/* ############Start of 82555 specific defines################## */ - -/* Intel 82555 specific registers */ -#define PHY_82555_CSR 0x10 /* 82555 CSR */ -#define PHY_82555_SPECIAL_CONTROL 0x11 /* 82555 special control register */ - -#define PHY_82555_RCV_ERR 0x15 /* 82555 100BaseTx Receive Error - * Frame Counter */ -#define PHY_82555_SYMBOL_ERR 0x16 /* 82555 RCV Symbol Error Counter */ -#define PHY_82555_PREM_EOF_ERR 0x17 /* 82555 100BaseTx RCV Premature End - * of Frame Error Counter */ -#define PHY_82555_EOF_COUNTER 0x18 /* 82555 end of frame error counter */ -#define PHY_82555_MDI_EQUALIZER_CSR 0x1a /* 82555 specific equalizer reg. */ - -/* 82555 CSR bits */ -#define PHY_82555_SPEED_BIT BIT_1 -#define PHY_82555_POLARITY_BIT BIT_8 - -/* 82555 equalizer reg. opcodes */ -#define ENABLE_ZERO_FORCING 0x2010 /* write to ASD conf. reg. 0 */ -#define DISABLE_ZERO_FORCING 0x2000 /* write to ASD conf. reg. 0 */ - -/* 82555 special control reg. opcodes */ -#define DISABLE_AUTO_POLARITY 0x0010 -#define EXTENDED_SQUELCH_BIT BIT_2 - -/* ############End of 82555 specific defines##################### */ - -/* Auto-Negotiation advertisement register bit definitions*/ -#define NWAY_AD_FC_SUPPORTED 0x0400 /* Flow Control supported */ - -/* Auto-Negotiation link partner ability register bit definitions*/ -#define NWAY_LP_ABILITY 0x07e0 /* technologies supported */ - -/* PHY 100 Extended Register 0 bit definitions*/ -#define PHY_100_ER0_FDX_INDIC BIT_0 /* 1 = FDX, 0 = half duplex */ -#define PHY_100_ER0_SPEED_INDIC BIT_1 /* 1 = 100Mbps, 0= 10Mbps */ - -/* National Semiconductor TX phy congestion control register bit definitions*/ -#define NSC_TX_CONG_TXREADY BIT_10 /* Makes TxReady an input */ -#define NSC_TX_CONG_ENABLE BIT_8 /* Enables congestion control */ - -/* National Semiconductor TX phy speed indication register bit definitions*/ -#define NSC_TX_SPD_INDC_SPEED BIT_6 /* 0 = 100Mbps, 1=10Mbps */ - -/************* function prototypes ************/ -extern unsigned char e100_phy_init(struct e100_private *bdp); -extern unsigned char e100_update_link_state(struct e100_private *bdp); -extern unsigned char e100_phy_check(struct e100_private *bdp); -extern void e100_phy_set_speed_duplex(struct e100_private *bdp, - unsigned char force_restart); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern int e100_mdi_write(struct e100_private *, u32, u32, u16); -extern int e100_mdi_read(struct e100_private *, u32, u32, u16 *); - -#endif diff -urN linux-2.4.35/drivers/net/e100/e100_test.c linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_test.c --- linux-2.4.35/drivers/net/e100/e100_test.c 2004-02-18 14:36:31 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_test.c 1970-01-01 01:00:00 +0100 @@ -1,500 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#include "e100_phy.h" -#include "e100_config.h" - -extern u16 e100_eeprom_read(struct e100_private *, u16); -extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8); -extern void e100_phy_reset(struct e100_private *bdp); -extern void e100_phy_autoneg(struct e100_private *bdp); -extern void e100_phy_set_loopback(struct e100_private *bdp); -extern void e100_force_speed_duplex(struct e100_private *bdp); - -static u8 e100_diag_selftest(struct net_device *); -static u8 e100_diag_eeprom(struct net_device *); -static u8 e100_diag_loopback(struct net_device *); - -static u8 e100_diag_one_loopback (struct net_device *, u8); -static u8 e100_diag_rcv_loopback_pkt(struct e100_private *); -static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *); -static u8 e100_diag_loopback_alloc(struct e100_private *); -static void e100_diag_loopback_cu_ru_exec(struct e100_private *); -static u8 e100_diag_check_pkt(u8 *); -static void e100_diag_loopback_free(struct e100_private *); -static int e100_cable_diag(struct e100_private *bdp); - -#define LB_PACKET_SIZE 1500 - -/** - * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines - * @dev: atapter's net device data struct - * @test_info: array with test request mask also used to store test results - * - * RETURNS: updated flags field of struct ethtool_test - */ -u32 -e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) -{ - struct e100_private* bdp = dev->priv; - u8 test_result = 0; - - if (!e100_get_link_state(bdp)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_link] = true; - } - if (!e100_diag_eeprom(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_eeprom] = true; - } - if (flags & ETH_TEST_FL_OFFLINE) { - u8 fail_mask; - if (netif_running(dev)) { - spin_lock_bh(&dev->xmit_lock); - e100_close(dev); - spin_unlock_bh(&dev->xmit_lock); - } - if (e100_diag_selftest(dev)) { - test_result = ETH_TEST_FL_FAILED; - test_info[test_self_test] = true; - } - - fail_mask = e100_diag_loopback(dev); - if (fail_mask) { - test_result = ETH_TEST_FL_FAILED; - if (fail_mask & PHY_LOOPBACK) - test_info[test_loopback_phy] = true; - if (fail_mask & MAC_LOOPBACK) - test_info[test_loopback_mac] = true; - } - - test_info[cable_diag] = e100_cable_diag(bdp); - /* Need hw init regardless of netif_running */ - e100_hw_init(bdp); - if (netif_running(dev)) { - e100_open(dev); - } - } - else { - test_info[test_self_test] = false; - test_info[test_loopback_phy] = false; - test_info[test_loopback_mac] = false; - test_info[cable_diag] = false; - } - - return flags | test_result; -} - -/** - * e100_diag_selftest - run hardware selftest - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_selftest(struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u32 st_timeout, st_result; - u8 retval = 0; - - if (!e100_selftest(bdp, &st_timeout, &st_result)) { - if (!st_timeout) { - if (st_result & CB_SELFTEST_REGISTER_BIT) - retval |= REGISTER_TEST_FAIL; - if (st_result & CB_SELFTEST_DIAG_BIT) - retval |= SELF_TEST_FAIL; - if (st_result & CB_SELFTEST_ROM_BIT) - retval |= ROM_TEST_FAIL; - } else { - retval = TEST_TIMEOUT; - } - } - - return retval; -} - -/** - * e100_diag_eeprom - validate eeprom checksum correctness - * @dev: atapter's net device data struct - * - */ -static u8 -e100_diag_eeprom (struct net_device *dev) -{ - struct e100_private *bdp = dev->priv; - u16 i, eeprom_sum, eeprom_actual_csm; - - for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) { - eeprom_sum += e100_eeprom_read(bdp, i); - } - - eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1); - - if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) { - return true; - } - - return false; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - */ -static u8 -e100_diag_loopback (struct net_device *dev) -{ - u8 rc = 0; - - printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { - rc |= PHY_LOOPBACK; - } - printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); - - printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_hw_init(dev->priv); - if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { - rc |= MAC_LOOPBACK; - } - printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name); - - return rc; -} - -/** - * e100_diag_loopback - performs loopback test - * @dev: atapter's net device data struct - * @mode: lopback test type - */ -static u8 -e100_diag_one_loopback (struct net_device *dev, u8 mode) -{ - struct e100_private *bdp = dev->priv; - u8 res = false; - u8 saved_dynamic_tbd = false; - u8 saved_extended_tcb = false; - - if (!e100_diag_loopback_alloc(bdp)) - return false; - - /* change the config block to standard tcb and the correct loopback */ - e100_diag_config_loopback(bdp, true, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - - e100_diag_loopback_cu_ru_exec(bdp); - - if (e100_diag_rcv_loopback_pkt(bdp)) { - res = true; - } - - e100_diag_loopback_free(bdp); - - /* change the config block to previous tcb mode and the no loopback */ - e100_diag_config_loopback(bdp, false, mode, - &saved_extended_tcb, &saved_dynamic_tbd); - return res; -} - -/** - * e100_diag_config_loopback - setup/clear loopback before/after lpbk test - * @bdp: atapter's private data struct - * @set_loopback: true if the function is called to set lb - * @loopback_mode: the loopback mode(MAC or PHY) - * @tcb_extended: true if need to set extended tcb mode after clean loopback - * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback - * - */ -void -e100_diag_config_loopback(struct e100_private* bdp, - u8 set_loopback, - u8 loopback_mode, - u8* tcb_extended, - u8* dynamic_tbd) -{ - /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd. - * the previous values are saved in the params tcb_extended/dynamic_tbd - * if set_loopback == false - we want to restore previous value. - */ - if (set_loopback || (*tcb_extended)) - *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended); - - if (set_loopback || (*dynamic_tbd)) - *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); - - if (set_loopback) { - /* ICH PHY loopback is broken */ - if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK) - loopback_mode = MAC_LOOPBACK; - /* Configure loopback on MAC */ - e100_config_loopback_mode(bdp,loopback_mode); - } else { - e100_config_loopback_mode(bdp,NO_LOOPBACK); - } - - e100_config(bdp); - - if (loopback_mode == PHY_LOOPBACK) { - if (set_loopback) - /* Set PHY loopback mode */ - e100_phy_set_loopback(bdp); - else - /* Reset PHY loopback mode */ - e100_phy_reset(bdp); - /* Wait for PHY state change */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } else { /* For MAC loopback wait 500 msec to take effect */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 2); - } -} - -/** - * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback - * @bdp: atapter's private data struct - * - */ -static u8 -e100_diag_loopback_alloc(struct e100_private *bdp) -{ - dma_addr_t dma_handle; - tcb_t *tcb; - rfd_t *rfd; - tbd_t *tbd; - - /* tcb, tbd and transmit buffer are allocated */ - tcb = pci_alloc_consistent(bdp->pdev, - (sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE), - &dma_handle); - if (tcb == NULL) - return false; - - memset(tcb, 0x00, sizeof (tcb_t) + sizeof (tbd_t) + LB_PACKET_SIZE); - tcb->tcb_phys = dma_handle; - tcb->tcb_hdr.cb_status = 0; - tcb->tcb_hdr.cb_cmd = - cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT); - /* Next command is null */ - tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(0xffffffff); - tcb->tcb_cnt = 0; - tcb->tcb_thrshld = bdp->tx_thld; - tcb->tcb_tbd_num = 1; - /* Set up tcb tbd pointer */ - tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t)); - tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t)); - /* Set up tbd transmit buffer */ - tbd->tbd_buf_addr = - cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t)); - tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024); - /* The value of first 512 bytes is FF */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 512); - /* The value of second 512 bytes is BA */ - memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512); - wmb(); - rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle); - - if (rfd == NULL) { - pci_free_consistent(bdp->pdev, - sizeof (tcb_t) + sizeof (tbd_t) + - LB_PACKET_SIZE, tcb, tcb->tcb_phys); - return false; - } - - memset(rfd, 0x00, sizeof (rfd_t)); - - /* init all fields in rfd */ - rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT); - rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE); - /* dma_handle is physical address of rfd */ - bdp->loopback.dma_handle = dma_handle; - bdp->loopback.tcb = tcb; - bdp->loopback.rfd = rfd; - wmb(); - return true; -} - -/** - * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) -{ - /*load CU & RU base */ - if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) - printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); - - bdp->next_cu_cmd = START_WAIT; - e100_start_cu(bdp, bdp->loopback.tcb); - bdp->last_tcb = NULL; - rmb(); -} -/** - * e100_diag_check_pkt - checks if a given packet is a loopback packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_check_pkt(u8 *datap) -{ - int i; - for (i = 0; i<512; i++) { - if( !((*datap)==0xFF && (*(datap + 512) == 0xBA)) ) { - printk (KERN_ERR "e100: check loopback packet failed at: %x\n", i); - return false; - } - } - printk (KERN_DEBUG "e100: Check received loopback packet OK\n"); - return true; -} - -/** - * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet - * @bdp: atapter's private data struct - * - * Returns true if OK false otherwise. - */ -static u8 -e100_diag_rcv_loopback_pkt(struct e100_private* bdp) -{ - rfd_t *rfdp; - u16 rfd_status; - unsigned long expires = jiffies + HZ * 2; - - rfdp =bdp->loopback.rfd; - - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - - while (!(rfd_status & RFD_STATUS_COMPLETE)) { - if (time_before(jiffies, expires)) { - yield(); - rmb(); - rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status); - } else { - break; - } - } - - if (rfd_status & RFD_STATUS_COMPLETE) { - printk(KERN_DEBUG "e100: Loopback packet received\n"); - return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size)); - } - else { - printk(KERN_ERR "e100: Loopback packet not received\n"); - return false; - } -} - -/** - * e100_diag_loopback_free - free data allocated for loopback pkt send/receive - * @bdp: atapter's private data struct - * - */ -static void -e100_diag_loopback_free (struct e100_private *bdp) -{ - pci_free_consistent(bdp->pdev, - sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE, - bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys); - - pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd, - bdp->loopback.dma_handle); -} - -static int -e100_cable_diag(struct e100_private *bdp) -{ - int saved_open_circut = 0xffff; - int saved_short_circut = 0xffff; - int saved_distance = 0xffff; - int saved_same = 0; - int cable_status = E100_CABLE_UNKNOWN; - int i; - - /* If we have link, */ - if (e100_get_link_state(bdp)) - return E100_CABLE_OK; - - if (bdp->rev_id < D102_REV_ID) - return E100_CABLE_UNKNOWN; - - /* Disable MDI/MDI-X auto switching */ - e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, - MDI_MDIX_RESET_ALL_MASK); - /* Set to 100 Full as required by cable test */ - e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, - BMCR_SPEED100 | BMCR_FULLDPLX); - - /* Test up to 100 times */ - for (i = 0; i < 100; i++) { - u16 ctrl_reg; - int distance, open_circut, short_circut, near_end; - - /* Enable and execute cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, - (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); - /* Wait for cable test finished */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100 + 1); - /* Read results */ - e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); - distance = ctrl_reg & HWI_TEST_DISTANCE; - open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; - short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; - - if ((distance == saved_distance) && - (open_circut == saved_open_circut) && - (short_circut == saved_short_circut)) - saved_same++; - else { - saved_same = 0; - saved_distance = distance; - saved_open_circut = open_circut; - saved_short_circut = short_circut; - } - /* If results are the same 3 times */ - if (saved_same == 3) { - near_end = ((distance * HWI_REGISTER_GRANULARITY) < - HWI_NEAR_END_BOUNDARY); - if (open_circut) - cable_status = (near_end) ? - E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; - if (short_circut) - cable_status = (near_end) ? - E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; - break; - } - } - /* Reset cable test */ - e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); - return cable_status; -} - diff -urN linux-2.4.35/drivers/net/e100/e100_ucode.h linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_ucode.h --- linux-2.4.35/drivers/net/e100/e100_ucode.h 2004-08-08 01:26:05 +0200 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/e100_ucode.h 1970-01-01 01:00:00 +0100 @@ -1,384 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - Linux NICS - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef _E100_UCODE_H_ -#define _E100_UCODE_H_ - -/* -e100_ucode.h - -This file contains the loadable micro code arrays to implement receive -bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, -D102 B-step, D102 B-step with TCO work around and D102 C-step. - -Each controller has its own specific micro code array. The array for one -controller is totally incompatible with any other controller, and if used -will most likely cause the controller to lock up and stop responding to -the driver. Each micro code array has its own parameter offsets (described -below), and they each have their own version number. -*/ - -/************************************************************************* -* CPUSaver parameters -* -* All CPUSaver parameters are 16-bit literals that are part of a -* "move immediate value" instruction. By changing the value of -* the literal in the instruction before the code is loaded, the -* driver can change algorithm. -* -* CPUSAVER_DWORD - This is the location of the instruction that loads -* the dead-man timer with its inital value. By writing a 16-bit -* value to the low word of this instruction, the driver can change -* the timer value. The current default is either x600 or x800; -* experiments show that the value probably should stay within the -* range of x200 - x1000. -* -* CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction -* that sets the maximum number of frames that will be bundled. In -* some situations, such as the TCP windowing algorithm, it may be -* better to limit the growth of the bundle size than let it go as -* high as it can, because that could cause too much added latency. -* The default is six, because this is the number of packets in the -* default TCP window size. A value of 1 would make CPUSaver indicate -* an interrupt for every frame received. If you do not want to put -* a limit on the bundle size, set this value to xFFFF. -* -* CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction -* that contains a bit-mask describing the minimum size frame that -* will be bundled. The default masks the lower 7 bits, which means -* that any frame less than 128 bytes in length will not be bundled, -* but will instead immediately generate an interrupt. This does -* not affect the current bundle in any way. Any frame that is 128 -* bytes or large will be bundled normally. This feature is meant -* to provide immediate indication of ACK frames in a TCP environment. -* Customers were seeing poor performance when a machine with CPUSaver -* enabled was sending but not receiving. The delay introduced when -* the ACKs were received was enough to reduce total throughput, because -* the sender would sit idle until the ACK was finally seen. -* -* The current default is 0xFF80, which masks out the lower 7 bits. -* This means that any frame which is x7F (127) bytes or smaller -* will cause an immediate interrupt. Because this value must be a -* bit mask, there are only a few valid values that can be used. To -* turn this feature off, the driver can write the value xFFFF to the -* lower word of this instruction (in the same way that the other -* parameters are used). Likewise, a value of 0xF800 (2047) would -* cause an interrupt to be generated for every frame, because all -* standard Ethernet frames are <= 2047 bytes in length. -*************************************************************************/ - -#ifndef UCODE_MAX_DWORDS -#define UCODE_MAX_DWORDS 134 -#endif - -/********************************************************/ -/* CPUSaver micro code for the D101A */ -/********************************************************/ - -/* Version 2.0 */ - -/* This value is the same for both A and B step of 558. */ - -#define D101_CPUSAVER_TIMER_DWORD 72 -#define D101_CPUSAVER_BUNDLE_DWORD UCODE_MAX_DWORDS -#define D101_CPUSAVER_MIN_SIZE_DWORD UCODE_MAX_DWORDS - -#define D101_A_RCVBUNDLE_UCODE \ -{\ -0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \ -0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \ -0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \ -0x00101213, 0x00041000, 0x0038051E, 0x00101313, \ -0x00010400, 0x00380521, 0x00050600, 0x00100824, \ -0x00101310, 0x00041000, 0x00080600, 0x00101B10, \ -0x0038051E, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101B */ -/********************************************************/ - -/* Version 2.0 */ - -#define D101_B0_RCVBUNDLE_UCODE \ -{\ -0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ -0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \ -0x00000000, 0x00124818, 0x000C1000, 0x00220809, \ -0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \ -0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \ -0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \ -0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \ -0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \ -0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \ -0x00010400, 0x00380522, 0x00050600, 0x00100837, \ -0x00101310, 0x00041000, 0x00080600, 0x00101790, \ -0x0038051F, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101M (B-step only) */ -/********************************************************/ - -/* Version 2.10.1 */ - -/* Parameter values for the D101M B-step */ -#define D101M_CPUSAVER_TIMER_DWORD 78 -#define D101M_CPUSAVER_BUNDLE_DWORD 65 -#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 - -#define D101M_B_RCVBUNDLE_UCODE \ -{\ -0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ -0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ -0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ -0x00380438, 0x00000000, 0x00140000, 0x00380555, \ -0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ -0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ -0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ -0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ -0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ -0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ -0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ -0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ -0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ -0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ -0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ -0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ -0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ -0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ -0x00380559, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ -0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ -0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ -} - -/********************************************************/ -/* CPUSaver micro code for the D101S */ -/********************************************************/ - -/* Version 1.20.1 */ - -/* Parameter values for the D101S */ -#define D101S_CPUSAVER_TIMER_DWORD 78 -#define D101S_CPUSAVER_BUNDLE_DWORD 67 -#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 - -#define D101S_RCVBUNDLE_UCODE \ -{\ -0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ -0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ -0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ -0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ -0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ -0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ -0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ -0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ -0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ -0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ -0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ -0x00101313, 0x00380700, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ -0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ -0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ -0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ -0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ -0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ -0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ -0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ -0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00130831, \ -0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ -0x00041000, 0x00010004, 0x00380700 \ -} - -/********************************************************/ -/* CPUSaver micro code for the D102 B-step */ -/********************************************************/ - -/* Version 2.0 */ -/* Parameter values for the D102 B-step */ -#define D102_B_CPUSAVER_TIMER_DWORD 82 -#define D102_B_CPUSAVER_BUNDLE_DWORD 106 -#define D102_B_CPUSAVER_MIN_SIZE_DWORD 70 - -#define D102_B_RCVBUNDLE_UCODE \ -{\ -0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \ -0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \ -0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \ -0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \ -0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \ -0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \ -0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \ -0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \ -0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \ -0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \ -0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \ -0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \ -0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \ -0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \ -0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \ -0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \ -0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \ -0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \ -0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \ -0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \ -0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \ -0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \ -0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \ -} - -/********************************************************/ -/* Micro code for the D102 C-step */ -/********************************************************/ - -/* Parameter values for the D102 C-step */ -#define D102_C_CPUSAVER_TIMER_DWORD 46 -#define D102_C_CPUSAVER_BUNDLE_DWORD 74 -#define D102_C_CPUSAVER_MIN_SIZE_DWORD 54 - -#define D102_C_RCVBUNDLE_UCODE \ -{ \ -0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \ -0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \ -0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \ -0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \ -0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \ -0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \ -0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \ -0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \ -0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \ -0x00E00E85, 0x00000000, 0x00000000, 0x00000000 \ -} - -/********************************************************/ -/* Micro code for the D102 E-step */ -/********************************************************/ - -/* Parameter values for the D102 E-step */ -#define D102_E_CPUSAVER_TIMER_DWORD 42 -#define D102_E_CPUSAVER_BUNDLE_DWORD 54 -#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 - -#define D102_E_RCVBUNDLE_UCODE \ -{\ -0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \ -0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ -0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ -0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ -0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \ -0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -} - -#endif /* _E100_UCODE_H_ */ diff -urN linux-2.4.35/drivers/net/e100/kcompat.h linux-2.4.35-e100-3.5.17/drivers/net/e100/kcompat.h --- linux-2.4.35/drivers/net/e100/kcompat.h 1970-01-01 01:00:00 +0100 +++ linux-2.4.35-e100-3.5.17/drivers/net/e100/kcompat.h 2006-09-14 22:58:08 +0200 @@ -0,0 +1,1731 @@ +/******************************************************************************* + + Intel PRO/100 Linux driver + Copyright(c) 1999 - 2006 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _KCOMPAT_H_ +#define _KCOMPAT_H_ + +#include + +#ifdef E100_NAPI +#undef CONFIG_E100_NAPI +#define CONFIG_E100_NAPI +#endif + +#ifdef E100_NO_NAPI +#undef CONFIG_E100_NAPI +#endif + +#ifdef DISABLE_PM +#undef CONFIG_PM +#endif + +#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) ) +#define E100_USE_PCI_ERS +#endif + +#ifndef PMSG_SUSPEND +#define PMSG_SUSPEND 3 +#endif + +#ifndef module_param +#define module_param(v,t,p) MODULE_PARM(v, "i"); +#endif + +#ifndef DMA_64BIT_MASK +#define DMA_64BIT_MASK 0xffffffffffffffffULL +#endif + +#ifndef DMA_32BIT_MASK +#define DMA_32BIT_MASK 0x00000000ffffffffULL +#endif + +/*****************************************************************************/ +#ifndef unlikely +#define unlikely(_x) _x +#define likely(_x) _x +#endif +/*****************************************************************************/ + +/*****************************************************************************/ +/* Installations with ethtool version without eeprom, adapter id, or statistics + * support */ +#ifndef ETH_GSTRING_LEN +#define ETH_GSTRING_LEN 32 +#endif + +#ifndef ETHTOOL_GSTATS +#define ETHTOOL_GSTATS 0x1d +#undef ethtool_drvinfo +#define ethtool_drvinfo k_ethtool_drvinfo +struct k_ethtool_drvinfo { + uint32_t cmd; + char driver[32]; + char version[32]; + char fw_version[32]; + char bus_info[32]; + char reserved1[32]; + char reserved2[16]; + uint32_t n_stats; + uint32_t testinfo_len; + uint32_t eedump_len; + uint32_t regdump_len; +}; + +struct ethtool_stats { + uint32_t cmd; + uint32_t n_stats; + uint64_t data[0]; +}; + +#ifndef ETHTOOL_PHYS_ID +#define ETHTOOL_PHYS_ID 0x1c +#ifndef ETHTOOL_GSTRINGS +#define ETHTOOL_GSTRINGS 0x1b +enum ethtool_stringset { + ETH_SS_TEST = 0, + ETH_SS_STATS, +}; +struct ethtool_gstrings { + u32 cmd; /* ETHTOOL_GSTRINGS */ + u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ + u32 len; /* number of strings in the string set */ + u8 data[0]; +}; +#ifndef ETHTOOL_TEST +#define ETHTOOL_TEST 0x1a +enum ethtool_test_flags { + ETH_TEST_FL_OFFLINE = (1 << 0), + ETH_TEST_FL_FAILED = (1 << 1), +}; +struct ethtool_test { + uint32_t cmd; + uint32_t flags; + uint32_t reserved; + uint32_t len; + uint64_t data[0]; +}; +#ifndef ETHTOOL_GEEPROM +#define ETHTOOL_GEEPROM 0xb +#undef ETHTOOL_GREGS +struct ethtool_eeprom { + uint32_t cmd; + uint32_t magic; + uint32_t offset; + uint32_t len; + uint8_t data[0]; +}; + +struct ethtool_value { + uint32_t cmd; + uint32_t data; +}; + +#ifndef ETHTOOL_GLINK +#define ETHTOOL_GLINK 0xa +#endif /* Ethtool version without link support */ +#endif /* Ethtool version without eeprom support */ +#endif /* Ethtool version without test support */ +#endif /* Ethtool version without strings support */ +#endif /* Ethtool version wihtout adapter id support */ +#endif /* Ethtool version without statistics support */ + +#ifndef ETHTOOL_GREGS +#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers */ +#define ethtool_regs _kc_ethtool_regs +/* for passing big chunks of data */ +struct _kc_ethtool_regs { + u32 cmd; + u32 version; /* driver-specific, indicates different chips/revs */ + u32 len; /* bytes */ + u8 data[0]; +}; +#endif +#ifndef ETHTOOL_GMSGLVL +#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ +#endif +#ifndef ETHTOOL_SMSGLVL +#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ +#endif +#ifndef ETHTOOL_NWAY_RST +#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv */ +#endif +#ifndef ETHTOOL_GLINK +#define ETHTOOL_GLINK 0x0000000a /* Get link status */ +#endif +#ifndef ETHTOOL_GEEPROM +#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ +#endif +#ifndef ETHTOOL_SEEPROM +#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */ +#endif +#ifndef ETHTOOL_GCOALESCE +#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ +/* for configuring coalescing parameters of chip */ +#define ethtool_coalesce _kc_ethtool_coalesce +struct _kc_ethtool_coalesce { + u32 cmd; /* ETHTOOL_{G,S}COALESCE */ + + /* How many usecs to delay an RX interrupt after + * a packet arrives. If 0, only rx_max_coalesced_frames + * is used. + */ + u32 rx_coalesce_usecs; + + /* How many packets to delay an RX interrupt after + * a packet arrives. If 0, only rx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause RX interrupts to never be + * generated. + */ + u32 rx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + u32 rx_coalesce_usecs_irq; + u32 rx_max_coalesced_frames_irq; + + /* How many usecs to delay a TX interrupt after + * a packet is sent. If 0, only tx_max_coalesced_frames + * is used. + */ + u32 tx_coalesce_usecs; + + /* How many packets to delay a TX interrupt after + * a packet is sent. If 0, only tx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause TX interrupts to never be + * generated. + */ + u32 tx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + u32 tx_coalesce_usecs_irq; + u32 tx_max_coalesced_frames_irq; + + /* How many usecs to delay in-memory statistics + * block updates. Some drivers do not have an in-memory + * statistic block, and in such cases this value is ignored. + * This value must not be zero. + */ + u32 stats_block_coalesce_usecs; + + /* Adaptive RX/TX coalescing is an algorithm implemented by + * some drivers to improve latency under low packet rates and + * improve throughput under high packet rates. Some drivers + * only implement one of RX or TX adaptive coalescing. Anything + * not implemented by the driver causes these values to be + * silently ignored. + */ + u32 use_adaptive_rx_coalesce; + u32 use_adaptive_tx_coalesce; + + /* When the packet rate (measured in packets per second) + * is below pkt_rate_low, the {rx,tx}_*_low parameters are + * used. + */ + u32 pkt_rate_low; + u32 rx_coalesce_usecs_low; + u32 rx_max_coalesced_frames_low; + u32 tx_coalesce_usecs_low; + u32 tx_max_coalesced_frames_low; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the + * normal {rx,tx}_* coalescing parameters are used. + */ + + /* When the packet rate is (measured in packets per second) + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ + u32 pkt_rate_high; + u32 rx_coalesce_usecs_high; + u32 rx_max_coalesced_frames_high; + u32 tx_coalesce_usecs_high; + u32 tx_max_coalesced_frames_high; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ + u32 rate_sample_interval; +}; +#endif +#ifndef ETHTOOL_SCOALESCE +#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ +#endif +#ifndef ETHTOOL_GRINGPARAM +#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ +/* for configuring RX/TX ring parameters */ +#define ethtool_ringparam _kc_ethtool_ringparam +struct _kc_ethtool_ringparam { + u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ + + /* Read only attributes. These indicate the maximum number + * of pending RX/TX ring entries the driver will allow the + * user to set. + */ + u32 rx_max_pending; + u32 rx_mini_max_pending; + u32 rx_jumbo_max_pending; + u32 tx_max_pending; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ + u32 rx_pending; + u32 rx_mini_pending; + u32 rx_jumbo_pending; + u32 tx_pending; +}; +#endif +#ifndef ETHTOOL_SRINGPARAM +#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */ +#endif +#ifndef ETHTOOL_GPAUSEPARAM +#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ +/* for configuring link flow control parameters */ +#define ethtool_pauseparam _kc_ethtool_pauseparam +struct _kc_ethtool_pauseparam { + u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ + + /* If the link is being auto-negotiated (via ethtool_cmd.autoneg + * being true) the user may set 'autonet' here non-zero to have the + * pause parameters be auto-negotiated too. In such a case, the + * {rx,tx}_pause values below determine what capabilities are + * advertised. + * + * If 'autoneg' is zero or the link is not being auto-negotiated, + * then {rx,tx}_pause force the driver to use/not-use pause + * flow control. + */ + u32 autoneg; + u32 rx_pause; + u32 tx_pause; +}; +#endif +#ifndef ETHTOOL_SPAUSEPARAM +#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ +#endif +#ifndef ETHTOOL_GRXCSUM +#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_SRXCSUM +#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_GTXCSUM +#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_STXCSUM +#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_GSG +#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable + * (ethtool_value) */ +#endif +#ifndef ETHTOOL_SSG +#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable + * (ethtool_value). */ +#endif +#ifndef ETHTOOL_TEST +#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ +#endif +#ifndef ETHTOOL_GSTRINGS +#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ +#endif +#ifndef ETHTOOL_PHYS_ID +#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ +#endif +#ifndef ETHTOOL_GSTATS +#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ +#endif +#ifndef ETHTOOL_GTSO +#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ +#endif +#ifndef ETHTOOL_STSO +#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ +#endif + +/* 2.4.0 => 2.2.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + +/**************************************/ +/* MODULE API */ + +#ifndef __init + #define __init +#endif + +#ifndef __exit + #define __exit +#endif + +#ifndef __devinit + #define __devinit +#endif + +#ifndef __devexit + #define __devexit +#endif + +#ifndef __devinitdata + #define __devinitdata +#endif + +#ifndef module_init + #define module_init(f) int init_module() { return f(); } +#endif + +#ifndef module_exit + #define module_exit(f) void cleanup_module() { return f(); } +#endif + +#ifndef MODULE_DEVICE_TABLE + #define MODULE_DEVICE_TABLE(bus, table) +#endif + +#ifndef SET_MODULE_OWNER + #define SET_MODULE_OWNER(X) +#else + #undef MOD_INC_USE_COUNT + #undef MOD_DEC_USE_COUNT + #define MOD_INC_USE_COUNT + #define MOD_DEC_USE_COUNT +#endif + +/**************************************/ +/* PCI DRIVER API */ + +#ifndef pci_device_id +#define pci_device_id _kc_pci_device_id +struct _kc_pci_device_id { + unsigned int vendor, device; + unsigned int subvendor, subdevice; + unsigned int class, classmask; + unsigned long driver_data; +}; +#endif + +#ifndef pci_driver +#define pci_driver _kc_pci_driver +struct _kc_pci_driver { + char *name; + struct pci_device_id *id_table; + int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); + void (*remove)(struct pci_dev *dev); + int (*save_state)(struct pci_dev *dev, u32 state); + int (*suspend)(struct pci_dev *dev, u32 state); + int (*resume)(struct pci_dev *dev); + int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); +}; +#endif + +#ifndef PCI_ANY_ID + #define PCI_ANY_ID (~0U) +#endif + +#ifndef pci_module_init +#define pci_module_init _kc_pci_module_init +extern int _kc_pci_module_init(struct pci_driver *drv); +#endif + +#ifndef pci_unregister_driver +#define pci_unregister_driver _kc_pci_unregister_driver +extern void _kc_pci_unregister_driver(struct pci_driver *drv); +#endif + +#ifndef pci_set_drvdata +#define pci_set_drvdata _kc_pci_set_drvdata +extern void _kc_pci_set_drvdata(struct pci_dev *dev, void *data); +#endif + +#ifndef pci_get_drvdata +#define pci_get_drvdata _kc_pci_get_drvdata +extern void * _kc_pci_get_drvdata(struct pci_dev *dev); +#endif + +#ifndef pci_enable_device +#define pci_enable_device _kc_pci_enable_device +extern int _kc_pci_enable_device(struct pci_dev *dev); +#endif + +#ifndef pci_resource_start +#define pci_resource_start _kc_pci_resource_start +extern int _kc_pci_resource_start(struct pci_dev *dev, int bar); +#endif + +#ifndef pci_resource_len +#define pci_resource_len _kc_pci_resource_len +extern unsigned long _kc_pci_resource_len(struct pci_dev *dev, int bar); +#endif + +#undef IORESOURCE_IO +#define IORESOURCE_IO PCI_BASE_ADDRESS_SPACE_IO + +#undef pci_resource_flags +#define pci_resource_flags(dev, i) (dev->base_address[i] & IORESOURCE_IO) + +/**************************************/ +/* PCI DMA MAPPING */ + +#ifndef PCI_DMA_TODEVICE + #define PCI_DMA_TODEVICE 1 +#endif + +#ifndef PCI_DMA_FROMDEVICE + #define PCI_DMA_FROMDEVICE 2 +#endif + +#ifndef dma_addr_t +#define dma_addr_t _kc_dma_addr_t +typedef u64 _kc_dma_addr_t; +#endif + +#ifndef pci_alloc_consistent +#define pci_alloc_consistent _kc_pci_alloc_consistent +extern void * _kc_pci_alloc_consistent(struct pci_dev *dev, size_t size, u64 *dma_handle); +#endif + +#ifndef pci_free_consistent +#define pci_free_consistent _kc_pci_free_consistent +extern void _kc_pci_free_consistent(struct pci_dev *dev, size_t size, void *vaddr, u64 dma_handle); +#endif + +#ifndef pci_map_single +#define pci_map_single _kc_pci_map_single +extern u64 _kc_pci_map_single(struct pci_dev *dev, void *addr, size_t size, int direction); +#endif + +#ifndef pci_unmap_single +#define pci_unmap_single _kc_pci_unmap_single +extern void _kc_pci_unmap_single(struct pci_dev *dev, u64 dma_addr, size_t size, int direction); +#endif + +#ifndef pci_dma_sync_single +#define pci_dma_sync_single _kc_pci_dma_sync_single +extern void _kc_pci_dma_sync_single(struct pci_dev *dev, u64 dma_addr, size_t size, int direction); +#endif + +/**************************************/ +/* NETWORK DRIVER API */ + +#ifndef net_device + #define net_device device +#endif + +#ifndef dev_kfree_skb_irq + #define dev_kfree_skb_irq dev_kfree_skb +#endif + +#ifndef dev_kfree_skb_any + #define dev_kfree_skb_any dev_kfree_skb +#endif + +#ifndef netif_running + #define netif_running(dev) (!!(int)(dev->flags & IFF_RUNNING)) +#endif + +#ifndef netif_start_queue + #define netif_start_queue(dev) clear_bit(0, &dev->tbusy) +#endif + +#ifndef netif_stop_queue + #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) +#endif + +#ifndef netif_wake_queue + #define netif_wake_queue(dev) do { clear_bit(0, &dev->tbusy); \ + mark_bh(NET_BH); } while(0) +#endif + +#ifndef netif_queue_stopped + #define netif_queue_stopped(dev) (dev->tbusy) +#endif + +#ifndef netif_device_attach +#define netif_device_attach _kc_netif_device_attach +extern void _kc_netif_device_attach(struct net_device *dev); +#endif + +#ifndef netif_device_detach +#define netif_device_detach _kc_netif_device_detach +extern void _kc_netif_device_detach(struct net_device *dev); +#endif + +#ifndef netif_carrier_on +#define netif_carrier_on _kc_netif_carrier_on +extern void _kc_netif_carrier_on(struct net_device *dev); +#endif + +#ifndef netif_carrier_off +#define netif_carrier_off _kc_netif_carrier_off +extern void _kc_netif_carrier_off(struct net_device *dev); +#endif + +#ifndef netif_carrier_ok +#define netif_carrier_ok _kc_netif_carrier_ok +extern int _kc_netif_carrier_ok(struct net_device *dev); +#endif + +/**************************************/ +/* OTHER */ + +#ifndef del_timer_sync + #define del_timer_sync del_timer +#endif + +#ifndef BUG + #define BUG() printk(KERN_CRIT "BUG in %s at line %d\n", __FILE__, __LINE__) +#endif + +#ifndef set_current_state + #define set_current_state(S) current->state = (S) +#endif + +#ifndef list_for_each + #define list_for_each(pos, head) \ + for(pos = (head)->next; pos != (head); pos = pos->next) +#endif + +#ifndef list_add_tail + #define list_add_tail(new, head) __list_add(new, (head)->prev, (head)) +#endif + +#ifndef ARRARY_SIZE + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#else /* remove 2.2.x only compatibility stuff */ + + #undef MOD_INC_USE_COUNT + #undef MOD_DEC_USE_COUNT + #define MOD_INC_USE_COUNT + #define MOD_DEC_USE_COUNT + +#endif /* 2.4.0 => 2.2.0 */ + + +/*****************************************************************************/ +/* 2.4.3 => 2.4.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) + +/**************************************/ +/* PCI DRIVER API */ + +#ifndef pci_set_dma_mask +#define pci_set_dma_mask _kc_pci_set_dma_mask +extern int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); +#endif + +#ifndef pci_request_regions +#define pci_request_regions _kc_pci_request_regions +extern int _kc_pci_request_regions(struct pci_dev *pdev, char *res_name); +#endif + +#ifndef pci_release_regions +#define pci_release_regions _kc_pci_release_regions +extern void _kc_pci_release_regions(struct pci_dev *pdev); +#endif + +/**************************************/ +/* NETWORK DRIVER API */ + +#ifndef alloc_etherdev +#define alloc_etherdev _kc_alloc_etherdev +extern struct net_device * _kc_alloc_etherdev(int sizeof_priv); +#endif + +#ifndef is_valid_ether_addr +#define is_valid_ether_addr _kc_is_valid_ether_addr +extern int _kc_is_valid_ether_addr(u8 *addr); +#endif + +#endif /* 2.4.3 => 2.4.0 */ + +/*****************************************************************************/ +/* 2.4.6 => 2.4.3 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) + +#ifndef pci_set_power_state +#define pci_set_power_state _kc_pci_set_power_state +extern int _kc_pci_set_power_state(struct pci_dev *dev, int state); +#endif + +#ifndef pci_save_state +#define pci_save_state _kc_pci_save_state +extern int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer); +#endif + +#ifndef pci_restore_state +#define pci_restore_state _kc_pci_restore_state +extern int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer); +#endif + +#ifndef pci_enable_wake +#define pci_enable_wake _kc_pci_enable_wake +extern int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable); +#endif + +#ifndef pci_disable_device +#define pci_disable_device _kc_pci_disable_device +extern void _kc_pci_disable_device(struct pci_dev *pdev); +#endif + +/* PCI PM entry point syntax changed, so don't support suspend/resume */ +#undef CONFIG_PM + +#endif /* 2.4.6 => 2.4.3 */ + +/*****************************************************************************/ +/* 2.4.10 => 2.4.6 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) ) + +/**************************************/ +/* MODULE API */ + +#ifndef MODULE_LICENSE + #define MODULE_LICENSE(X) +#endif + +/**************************************/ +/* OTHER */ + +#undef min +#define min(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#undef max +#define max(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + +#endif /* 2.4.10 -> 2.4.6 */ + +/*****************************************************************************/ +/* 2.4.13 => 2.4.10 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) + +/**************************************/ +/* PCI DMA MAPPING */ + +#ifndef virt_to_page + #define virt_to_page(v) (mem_map + (virt_to_phys(v) >> PAGE_SHIFT)) +#endif + +#ifndef pci_map_page +#define pci_map_page _kc_pci_map_page +extern u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction); +#endif + +#ifndef pci_unmap_page +#define pci_unmap_page _kc_pci_unmap_page +extern void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction); +#endif + +/* pci_set_dma_mask takes dma_addr_t, which is only 32-bits prior to 2.4.13 */ + +#undef PCI_DMA_32BIT +#define PCI_DMA_32BIT 0xffffffff +#undef PCI_DMA_64BIT +#define PCI_DMA_64BIT 0xffffffff + +/**************************************/ +/* OTHER */ + +#ifndef cpu_relax +#define cpu_relax() rep_nop() +#endif + +#endif /* 2.4.13 => 2.4.10 */ + +/*****************************************************************************/ +/* 2.4.19 => 2.4.12 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) ) + +#ifndef __devexit_p + #define __devexit_p(x) &(x) +#endif + +#ifndef VLAN_HLEN +#define VLAN_HLEN 4 +#endif + +#ifndef VLAN_ETH_HLEN +#define VLAN_ETH_HLEN 18 +#endif + +#ifndef VLAN_ETH_FRAME_LEN +#define VLAN_ETH_FRAME_LEN 1518 +#endif + +#endif /* 2.4.19 => 2.4.13 */ + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) || \ + ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) ) +#define ETHTOOL_OPS_COMPAT +#endif + +/*****************************************************************************/ +/* 2.4.20 => 2.4.19 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) ) + +/* we won't support NAPI on less than 2.4.20 */ +#ifdef CONFIG_E100_NAPI +#undef CONFIG_E100_NAPI +#endif + +#ifndef HAVE_NETIF_MSG +/* + * Network interface message level settings + */ +#define HAVE_NETIF_MSG 1 + +enum { + NETIF_MSG_DRV = 0x0001, + NETIF_MSG_PROBE = 0x0002, + NETIF_MSG_LINK = 0x0004, + NETIF_MSG_TIMER = 0x0008, + NETIF_MSG_IFDOWN = 0x0010, + NETIF_MSG_IFUP = 0x0020, + NETIF_MSG_RX_ERR = 0x0040, + NETIF_MSG_TX_ERR = 0x0080, + NETIF_MSG_TX_QUEUED = 0x0100, + NETIF_MSG_INTR = 0x0200, + NETIF_MSG_TX_DONE = 0x0400, + NETIF_MSG_RX_STATUS = 0x0800, + NETIF_MSG_PKTDATA = 0x1000, + NETIF_MSG_HW = 0x2000, + NETIF_MSG_WOL = 0x4000, +}; +#else +#define NETIF_MSG_HW 0x2000 +#define NETIF_MSG_WOL 0x4000 +#endif + +#ifndef MII_RESV1 +#define MII_RESV1 0x17 /* Reserved... */ +#endif + +#endif /* 2.4.20 => 2.4.18 */ + +#ifndef ETHTOOL_BUSINFO_LEN +#define ETHTOOL_BUSINFO_LEN 32 +#endif + + +#define mii_if_info _kc_mii_if_info +struct _kc_mii_if_info { + int phy_id; + int advertising; + int phy_id_mask; + int reg_num_mask; + + unsigned int full_duplex : 1; /* is full duplex? */ + unsigned int force_media : 1; /* is autoneg. disabled? */ + + struct net_device *dev; + int (*mdio_read) (struct net_device *dev, int phy_id, int location); + void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); +}; + +struct ethtool_cmd; +struct mii_ioctl_data; + +#undef mii_link_ok +#define mii_link_ok _kc_mii_link_ok +#undef mii_nway_restart +#define mii_nway_restart _kc_mii_nway_restart +#undef mii_ethtool_gset +#define mii_ethtool_gset _kc_mii_ethtool_gset +#undef mii_ethtool_sset +#define mii_ethtool_sset _kc_mii_ethtool_sset +#undef mii_check_link +#define mii_check_link _kc_mii_check_link +#undef generic_mii_ioctl +#define generic_mii_ioctl _kc_generic_mii_ioctl +extern int _kc_mii_link_ok (struct mii_if_info *mii); +extern int _kc_mii_nway_restart (struct mii_if_info *mii); +extern int _kc_mii_ethtool_gset(struct mii_if_info *mii, + struct ethtool_cmd *ecmd); +extern int _kc_mii_ethtool_sset(struct mii_if_info *mii, + struct ethtool_cmd *ecmd); +extern void _kc_mii_check_link (struct mii_if_info *mii); +extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, + struct mii_ioctl_data *mii_data, int cmd, + unsigned int *duplex_changed); + + +struct _kc_pci_dev_ext { + struct pci_dev *dev; + void *pci_drvdata; + struct pci_driver *driver; +}; + +struct _kc_net_dev_ext { + struct net_device *dev; + unsigned int carrier; +}; + + +/**************************************/ +/* mii support */ + +int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) +{ + struct net_device *dev = mii->dev; + u32 advert, bmcr, lpa, nego; + + ecmd->supported = + (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); + + /* only supports twisted-pair */ + ecmd->port = PORT_MII; + + /* only supports internal transceiver */ + ecmd->transceiver = XCVR_INTERNAL; + + /* this isn't fully supported at higher layers */ + ecmd->phy_address = mii->phy_id; + + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); + if (advert & ADVERTISE_10HALF) + ecmd->advertising |= ADVERTISED_10baseT_Half; + if (advert & ADVERTISE_10FULL) + ecmd->advertising |= ADVERTISED_10baseT_Full; + if (advert & ADVERTISE_100HALF) + ecmd->advertising |= ADVERTISED_100baseT_Half; + if (advert & ADVERTISE_100FULL) + ecmd->advertising |= ADVERTISED_100baseT_Full; + + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA); + if (bmcr & BMCR_ANENABLE) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->autoneg = AUTONEG_ENABLE; + + nego = mii_nway_result(advert & lpa); + if (nego == LPA_100FULL || nego == LPA_100HALF) + ecmd->speed = SPEED_100; + else + ecmd->speed = SPEED_10; + if (nego == LPA_100FULL || nego == LPA_10FULL) { + ecmd->duplex = DUPLEX_FULL; + mii->full_duplex = 1; + } else { + ecmd->duplex = DUPLEX_HALF; + mii->full_duplex = 0; + } + } else { + ecmd->autoneg = AUTONEG_DISABLE; + + ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; + ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + } + + /* ignore maxtxpkt, maxrxpkt for now */ + + return 0; +} + +int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) +{ + struct net_device *dev = mii->dev; + + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + return -EINVAL; + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + if (ecmd->port != PORT_MII) + return -EINVAL; + if (ecmd->transceiver != XCVR_INTERNAL) + return -EINVAL; + if (ecmd->phy_address != mii->phy_id) + return -EINVAL; + if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + return -EINVAL; + + /* ignore supported, maxtxpkt, maxrxpkt */ + + if (ecmd->autoneg == AUTONEG_ENABLE) { + u32 bmcr, advert, tmp; + + if ((ecmd->advertising & (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full)) == 0) + return -EINVAL; + + /* advertise only what has been requested */ + advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); + tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (ADVERTISED_10baseT_Half) + tmp |= ADVERTISE_10HALF; + if (ADVERTISED_10baseT_Full) + tmp |= ADVERTISE_10FULL; + if (ADVERTISED_100baseT_Half) + tmp |= ADVERTISE_100HALF; + if (ADVERTISED_100baseT_Full) + tmp |= ADVERTISE_100FULL; + if (advert != tmp) { + mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); + mii->advertising = tmp; + } + + /* turn on autonegotiation, and force a renegotiate */ + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); + + mii->force_media = 0; + } else { + u32 bmcr, tmp; + + /* turn off auto negotiation, set speed and duplexity */ + bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); + tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); + if (ecmd->speed == SPEED_100) + tmp |= BMCR_SPEED100; + if (ecmd->duplex == DUPLEX_FULL) { + tmp |= BMCR_FULLDPLX; + mii->full_duplex = 1; + } else + mii->full_duplex = 0; + if (bmcr != tmp) + mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); + + mii->force_media = 1; + } + return 0; +} + +int _kc_mii_link_ok (struct mii_if_info *mii) +{ + /* first, a dummy read, needed to latch some MII phys */ + mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); + if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS) + return 1; + return 0; +} + +int _kc_mii_nway_restart (struct mii_if_info *mii) +{ + int bmcr; + int r = -EINVAL; + + /* if autoneg is off, it's an error */ + bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); + + if (bmcr & BMCR_ANENABLE) { + bmcr |= BMCR_ANRESTART; + mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr); + r = 0; + } + + return r; +} + +void _kc_mii_check_link (struct mii_if_info *mii) +{ + int cur_link = mii_link_ok(mii); + int prev_link = netif_carrier_ok(mii->dev); + + if (cur_link && !prev_link) + netif_carrier_on(mii->dev); + else if (prev_link && !cur_link) + netif_carrier_off(mii->dev); +} + +int _kc_generic_mii_ioctl(struct mii_if_info *mii_if, + struct mii_ioctl_data *mii_data, int cmd, + unsigned int *duplex_chg_out) +{ + int rc = 0; + unsigned int duplex_changed = 0; + + if (duplex_chg_out) + *duplex_chg_out = 0; + + mii_data->phy_id &= mii_if->phy_id_mask; + mii_data->reg_num &= mii_if->reg_num_mask; + + switch(cmd) { + case SIOCDEVPRIVATE: /* binary compat, remove in 2.5 */ + case SIOCGMIIPHY: + mii_data->phy_id = mii_if->phy_id; + /* fall through */ + + case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */ + case SIOCGMIIREG: + mii_data->val_out = + mii_if->mdio_read(mii_if->dev, mii_data->phy_id, + mii_data->reg_num); + break; + + case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */ + case SIOCSMIIREG: { + u16 val = mii_data->val_in; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (mii_data->phy_id == mii_if->phy_id) { + switch(mii_data->reg_num) { + case MII_BMCR: { + unsigned int new_duplex = 0; + if (val & (BMCR_RESET|BMCR_ANENABLE)) + mii_if->force_media = 0; + else + mii_if->force_media = 1; + if (mii_if->force_media && + (val & BMCR_FULLDPLX)) + new_duplex = 1; + if (mii_if->full_duplex != new_duplex) { + duplex_changed = 1; + mii_if->full_duplex = new_duplex; + } + break; + } + case MII_ADVERTISE: + mii_if->advertising = val; + break; + default: + /* do nothing */ + break; + } + } + + mii_if->mdio_write(mii_if->dev, mii_data->phy_id, + mii_data->reg_num, val); + break; + } + + default: + rc = -EOPNOTSUPP; + break; + } + + if ((rc == 0) && (duplex_chg_out) && (duplex_changed)) + *duplex_chg_out = 1; + + return rc; +} + +/*****************************************************************************/ +/* 2.4.13 => 2.4.3 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) ) + +/**************************************/ +/* PCI DMA MAPPING */ + +#if defined(CONFIG_HIGHMEM) + +#ifndef PCI_DRAM_OFFSET +#define PCI_DRAM_OFFSET 0 +#endif + +u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction) +{ + return (((u64)(page - mem_map) << PAGE_SHIFT) + offset + PCI_DRAM_OFFSET); +} + +#else /* CONFIG_HIGHMEM */ + +u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction) +{ + return pci_map_single(dev, (void *)page_address(page) + offset, size, direction); +} + +#endif /* CONFIG_HIGHMEM */ + +void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction) +{ + return pci_unmap_single(dev, dma_addr, size, direction); +} + +#endif /* 2.4.13 => 2.4.3 */ + + +/*****************************************************************************/ +/* 2.4.3 => 2.4.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) ) + +/**************************************/ +/* PCI DRIVER API */ + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) +int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) { return 0; } +#else +int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +{ + if(!pci_dma_supported(dev, mask)) + return -EIO; + dev->dma_mask = mask; + return 0; +} +#endif + +int _kc_pci_request_regions(struct pci_dev *dev, char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(dev, i) == 0) + continue; + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + if ((dev->base_address[i] & PCI_BASE_ADDRESS_SPACE_IO)) + request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name); +#else + if (pci_resource_flags(dev, i) & IORESOURCE_IO) { + if (!request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) { + pci_release_regions(dev); + return -EBUSY; + } + } else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) { + if (!request_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) { + pci_release_regions(dev); + return -EBUSY; + } + } +#endif + } + return 0; +} + +void _kc_pci_release_regions(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(dev, i) == 0) + continue; + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + if ((dev->base_address[i] & PCI_BASE_ADDRESS_SPACE)) + release_region(pci_resource_start(dev, i), pci_resource_len(dev, i)); +#else + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + release_region(pci_resource_start(dev, i), pci_resource_len(dev, i)); + + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + release_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i)); +#endif + } +} + +/**************************************/ +/* NETWORK DRIVER API */ + +#define _KC_MAX_NET_DEV 32 +static int my_net_count = 0; +static struct _kc_net_dev_ext my_net_devices[_KC_MAX_NET_DEV]; + +struct net_device * _kc_alloc_etherdev(int sizeof_priv) +{ + struct net_device *dev; + int alloc_size; + + if(my_net_count >= _KC_MAX_NET_DEV) + return NULL; + + alloc_size = sizeof (*dev) + sizeof_priv + IFNAMSIZ + 31; + + dev = kmalloc(alloc_size, GFP_KERNEL); + + if (!dev) return NULL; + + memset(dev, 0, alloc_size); + + if (sizeof_priv) + dev->priv = (void *) (((unsigned long)(dev + 1) + 31) & ~31); + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + dev->name = (char *) dev->priv + sizeof_priv; +#endif + dev->name[0] = '\0'; + + ether_setup(dev); + + my_net_devices[my_net_count].dev = dev; + my_net_count++; + + return dev; +} + +int _kc_is_valid_ether_addr(u8 *addr) +{ + const char zaddr[6] = {0,}; + + return !(addr[0]&1) && memcmp( addr, zaddr, 6); +} + +#endif /* 2.4.3 => 2.4.0 */ + + +/*****************************************************************************/ +/* 2.4.0 => 2.2.0 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ) + +/**************************************/ +/* PCI DRIVER API */ + +#define _KC_MAX_PCI_DEV 32 +static int my_pci_count = 0; +static struct _kc_pci_dev_ext my_pci_devices[_KC_MAX_PCI_DEV]; + +int _kc_pci_module_init(struct pci_driver *drv) +{ + struct pci_dev *dev; + struct pci_device_id *pciid; + uint16_t subvendor, subdevice; + + my_pci_count = 0; + + for(dev = pci_devices; dev; dev = dev->next) { + + if(my_pci_count >= _KC_MAX_PCI_DEV) + break; + + pciid = &drv->id_table[0]; + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); + + while(pciid->vendor != 0) { + if(((pciid->vendor == dev->vendor) || + (pciid->vendor == PCI_ANY_ID)) && + + ((pciid->device == dev->device) || + (pciid->device == PCI_ANY_ID)) && + + ((pciid->subvendor == subvendor) || + (pciid->subvendor == PCI_ANY_ID)) && + + ((pciid->subdevice == subdevice) || + (pciid->subdevice == PCI_ANY_ID))) { + + my_pci_devices[my_pci_count].dev = dev; + my_pci_devices[my_pci_count].driver = drv; + my_pci_count++; + if(drv->probe(dev, pciid)) { + my_pci_count--; + my_pci_devices[my_pci_count].dev = NULL; + } + break; + } + pciid++; + } + } + return (my_pci_count > 0) ? 0 : -ENODEV; +} + +void _kc_pci_unregister_driver(struct pci_driver *drv) +{ + int i; + for(i = 0; i < my_pci_count; i++) { + if(my_pci_devices[i].dev) { + drv->remove(my_pci_devices[i].dev); + my_pci_devices[i].dev = NULL; + } + } + my_pci_count = 0; +} + +void _kc_pci_set_drvdata(struct pci_dev *dev, void *data) +{ + int i; + for(i = 0; i < my_pci_count; i++) { + if(my_pci_devices[i].dev == dev) { + my_pci_devices[i].pci_drvdata = data; + } + } +} + +void * _kc_pci_get_drvdata(struct pci_dev *dev) +{ + int i; + for(i = 0; i < my_pci_count; i++) { + if(my_pci_devices[i].dev == dev) { + return my_pci_devices[i].pci_drvdata; + } + } + return NULL; +} + +int _kc_pci_enable_device(struct pci_dev *dev) { return 0; } + +int _kc_pci_resource_start(struct pci_dev *dev, int bar) +{ + return ((dev->base_address[bar] & PCI_BASE_ADDRESS_SPACE) ? + (dev->base_address[bar] & PCI_BASE_ADDRESS_IO_MASK) : + (dev->base_address[bar] & PCI_BASE_ADDRESS_MEM_MASK)); +} + +unsigned long _kc_pci_resource_len(struct pci_dev *dev, int bar) +{ + u32 old, len; + + int bar_reg = PCI_BASE_ADDRESS_0 + (bar << 2); + + pci_read_config_dword(dev, bar_reg, &old); + pci_write_config_dword(dev, bar_reg, ~0); + pci_read_config_dword(dev, bar_reg, &len); + pci_write_config_dword(dev, bar_reg, old); + + if((len & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) + len = ~(len & PCI_BASE_ADDRESS_MEM_MASK); + else + len = ~(len & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; + return (len + 1); +} + +struct pci_driver *_kc_pci_dev_driver(struct pci_dev *dev) +{ + int i; + for(i = 0; i < my_pci_count; i++) { + if(my_pci_devices[i].dev == dev) { + return my_pci_devices[i].driver; + } + } + return NULL; +} + +/**************************************/ +/* PCI DMA MAPPING */ + +void * _kc_pci_alloc_consistent(struct pci_dev *dev, size_t size, u64 *dma_handle) +{ + void *vaddr = kmalloc(size, GFP_KERNEL); + + if(vaddr) + *dma_handle = virt_to_bus(vaddr); + return vaddr; +} + +void _kc_pci_free_consistent(struct pci_dev *dev, size_t size, void *addr, u64 dma_handle) +{ + kfree(addr); +} + +u64 _kc_pci_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + return virt_to_bus(addr); +} + +void _kc_pci_unmap_single(struct pci_dev *dev, u64 dma_addr, size_t size, int direction) { return; } + +void _kc_pci_dma_sync_single(struct pci_dev *dev, u64 dma_addr, size_t size, int direction) { return; } + +/**************************************/ +/* NETWORK DRIVER API */ + +void _kc_netif_device_attach(struct net_device *dev) +{ + if(netif_running(dev) && netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } +} + +void _kc_netif_device_detach(struct net_device *dev) +{ + if(netif_running(dev)) { + netif_stop_queue(dev); + } +} + +void _kc_netif_carrier_on(struct net_device *dev) +{ + int i; + for(i = 0; i < my_net_count; i++) { + if(my_net_devices[i].dev == dev) { + set_bit(0, &my_net_devices[i].carrier); + } + } +} + +void _kc_netif_carrier_off(struct net_device *dev) +{ + int i; + for(i = 0; i < my_net_count; i++) { + if(my_net_devices[i].dev == dev) { + clear_bit(0, &my_net_devices[i].carrier); + } + } +} + +int _kc_netif_carrier_ok(struct net_device *dev) +{ + int i; + for(i = 0; i < my_net_count; i++) { + if(my_net_devices[i].dev == dev) { + return test_bit(0, &my_net_devices[i].carrier); + } + } + return 0; +} + +#endif /* 2.4.0 => 2.2.0 */ + +/*****************************************************************************/ +/* 2.4.6 => 2.4.3 */ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) ) + +int _kc_pci_set_power_state(struct pci_dev *dev, int state) +{ return 0; } +int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer) +{ return 0; } +int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer) +{ return 0; } +int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable) +{ return 0; } +void _kc_pci_disable_device(struct pci_dev *pdev) +{} + +#endif /* 2.4.6 => 2.4.3 */ + +#ifndef IRQ_HANDLED +#define irqreturn_t void +#define IRQ_HANDLED +#define IRQ_NONE +#endif + +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(net, pdev) +#endif + +#ifndef likely +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#ifndef HAVE_FREE_NETDEV +#define free_netdev(x) kfree(x) +#endif + +#ifdef HAVE_POLL_CONTROLLER +#define CONFIG_NET_POLL_CONTROLLER +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) ) +#define pci_name(x) ((x)->slot_name) +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) ) +#ifdef CONFIG_E100_NAPI +#ifndef netif_poll_disable +#define netif_poll_disable(x) _kc_netif_poll_disable(x) +static inline void _kc_netif_poll_disable(struct net_device *dev) +{ + while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) { + /* No hurry. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +} +#endif + +#ifndef netif_poll_enable +#define netif_poll_enable(x) _kc_netif_poll_enable(x) +static inline void _kc_netif_poll_enable(struct net_device *dev) +{ + clear_bit(__LINK_STATE_RX_SCHED, &dev->state); +} +#endif +#endif +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) ) +#include +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task +#define MODULE_INFO(version, _version) +#endif + +#ifndef module_param +#define module_param(v,t,p) MODULE_PARM(v, "i"); +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) +#define MODULE_VERSION(_version) MODULE_INFO(version, _version) +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) +#define pci_dma_sync_single_for_cpu pci_dma_sync_single +#define pci_dma_sync_single_for_device pci_dma_sync_single_for_cpu +#define pci_dma_mapping_error(X) 0 +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) ) +#undef if_mii +#define if_mii _kc_if_mii +static inline struct mii_ioctl_data *_kc_if_mii(struct ifreq *rq) +{ + return (struct mii_ioctl_data *) &rq->ifr_ifru; +} +#endif /* < 2.6.7 */ + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) ) +#define msleep(x) do { set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout((x * HZ)/1000 + 2); \ + } while(0) +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) ) +#define msleep_interruptible(x) do {set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout((x * HZ)/1000); \ + } while(0) +#define __iomem +#endif + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) +#ifdef pci_save_state +#undef pci_save_state +#endif +#define pci_save_state(X) { \ + int i; \ + if (nic->pm_state) { \ + for (i = 0; i < 16; i++) { \ + pci_read_config_dword((X), \ + i * 4, \ + &nic->pm_state[i]); \ + } \ + } \ +} + +#ifdef pci_restore_state +#undef pci_restore_state +#endif +#define pci_restore_state(X) { \ + int i; \ + if (nic->pm_state) { \ + for (i = 0; i < 16; i++) { \ + pci_write_config_dword((X), \ + i * 4, \ + nic->pm_state[i]); \ + } \ + } else { \ + for (i = 0; i < 6; i++) { \ + pci_write_config_dword((X), \ + PCI_BASE_ADDRESS_0 + (i * 4), \ + (X)->resource[i].start); \ + } \ + pci_write_config_byte((X), PCI_INTERRUPT_LINE, (X)->irq); \ + } \ +} +#endif /* 2.4.6 <= x < 2.6.10 */ + +#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) ) || \ + (( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) && \ + ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) ))) +#define netdev_priv(x) x->priv +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) ) +#ifdef module_param_array_named +#undef module_param_array_named +#define module_param_array_named(name, array, type, nump, perm) \ + static struct kparam_array __param_arr_##name \ + = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type, \ + sizeof(array[0]), array }; \ + module_param_call(name, param_array_set, param_array_get, \ + &__param_arr_##name, perm) +#endif /* module_param_array_named */ +#endif /* < 2.6.10 */ + +#ifndef NET_IP_ALIGN +#define NET_IP_ALIGN 2 +#endif + + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ) +#define PCI_D0 0 +#define PCI_D1 1 +#define PCI_D2 2 +#define PCI_D3hot 3 +#define PCI_D3cold 4 +#define pci_choose_state(pdev,state) state +#endif + +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ) +#define pm_message_t u32 +#endif + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) ) +#define E100_USE_SHUTDOWN_HANDLER +#else +#define E100_USE_REBOOT_NOTIFIER +#endif + +#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17) ) +#if ( LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) ) +#define IRQF_PROBE_SHARED 0 +#else +#define IRQF_PROBE_SHARED SA_PROBEIRQ +#endif /* <= 2.6.16 */ +#define IRQF_SHARED SA_SHIRQ + +#ifndef netdev_alloc_skb +#define netdev_alloc_skb _kc_netdev_alloc_skb +static inline struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev, + unsigned int length) +{ + /* 16 == NET_PAD_SKB */ + struct sk_buff *skb; + skb = alloc_skb(length + 16, GFP_ATOMIC); + if (likely(skb != NULL)) { + skb_reserve(skb, 16); + skb->dev = dev; + } + return skb; +} +#endif + +#endif /* <= 2.6.17 */ +#endif /* _KCOMPAT_H_ */