diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-09-04 16:24:41 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2003-09-04 16:24:41 +0000 |
commit | 53d8ff654313416eda81402698a872e674431b0f (patch) | |
tree | 332973a769c122f86711db095bedd0bddf2c4b04 | |
parent | 07e8be555cee5cc5d717c005f801d638f8d1495f (diff) | |
download | xen-53d8ff654313416eda81402698a872e674431b0f.tar.gz xen-53d8ff654313416eda81402698a872e674431b0f.tar.bz2 xen-53d8ff654313416eda81402698a872e674431b0f.zip |
bitkeeper revision 1.405 (3f576749oUqfWqUHieN31fCpXGcUcQ)
interrupt.c, pcnet32.c, time.c, setup.c:
More fixes, to network code and to timer code.
.del-8139too.c~2cde387fe3225d91:
Delete: xen/drivers/net/8139too.c
.del-via-rhine.c~6bd6f82d46529478:
Delete: xen/drivers/net/via-rhine.c
-rw-r--r-- | .rootkeys | 2 | ||||
-rw-r--r-- | xen/arch/i386/setup.c | 3 | ||||
-rw-r--r-- | xen/arch/i386/time.c | 6 | ||||
-rw-r--r-- | xen/drivers/net/8139too.c | 2671 | ||||
-rw-r--r-- | xen/drivers/net/pcnet32.c | 17 | ||||
-rw-r--r-- | xen/drivers/net/tulip/interrupt.c | 4 | ||||
-rw-r--r-- | xen/drivers/net/via-rhine.c | 1933 |
7 files changed, 27 insertions, 4609 deletions
@@ -230,7 +230,6 @@ 3ddb79bdPyAvT_WZTAFhaX0jp-yXSw xen/drivers/ide/ide_modes.h 3e4a8d401aSwOzCScQXR3lsmNlAwUQ xen/drivers/ide/piix.c 3ddb79bfMlOcWUwjtg6oMYhGySHDDw xen/drivers/net/3c59x.c -3f0c423bjmEpn1Nbk1Q8fv8ElccwAA xen/drivers/net/8139too.c 3ddb79c0tWiE8xIFHszxipeVCGKTSA xen/drivers/net/Makefile 3f0c4247730LYUgz3p5ziYqy-s_glw xen/drivers/net/SUPPORTED_CARDS 3ddb79bfU-H1Hms4BuJEPPydjXUEaQ xen/drivers/net/Space.c @@ -271,7 +270,6 @@ 3f0c428eZQhoTueBPxOO5YbuzoTofw xen/drivers/net/tulip/timer.c 3f0c428eoDFGJZJrBRnA7918Yovt0A xen/drivers/net/tulip/tulip.h 3f0c428e46klSV-upTm6D8tCdzQs8Q xen/drivers/net/tulip/tulip_core.c -3f0c428eu_CTRPhmTgGIjoiGI_PmrA xen/drivers/net/via-rhine.c 3ddb79beUWngyIhMHgyPtuTem4o4JA xen/drivers/pci/Makefile 3ddb79beU9td0Mnm0VUMklerBa37qQ xen/drivers/pci/compat.c 3ddb79beHkGQE58z5t5gyUCYiwOxvw xen/drivers/pci/gen-devlist.c diff --git a/xen/arch/i386/setup.c b/xen/arch/i386/setup.c index 4cc63616a7..2c254d51da 100644 --- a/xen/arch/i386/setup.c +++ b/xen/arch/i386/setup.c @@ -330,6 +330,7 @@ void __init start_of_day(void) extern void initialize_serial(void); extern void initialize_keyboard(void); extern int opt_nosmp, opt_watchdog; + extern int do_timer_lists_from_pit; unsigned long low_mem_size; if ( opt_watchdog ) @@ -388,6 +389,8 @@ void __init start_of_day(void) disable_pit(); else if ( smp_num_cpus != 1 ) panic("We really need local APICs on SMP machines!"); + else + do_timer_lists_from_pit = 1; ac_timer_init(); /* init accurate timers */ init_xeno_time(); /* initialise the time */ diff --git a/xen/arch/i386/time.c b/xen/arch/i386/time.c index 1797eb7d72..ae7ecae1a2 100644 --- a/xen/arch/i386/time.c +++ b/xen/arch/i386/time.c @@ -49,6 +49,7 @@ unsigned long cpu_khz; /* Detected as we calibrate the TSC */ unsigned long ticks_per_usec; /* TSC ticks per microsecond. */ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; int timer_ack = 0; +int do_timer_lists_from_pit = 0; /* PRIVATE */ @@ -92,8 +93,11 @@ static inline void do_timer_interrupt( spin_unlock(&i8259A_lock); } #endif + do_timer(regs); - do_ac_timer(); + + if ( do_timer_lists_from_pit ) + do_ac_timer(); } /* diff --git a/xen/drivers/net/8139too.c b/xen/drivers/net/8139too.c deleted file mode 100644 index 24882e8817..0000000000 --- a/xen/drivers/net/8139too.c +++ /dev/null @@ -1,2671 +0,0 @@ -/* - - 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. - - Maintained by Jeff Garzik <jgarzik@pobox.com> - Copyright 2000-2002 Jeff Garzik - - Much code comes from Donald Becker's rtl8139.c driver, - versions 1.13 and older. This driver was originally based - on rtl8139.c version 1.07. Header of rtl8139.c version 1.13: - - -----<snip>----- - - Written 1997-2001 by Donald Becker. - This software may be used and distributed according to the - terms of the GNU General Public License (GPL), incorporated - herein by reference. Drivers based on or derived from this - code fall under the GPL and must retain the authorship, - copyright and license notice. This file is not a complete - program and may only be used when the entire operating - system is licensed under the GPL. - - This driver is for boards based on the RTL8129 and RTL8139 - PCI ethernet chips. - - The author may be reached as becker@scyld.com, or C/O Scyld - Computing Corporation 410 Severn Ave., Suite 210 Annapolis - MD 21403 - - Support and updates available at - http://www.scyld.com/network/rtl8139.html - - Twister-tuning table provided by Kinston - <shangh@realtek.com.tw>. - - -----<snip>----- - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - Contributors: - - Donald Becker - he wrote the original driver, kudos to him! - (but please don't e-mail him for support, this isn't his driver) - - Tigran Aivazian - bug fixes, skbuff free cleanup - - Martin Mares - suggestions for PCI cleanup - - David S. Miller - PCI DMA and softnet updates - - Ernst Gill - fixes ported from BSD driver - - Daniel Kobras - identified specific locations of - posted MMIO write bugginess - - Gerard Sharp - bug fix, testing and feedback - - David Ford - Rx ring wrap fix - - Dan DeMaggio - swapped RTL8139 cards with me, and allowed me - to find and fix a crucial bug on older chipsets. - - Donald Becker/Chris Butterworth/Marcus Westergren - - Noticed various Rx packet size-related buglets. - - Santiago Garcia Mantinan - testing and feedback - - Jens David - 2.2.x kernel backports - - Martin Dennett - incredibly helpful insight on undocumented - features of the 8139 chips - - Jean-Jacques Michel - bug fix - - Tobias Ringström - Rx interrupt status checking suggestion - - Andrew Morton - Clear blocked signals, avoid - buffer overrun setting current->comm. - - Kalle Olavi Niemitalo - Wake-on-LAN ioctls - - Robert Kuebel - Save kernel thread from dying on any signal. - - Submitting bug reports: - - "rtl8139-diag -mmmaaavvveefN" output - enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log - - See 8139too.txt for more details. - -*/ - -#define DRV_NAME "8139too" -#define DRV_VERSION "0.9.26" - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/lib.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/delay.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */ -static int next_tick = 3 * HZ; - -#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION -#define PFX DRV_NAME ": " - - -/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ -#ifdef CONFIG_8139TOO_PIO -#define USE_IO_OPS 1 -#endif - -/* define to 1 to enable copious debugging info */ -#undef RTL8139_DEBUG - -/* define to 1 to disable lightweight runtime debugging checks */ -#undef RTL8139_NDEBUG - - -#ifdef RTL8139_DEBUG -/* note: prints function name for you */ -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - -#ifdef RTL8139_NDEBUG -# define assert(expr) do {} while (0) -#else -# define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - } -#endif - - -/* A few user-configurable values. */ -/* media options */ -#define MAX_UNITS 8 -static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; - -#if 0 -/* bitmapped message enable number */ -static int debug = -1; -#endif - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -#define RX_BUF_PAD 16 -#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ -#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) - -/* Number of Tx descriptor registers. */ -#define NUM_TX_DESC 4 - -/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ -#define MAX_ETH_FRAME_SIZE 1536 - -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE -#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ -#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ -#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ -#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */ - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (6*HZ) - - -enum { - HAS_MII_XCVR = 0x010000, - HAS_CHIP_XCVR = 0x020000, - HAS_LNK_CHNG = 0x040000, -}; - -#define RTL_NUM_STATS 4 /* number of ETHTOOL_GSTATS u64's */ -#define RTL_REGS_VER 1 /* version of reg. data in ETHTOOL_GREGS */ -#define RTL_MIN_IO_SIZE 0x80 -#define RTL8139B_IO_SIZE 256 - -#define RTL8129_CAPS HAS_MII_XCVR -#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG - -typedef enum { - RTL8139 = 0, - RTL8139_CB, - SMC1211TX, - /*MPX5030,*/ - DELTA8139, - ADDTRON8139, - DFE538TX, - DFE690TXD, - FE2000VX, - ALLIED8139, - RTL8129, - FNW3603TX, - FNW3800TX, -} board_t; - - -/* indexed by board_t, above */ -static struct { - const char *name; - u32 hw_flags; -} board_info[] __devinitdata = { - { "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS }, - { "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS }, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS }, -/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/ - { "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS }, - { "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS }, - { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, - { "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS }, - { "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS }, - { "Allied Telesyn 8139 CardBus", RTL8139_CAPS }, - { "RealTek RTL8129", RTL8129_CAPS }, - { "Planex FNW-3603-TX 10/100 CardBus", RTL8139_CAPS }, - { "Planex FNW-3800-TX 10/100 CardBus", RTL8139_CAPS }, -}; - - -static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = { - {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, - {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB }, - {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX }, -/* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/ - {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 }, - {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 }, - {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX }, - {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD }, - {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX }, - {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALLIED8139 }, - {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3603TX }, - {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FNW3800TX }, - -#ifdef CONFIG_8139TOO_8129 - {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 }, -#endif - - /* some crazy cards report invalid vendor ids like - * 0x0001 here. The other ids are valid and constant, - * so we simply don't match on the main vendor id. - */ - {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 }, - {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, DFE538TX }, - {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, FE2000VX }, - - {0,} -}; -MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl); - -#if 0 -static struct { - const char str[ETH_GSTRING_LEN]; -} ethtool_stats_keys[] = { - { "early_rx" }, - { "tx_buf_mapped" }, - { "tx_timeouts" }, - { "rx_lost_in_ring" }, -}; -#endif - -/* The rest of these values should never change. */ - -/* Symbolic offsets to registers. */ -enum RTL8139_registers { - MAC0 = 0, /* Ethernet hardware address. */ - MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ - RxBuf = 0x30, - ChipCmd = 0x37, - RxBufPtr = 0x38, - RxBufAddr = 0x3A, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - ChipVersion = 0x43, - RxConfig = 0x44, - Timer = 0x48, /* A general-purpose counter. */ - RxMissed = 0x4C, /* 24 bits valid, write clears. */ - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - FlashReg = 0x54, - MediaStatus = 0x58, - Config3 = 0x59, - Config4 = 0x5A, /* absent on RTL-8139A */ - HltClk = 0x5B, - MultiIntr = 0x5C, - TxSummary = 0x60, - BasicModeCtrl = 0x62, - BasicModeStatus = 0x64, - NWayAdvert = 0x66, - NWayLPAR = 0x68, - NWayExpansion = 0x6A, - /* Undocumented registers, but required for proper operation. */ - FIFOTMS = 0x70, /* FIFO Control and test. */ - CSCR = 0x74, /* Chip Status and Configuration Register. */ - PARA78 = 0x78, - PARA7c = 0x7c, /* Magic transceiver parameter register. */ - Config5 = 0xD8, /* absent on RTL-8139A */ -}; - -enum ClearBitMasks { - MultiIntrClear = 0xF000, - ChipCmdClear = 0xE2, - Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), -}; - -enum ChipCmdBits { - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, -}; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatusBits { - PCIErr = 0x8000, - PCSTimeout = 0x4000, - RxFIFOOver = 0x40, - RxUnderrun = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, - - RxAckBits = RxFIFOOver | RxOverflow | RxOK, -}; - -enum TxStatusBits { - TxHostOwns = 0x2000, - TxUnderrun = 0x4000, - TxStatOK = 0x8000, - TxOutOfWindow = 0x20000000, - TxAborted = 0x40000000, - TxCarrierLost = 0x80000000, -}; -enum RxStatusBits { - RxMulticast = 0x8000, - RxPhysical = 0x4000, - RxBroadcast = 0x2000, - RxBadSymbol = 0x0020, - RxRunt = 0x0010, - RxTooLong = 0x0008, - RxCRCErr = 0x0004, - RxBadAlign = 0x0002, - RxStatusOK = 0x0001, -}; - -/* Bits in RxConfig. */ -enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, -}; - -/* Bits in TxConfig. */ -enum tx_config_bits { - TxIFG1 = (1 << 25), /* Interframe Gap Time */ - TxIFG0 = (1 << 24), /* Enabling these bits violates IEEE 802.3 */ - TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ - TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ - TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ - TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ - - TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ -}; - -/* Bits in Config1 */ -enum Config1Bits { - Cfg1_PM_Enable = 0x01, - Cfg1_VPD_Enable = 0x02, - Cfg1_PIO = 0x04, - Cfg1_MMIO = 0x08, - LWAKE = 0x10, /* not on 8139, 8139A */ - Cfg1_Driver_Load = 0x20, - Cfg1_LED0 = 0x40, - Cfg1_LED1 = 0x80, - SLEEP = (1 << 1), /* only on 8139, 8139A */ - PWRDN = (1 << 0), /* only on 8139, 8139A */ -}; - -/* Bits in Config3 */ -enum Config3Bits { - Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ - Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ - Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ - Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ - Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ - Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ - Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ - Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ -}; - -/* Bits in Config4 */ -enum Config4Bits { - LWPTN = (1 << 2), /* not on 8139, 8139A */ -}; - -/* Bits in Config5 */ -enum Config5Bits { - Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ - Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ - Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ - Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ - Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ - Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ - Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ -}; - -enum RxConfigBits { - /* rx fifo threshold */ - RxCfgFIFOShift = 13, - RxCfgFIFONone = (7 << RxCfgFIFOShift), - - /* Max DMA burst */ - RxCfgDMAShift = 8, - RxCfgDMAUnlimited = (7 << RxCfgDMAShift), - - /* rx ring buffer length */ - RxCfgRcv8K = 0, - RxCfgRcv16K = (1 << 11), - RxCfgRcv32K = (1 << 12), - RxCfgRcv64K = (1 << 11) | (1 << 12), - - /* Disable packet wrap at end of Rx buffer */ - RxNoWrap = (1 << 7), -}; - - -/* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links on some boards. */ -enum CSCRBits { - CSCR_LinkOKBit = 0x0400, - CSCR_LinkChangeBit = 0x0800, - CSCR_LinkStatusBits = 0x0f000, - CSCR_LinkDownOffCmd = 0x003c0, - CSCR_LinkDownCmd = 0x0f3c0, -}; - - -enum Cfg9346Bits { - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, -}; - -#ifdef CONFIG_8139TOO_TUNE_TWISTER - -enum TwisterParamVals { - PARA78_default = 0x78fa8388, - PARA7c_default = 0xcb38de43, /* param[0][3] */ - PARA7c_xxx = 0xcb38de43, -}; - -static const unsigned long param[4][4] = { - {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43}, - {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83}, - {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83}, - {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83} -}; - -#endif /* CONFIG_8139TOO_TUNE_TWISTER */ - -typedef enum { - CH_8139 = 0, - CH_8139_K, - CH_8139A, - CH_8139B, - CH_8130, - CH_8139C, -} chip_t; - -enum chip_flags { - HasHltClk = (1 << 0), - HasLWake = (1 << 1), -}; - - -/* directly indexed by chip_t, above */ -const static struct { - const char *name; - u8 version; /* from RTL8139C docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ - u32 flags; -} rtl_chip_info[] = { - { "RTL-8139", - 0x40, - 0xf0fe0040, /* XXX copied from RTL8139A, verify */ - HasHltClk, - }, - - { "RTL-8139 rev K", - 0x60, - 0xf0fe0040, - HasHltClk, - }, - - { "RTL-8139A", - 0x70, - 0xf0fe0040, - HasHltClk, /* XXX undocumented? */ - }, - - { "RTL-8139B", - 0x78, - 0xf0fc0040, - HasLWake, - }, - - { "RTL-8130", - 0x7C, - 0xf0fe0040, /* XXX copied from RTL8139A, verify */ - HasLWake, - }, - - { "RTL-8139C", - 0x74, - 0xf0fc0040, /* XXX copied from RTL8139B, verify */ - HasLWake, - }, - -}; - -struct rtl_extra_stats { - unsigned long early_rx; - unsigned long tx_buf_mapped; - unsigned long tx_timeouts; - unsigned long rx_lost_in_ring; -}; - -struct rtl8139_private { - void *mmio_addr; - int drv_flags; - struct pci_dev *pci_dev; - struct net_device_stats stats; - unsigned char *rx_ring; - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int tx_flag; - unsigned long cur_tx; - unsigned long dirty_tx; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - signed char phys[4]; /* MII device addresses. */ - char twistie, twist_row, twist_col; /* Twister tune state. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - spinlock_t lock; - chip_t chipset; -#if 0 - pid_t thr_pid; - wait_queue_head_t thr_wait; - struct completion thr_exited; -#else - struct timer_list timer; -#endif - u32 rx_config; - struct rtl_extra_stats xstats; - int time_to_die; - struct mii_if_info mii; - unsigned int regs_len; -}; - -MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>"); -MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM (debug, "i"); -MODULE_PARM_DESC (debug, "8139too bitmapped message enable number"); -MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses"); -MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt"); -MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"); -MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)"); - -static int read_eeprom (void *ioaddr, int location, int addr_len); -static int rtl8139_open (struct net_device *dev); -static int mdio_read (struct net_device *dev, int phy_id, int location); -static void mdio_write (struct net_device *dev, int phy_id, int location, - int val); -#if 0 -static int rtl8139_thread (void *data); -#else -static void rtl8139_timer (unsigned long arg); -#endif -static void rtl8139_tx_timeout (struct net_device *dev); -static void rtl8139_init_ring (struct net_device *dev); -static int rtl8139_start_xmit (struct sk_buff *skb, - struct net_device *dev); -static void rtl8139_interrupt (int irq, void *dev_instance, - struct pt_regs *regs); -static int rtl8139_close (struct net_device *dev); -#if 0 -static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); -#endif -static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); -static void rtl8139_set_rx_mode (struct net_device *dev); -static void __set_rx_mode (struct net_device *dev); -static void rtl8139_hw_start (struct net_device *dev); - -#ifdef USE_IO_OPS - -#define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg)) -#define RTL_R16(reg) inw (((unsigned long)ioaddr) + (reg)) -#define RTL_R32(reg) ((unsigned long) inl (((unsigned long)ioaddr) + (reg))) -#define RTL_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg)) -#define RTL_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg)) -#define RTL_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg)) -#define RTL_W8_F RTL_W8 -#define RTL_W16_F RTL_W16 -#define RTL_W32_F RTL_W32 -#undef readb -#undef readw -#undef readl -#undef writeb -#undef writew -#undef writel -#define readb(addr) inb((unsigned long)(addr)) -#define readw(addr) inw((unsigned long)(addr)) -#define readl(addr) inl((unsigned long)(addr)) -#define writeb(val,addr) outb((val),(unsigned long)(addr)) -#define writew(val,addr) outw((val),(unsigned long)(addr)) -#define writel(val,addr) outl((val),(unsigned long)(addr)) - -#else - -/* write MMIO register, with flush */ -/* Flush avoids rtl8139 bug w/ posted MMIO writes */ -#define RTL_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0) -#define RTL_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0) -#define RTL_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0) - - -#define MMIO_FLUSH_AUDIT_COMPLETE 1 -#if MMIO_FLUSH_AUDIT_COMPLETE - -/* write MMIO register */ -#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) - -#else - -/* write MMIO register, then flush */ -#define RTL_W8 RTL_W8_F -#define RTL_W16 RTL_W16_F -#define RTL_W32 RTL_W32_F - -#endif /* MMIO_FLUSH_AUDIT_COMPLETE */ - -/* read MMIO register */ -#define RTL_R8(reg) readb (ioaddr + (reg)) -#define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) - -#endif /* USE_IO_OPS */ - - -static const u16 rtl8139_intr_mask = - PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | - TxErr | TxOK | RxErr | RxOK; - -static const unsigned int rtl8139_rx_config = - RxCfgRcv32K | RxNoWrap | - (RX_FIFO_THRESH << RxCfgFIFOShift) | - (RX_DMA_BURST << RxCfgDMAShift); - -static const unsigned int rtl8139_tx_config = - (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift); - -static void __rtl8139_cleanup_dev (struct net_device *dev) -{ - struct rtl8139_private *tp; - struct pci_dev *pdev; - - assert (dev != NULL); - assert (dev->priv != NULL); - - tp = dev->priv; - assert (tp->pci_dev != NULL); - pdev = tp->pci_dev; - -#ifndef USE_IO_OPS - if (tp->mmio_addr) - iounmap (tp->mmio_addr); -#endif /* !USE_IO_OPS */ - - /* it's ok to call this even if we have no regions to free */ - pci_release_regions (pdev); - -#ifndef RTL8139_NDEBUG - /* poison memory before freeing */ - memset (dev, 0xBC, - sizeof (struct net_device) + - sizeof (struct rtl8139_private)); -#endif /* RTL8139_NDEBUG */ - - kfree (dev); - - pci_set_drvdata (pdev, NULL); -} - - -static void rtl8139_chip_reset (void *ioaddr) -{ - int i; - - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) { - barrier(); - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; - udelay (10); - } -} - - -static int __devinit rtl8139_init_board (struct pci_dev *pdev, - struct net_device **dev_out) -{ - void *ioaddr; - struct net_device *dev; - struct rtl8139_private *tp; - u8 tmp8; - int rc; - unsigned int i; - u32 pio_start, pio_end, pio_flags, pio_len; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - u32 tmp; - - assert (pdev != NULL); - - *dev_out = NULL; - - /* dev and dev->priv zeroed in alloc_etherdev */ - dev = alloc_etherdev (sizeof (*tp)); - if (dev == NULL) { - printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - tp = dev->priv; - tp->pci_dev = pdev; - - /* enable device (incl. PCI PM wakeup and hotplug setup) */ - rc = pci_enable_device (pdev); - if (rc) - goto err_out; - - pio_start = pci_resource_start (pdev, 0); - pio_end = pci_resource_end (pdev, 0); - pio_flags = pci_resource_flags (pdev, 0); - pio_len = pci_resource_len (pdev, 0); - - mmio_start = pci_resource_start (pdev, 1); - mmio_end = pci_resource_end (pdev, 1); - mmio_flags = pci_resource_flags (pdev, 1); - mmio_len = pci_resource_len (pdev, 1); - - /* set this immediately, we need to know before - * we talk to the chip directly */ - DPRINTK("PIO region size == 0x%02X\n", pio_len); - DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - -#ifdef USE_IO_OPS - /* make sure PCI base addr 0 is PIO */ - if (!(pio_flags & IORESOURCE_IO)) { - printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name); - rc = -ENODEV; - goto err_out; - } - /* check for weird/broken PCI region reporting */ - if (pio_len < RTL_MIN_IO_SIZE) { - printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pdev->slot_name); - rc = -ENODEV; - goto err_out; - } -#else - /* make sure PCI base addr 1 is MMIO */ - if (!(mmio_flags & IORESOURCE_MEM)) { - printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name); - rc = -ENODEV; - goto err_out; - } - if (mmio_len < RTL_MIN_IO_SIZE) { - printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pdev->slot_name); - rc = -ENODEV; - goto err_out; - } -#endif - - rc = pci_request_regions (pdev, "8139too"); - if (rc) - goto err_out; - - /* enable PCI bus-mastering */ - pci_set_master (pdev); - -#ifdef USE_IO_OPS - ioaddr = (void *) pio_start; - dev->base_addr = pio_start; - tp->mmio_addr = ioaddr; - tp->regs_len = pio_len; -#else - /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, mmio_len); - if (ioaddr == NULL) { - printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pdev->slot_name); - rc = -EIO; - goto err_out; - } - dev->base_addr = (long) ioaddr; - tp->mmio_addr = ioaddr; - tp->regs_len = mmio_len; -#endif /* USE_IO_OPS */ - - /* Bring old chips out of low-power mode. */ - RTL_W8 (HltClk, 'R'); - - /* check for missing/broken hardware */ - if (RTL_R32 (TxConfig) == 0xFFFFFFFF) { - printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n", - pdev->slot_name); - rc = -EIO; - goto err_out; - } - - /* identify chip attached to board */ - tmp = RTL_R8 (ChipVersion); - for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++) - if (tmp == rtl_chip_info[i].version) { - tp->chipset = i; - goto match; - } - - /* if unknown chip, assume array element #0, original RTL-8139 in this case */ - printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n", - pdev->slot_name); - printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig)); - tp->chipset = 0; - -match: - DPRINTK ("chipset id (%d) == index %d, '%s'\n", - tmp, - tp->chipset, - rtl_chip_info[tp->chipset].name); - - if (tp->chipset >= CH_8139B) { - u8 new_tmp8 = tmp8 = RTL_R8 (Config1); - DPRINTK("PCI PM wakeup\n"); - if ((rtl_chip_info[tp->chipset].flags & HasLWake) && - (tmp8 & LWAKE)) - new_tmp8 &= ~LWAKE; - new_tmp8 |= Cfg1_PM_Enable; - if (new_tmp8 != tmp8) { - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tmp8); - RTL_W8 (Cfg9346, Cfg9346_Lock); - } - if (rtl_chip_info[tp->chipset].flags & HasLWake) { - tmp8 = RTL_R8 (Config4); - if (tmp8 & LWPTN) - RTL_W8 (Config4, tmp8 & ~LWPTN); - } - } else { - DPRINTK("Old chip wakeup\n"); - tmp8 = RTL_R8 (Config1); - tmp8 &= ~(SLEEP | PWRDN); - RTL_W8 (Config1, tmp8); - } - - rtl8139_chip_reset (ioaddr); - - *dev_out = dev; - return 0; - -err_out: - __rtl8139_cleanup_dev (dev); - return rc; -} - - -static int __devinit rtl8139_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev = NULL; - struct rtl8139_private *tp; - int i, addr_len, option; - void *ioaddr; - static int board_idx = -1; - u8 pci_rev; - - assert (pdev != NULL); - assert (ent != NULL); - - board_idx++; - - /* when we're built into the kernel, the driver version message - * is only printed if at least one 8139 board has been found - */ -#ifndef MODULE - { - static int printed_version; - if (!printed_version++) - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); - } -#endif - - pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); - - if (pdev->vendor == PCI_VENDOR_ID_REALTEK && - pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) { - printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n", - pdev->slot_name, pdev->vendor, pdev->device, pci_rev); - printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n"); - } - - i = rtl8139_init_board (pdev, &dev); - if (i < 0) - return i; - - tp = dev->priv; - ioaddr = tp->mmio_addr; - - assert (ioaddr != NULL); - assert (dev != NULL); - assert (tp != NULL); - - addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; - for (i = 0; i < 3; i++) - ((u16 *) (dev->dev_addr))[i] = - le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); - - /* The Rtl8139-specific entries in the device structure. */ - dev->open = rtl8139_open; - dev->hard_start_xmit = rtl8139_start_xmit; - dev->stop = rtl8139_close; - dev->get_stats = rtl8139_get_stats; - dev->set_multicast_list = rtl8139_set_rx_mode; -#if 0 - dev->do_ioctl = netdev_ioctl; -#endif - dev->tx_timeout = rtl8139_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* note: the hardware is not capable of sg/csum/highdma, however - * through the use of skb_copy_and_csum_dev we enable these - * features - */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; - - dev->irq = pdev->irq; - - /* dev->priv/tp zeroed and aligned in init_etherdev */ - tp = dev->priv; - - /* note: tp->chipset set in rtl8139_init_board */ - tp->drv_flags = board_info[ent->driver_data].hw_flags; - tp->mmio_addr = ioaddr; - spin_lock_init (&tp->lock); -#if 0 - init_waitqueue_head (&tp->thr_wait); - init_completion (&tp->thr_exited); -#endif - tp->mii.dev = dev; - tp->mii.mdio_read = mdio_read; - tp->mii.mdio_write = mdio_write; - tp->mii.phy_id_mask = 0x3f; - tp->mii.reg_num_mask = 0x1f; - - /* dev is fully set up and ready to use now */ - DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); - i = register_netdev (dev); - if (i) goto err_out; - - pci_set_drvdata (pdev, dev); - - printk (KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", - dev->name, - board_info[ent->driver_data].name, - dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], - dev->irq); - - printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", - dev->name, rtl_chip_info[tp->chipset].name); - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ -#ifdef CONFIG_8139TOO_8129 - if (tp->drv_flags & HAS_MII_XCVR) { - int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { - int mii_status = mdio_read(dev, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - u16 advertising = mdio_read(dev, phy, 4); - tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " - "advertising %4.4x.\n", - dev->name, phy, mii_status, advertising); - } - } - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", - dev->name); - tp->phys[0] = 32; - } - } else -#endif - tp->phys[0] = 32; - tp->mii.phy_id = tp->phys[0]; - - /* The lower four bits are the media type. */ - option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; - if (option > 0) { - tp->mii.full_duplex = (option & 0x210) ? 1 : 0; - tp->default_port = option & 0xFF; - if (tp->default_port) - tp->mii.force_media = 1; - } - if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) - tp->mii.full_duplex = full_duplex[board_idx]; - if (tp->mii.full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); - /* Changing the MII-advertised media because might prevent - re-connection. */ - tp->mii.force_media = 1; - } - if (tp->default_port) { - printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n", - (option & 0x20 ? 100 : 10), - (option & 0x10 ? "full" : "half")); - mdio_write(dev, tp->phys[0], 0, - ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */ - ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ - } - - /* Put the chip into low-power mode. */ - if (rtl_chip_info[tp->chipset].flags & HasHltClk) - RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - - alert_slow_netdevice(dev, (char *)board_info[ent->driver_data].name); - - return 0; - -err_out: - __rtl8139_cleanup_dev (dev); - return i; -} - - -static void __devexit rtl8139_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct rtl8139_private *np; - - assert (dev != NULL); - np = dev->priv; - assert (np != NULL); - - unregister_netdev (dev); - - __rtl8139_cleanup_dev (dev); -} - - -/* Serial EEPROM section. */ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ -#define EE_CS 0x08 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x00 -#define EE_WRITE_1 0x02 -#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ -#define EE_ENB (0x80 | EE_CS) - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. - */ - -#define eeprom_delay() readl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5) -#define EE_READ_CMD (6) -#define EE_ERASE_CMD (7) - -static int __devinit read_eeprom (void *ioaddr, int location, int addr_len) -{ - int i; - unsigned retval = 0; - void *ee_addr = ioaddr + Cfg9346; - int read_cmd = location | (EE_READ_CMD << addr_len); - - writeb (EE_ENB & ~EE_CS, ee_addr); - writeb (EE_ENB, ee_addr); - eeprom_delay (); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - writeb (EE_ENB | dataval, ee_addr); - eeprom_delay (); - writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay (); - } - writeb (EE_ENB, ee_addr); - eeprom_delay (); - - for (i = 16; i > 0; i--) { - writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay (); - retval = - (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : - 0); - writeb (EE_ENB, ee_addr); - eeprom_delay (); - } - - /* Terminate the EEPROM access. */ - writeb (~EE_CS, ee_addr); - eeprom_delay (); - - return retval; -} - -/* MII serial management: mostly bogus for now. */ -/* Read and write the MII management registers using software-generated - serial MDIO protocol. - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -#define MDIO_DIR 0x80 -#define MDIO_DATA_OUT 0x04 -#define MDIO_DATA_IN 0x02 -#define MDIO_CLK 0x01 -#define MDIO_WRITE0 (MDIO_DIR) -#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) - -#define mdio_delay(mdio_addr) readb(mdio_addr) - - -static char mii_2_8139_map[8] = { - BasicModeCtrl, - BasicModeStatus, - 0, - 0, - NWayAdvert, - NWayLPAR, - NWayExpansion, - 0 -}; - - -#ifdef CONFIG_8139TOO_8129 -/* Syncronize the MII management interface by shifting 32 one bits out. */ -static void mdio_sync (void *mdio_addr) -{ - int i; - - for (i = 32; i >= 0; i--) { - writeb (MDIO_WRITE1, mdio_addr); - mdio_delay (mdio_addr); - writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay (mdio_addr); - } -} -#endif - -static int mdio_read (struct net_device *dev, int phy_id, int location) -{ - struct rtl8139_private *tp = dev->priv; - int retval = 0; -#ifdef CONFIG_8139TOO_8129 - void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int i; -#endif - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - return location < 8 && mii_2_8139_map[location] ? - readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; - } - -#ifdef CONFIG_8139TOO_8129 - mdio_sync (mdio_addr); - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; - - writeb (MDIO_DIR | dataval, mdio_addr); - mdio_delay (mdio_addr); - writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay (mdio_addr); - } - - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - writeb (0, mdio_addr); - mdio_delay (mdio_addr); - retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); - writeb (MDIO_CLK, mdio_addr); - mdio_delay (mdio_addr); - } -#endif - - return (retval >> 1) & 0xffff; -} - - -static void mdio_write (struct net_device *dev, int phy_id, int location, - int value) -{ - struct rtl8139_private *tp = dev->priv; -#ifdef CONFIG_8139TOO_8129 - void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; - int i; -#endif - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - void *ioaddr = tp->mmio_addr; - if (location == 0) { - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W16 (BasicModeCtrl, value); - RTL_W8 (Cfg9346, Cfg9346_Lock); - } else if (location < 8 && mii_2_8139_map[location]) - RTL_W16 (mii_2_8139_map[location], value); - return; - } - -#ifdef CONFIG_8139TOO_8129 - mdio_sync (mdio_addr); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = - (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - writeb (dataval, mdio_addr); - mdio_delay (mdio_addr); - writeb (dataval | MDIO_CLK, mdio_addr); - mdio_delay (mdio_addr); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - writeb (0, mdio_addr); - mdio_delay (mdio_addr); - writeb (MDIO_CLK, mdio_addr); - mdio_delay (mdio_addr); - } -#endif -} - - -static int rtl8139_open (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - int retval; -#ifdef RTL8139_DEBUG - void *ioaddr = tp->mmio_addr; -#endif - - retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) - return retval; - - tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - &tp->rx_ring_dma); - if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { - free_irq(dev->irq, dev); - - if (tp->tx_bufs) - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - tp->tx_bufs, tp->tx_bufs_dma); - if (tp->rx_ring) - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - tp->rx_ring, tp->rx_ring_dma); - - return -ENOMEM; - - } - - tp->mii.full_duplex = tp->mii.force_media; - tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; - tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0; - tp->time_to_die = 0; - - rtl8139_init_ring (dev); - rtl8139_hw_start (dev); - - DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" - " GP Pins %2.2x %s-duplex.\n", - dev->name, pci_resource_start (tp->pci_dev, 1), - dev->irq, RTL_R8 (MediaStatus), - tp->mii.full_duplex ? "full" : "half"); - -#if 0 - tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES); - if (tp->thr_pid < 0) - printk (KERN_WARNING "%s: unable to start kernel thread\n", - dev->name); -#else - init_timer(&tp->timer); - tp->timer.expires = jiffies + next_tick; - tp->timer.data = (unsigned long)dev; - tp->timer.function = rtl8139_timer; - add_timer(&tp->timer); -#endif - - return 0; -} - - -static void rtl_check_media (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - - if (tp->phys[0] >= 0) { - u16 mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA); - if (mii_lpa == 0xffff) - ; /* Not there */ - else if ((mii_lpa & LPA_100FULL) == LPA_100FULL - || (mii_lpa & 0x00C0) == LPA_10FULL) - tp->mii.full_duplex = 1; - - printk (KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability %4.4x.\n", - dev->name, mii_lpa == 0 ? "" : - (mii_lpa & 0x0180) ? "100mbps " : "10mbps ", - tp->mii.full_duplex ? "full" : "half", mii_lpa); - } -} - -/* Start the hardware at open or resume. */ -static void rtl8139_hw_start (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - u32 i; - u8 tmp; - - /* Bring old chips out of low-power mode. */ - if (rtl_chip_info[tp->chipset].flags & HasHltClk) - RTL_W8 (HltClk, 'R'); - - rtl8139_chip_reset (ioaddr); - - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - /* Restore our idea of the MAC address. */ - RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; - RTL_W32 (RxConfig, tp->rx_config); - - /* Check this value: the documentation for IFG contradicts ifself. */ - RTL_W32 (TxConfig, rtl8139_tx_config); - - tp->cur_rx = 0; - - rtl_check_media (dev); - - if (tp->chipset >= CH_8139B) { - /* Disable magic packet scanning, which is enabled - * when PM is enabled in Config1. It can be reenabled - * via ETHTOOL_SWOL if desired. */ - RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic); - } - - DPRINTK("init buffer addresses\n"); - - /* Lock Config[01234] and BMCR register writes */ - RTL_W8 (Cfg9346, Cfg9346_Lock); - - /* init Rx ring buffer DMA address */ - RTL_W32_F (RxBuf, tp->rx_ring_dma); - - /* init Tx buffer DMA addresses */ - for (i = 0; i < NUM_TX_DESC; i++) - RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); - - RTL_W32 (RxMissed, 0); - - rtl8139_set_rx_mode (dev); - - /* no early-rx interrupts */ - RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); - - /* make sure RxTx has started */ - tmp = RTL_R8 (ChipCmd); - if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb))) - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16 (IntrMask, rtl8139_intr_mask); - - netif_start_queue (dev); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void rtl8139_init_ring (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - int i; - - tp->cur_rx = 0; - tp->cur_tx = 0; - tp->dirty_tx = 0; - - for (i = 0; i < NUM_TX_DESC; i++) - tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; -} - - -#ifndef CONFIG_8139TOO_TUNE_TWISTER -static inline void rtl8139_tune_twister (struct net_device *dev, - struct rtl8139_private *tp) {} -#else -static void rtl8139_tune_twister (struct net_device *dev, - struct rtl8139_private *tp) -{ - int linkcase; - void *ioaddr = tp->mmio_addr; - - /* This is a complicated state machine to configure the "twister" for - impedance/echos based on the cable length. - All of this is magic and undocumented. - */ - switch (tp->twistie) { - case 1: - if (RTL_R16 (CSCR) & CSCR_LinkOKBit) { - /* We have link beat, let us tune the twister. */ - RTL_W16 (CSCR, CSCR_LinkDownOffCmd); - tp->twistie = 2; /* Change to state 2. */ - next_tick = HZ / 10; - } else { - /* Just put in some reasonable defaults for when beat returns. */ - RTL_W16 (CSCR, CSCR_LinkDownCmd); - RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */ - RTL_W32 (PARA78, PARA78_default); - RTL_W32 (PARA7c, PARA7c_default); - tp->twistie = 0; /* Bail from future actions. */ - } - break; - case 2: - /* Read how long it took to hear the echo. */ - linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits; - if (linkcase == 0x7000) - tp->twist_row = 3; - else if (linkcase == 0x3000) - tp->twist_row = 2; - else if (linkcase == 0x1000) - tp->twist_row = 1; - else - tp->twist_row = 0; - tp->twist_col = 0; - tp->twistie = 3; /* Change to state 2. */ - next_tick = HZ / 10; - break; - case 3: - /* Put out four tuning parameters, one per 100msec. */ - if (tp->twist_col == 0) - RTL_W16 (FIFOTMS, 0); - RTL_W32 (PARA7c, param[(int) tp->twist_row] - [(int) tp->twist_col]); - next_tick = HZ / 10; - if (++tp->twist_col >= 4) { - /* For short cables we are done. - For long cables (row == 3) check for mistune. */ - tp->twistie = - (tp->twist_row == 3) ? 4 : 0; - } - break; - case 4: - /* Special case for long cables: check for mistune. */ - if ((RTL_R16 (CSCR) & - CSCR_LinkStatusBits) == 0x7000) { - tp->twistie = 0; - break; - } else { - RTL_W32 (PARA7c, 0xfb38de03); - tp->twistie = 5; - next_tick = HZ / 10; - } - break; - case 5: - /* Retune for shorter cable (column 2). */ - RTL_W32 (FIFOTMS, 0x20); - RTL_W32 (PARA78, PARA78_default); - RTL_W32 (PARA7c, PARA7c_default); - RTL_W32 (FIFOTMS, 0x00); - tp->twist_row = 2; - tp->twist_col = 0; - tp->twistie = 3; - next_tick = HZ / 10; - break; - - default: - /* do nothing */ - break; - } -} -#endif /* CONFIG_8139TOO_TUNE_TWISTER */ - - -static inline void rtl8139_thread_iter (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr) -{ - int mii_lpa; - - mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); - - if (!tp->mii.force_media && mii_lpa != 0xffff) { - int duplex = (mii_lpa & LPA_100FULL) - || (mii_lpa & 0x01C0) == 0x0040; - if (tp->mii.full_duplex != duplex) { - tp->mii.full_duplex = duplex; - - if (mii_lpa) { - printk (KERN_INFO - "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", - dev->name, - tp->mii.full_duplex ? "full" : "half", - tp->phys[0], mii_lpa); - } else { - printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n", - dev->name); - } -#if 0 - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, Cfg9346_Lock); -#endif - } - } - - next_tick = HZ * 60; - - rtl8139_tune_twister (dev, tp); - - DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", - dev->name, RTL_R16 (NWayLPAR)); - DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", - dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus)); - DPRINTK ("%s: Chip config %2.2x %2.2x.\n", - dev->name, RTL_R8 (Config0), - RTL_R8 (Config1)); -} - - -#if 0 -static int rtl8139_thread (void *data) -{ - struct net_device *dev = data; - struct rtl8139_private *tp = dev->priv; - unsigned long timeout; - - daemonize (); - reparent_to_init(); - spin_lock_irq(¤t->sigmask_lock); - sigemptyset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - strncpy (current->comm, dev->name, sizeof(current->comm) - 1); - current->comm[sizeof(current->comm) - 1] = '\0'; - - while (1) { - timeout = next_tick; - do { - timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); - } while (!signal_pending (current) && (timeout > 0)); - - if (signal_pending (current)) { - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); - } - - if (tp->time_to_die) - break; - - rtnl_lock (); - rtl8139_thread_iter (dev, tp, tp->mmio_addr); - rtnl_unlock (); - } - - complete_and_exit (&tp->thr_exited, 0); -} -#else -static void rtl8139_timer(unsigned long arg) -{ - struct net_device *dev = (struct net_device *)arg; - struct rtl8139_private *tp = dev->priv; - rtl8139_thread_iter (dev, tp, tp->mmio_addr); - mod_timer(&tp->timer, jiffies + next_tick); -} -#endif - - -static void rtl8139_tx_clear (struct rtl8139_private *tp) -{ - tp->cur_tx = 0; - tp->dirty_tx = 0; - - /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ -} - - -static void rtl8139_tx_timeout (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - int i; - u8 tmp8; - unsigned long flags; - - DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " - "media %2.2x.\n", dev->name, - RTL_R8 (ChipCmd), - RTL_R16 (IntrStatus), - RTL_R8 (MediaStatus)); - - tp->xstats.tx_timeouts++; - - /* disable Tx ASAP, if not already */ - tmp8 = RTL_R8 (ChipCmd); - if (tmp8 & CmdTxEnb) - RTL_W8 (ChipCmd, CmdRxEnb); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0x0000); - - /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", - dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == tp->dirty_tx % NUM_TX_DESC ? - " (queue head)" : ""); - - /* Stop a shared interrupt from scavenging while we are. */ - spin_lock_irqsave (&tp->lock, flags); - rtl8139_tx_clear (tp); - spin_unlock_irqrestore (&tp->lock, flags); - - /* ...and finally, reset everything */ - rtl8139_hw_start (dev); - - netif_wake_queue (dev); -} - - -static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - unsigned int entry; - unsigned int len = skb->len; - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % NUM_TX_DESC; - - if (likely(len < TX_BUF_SIZE)) { - if(len < ETH_ZLEN) - memset(tp->tx_buf[entry], 0, ETH_ZLEN); -#if 0 - skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); -#else - skb_copy_bits(skb, 0, tp->tx_buf[entry], skb->len); -#endif - dev_kfree_skb(skb); - } else { - dev_kfree_skb(skb); - tp->stats.tx_dropped++; - return 0; - } - - /* Note: the chip doesn't have auto-pad! */ - spin_lock_irq(&tp->lock); - RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), - tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); - - dev->trans_start = jiffies; - - tp->cur_tx++; - wmb(); - - if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) - netif_stop_queue (dev); - spin_unlock_irq(&tp->lock); - - DPRINTK ("%s: Queued Tx packet size %u to slot %d.\n", - dev->name, len, entry); - - return 0; -} - - -static void rtl8139_tx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr) -{ - unsigned long dirty_tx, tx_left; - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); - - dirty_tx = tp->dirty_tx; - tx_left = tp->cur_tx - dirty_tx; - while (tx_left > 0) { - int entry = dirty_tx % NUM_TX_DESC; - int txstatus; - - txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); - - if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) - break; /* It still hasn't been Txed */ - - /* Note: TxCarrierLost is always asserted at 100mbps. */ - if (txstatus & (TxOutOfWindow | TxAborted)) { - /* There was an major error, log it. */ - DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); - tp->stats.tx_errors++; - if (txstatus & TxAborted) { - tp->stats.tx_aborted_errors++; - RTL_W32 (TxConfig, TxClearAbt); - RTL_W16 (IntrStatus, TxErr); - wmb(); - } - if (txstatus & TxCarrierLost) - tp->stats.tx_carrier_errors++; - if (txstatus & TxOutOfWindow) - tp->stats.tx_window_errors++; - } else { - if (txstatus & TxUnderrun) { - /* Add 64 to the Tx FIFO threshold. */ - if (tp->tx_flag < 0x00300000) - tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; - } - tp->stats.collisions += (txstatus >> 24) & 15; - tp->stats.tx_bytes += txstatus & 0x7ff; - tp->stats.tx_packets++; - } - - dirty_tx++; - tx_left--; - } - -#ifndef RTL8139_NDEBUG - if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", - dev->name, dirty_tx, tp->cur_tx); - dirty_tx += NUM_TX_DESC; - } -#endif /* RTL8139_NDEBUG */ - - /* only wake the queue if we did work, and the queue is stopped */ - if (tp->dirty_tx != dirty_tx) { - tp->dirty_tx = dirty_tx; - mb(); - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); - } -} - - -/* TODO: clean this up! Rx reset need not be this intensive */ -static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) -{ - u8 tmp8; -#ifdef CONFIG_8139_OLD_RX_RESET - int tmp_work; -#endif - - DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", - dev->name, rx_status); - tp->stats.rx_errors++; - if (!(rx_status & RxStatusOK)) { - if (rx_status & RxTooLong) { - DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", - dev->name, rx_status); - /* A.C.: The chip hangs here. */ - } - if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; - if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; - if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; - } else { - tp->xstats.rx_lost_in_ring++; - } - -#ifndef CONFIG_8139_OLD_RX_RESET - tmp8 = RTL_R8 (ChipCmd); - RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb); - RTL_W8 (ChipCmd, tmp8); - RTL_W32 (RxConfig, tp->rx_config); - tp->cur_rx = 0; -#else - /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - - /* disable receive */ - RTL_W8_F (ChipCmd, CmdTxEnb); - tmp_work = 200; - while (--tmp_work > 0) { - udelay(1); - tmp8 = RTL_R8 (ChipCmd); - if (!(tmp8 & CmdRxEnb)) - break; - } - if (tmp_work <= 0) - printk (KERN_WARNING PFX "rx stop wait too long\n"); - /* restart receive */ - tmp_work = 200; - while (--tmp_work > 0) { - RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb); - udelay(1); - tmp8 = RTL_R8 (ChipCmd); - if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) - break; - } - if (tmp_work <= 0) - printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); - - /* and reinitialize all rx related registers */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - /* Must enable Tx/Rx before setting transfer thresholds! */ - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys; - RTL_W32 (RxConfig, tp->rx_config); - tp->cur_rx = 0; - - DPRINTK("init buffer addresses\n"); - - /* Lock Config[01234] and BMCR register writes */ - RTL_W8 (Cfg9346, Cfg9346_Lock); - - /* init Rx ring buffer DMA address */ - RTL_W32_F (RxBuf, tp->rx_ring_dma); - - /* A.C.: Reset the multicast list. */ - __set_rx_mode (dev); -#endif -} - -static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, void *ioaddr) -{ - unsigned char *rx_ring; - u16 cur_rx; - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); - - rx_ring = tp->rx_ring; - cur_rx = tp->cur_rx; - - DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, - RTL_R16 (RxBufAddr), - RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - - while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status; - unsigned int rx_size; - unsigned int pkt_size; - struct sk_buff *skb; - - rmb(); - - /* read size+status of next frame from DMA ring buffer */ - rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); - rx_size = rx_status >> 16; - pkt_size = rx_size - 4; - - DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, - rx_size, cur_rx); -#if RTL8139_DEBUG > 2 - { - int i; - DPRINTK ("%s: Frame contents ", dev->name); - for (i = 0; i < 70; i++) - printk (" %2.2x", - rx_ring[ring_offset + i]); - printk (".\n"); - } -#endif - - /* Packet copy from FIFO still in progress. - * Theoretically, this should never happen - * since EarlyRx is disabled. - */ - if (rx_size == 0xfff0) { - tp->xstats.early_rx++; - break; - } - - /* If Rx err or invalid rx_size/rx_status received - * (which happens if we get lost in the ring), - * Rx process gets reset, so we abort any further - * Rx processing. - */ - if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) || - (rx_size < 8) || - (!(rx_status & RxStatusOK))) { - rtl8139_rx_err (rx_status, dev, tp, ioaddr); - return; - } - - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - - /* TODO: consider allocating skb's outside of - * interrupt context, both to speed interrupt processing, - * and also to reduce the chances of having to - * drop packets here under memory pressure. - */ - - skb = dev_alloc_skb (pkt_size + 2); - if (skb) { - skb->dev = dev; - skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - - eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); - skb_put (skb, pkt_size); - - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } else { - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); - tp->stats.rx_dropped++; - } - - cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - RTL_W16 (RxBufPtr, cur_rx - 16); - - if (RTL_R16 (IntrStatus) & RxAckBits) - RTL_W16_F (IntrStatus, RxAckBits); - } - - DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, - RTL_R16 (RxBufAddr), - RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - - tp->cur_rx = cur_rx; -} - - -static void rtl8139_weird_interrupt (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr, - int status, int link_changed) -{ - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - - assert (dev != NULL); - assert (tp != NULL); - assert (ioaddr != NULL); - - /* Update the error count. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - - if ((status & RxUnderrun) && link_changed && - (tp->drv_flags & HAS_LNK_CHNG)) { - /* Really link-change on new chips. */ - int lpar = RTL_R16 (NWayLPAR); - int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040 - || tp->mii.force_media; - if (tp->mii.full_duplex != duplex) { - tp->mii.full_duplex = duplex; -#if 0 - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, Cfg9346_Lock); -#endif - } - status &= ~RxUnderrun; - } - - /* XXX along with rtl8139_rx_err, are we double-counting errors? */ - if (status & - (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; - - if (status & PCSTimeout) - tp->stats.rx_length_errors++; - if (status & (RxUnderrun | RxFIFOOver)) - tp->stats.rx_fifo_errors++; - if (status & PCIErr) { - u16 pci_cmd_status; - pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); - pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); - - printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", - dev->name, pci_cmd_status); - } -} - - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void rtl8139_interrupt (int irq, void *dev_instance, - struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_instance; - struct rtl8139_private *tp = dev->priv; - int boguscnt = max_interrupt_work; - void *ioaddr = tp->mmio_addr; - int ackstat, status; - int link_changed = 0; /* avoid bogus "uninit" warning */ - - spin_lock (&tp->lock); - - do { - status = RTL_R16 (IntrStatus); - - /* h/w no longer present (hotplug?) or major error, bail */ - if (status == 0xFFFF) - break; - - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; - - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; - - /* The chip takes special action when we clear RxAckBits, - * so we clear them later in rtl8139_rx_interrupt - */ - ackstat = status & ~(RxAckBits | TxErr); - RTL_W16 (IntrStatus, ackstat); - - DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", - dev->name, ackstat, status, RTL_R16 (IntrStatus)); - - if (netif_running (dev) && (status & RxAckBits)) - rtl8139_rx_interrupt (dev, tp, ioaddr); - - /* Check uncommon events with one test. */ - if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | RxErr)) - rtl8139_weird_interrupt (dev, tp, ioaddr, - status, link_changed); - - if (netif_running (dev) && (status & (TxOK | TxErr))) { - rtl8139_tx_interrupt (dev, tp, ioaddr); - if (status & TxErr) - RTL_W16 (IntrStatus, TxErr); - } - - boguscnt--; - } while (boguscnt > 0); - - if (boguscnt <= 0) { - printk (KERN_WARNING "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, status); - - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); - } - - spin_unlock (&tp->lock); - - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); -} - - -static int rtl8139_close (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; -#if 0 - int ret = 0; -#endif - unsigned long flags; - - netif_stop_queue (dev); - -#if 0 - if (tp->thr_pid >= 0) { - tp->time_to_die = 1; - wmb(); - ret = kill_proc (tp->thr_pid, SIGTERM, 1); - if (ret) { - printk (KERN_ERR "%s: unable to signal thread\n", dev->name); - return ret; - } - wait_for_completion (&tp->thr_exited); - } -#else - del_timer_sync(&tp->timer); -#endif - - DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); - - spin_lock_irqsave (&tp->lock, flags); - - /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8 (ChipCmd, 0); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16 (IntrMask, 0); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); - - synchronize_irq (); - free_irq (dev->irq, dev); - - rtl8139_tx_clear (tp); - - pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, - tp->tx_bufs, tp->tx_bufs_dma); - tp->rx_ring = NULL; - tp->tx_bufs = NULL; - - /* Green! Put the chip in low-power mode. */ - RTL_W8 (Cfg9346, Cfg9346_Unlock); - - if (rtl_chip_info[tp->chipset].flags & HasHltClk) - RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - - return 0; -} - - -/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to - kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and - other threads or interrupts aren't messing with the 8139. */ -static void netdev_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct rtl8139_private *np = dev->priv; - void *ioaddr = np->mmio_addr; - - if (rtl_chip_info[np->chipset].flags & HasLWake) { - u8 cfg3 = RTL_R8 (Config3); - u8 cfg5 = RTL_R8 (Config5); - - wol->supported = WAKE_PHY | WAKE_MAGIC - | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; - - wol->wolopts = 0; - if (cfg3 & Cfg3_LinkUp) - wol->wolopts |= WAKE_PHY; - if (cfg3 & Cfg3_Magic) - wol->wolopts |= WAKE_MAGIC; - /* (KON)FIXME: See how netdev_set_wol() handles the - following constants. */ - if (cfg5 & Cfg5_UWF) - wol->wolopts |= WAKE_UCAST; - if (cfg5 & Cfg5_MWF) - wol->wolopts |= WAKE_MCAST; - if (cfg5 & Cfg5_BWF) - wol->wolopts |= WAKE_BCAST; - } -} - - -/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes - that wol points to kernel memory and other threads or interrupts - aren't messing with the 8139. */ -static int netdev_set_wol (struct net_device *dev, - const struct ethtool_wolinfo *wol) -{ - struct rtl8139_private *np = dev->priv; - void *ioaddr = np->mmio_addr; - u32 support; - u8 cfg3, cfg5; - - support = ((rtl_chip_info[np->chipset].flags & HasLWake) - ? (WAKE_PHY | WAKE_MAGIC - | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST) - : 0); - if (wol->wolopts & ~support) - return -EINVAL; - - cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic); - if (wol->wolopts & WAKE_PHY) - cfg3 |= Cfg3_LinkUp; - if (wol->wolopts & WAKE_MAGIC) - cfg3 |= Cfg3_Magic; - RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config3, cfg3); - RTL_W8 (Cfg9346, Cfg9346_Lock); - - cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF); - /* (KON)FIXME: These are untested. We may have to set the - CRC0, Wakeup0 and LSBCRC0 registers too, but I have no - documentation. */ - if (wol->wolopts & WAKE_UCAST) - cfg5 |= Cfg5_UWF; - if (wol->wolopts & WAKE_MCAST) - cfg5 |= Cfg5_MWF; - if (wol->wolopts & WAKE_BCAST) - cfg5 |= Cfg5_BWF; - RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */ - - return 0; -} - -#if 0 -static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) -{ - struct rtl8139_private *np = dev->priv; - u32 ethcmd; - - /* dev_ioctl() in ../../net/core/dev.c has already checked - capable(CAP_NET_ADMIN), so don't bother with that here. */ - - if (get_user(ethcmd, (u32 *)useraddr)) - return -EFAULT; - - switch (ethcmd) { - - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - strcpy (info.driver, DRV_NAME); - strcpy (info.version, DRV_VERSION); - strcpy (info.bus_info, np->pci_dev->slot_name); - info.regdump_len = np->regs_len; - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } - - /* get settings */ - case ETHTOOL_GSET: { - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - spin_lock_irq(&np->lock); - mii_ethtool_gset(&np->mii, &ecmd); - spin_unlock_irq(&np->lock); - if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } - /* set settings */ - case ETHTOOL_SSET: { - int r; - struct ethtool_cmd ecmd; - if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) - return -EFAULT; - spin_lock_irq(&np->lock); - r = mii_ethtool_sset(&np->mii, &ecmd); - spin_unlock_irq(&np->lock); - return r; - } - /* restart autonegotiation */ - case ETHTOOL_NWAY_RST: { - return mii_nway_restart(&np->mii); - } - /* get link status */ - case ETHTOOL_GLINK: { - struct ethtool_value edata = {ETHTOOL_GLINK}; - edata.data = mii_link_ok(&np->mii); - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - - /* get message-level */ - case ETHTOOL_GMSGLVL: { - struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - /* set message-level */ - case ETHTOOL_SMSGLVL: { - struct ethtool_value edata; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - debug = edata.data; - return 0; - } - - case ETHTOOL_GWOL: - { - struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; - spin_lock_irq (&np->lock); - netdev_get_wol (dev, &wol); - spin_unlock_irq (&np->lock); - if (copy_to_user (useraddr, &wol, sizeof (wol))) - return -EFAULT; - return 0; - } - - case ETHTOOL_SWOL: - { - struct ethtool_wolinfo wol; - int rc; - if (copy_from_user (&wol, useraddr, sizeof (wol))) - return -EFAULT; - spin_lock_irq (&np->lock); - rc = netdev_set_wol (dev, &wol); - spin_unlock_irq (&np->lock); - return rc; - } - -/* TODO: we are too slack to do reg dumping for pio, for now */ -#ifndef CONFIG_8139TOO_PIO - /* NIC register dump */ - case ETHTOOL_GREGS: { - struct ethtool_regs regs; - unsigned int regs_len = np->regs_len; - u8 *regbuf = kmalloc(regs_len, GFP_KERNEL); - int rc; - - if (!regbuf) - return -ENOMEM; - memset(regbuf, 0, regs_len); - - rc = copy_from_user(®s, useraddr, sizeof(regs)); - if (rc) { - rc = -EFAULT; - goto err_out_gregs; - } - - if (regs.len > regs_len) - regs.len = regs_len; - if (regs.len < regs_len) { - rc = -EINVAL; - goto err_out_gregs; - } - - regs.version = RTL_REGS_VER; - rc = copy_to_user(useraddr, ®s, sizeof(regs)); - if (rc) { - rc = -EFAULT; - goto err_out_gregs; - } - - useraddr += offsetof(struct ethtool_regs, data); - - spin_lock_irq(&np->lock); - memcpy_fromio(regbuf, np->mmio_addr, regs_len); - spin_unlock_irq(&np->lock); - - if (copy_to_user(useraddr, regbuf, regs_len)) - rc = -EFAULT; - -err_out_gregs: - kfree(regbuf); - return rc; - } -#endif /* CONFIG_8139TOO_PIO */ - - /* get string list(s) */ - case ETHTOOL_GSTRINGS: { - struct ethtool_gstrings estr = { ETHTOOL_GSTRINGS }; - - if (copy_from_user(&estr, useraddr, sizeof(estr))) - return -EFAULT; - if (estr.string_set != ETH_SS_STATS) - return -EINVAL; - - estr.len = RTL_NUM_STATS; - if (copy_to_user(useraddr, &estr, sizeof(estr))) - return -EFAULT; - if (copy_to_user(useraddr + sizeof(estr), - ðtool_stats_keys, - sizeof(ethtool_stats_keys))) - return -EFAULT; - return 0; - } - - /* get NIC-specific statistics */ - case ETHTOOL_GSTATS: { - struct ethtool_stats estats = { ETHTOOL_GSTATS }; - u64 *tmp_stats; - const unsigned int sz = sizeof(u64) * RTL_NUM_STATS; - int i; - - estats.n_stats = RTL_NUM_STATS; - if (copy_to_user(useraddr, &estats, sizeof(estats))) - return -EFAULT; - - tmp_stats = kmalloc(sz, GFP_KERNEL); - if (!tmp_stats) - return -ENOMEM; - memset(tmp_stats, 0, sz); - - i = 0; - tmp_stats[i++] = np->xstats.early_rx; - tmp_stats[i++] = np->xstats.tx_buf_mapped; - tmp_stats[i++] = np->xstats.tx_timeouts; - tmp_stats[i++] = np->xstats.rx_lost_in_ring; - if (i != RTL_NUM_STATS) - BUG(); - - i = copy_to_user(useraddr + sizeof(estats), tmp_stats, sz); - kfree(tmp_stats); - - if (i) - return -EFAULT; - return 0; - } - default: - break; - } - - return -EOPNOTSUPP; -} - - -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct rtl8139_private *np = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - if (cmd == SIOCETHTOOL) - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - - else { - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, data, cmd, NULL); - spin_unlock_irq(&np->lock); - } - - return rc; -} -#endif - - -static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - unsigned long flags; - - if (netif_running(dev)) { - spin_lock_irqsave (&tp->lock, flags); - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - spin_unlock_irqrestore (&tp->lock, flags); - } - - return &tp->stats; -} - -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - -static void __set_rx_mode (struct net_device *dev) -{ - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - u32 mc_filter[2]; /* Multicast hash filter */ - int i, rx_mode; - u32 tmp; - - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", - dev->name, dev->flags, RTL_R32 (RxConfig)); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (dev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", - dev->name); - rx_mode = - AcceptBroadcast | AcceptMulticast | AcceptMyPhys | - AcceptAllPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else { - struct dev_mc_list *mclist; - rx_mode = AcceptBroadcast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { - int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - rx_mode |= AcceptMulticast; - } - } - - /* We can safely update without stopping the chip. */ - tmp = rtl8139_rx_config | rx_mode; - if (tp->rx_config != tmp) { - RTL_W32_F (RxConfig, tmp); - tp->rx_config = tmp; - } - RTL_W32_F (MAR0 + 0, mc_filter[0]); - RTL_W32_F (MAR0 + 4, mc_filter[1]); -} - -static void rtl8139_set_rx_mode (struct net_device *dev) -{ - unsigned long flags; - struct rtl8139_private *tp = dev->priv; - - spin_lock_irqsave (&tp->lock, flags); - __set_rx_mode(dev); - spin_unlock_irqrestore (&tp->lock, flags); -} - -#ifdef CONFIG_PM - -static int rtl8139_suspend (struct pci_dev *pdev, u32 state) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct rtl8139_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - unsigned long flags; - - if (!netif_running (dev)) - return 0; - - netif_device_detach (dev); - - spin_lock_irqsave (&tp->lock, flags); - - /* Disable interrupts, stop Tx and Rx. */ - RTL_W16 (IntrMask, 0); - RTL_W8 (ChipCmd, 0); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); - RTL_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); - return 0; -} - - -static int rtl8139_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - - if (!netif_running (dev)) - return 0; - netif_device_attach (dev); - rtl8139_hw_start (dev); - return 0; -} - -#endif /* CONFIG_PM */ - - -static struct pci_driver rtl8139_pci_driver = { - .name = DRV_NAME, - .id_table = rtl8139_pci_tbl, - .probe = rtl8139_init_one, - .remove = __devexit_p(rtl8139_remove_one), -#ifdef CONFIG_PM - .suspend = rtl8139_suspend, - .resume = rtl8139_resume, -#endif /* CONFIG_PM */ -}; - - -static int __init rtl8139_init_module (void) -{ - /* when we're a module, we always print a version message, - * even if no 8139 board is found. - */ -#ifdef MODULE - printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); -#endif - - return pci_module_init (&rtl8139_pci_driver); -} - - -static void __exit rtl8139_cleanup_module (void) -{ - pci_unregister_driver (&rtl8139_pci_driver); -} - - -module_init(rtl8139_init_module); -module_exit(rtl8139_cleanup_module); diff --git a/xen/drivers/net/pcnet32.c b/xen/drivers/net/pcnet32.c index 8dbb05c684..3c1c65a2e0 100644 --- a/xen/drivers/net/pcnet32.c +++ b/xen/drivers/net/pcnet32.c @@ -85,7 +85,9 @@ static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; static int max_interrupt_work = 80; +#ifdef COPYBREAK static int rx_copybreak = 200; +#endif #define PCNET32_PORT_AUI 0x00 #define PCNET32_PORT_10BT 0x01 @@ -1315,7 +1317,11 @@ pcnet32_rx(struct net_device *dev) } else { int rx_in_place = 0; +#ifdef COPYBREAK if (pkt_len > rx_copybreak) { +#else + { +#endif struct sk_buff *newskb; if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { @@ -1332,9 +1338,12 @@ pcnet32_rx(struct net_device *dev) rx_in_place = 1; } else skb = NULL; - } else { + } +#ifdef COPYBREAK + else { skb = dev_alloc_skb(pkt_len+2); - } + } +#endif if (skb == NULL) { int i; @@ -1351,6 +1360,7 @@ pcnet32_rx(struct net_device *dev) break; } skb->dev = dev; +#ifdef COPYBREAK if (!rx_in_place) { skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ @@ -1358,6 +1368,7 @@ pcnet32_rx(struct net_device *dev) (unsigned char *)(lp->rx_skbuff[entry]->tail), pkt_len,0); } +#endif lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); @@ -1676,8 +1687,10 @@ MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt"); +#ifdef COPYBREAK MODULE_PARM(rx_copybreak, "i"); MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); +#endif MODULE_PARM(tx_start_pt, "i"); MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); MODULE_PARM(pcnet32vlb, "i"); diff --git a/xen/drivers/net/tulip/interrupt.c b/xen/drivers/net/tulip/interrupt.c index d99b386356..25f27b4134 100644 --- a/xen/drivers/net/tulip/interrupt.c +++ b/xen/drivers/net/tulip/interrupt.c @@ -168,6 +168,7 @@ static int tulip_rx(struct net_device *dev) if (drop) goto throttle; #endif +#ifdef COPYBREAK /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ if (pkt_len < tulip_rx_copybreak @@ -187,6 +188,9 @@ static int tulip_rx(struct net_device *dev) pkt_len); #endif } else { /* Pass up the skb already on the Rx ring. */ +#else + { +#endif /* COPYBREAK */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len); diff --git a/xen/drivers/net/via-rhine.c b/xen/drivers/net/via-rhine.c deleted file mode 100644 index f8d42fefda..0000000000 --- a/xen/drivers/net/via-rhine.c +++ /dev/null @@ -1,1933 +0,0 @@ -/* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */ -/* - Written 1998-2001 by Donald Becker. - - This software may be used and distributed according to the terms of - the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. - - This driver is designed for the VIA VT86C100A Rhine-I. - It also works with the 6102 Rhine-II, and 6105/6105M Rhine-III. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - - This driver contains some changes from the original Donald Becker - version. He may or may not be interested in bug reports on this - code. You can find his versions at: - http://www.scyld.com/network/via-rhine.html - - - Linux kernel version history: - - LK1.1.0: - - Jeff Garzik: softnet 'n stuff - - LK1.1.1: - - Justin Guyett: softnet and locking fixes - - Jeff Garzik: use PCI interface - - LK1.1.2: - - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions - - LK1.1.3: - - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c - code) update "Theory of Operation" with - softnet/locking changes - - Dave Miller: PCI DMA and endian fixups - - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation - - LK1.1.4: - - Urban Widmark: fix gcc 2.95.2 problem and - remove writel's to fixed address 0x7c - - LK1.1.5: - - Urban Widmark: mdio locking, bounce buffer changes - merges from Beckers 1.05 version - added netif_running_on/off support - - LK1.1.6: - - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) - set netif_running_on/off on startup, del_timer_sync - - LK1.1.7: - - Manfred Spraul: added reset into tx_timeout - - LK1.1.9: - - Urban Widmark: merges from Beckers 1.10 version - (media selection + eeprom reload) - - David Vrabel: merges from D-Link "1.11" version - (disable WOL and PME on startup) - - LK1.1.10: - - Manfred Spraul: use "singlecopy" for unaligned buffers - don't allocate bounce buffers for !ReqTxAlign cards - - LK1.1.11: - - David Woodhouse: Set dev->base_addr before the first time we call - wait_for_reset(). It's a lot happier that way. - Free np->tx_bufs only if we actually allocated it. - - LK1.1.12: - - Martin Eriksson: Allow Memory-Mapped IO to be enabled. - - LK1.1.13 (jgarzik): - - Add ethtool support - - Replace some MII-related magic numbers with constants - - LK1.1.14 (Ivan G.): - - fixes comments for Rhine-III - - removes W_MAX_TIMEOUT (unused) - - adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card - is R-I and has Davicom chip, flag is referenced in kernel driver) - - sends chip_id as a parameter to wait_for_reset since np is not - initialized on first call - - changes mmio "else if (chip_id==VT6102)" to "else" so it will work - for Rhine-III's (documentation says same bit is correct) - - transmit frame queue message is off by one - fixed - - adds IntrNormalSummary to "Something Wicked" exclusion list - so normal interrupts will not trigger the message (src: Donald Becker) - (Roger Luethi) - - show confused chip where to continue after Tx error - - location of collision counter is chip specific - - allow selecting backoff algorithm (module parameter) - - LK1.1.15 (jgarzik): - - Use new MII lib helper generic_mii_ioctl - - LK1.1.16 (Roger Luethi) - - Etherleak fix - - Handle Tx buffer underrun - - Fix bugs in full duplex handling - - New reset code uses "force reset" cmd on Rhine-II - - Various clean ups - - LK1.1.17 (Roger Luethi) - - Fix race in via_rhine_start_tx() - - On errors, wait for Tx engine to turn off before scavenging - - Handle Tx descriptor write-back race on Rhine-II - - Force flushing for PCI posted writes - - More reset code changes - -*/ - -#define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.17" -#define DRV_RELDATE "March-1-2003" - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/crc32.h> -#include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> - -#undef RX_RING_SIZE -#undef TX_RING_SIZE - -/* A few user-configurable values. - These may be modified when a driver module is loaded. */ - -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -static int max_interrupt_work = 20; - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak; - -/* Select a backoff algorithm (Ethernet capture effect) */ -static int backoff; - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. - The default is autonegotation for speed and duplex. - This should rarely be overridden. - Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps. - Use option values 0x10 and 0x100 for forcing half duplex fixed speed. - Use option values 0x20 and 0x200 for forcing full duplex operation. -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). - The Rhine has a 64 element 8390-like hash table. */ -static const int multicast_filter_limit = 32; - - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for compile efficiency. - The compiler will convert <unsigned>'%'<2^N> into a bit mask. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 16 - - -/* Operational parameters that usually are not changed. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) - -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -/* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" -KERN_INFO " http://www.scyld.com/network/via-rhine.html\n"; - -static char shortname[] = DRV_NAME; - - -/* This driver was written to use PCI memory space, however most versions - of the Rhine only work correctly with I/O space accesses. */ -#ifdef CONFIG_VIA_RHINE_MMIO -#define USE_MEM -#else -#define USE_IO -#undef readb -#undef readw -#undef readl -#undef writeb -#undef writew -#undef writel -#define readb inb -#define readw inw -#define readl inl -#define writeb outb -#define writew outw -#define writel outl -#endif - -MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); -MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(debug, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(backoff, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); -MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); -MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); -MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); - -/* - Theory of Operation - -I. Board Compatibility - -This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet -controller. - -II. Board-specific settings - -Boards with this chip are functional only in a bus-master PCI slot. - -Many operational settings are loaded from the EEPROM to the Config word at -offset 0x78. For most of these settings, this driver assumes that they are -correct. -If this driver is compiled to use PCI memory space operations the EEPROM -must be configured to enable memory ops. - -III. Driver operation - -IIIa. Ring buffers - -This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. - -IIIb/c. Transmit/Receive Structure - -This driver attempts to use a zero-copy receive and transmit scheme. - -Alas, all data buffers are required to start on a 32 bit boundary, so -the driver must often copy transmit packets into bounce buffers. - -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the chip as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in the last phase of via_rhine_rx(). - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. New boards are typically used in generously configured machines -and the underfilled buffers have negligible impact compared to the benefit of -a single allocation size, so the default value of zero results in never -copying packets. When copying is done, the cost is usually mitigated by using -a combined copy/checksum routine. Copying also preloads the cache, which is -most useful with small frames. - -Since the VIA chips are only able to transfer data to buffers on 32 bit -boundaries, the IP header at offset 14 in an ethernet frame isn't -longword aligned for further processing. Copying these unaligned buffers -has the beneficial effect of 16-byte aligning the IP header. - -IIId. Synchronization - -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->priv->lock spinlock. The other thread is the interrupt handler, which -is single threaded by the hardware and interrupt handling software. - -The send packet thread has partial control over the Tx ring. It locks the -dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring -is not available it stops the transmit queue by calling netif_stop_queue. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. If at least half of the entries in -the Rx ring are available the transmit queue is woken up if it was stopped. - -IV. Notes - -IVb. References - -Preliminary VT86C100A manual from http://www.via.com.tw/ -http://www.scyld.com/expert/100mbps.html -http://www.scyld.com/expert/NWay.html -ftp://ftp.via.com.tw/public/lan/Products/NIC/VT86C100A/Datasheet/VT86C100A03.pdf -ftp://ftp.via.com.tw/public/lan/Products/NIC/VT6102/Datasheet/VT6102_021.PDF - - -IVc. Errata - -The VT86C100A manual is not reliable information. -The 3043 chip does not handle unaligned transmit or receive buffers, resulting -in significant performance degradation for bounce buffer copies on transmit -and unaligned IP headers on receive. -The chip does not pad to minimum transmit length. - -*/ - - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ - -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; - -enum via_rhine_chips { - VT86C100A = 0, - VT6102, - VT6105, - VT6105M -}; - -struct via_rhine_chip_info { - const char *name; - u16 pci_flags; - int io_size; - int drv_flags; -}; - - -enum chip_capability_flags { - CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, - ReqTxAlign=0x10, HasWOL=0x20, }; - -#ifdef USE_MEM -#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) -#else -#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) -#endif -/* Beware of PCI posted writes */ -#define IOSYNC do { readb(dev->base_addr + StationAddr); } while (0) - -/* directly indexed by enum via_rhine_chips, above */ -static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = -{ - { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, - CanHaveMII | ReqTxAlign | HasDavicomPhy }, - { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, - { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, - { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, -}; - -static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = -{ - {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, - {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, - {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, - {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, - {0,} /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); - - -/* Offsets to the device registers. */ -enum register_offsets { - StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, - IntrStatus=0x0C, IntrEnable=0x0E, - MulticastFilter0=0x10, MulticastFilter1=0x14, - RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, - MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, - ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, - RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, - StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7, - PwrcsrClr=0xAC, -}; - -/* Bits in ConfigD */ -enum backoff_bits { - BackOptional=0x01, BackModify=0x02, - BackCaptureEffect=0x04, BackRandom=0x08 -}; - -#ifdef USE_MEM -/* Registers we check that mmio and reg are the same. */ -int mmio_verify_registers[] = { - RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD, - 0 -}; -#endif - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210, - IntrPCIErr=0x0040, - IntrStatsMax=0x0080, IntrRxEarly=0x0100, - IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, - IntrTxAborted=0x2000, IntrLinkChange=0x4000, - IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, - IntrTxDescRace=0x080000, /* mapped from IntrStatus2 */ - IntrTxErrSummary=0x082210, -}; - -/* The Rx and Tx buffer descriptors. */ -struct rx_desc { - s32 rx_status; - u32 desc_length; /* Chain flag, Buffer/frame length */ - u32 addr; - u32 next_desc; -}; -struct tx_desc { - s32 tx_status; - u32 desc_length; /* Chain flag, Tx Config, Frame length */ - u32 addr; - u32 next_desc; -}; - -/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ -#define TXDESC 0x00e08000 - -enum rx_status_bits { - RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F -}; - -/* Bits in *_desc.*_status */ -enum desc_status_bits { - DescOwn=0x80000000 -}; - -/* Bits in ChipCmd. */ -enum chip_cmd_bits { - CmdInit=0x0001, CmdStart=0x0002, CmdStop=0x0004, CmdRxOn=0x0008, - CmdTxOn=0x0010, CmdTxDemand=0x0020, CmdRxDemand=0x0040, - CmdEarlyRx=0x0100, CmdEarlyTx=0x0200, CmdFDuplex=0x0400, - CmdNoTxPoll=0x0800, CmdReset=0x8000, -}; - -#define MAX_MII_CNT 4 -struct netdev_private { - /* Descriptor rings */ - struct rx_desc *rx_ring; - struct tx_desc *tx_ring; - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t rx_skbuff_dma[RX_RING_SIZE]; - - /* The saved address of a sent-in-place packet/buffer, for later free(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; - - /* Tx bounce buffers */ - unsigned char *tx_buf[TX_RING_SIZE]; - unsigned char *tx_bufs; - dma_addr_t tx_bufs_dma; - - struct pci_dev *pdev; - struct net_device_stats stats; - struct timer_list timer; /* Media monitoring timer. */ - spinlock_t lock; - - /* Frequently used values: keep some adjacent for cache effect. */ - int chip_id, drv_flags; - struct rx_desc *rx_head_desc; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int cur_tx, dirty_tx; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - u16 chip_cmd; /* Current setting for ChipCmd */ - - /* These values are keep track of the transceiver/media in use. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - u8 tx_thresh, rx_thresh; - - /* MII transceiver section. */ - unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ - unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ - u16 mii_status; /* last read MII status */ - struct mii_if_info mii_if; -}; - -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int via_rhine_open(struct net_device *dev); -static void via_rhine_check_duplex(struct net_device *dev); -static void via_rhine_timer(unsigned long data); -static void via_rhine_tx_timeout(struct net_device *dev); -static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev); -static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static void via_rhine_tx(struct net_device *dev); -static void via_rhine_rx(struct net_device *dev); -static void via_rhine_error(struct net_device *dev, int intr_status); -static void via_rhine_set_rx_mode(struct net_device *dev); -static struct net_device_stats *via_rhine_get_stats(struct net_device *dev); -#if 0 -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif -static int via_rhine_close(struct net_device *dev); - -static inline u32 get_intr_status(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; - u32 intr_status; - - intr_status = readw(ioaddr + IntrStatus); - /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ - if (np->chip_id == VT6102) - intr_status |= readb(ioaddr + IntrStatus2) << 16; - return intr_status; -} - -static void wait_for_reset(struct net_device *dev, int chip_id, char *name) -{ - long ioaddr = dev->base_addr; - int boguscnt = 20; - - IOSYNC; - - if (readw(ioaddr + ChipCmd) & CmdReset) { - printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", name); - - /* Rhine-II needs to be forced sometimes */ - if (chip_id == VT6102) - writeb(0x40, ioaddr + MiscCmd); - - /* VT86C100A may need long delay after reset (dlink) */ - /* Seen on Rhine-II as well (rl) */ - while ((readw(ioaddr + ChipCmd) & CmdReset) && --boguscnt) - udelay(5); - - } - - if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", name, - boguscnt ? "succeeded" : "failed"); -} - -#ifdef USE_MEM -static void __devinit enable_mmio(long ioaddr, int chip_id) -{ - int n; - if (chip_id == VT86C100A) { - /* More recent docs say that this bit is reserved ... */ - n = inb(ioaddr + ConfigA) | 0x20; - outb(n, ioaddr + ConfigA); - } else { - n = inb(ioaddr + ConfigD) | 0x80; - outb(n, ioaddr + ConfigD); - } -} -#endif - -static void __devinit reload_eeprom(long ioaddr) -{ - int i; - outb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) - break; -} - -static int __devinit via_rhine_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct netdev_private *np; - int i, option; - int chip_id = (int) ent->driver_data; - static int card_idx = -1; - long ioaddr; - long memaddr; - int io_size; - int pci_flags; -#ifdef USE_MEM - long ioaddr0; -#endif - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); -#endif - - card_idx++; - option = card_idx < MAX_UNITS ? options[card_idx] : 0; - io_size = via_rhine_chip_info[chip_id].io_size; - pci_flags = via_rhine_chip_info[chip_id].pci_flags; - - if (pci_enable_device (pdev)) - goto err_out; - - /* this should always be supported */ - if (pci_set_dma_mask(pdev, 0xffffffff)) { - printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); - goto err_out; - } - - /* sanity check */ - if ((pci_resource_len (pdev, 0) < io_size) || - (pci_resource_len (pdev, 1) < io_size)) { - printk (KERN_ERR "Insufficient PCI resources, aborting\n"); - goto err_out; - } - - ioaddr = pci_resource_start (pdev, 0); - memaddr = pci_resource_start (pdev, 1); - - if (pci_flags & PCI_USES_MASTER) - pci_set_master (pdev); - - dev = alloc_etherdev(sizeof(*np)); - if (dev == NULL) { - printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); - goto err_out; - } - SET_MODULE_OWNER(dev); - - if (pci_request_regions(pdev, shortname)) - goto err_out_free_netdev; - -#ifdef USE_MEM - ioaddr0 = ioaddr; - enable_mmio(ioaddr0, chip_id); - - ioaddr = (long) ioremap (memaddr, io_size); - if (!ioaddr) { - printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n", - pdev->slot_name, io_size, memaddr); - goto err_out_free_res; - } - - /* Check that selected MMIO registers match the PIO ones */ - i = 0; - while (mmio_verify_registers[i]) { - int reg = mmio_verify_registers[i++]; - unsigned char a = inb(ioaddr0+reg); - unsigned char b = readb(ioaddr+reg); - if (a != b) { - printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n", - reg, a, b); - goto err_out_unmap; - } - } -#endif - - /* D-Link provided reset code (with comment additions) */ - if (via_rhine_chip_info[chip_id].drv_flags & HasWOL) { - unsigned char byOrgValue; - - /* clear sticky bit before reset & read ethernet address */ - byOrgValue = readb(ioaddr + StickyHW); - byOrgValue = byOrgValue & 0xFC; - writeb(byOrgValue, ioaddr + StickyHW); - - /* (bits written are cleared?) */ - /* disable force PME-enable */ - writeb(0x80, ioaddr + WOLcgClr); - /* disable power-event config bit */ - writeb(0xFF, ioaddr + WOLcrClr); - /* clear power status (undocumented in vt6102 docs?) */ - writeb(0xFF, ioaddr + PwrcsrClr); - } - - /* Reset the chip to erase previous misconfiguration. */ - writew(CmdReset, ioaddr + ChipCmd); - - dev->base_addr = ioaddr; - wait_for_reset(dev, chip_id, shortname); - - /* Reload the station address from the EEPROM. */ -#ifdef USE_IO - reload_eeprom(ioaddr); -#else - reload_eeprom(ioaddr0); - /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. - If reload_eeprom() was done first this could be avoided, but it is - not known if that still works with the "win98-reboot" problem. */ - enable_mmio(ioaddr0, chip_id); -#endif - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(ioaddr + StationAddr + i); - - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx); - goto err_out_unmap; - } - - if (chip_id == VT6102) { - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); - } - - /* Select backoff algorithm */ - if (backoff) - writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), - ioaddr + ConfigD); - - dev->irq = pdev->irq; - - np = dev->priv; - spin_lock_init (&np->lock); - np->chip_id = chip_id; - np->drv_flags = via_rhine_chip_info[chip_id].drv_flags; - np->pdev = pdev; - np->mii_if.dev = dev; - np->mii_if.mdio_read = mdio_read; - np->mii_if.mdio_write = mdio_write; - np->mii_if.phy_id_mask = 0x1f; - np->mii_if.reg_num_mask = 0x1f; - - if (dev->mem_start) - option = dev->mem_start; - - /* The chip-specific entries in the device structure. */ - dev->open = via_rhine_open; - dev->hard_start_xmit = via_rhine_start_tx; - dev->stop = via_rhine_close; - dev->get_stats = via_rhine_get_stats; - dev->set_multicast_list = via_rhine_set_rx_mode; -#if 0 - dev->do_ioctl = netdev_ioctl; -#endif - dev->tx_timeout = via_rhine_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; -#if 0 - if (np->drv_flags & ReqTxAlign) -#endif - dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; - - /* dev->name not defined before register_netdev()! */ - i = register_netdev(dev); - if (i) - goto err_out_unmap; - - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x220) - np->mii_if.full_duplex = 1; - np->default_port = option & 15; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - np->mii_if.full_duplex = 1; - - if (np->mii_if.full_duplex) { - printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation" - " disabled.\n", dev->name); - np->mii_if.force_media = 1; - } - - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, via_rhine_chip_info[chip_id].name, - (pci_flags & PCI_USES_IO) ? ioaddr : memaddr); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); - - pci_set_drvdata(pdev, dev); - - if (np->drv_flags & CanHaveMII) { - int phy, phy_idx = 0; - np->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phy; - np->mii_if.advertising = mdio_read(dev, phy, 4); - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x Link %4.4x.\n", - dev->name, phy, mii_status, np->mii_if.advertising, - mdio_read(dev, phy, 5)); - - /* set IFF_RUNNING */ - if (mii_status & BMSR_LSTATUS) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } - } - np->mii_cnt = phy_idx; - np->mii_if.phy_id = np->phys[0]; - } - - /* Allow forcing the media type. */ - if (option > 0) { - if (option & 0x220) - np->mii_if.full_duplex = 1; - np->default_port = option & 0x3ff; - if (np->default_port & 0x330) { - /* FIXME: shouldn't someone check this variable? */ - /* np->medialock = 1; */ - printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", - (option & 0x300 ? 100 : 10), - (option & 0x220 ? "full" : "half")); - if (np->mii_cnt) - mdio_write(dev, np->phys[0], MII_BMCR, - ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */ - } - } - - alert_slow_netdevice(dev, (char *)via_rhine_chip_info[chip_id].name); - - return 0; - -err_out_unmap: -#ifdef USE_MEM - iounmap((void *)ioaddr); -err_out_free_res: -#endif - pci_release_regions(pdev); -err_out_free_netdev: - kfree (dev); -err_out: - return -ENODEV; -} - -static int alloc_ring(struct net_device* dev) -{ - struct netdev_private *np = dev->priv; - void *ring; - dma_addr_t ring_dma; - - ring = pci_alloc_consistent(np->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - &ring_dma); - if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); - return -ENOMEM; - } - if (np->drv_flags & ReqTxAlign) { - np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - &np->tx_bufs_dma); - if (np->tx_bufs == NULL) { - pci_free_consistent(np->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - ring, ring_dma); - return -ENOMEM; - } - } - - np->rx_ring = ring; - np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); - np->rx_ring_dma = ring_dma; - np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); - - return 0; -} - -void free_ring(struct net_device* dev) -{ - struct netdev_private *np = dev->priv; - - pci_free_consistent(np->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - np->rx_ring, np->rx_ring_dma); - np->tx_ring = NULL; - - if (np->tx_bufs) - pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - np->tx_bufs, np->tx_bufs_dma); - - np->tx_bufs = NULL; - -} - -static void alloc_rbufs(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - dma_addr_t next; - int i; - - np->dirty_rx = np->cur_rx = 0; - - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_head_desc = &np->rx_ring[0]; - next = np->rx_ring_dma; - - /* Init the ring entries */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); - next += sizeof(struct rx_desc); - np->rx_ring[i].next_desc = cpu_to_le32(next); - np->rx_skbuff[i] = 0; - } - /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); - - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - - np->rx_skbuff_dma[i] = - pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); - - np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); - np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); -} - -static void free_rbufs(struct net_device* dev) -{ - struct netdev_private *np = dev->priv; - int i; - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->rx_skbuff[i]) { - pci_unmap_single(np->pdev, - np->rx_skbuff_dma[i], - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb(np->rx_skbuff[i]); - } - np->rx_skbuff[i] = 0; - } -} - -static void alloc_tbufs(struct net_device* dev) -{ - struct netdev_private *np = dev->priv; - dma_addr_t next; - int i; - - np->dirty_tx = np->cur_tx = 0; - next = np->tx_ring_dma; - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); - next += sizeof(struct tx_desc); - np->tx_ring[i].next_desc = cpu_to_le32(next); - np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; - } - np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); - -} - -static void free_tbufs(struct net_device* dev) -{ - struct netdev_private *np = dev->priv; - int i; - - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); - np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->tx_skbuff[i]) { - if (np->tx_skbuff_dma[i]) { - pci_unmap_single(np->pdev, - np->tx_skbuff_dma[i], - np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - } - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = 0; - np->tx_buf[i] = 0; - } -} - -static void init_registers(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int i; - - for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + i); - - /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ - /* Configure initial FIFO thresholds. */ - writeb(0x20, ioaddr + TxConfig); - np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ - np->mii_if.full_duplex = 0; - - if (dev->if_port == 0) - dev->if_port = np->default_port; - - writel(np->rx_ring_dma, ioaddr + RxRingPtr); - writel(np->tx_ring_dma, ioaddr + TxRingPtr); - - via_rhine_set_rx_mode(dev); - - /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | - IntrRxDropped | IntrRxNoBuf | IntrTxAborted | - IntrTxDone | IntrTxError | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange, - ioaddr + IntrEnable); - - np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (np->mii_if.force_media) - np->chip_cmd |= CmdFDuplex; - writew(np->chip_cmd, ioaddr + ChipCmd); - - via_rhine_check_duplex(dev); - - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - /* For ESI phys, turn on bit 7 in register 0x17. */ - mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | - (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); -} -/* Read and write over the MII Management Data I/O (MDIO) interface. */ - -static int mdio_read(struct net_device *dev, int phy_id, int regnum) -{ - long ioaddr = dev->base_addr; - int boguscnt = 1024; - - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); - writeb(phy_id, ioaddr + MIIPhyAddr); - writeb(regnum, ioaddr + MIIRegAddr); - writeb(0x40, ioaddr + MIICmd); /* Trigger read */ - boguscnt = 1024; - while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0) - ; - return readw(ioaddr + MIIData); -} - -static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int boguscnt = 1024; - - if (phy_id == np->phys[0]) { - switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ - if (value & 0x9000) /* Autonegotiation. */ - np->mii_if.force_media = 0; - else - np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0; - break; - case MII_ADVERTISE: - np->mii_if.advertising = value; - break; - } - } - - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); - writeb(phy_id, ioaddr + MIIPhyAddr); - writeb(regnum, ioaddr + MIIRegAddr); - writew(value, ioaddr + MIIData); - writeb(0x20, ioaddr + MIICmd); /* Trigger write. */ -} - - -static int via_rhine_open(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int i; - - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); - - i = request_irq(np->pdev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev); - if (i) - return i; - - if (debug > 1) - printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", - dev->name, np->pdev->irq); - - i = alloc_ring(dev); - if (i) - return i; - alloc_rbufs(dev); - alloc_tbufs(dev); - wait_for_reset(dev, np->chip_id, dev->name); - init_registers(dev); - if (debug > 2) - printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " - "MII status: %4.4x.\n", - dev->name, readw(ioaddr + ChipCmd), - mdio_read(dev, np->phys[0], MII_BMSR)); - - netif_start_queue(dev); - - /* Set the timer to check for link beat. */ - init_timer(&np->timer); - np->timer.expires = jiffies + 2; - np->timer.data = (unsigned long)dev; - np->timer.function = &via_rhine_timer; /* timer handler */ - add_timer(&np->timer); - - return 0; -} - -static void via_rhine_check_duplex(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); - int negotiated = mii_lpa & np->mii_if.advertising; - int duplex; - - if (np->mii_if.force_media || mii_lpa == 0xffff) - return; - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (np->mii_if.full_duplex != duplex) { - np->mii_if.full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner capability of %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], mii_lpa); - if (duplex) - np->chip_cmd |= CmdFDuplex; - else - np->chip_cmd &= ~CmdFDuplex; - writew(np->chip_cmd, ioaddr + ChipCmd); - } -} - - -static void via_rhine_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 10*HZ; - int mii_status; - - if (debug > 3) { - printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", - dev->name, readw(ioaddr + IntrStatus)); - } - - spin_lock_irq (&np->lock); - - via_rhine_check_duplex(dev); - - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = mdio_read(dev, np->phys[0], MII_BMSR); - if ( (mii_status & BMSR_LSTATUS) != (np->mii_status & BMSR_LSTATUS) ) { - if (mii_status & BMSR_LSTATUS) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } - np->mii_status = mii_status; - - spin_unlock_irq (&np->lock); - - np->timer.expires = jiffies + next_tick; - add_timer(&np->timer); -} - - -static void via_rhine_tx_timeout (struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - - printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, readw (ioaddr + IntrStatus), - mdio_read (dev, np->phys[0], MII_BMSR)); - - dev->if_port = 0; - - /* protect against concurrent rx interrupts */ - disable_irq(np->pdev->irq); - - spin_lock(&np->lock); - - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); - - /* clear all descriptors */ - free_tbufs(dev); - free_rbufs(dev); - alloc_tbufs(dev); - alloc_rbufs(dev); - - /* Reinitialize the hardware. */ - wait_for_reset(dev, np->chip_id, dev->name); - init_registers(dev); - - spin_unlock(&np->lock); - enable_irq(np->pdev->irq); - - dev->trans_start = jiffies; - np->stats.tx_errors++; - netif_wake_queue(dev); -} - -static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - unsigned entry; - u32 intr_status; - - /* Caution: the write order is important here, set the field - with the "ownership" bits last. */ - - /* Calculate the next Tx descriptor entry. */ - entry = np->cur_tx % TX_RING_SIZE; - - if (skb->len < ETH_ZLEN) { -#if 0 - skb = skb_padto(skb, ETH_ZLEN); - if(skb == NULL) - return 0; -#else - memset(np->tx_buf[entry], 0, ETH_ZLEN); -#endif - } - - np->tx_skbuff[entry] = skb; - -#if 0 - if ((np->drv_flags & ReqTxAlign) && - (((long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW) - ) { -#endif - /* Must use alignment buffer. */ - if (skb->len > PKT_BUF_SZ) { - /* packet too long, drop it */ - dev_kfree_skb(skb); - np->tx_skbuff[entry] = NULL; - np->stats.tx_dropped++; - return 0; - } -#if 0 - skb_copy_and_csum_dev(skb, np->tx_buf[entry]); -#else - skb_copy_bits(skb, 0, np->tx_buf[entry], skb->len); -#endif - np->tx_skbuff_dma[entry] = 0; - np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + - (np->tx_buf[entry] - np->tx_bufs)); -#if 0 - } else { - np->tx_skbuff_dma[entry] = - pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]); - } -#endif - - np->tx_ring[entry].desc_length = - cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - - /* lock eth irq */ - spin_lock_irq (&np->lock); - wmb(); - np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); - wmb(); - - np->cur_tx++; - - /* Non-x86 Todo: explicitly flush cache lines here. */ - - /* - * Wake the potentially-idle transmit channel unless errors are - * pending (the ISR must sort them out first). - */ - intr_status = get_intr_status(dev); - if ((intr_status & IntrTxErrSummary) == 0) { - writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - } - IOSYNC; - - if (np->cur_tx == np->dirty_tx + TX_QUEUE_LEN) - netif_stop_queue(dev); - - dev->trans_start = jiffies; - - spin_unlock_irq (&np->lock); - - if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx-1, entry); - } - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) -{ - struct net_device *dev = dev_instance; - long ioaddr; - u32 intr_status; - int boguscnt = max_interrupt_work; - - ioaddr = dev->base_addr; - - while ((intr_status = get_intr_status(dev))) { - /* Acknowledge all of the current interrupt sources ASAP. */ - if (intr_status & IntrTxDescRace) - writeb(0x08, ioaddr + IntrStatus2); - writew(intr_status & 0xffff, ioaddr + IntrStatus); - IOSYNC; - - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n", - dev->name, intr_status); - - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | - IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) - via_rhine_rx(dev); - - if (intr_status & (IntrTxErrSummary | IntrTxDone)) { - if (intr_status & IntrTxErrSummary) { - int cnt = 20; - /* Avoid scavenging before Tx engine turned off */ - while ((readw(ioaddr+ChipCmd) & CmdTxOn) && --cnt) - udelay(5); - if (debug > 2 && !cnt) - printk(KERN_WARNING "%s: via_rhine_interrupt() " - "Tx engine still on.\n", - dev->name); - } - via_rhine_tx(dev); - } - - /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (IntrPCIErr | IntrLinkChange | - IntrStatsMax | IntrTxError | IntrTxAborted | - IntrTxUnderrun | IntrTxDescRace)) - via_rhine_error(dev, intr_status); - - if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=%#8.8x.\n", - dev->name, intr_status); - break; - } - } - - if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n", - dev->name, readw(ioaddr + IntrStatus)); -} - -/* This routine is logically part of the interrupt handler, but isolated - for clarity. */ -static void via_rhine_tx(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE; - - spin_lock (&np->lock); - - /* find and cleanup dirty tx descriptors */ - while (np->dirty_tx != np->cur_tx) { - txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); - if (debug > 6) - printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n", - entry, txstatus); - if (txstatus & DescOwn) - break; - if (txstatus & 0x8000) { - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); - np->stats.tx_errors++; - if (txstatus & 0x0400) np->stats.tx_carrier_errors++; - if (txstatus & 0x0200) np->stats.tx_window_errors++; - if (txstatus & 0x0100) np->stats.tx_aborted_errors++; - if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; - if (((np->chip_id == VT86C100A) && txstatus & 0x0002) || - (txstatus & 0x0800) || (txstatus & 0x1000)) { - np->stats.tx_fifo_errors++; - np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); - break; /* Keep the skb - we try again */ - } - /* Transmitter restarted in 'abnormal' handler. */ - } else { - if (np->chip_id == VT86C100A) - np->stats.collisions += (txstatus >> 3) & 0x0F; - else - np->stats.collisions += txstatus & 0x0F; - if (debug > 6) - printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", - (txstatus >> 3) & 0xF, - txstatus & 0xF); - np->stats.tx_bytes += np->tx_skbuff[entry]->len; - np->stats.tx_packets++; - } - /* Free the original skb. */ - if (np->tx_skbuff_dma[entry]) { - pci_unmap_single(np->pdev, - np->tx_skbuff_dma[entry], - np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - } - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = NULL; - entry = (++np->dirty_tx) % TX_RING_SIZE; - } - if ((np->cur_tx - np->dirty_tx) < TX_QUEUE_LEN - 4) - netif_wake_queue (dev); - - spin_unlock (&np->lock); -} - -/* This routine is logically part of the interrupt handler, but isolated - for clarity and better register allocation. */ -static void via_rhine_rx(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - int entry = np->cur_rx % RX_RING_SIZE; - int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; - - if (debug > 4) { - printk(KERN_DEBUG "%s: via_rhine_rx(), entry %d status %8.8x.\n", - dev->name, entry, le32_to_cpu(np->rx_head_desc->rx_status)); - } - - /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { - struct rx_desc *desc = np->rx_head_desc; - u32 desc_status = le32_to_cpu(desc->rx_status); - int data_size = desc_status >> 16; - - if (debug > 4) - printk(KERN_DEBUG " via_rhine_rx() status is %8.8x.\n", - desc_status); - if (--boguscnt < 0) - break; - if ( (desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { - if ((desc_status & RxWholePkt) != RxWholePkt) { - printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, entry %#x length %d status %8.8x!\n", - dev->name, entry, data_size, desc_status); - printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", - dev->name, np->rx_head_desc, &np->rx_ring[entry]); - np->stats.rx_length_errors++; - } else if (desc_status & RxErr) { - /* There was a error. */ - if (debug > 2) - printk(KERN_DEBUG " via_rhine_rx() Rx error was %8.8x.\n", - desc_status); - np->stats.rx_errors++; - if (desc_status & 0x0030) np->stats.rx_length_errors++; - if (desc_status & 0x0048) np->stats.rx_fifo_errors++; - if (desc_status & 0x0004) np->stats.rx_frame_errors++; - if (desc_status & 0x0002) { - /* this can also be updated outside the interrupt handler */ - spin_lock (&np->lock); - np->stats.rx_crc_errors++; - spin_unlock (&np->lock); - } - } - } else { - struct sk_buff *skb; - /* Length should omit the CRC */ - int pkt_len = data_size - 4; - - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry], - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - - /* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum - is memcpy for all archs so this is kind of pointless right - now ... or? */ -#if HAS_IP_COPYSUM /* Call copy + cksum if available. */ - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); - skb_put(skb, pkt_len); -#else - memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, - pkt_len); -#endif - } else { - skb = np->rx_skbuff[entry]; - if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", - dev->name); - break; - } - np->rx_skbuff[entry] = NULL; - skb_put(skb, pkt_len); - pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry], - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - np->stats.rx_bytes += pkt_len; - np->stats.rx_packets++; - } - entry = (++np->cur_rx) % RX_RING_SIZE; - np->rx_head_desc = &np->rx_ring[entry]; - } - - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_skbuff_dma[entry] = - pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); - np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]); - } - np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); - } - - /* Pre-emptively restart Rx engine. */ - writew(readw(dev->base_addr + ChipCmd) | CmdRxOn | CmdRxDemand, - dev->base_addr + ChipCmd); -} - -/* Clears the "tally counters" for CRC errors and missed frames(?). - It has been reported that some chips need a write of 0 to clear - these, for others the counters are set to 1 when written to and - instead cleared when read. So we clear them both ways ... */ -static inline void clear_tally_counters(const long ioaddr) -{ - writel(0, ioaddr + RxMissed); - readw(ioaddr + RxCRCErrs); - readw(ioaddr + RxMissed); -} - -static void via_rhine_restart_tx(struct net_device *dev) { - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - int entry = np->dirty_tx % TX_RING_SIZE; - u32 intr_status; - - /* - * If new errors occured, we need to sort them out before doing Tx. - * In that case the ISR will be back here RSN anyway. - */ - intr_status = get_intr_status(dev); - - if ((intr_status & IntrTxErrSummary) == 0) { - - /* We know better than the chip where it should continue. */ - writel(np->tx_ring_dma + entry * sizeof(struct tx_desc), - ioaddr + TxRingPtr); - - writew(CmdTxDemand | np->chip_cmd, ioaddr + ChipCmd); - IOSYNC; - } - else { - /* This should never happen */ - if (debug > 1) - printk(KERN_WARNING "%s: via_rhine_restart_tx() " - "Another error occured %8.8x.\n", - dev->name, intr_status); - } - -} - -static void via_rhine_error(struct net_device *dev, int intr_status) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - - spin_lock (&np->lock); - - if (intr_status & (IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) { - /* Link failed, restart autonegotiation. */ - if (np->drv_flags & HasDavicomPhy) - mdio_write(dev, np->phys[0], MII_BMCR, 0x3300); - } else - via_rhine_check_duplex(dev); - if (debug) - printk(KERN_ERR "%s: MII status changed: Autonegotiation " - "advertising %4.4x partner %4.4x.\n", dev->name, - mdio_read(dev, np->phys[0], MII_ADVERTISE), - mdio_read(dev, np->phys[0], MII_LPA)); - } - if (intr_status & IntrStatsMax) { - np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); - np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - clear_tally_counters(ioaddr); - } - if (intr_status & IntrTxAborted) { - if (debug > 1) - printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n", - dev->name, intr_status); - } - if (intr_status & IntrTxUnderrun) { - if (np->tx_thresh < 0xE0) - writeb(np->tx_thresh += 0x20, ioaddr + TxConfig); - if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, Tx " - "threshold now %2.2x.\n", - dev->name, np->tx_thresh); - } - if (intr_status & IntrTxDescRace) { - if (debug > 2) - printk(KERN_INFO "%s: Tx descriptor write-back race.\n", - dev->name); - } - if (intr_status & ( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace )) - via_rhine_restart_tx(dev); - - if (intr_status & ~( IntrLinkChange | IntrStatsMax | IntrTxUnderrun | - IntrTxError | IntrTxAborted | IntrNormalSummary | - IntrTxDescRace )) { - if (debug > 1) - printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n", - dev->name, intr_status); - } - - spin_unlock (&np->lock); -} - -static struct net_device_stats *via_rhine_get_stats(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - unsigned long flags; - - spin_lock_irqsave(&np->lock, flags); - np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); - np->stats.rx_missed_errors += readw(ioaddr + RxMissed); - clear_tally_counters(ioaddr); - spin_unlock_irqrestore(&np->lock, flags); - - return &np->stats; -} - -static void via_rhine_set_rx_mode(struct net_device *dev) -{ - struct netdev_private *np = dev->priv; - long ioaddr = dev->base_addr; - u32 mc_filter[2]; /* Multicast hash filter */ - u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */ - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); - rx_mode = 0x1C; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - /* Too many to match, or accept all multicasts. */ - writel(0xffffffff, ioaddr + MulticastFilter0); - writel(0xffffffff, ioaddr + MulticastFilter1); - rx_mode = 0x0C; - } else { - struct dev_mc_list *mclist; - int i; - memset(mc_filter, 0, sizeof(mc_filter)); - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { - int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); - } - writel(mc_filter[0], ioaddr + MulticastFilter0); - writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x0C; - } - writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); -} - -#if 0 -static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) -{ - struct netdev_private *np = dev->priv; - u32 ethcmd; - - if (get_user(ethcmd, (u32 *)useraddr)) - return -EFAULT; - - switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - strcpy (info.driver, DRV_NAME); - strcpy (info.version, DRV_VERSION); - strcpy (info.bus_info, np->pdev->slot_name); - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } - - /* get settings */ - case ETHTOOL_GSET: { - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - if (!(np->drv_flags & CanHaveMII)) - break; - spin_lock_irq(&np->lock); - mii_ethtool_gset(&np->mii_if, &ecmd); - spin_unlock_irq(&np->lock); - if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } - /* set settings */ - case ETHTOOL_SSET: { - int r; - struct ethtool_cmd ecmd; - if (!(np->drv_flags & CanHaveMII)) - break; - if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) - return -EFAULT; - spin_lock_irq(&np->lock); - r = mii_ethtool_sset(&np->mii_if, &ecmd); - spin_unlock_irq(&np->lock); - return r; - } - /* restart autonegotiation */ - case ETHTOOL_NWAY_RST: { - if (!(np->drv_flags & CanHaveMII)) - break; - return mii_nway_restart(&np->mii_if); - } - /* get link status */ - case ETHTOOL_GLINK: { - struct ethtool_value edata = {ETHTOOL_GLINK}; - if (!(np->drv_flags & CanHaveMII)) - break; - edata.data = mii_link_ok(&np->mii_if); - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - - /* get message-level */ - case ETHTOOL_GMSGLVL: { - struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - /* set message-level */ - case ETHTOOL_SMSGLVL: { - struct ethtool_value edata; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - debug = edata.data; - return 0; - } - default: - break; - } - - return -EOPNOTSUPP; -} - -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct netdev_private *np = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - if (cmd == SIOCETHTOOL) - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - - else { - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); - spin_unlock_irq(&np->lock); - } - - return rc; -} -#endif - -static int via_rhine_close(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; - - del_timer_sync(&np->timer); - - spin_lock_irq(&np->lock); - - netif_stop_queue(dev); - - if (debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, readw(ioaddr + ChipCmd)); - - /* Switch to loopback mode to avoid hardware races. */ - writeb(np->tx_thresh | 0x02, ioaddr + TxConfig); - - /* Disable interrupts by clearing the interrupt mask. */ - writew(0x0000, ioaddr + IntrEnable); - - /* Stop the chip's Tx and Rx processes. */ - writew(CmdStop, ioaddr + ChipCmd); - - spin_unlock_irq(&np->lock); - - free_irq(np->pdev->irq, dev); - free_rbufs(dev); - free_tbufs(dev); - free_ring(dev); - - return 0; -} - - -static void __devexit via_rhine_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - unregister_netdev(dev); - - pci_release_regions(pdev); - -#ifdef USE_MEM - iounmap((char *)(dev->base_addr)); -#endif - - kfree(dev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - - -static struct pci_driver via_rhine_driver = { - .name = "via-rhine", - .id_table = via_rhine_pci_tbl, - .probe = via_rhine_init_one, - .remove = __devexit_p(via_rhine_remove_one), -}; - - -static int __init via_rhine_init (void) -{ -/* when a module, this is printed whether or not devices are found in probe */ -#ifdef MODULE - printk(version); -#endif - return pci_module_init (&via_rhine_driver); -} - - -static void __exit via_rhine_cleanup (void) -{ - pci_unregister_driver (&via_rhine_driver); -} - - -module_init(via_rhine_init); -module_exit(via_rhine_cleanup); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ |