diff options
author | Marcus Brinkmann <marcus@gnu.org> | 2001-08-18 00:56:42 +0000 |
---|---|---|
committer | Marcus Brinkmann <marcus@gnu.org> | 2001-08-18 00:56:42 +0000 |
commit | bd4568df4e4ebfcd333a36c44afd58a8717a8722 (patch) | |
tree | 1364c96451a88d2bb7861a3828b984a8bef695e1 /linux/src | |
parent | 4c582b3d2422525c041874eeb7eb2d3af683a84b (diff) |
2001-08-18 Marcus Brinkmann <marcus@gnu.org>
* linux/src/drivers/net/eepro100.c: File updated to version in
Linux 2.2.19. This time for real.
Diffstat (limited to 'linux/src')
-rw-r--r-- | linux/src/drivers/net/eepro100.c | 1930 |
1 files changed, 1284 insertions, 646 deletions
diff --git a/linux/src/drivers/net/eepro100.c b/linux/src/drivers/net/eepro100.c index 4e6db45..a2a6e30 100644 --- a/linux/src/drivers/net/eepro100.c +++ b/linux/src/drivers/net/eepro100.c @@ -1,82 +1,143 @@ -/* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */ +/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */ /* - NOTICE: this version tested with kernels 1.3.72 and later only! - Written 1996-1998 by Donald Becker. + NOTICE: this version of the driver is supposed to work with 2.2 kernels. + Written 1996-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. - This driver is for the Intel EtherExpress Pro 100B boards. - It should work with other i82557 boards (if any others exist). - To use a built-in driver, install as drivers/net/eepro100.c. + This driver is for the Intel EtherExpress Pro100 (Speedo3) design. + It should work with all i82557/558/559 boards. + To use as a module, use the compile-command at the end of the file. The author may be reached as becker@CESDIS.usra.edu, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 For updates see - <base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html"> + http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html + For installation instructions + http://cesdis.gsfc.nasa.gov/linux/misc/modules.html + There is a Majordomo mailing list based at + linux-eepro100@cesdis.gsfc.nasa.gov + + The driver also contains updates by different kernel developers. + This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>. + Please use this email address and linux-kernel mailing list for bug reports. + + Modification history: + 2000 Mar 24 Dragan Stancevic <visitor@valinux.com> + Disabled FC and ER, to avoid lockups when when we get FCP interrupts. + 2000 May 27 Andrey Moruga <moruga@sw.com.sg> + Code duplication for 82559ER support was removed. + Accurate handling of all supported chips was implemented. + Some fixes in 2.3 clone of the driver were ported. + 2000 May 30 Dragan Stancevic <visitor@valinux.com> and + Andrey Moruga <moruga@sw.com.sg> + Honor PortReset timing specification. + 2000 Jul 25 Dragan Stancevic <visitor@valinux.com> + Changed to MMIO, resized FIFOs, resized rings, changed ISR timeout + Problem reported by: + Marc MERLIN <merlin@valinux.com> + 2000 Nov 15 Dragan Stancevic <visitor@valinux.com> + Changed command completion time and added debug info as to which + CMD timed out. Problem reported by: + "Ulrich Windl" <Ulrich.Windl@rz.uni-regensburg.de> */ +/*#define USE_IO*/ static const char *version = -"eepro100.c:v0.99B 4/7/98 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n"; +"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n" +"eepro100.c: $Revision: 1.2 $ 2000/05/31 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n" +"eepro100.c: VA Linux custom, Dragan Stancevic <visitor@valinux.com> 2000/11/15\n"; /* A few user-configurable values that apply to all boards. - First set are undocumented and spelled per Intel recommendations. */ + First set is undocumented and spelled per Intel recommendations. */ static int congenb = 0; /* Enable congestion control in the DP83840. */ -static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ -static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +static int txfifo = 0; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 0xF; /* Rx FIFO threshold, default 32 bytes. */ /* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ static int txdmacount = 128; static int rxdmacount = 0; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ +#if defined(__alpha__) || defined(__sparc__) +/* force copying of all packets to avoid unaligned accesses on Alpha */ +static int rx_copybreak = 1518; +#else static int rx_copybreak = 200; +#endif /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; +static int max_interrupt_work = 200; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ static int multicast_filter_limit = 64; +/* 'options' is used to pass a transceiver override or full-duplex flag + e.g. "options=16" for FD, "options=32" for 100mbps-only. */ +static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; #ifdef MODULE -#ifdef MODVERSIONS -#include <linux/modversions.h> +static int debug = -1; /* The debug level */ #endif -#include <linux/module.h> -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT + +/* A few values that may be tweaked. */ +/* The ring sizes should be a power of two for efficiency. */ +#define TX_RING_SIZE 64 +#define RX_RING_SIZE 64 +/* How much slots multicast filter setup may take. + Do not descrease without changing set_rx_mode() implementaion. */ +#define TX_MULTICAST_SIZE 2 +#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2) +/* Actual number of TX packets queued, must be + <= TX_RING_SIZE-TX_MULTICAST_RESERV. */ +#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV) +/* Hysteresis marking queue as no longer full. */ +#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4) + +/* Operational parameters that usually are not changed. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) +/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/ +#define PKT_BUF_SZ 1536 + +#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 #include <linux/version.h> +#include <linux/module.h> +#if defined(MODVERSIONS) +#include <linux/modversions.h> +#endif + #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/string.h> #include <linux/timer.h> -#include <linux/ptrace.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> -#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/spinlock.h> + #include <asm/bitops.h> #include <asm/io.h> -#include <asm/dma.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/delay.h> -/* Unused in the 2.0.* version, but retained for documentation. */ -#if LINUX_VERSION_CODE > 0x20118 -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); -MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver"); +#if defined(MODULE) +MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>"); +MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); @@ -91,9 +152,31 @@ MODULE_PARM(multicast_filter_limit, "i"); #endif #define RUN_AT(x) (jiffies + (x)) - -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) +/* Condensed bus+endian portability operations. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +#define net_device device +#define pci_base_address(p, n) (p)->base_address[n] + +#define dev_free_skb(skb) dev_kfree_skb(skb); +#define netif_wake_queue(dev) do { \ + clear_bit(0, (void*)&dev->tbusy); \ + mark_bh(NET_BH); \ + } while(0) +#define netif_start_queue(dev) clear_bit(0, (void*)&dev->tbusy) +#define netif_stop_queue(dev) set_bit(0, (void*)&dev->tbusy) +#ifndef PCI_DEVICE_ID_INTEL_82559ER +#define PCI_DEVICE_ID_INTEL_82559ER 0x1209 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ID1029 +#define PCI_DEVICE_ID_INTEL_ID1029 0x1029 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ID1030 +#define PCI_DEVICE_ID_INTEL_ID1030 0x1030 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ID2449 +#define PCI_DEVICE_ID_INTEL_ID2449 0x2449 #endif /* The total I/O port extent of the board. @@ -132,7 +215,7 @@ single buffer descriptor with each frame descriptor. Despite the extra space overhead in each receive skbuff, the driver must use the simplified Rx buffer mode to assure that only a single data buffer is associated with each RxFD. The driver implements this by reserving space -for the Rx descriptor at the head of each Rx skbuff +for the Rx descriptor at the head of each Rx skbuff. The Speedo-3 has receive and command unit base addresses that are added to almost all descriptor pointers. The driver sets these to zero, so that all @@ -147,10 +230,13 @@ IIIB. Transmit structure The driver must use the complex Tx command+descriptor mode in order to have a indirect pointer to the skbuff data section. Each Tx command block -(TxCB) is associated with a single, immediately appended Tx buffer descriptor +(TxCB) is associated with two immediately appended Tx Buffer Descriptor (TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the speedo_private data structure for each adapter instance. +The newer i82558 explicitly supports this structure, and can read the two +TxBDs in the same PCI burst as the TxCB. + This ring structure is used for all normal transmit packets, but the transmit packet descriptors aren't long enough for most non-Tx commands such as CmdConfigure. This is complicated by the possibility that the chip has @@ -181,10 +267,10 @@ Note: Watch out for the potential race condition here: imagine doing the CU_RESUME the chip processes the next-yet-valid post-final-command. So blindly sending a CU_RESUME is only safe if we do it immediately after -erasing the previous CmdSuspend, without the possibility of an intervening -delay. Thus the resume command is always within the interrupts-disabled -region. This is a timing dependence, but handling this condition in a -timing-independent way would considerably complicate the code. +after erasing the previous CmdSuspend, without the possibility of an +intervening delay. Thus the resume command is always within the +interrupts-disabled region. This is a timing dependence, but handling this +condition in a timing-independent way would considerably complicate the code. Note: In previous generation Intel chips, restarting the command unit was a notoriously slow process. This is presumably no longer true. @@ -205,24 +291,6 @@ allocate a new, minimally-sized skbuff. For large frames the copying cost is non-trivial, and the larger copy might flush the cache of useful data, so we pass up the skbuff the packet was received into. -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->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'sp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by setting -the 'base' to zero. Iff the 'sp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - IV. Notes Thanks to Steve Williams of Intel for arranging the non-disclosure agreement @@ -231,28 +299,95 @@ having to sign an Intel NDA when I'm helping Intel sell their own product! */ -/* A few values that may be tweaked. */ -/* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 16 /* Effectively 2 entries fewer. */ -#define RX_RING_SIZE 16 -/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/ -#define PKT_BUF_SZ 1536 +/* This table drives the PCI probe routines. */ +static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int chip_idx, int card_idx); -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((800*HZ)/1000) +#ifdef USE_IO +#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1 +#define SPEEDO_SIZE 32 +#else +#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0 +#define SPEEDO_SIZE 0x1000 +#endif -/* How to wait for the command unit to accept a command. - Typically this takes 0 ticks. */ -static inline void wait_for_cmd_done(int cmd_ioaddr) +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, +}; +struct pci_id_info { + const char *name; + u16 vendor_id, device_id; + int pci_index; +} static pci_tbl[] = { + { "Intel PCI EtherExpress Pro100 82557", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, + 0 + }, + { "Intel PCI EtherExpress Pro100 82559ER", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, + 0 + }, + { "Intel PCI EtherExpress Pro100 ID1029", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, + 0 + }, + { "Intel Corporation 82559 InBusiness 10/100", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, + 0 + }, + { "Intel PCI EtherExpress Pro100 82562EM", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449, + 0 + }, + {0,} /* 0 terminated list. */ +}; + +static inline unsigned int io_inw(unsigned long port) +{ + return inw(port); +} +static inline void io_outw(unsigned int val, unsigned long port) { - short wait = 100; - do ; - while(inb(cmd_ioaddr) && --wait >= 0); + outw(val, port); } -/* Operational parameter that usually are not changed. */ +#ifndef USE_IO +#undef inb +#undef inw +#undef inl +#undef outb +#undef outw +#undef outl +#define inb readb +#define inw readw +#define inl readl +#define outb writeb +#define outw writew +#define outl writel +#endif -/* The rest of these values should never change. */ +/* How to wait for the command unit to accept a command. + Typically this takes 0 ticks. */ +static inline void wait_for_cmd_done(long cmd_ioaddr) +{ + int wait = 20000; + char cmd_reg1, cmd_reg2; + do ; + while((cmd_reg1 = inb(cmd_ioaddr)) && (--wait >= 0)); + + /* Last chance to change your mind --Dragan*/ + if (wait < 0){ + cmd_reg2 = inb(cmd_ioaddr); + if(cmd_reg2){ + printk(KERN_ALERT "eepro100: cmd_wait for(%#2.2x) timedout with(%#2.2x)!\n", + cmd_reg1, cmd_reg2); + + } + } + +} /* Offsets to the various registers. All accesses need not be longword aligned. */ @@ -266,34 +401,45 @@ enum speedo_offsets { }; /* Commands that can be put in a command list entry. */ enum commands { - CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3, - CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7, - CmdSuspend = 0x4000, /* Suspend after completion. */ - CmdIntr = 0x2000, /* Interrupt after completion. */ - CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ + CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000, + CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000, + CmdDump = 0x60000, CmdDiagnose = 0x70000, + CmdSuspend = 0x40000000, /* Suspend after completion. */ + CmdIntr = 0x20000000, /* Interrupt after completion. */ + CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */ }; +/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the + status bits. Previous driver versions used separate 16 bit fields for + commands and statuses. --SAW + */ +#if defined(__LITTLE_ENDIAN) +#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000 +#elif defined(__BIG_ENDIAN) +#define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040 +#else +#error Unsupported byteorder +#endif -/* The SCB accepts the following controls for the Tx and Rx units: */ -#define CU_START 0x0010 -#define CU_RESUME 0x0020 -#define CU_STATSADDR 0x0040 -#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ -#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */ -#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ - -#define RX_START 0x0001 -#define RX_RESUME 0x0002 -#define RX_ABORT 0x0004 -#define RX_ADDR_LOAD 0x0006 -#define RX_RESUMENR 0x0007 -#define INT_MASK 0x0100 -#define DRVR_INT 0x0200 /* Driver generated interrupt. */ +enum SCBCmdBits { + SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, + SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, + SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, + /* The rest are Rx and Tx commands. */ + CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, + CUCmdBase=0x0060, /* CU Base address (set to zero) . */ + CUDumpStats=0x0070, /* Dump then reset stats counters. */ + RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, + RxResumeNoResources=0x0007, +}; + +enum SCBPort_cmds { + PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3, +}; /* The Speedo3 Rx and Tx frame/buffer descriptors. */ -struct descriptor { /* A generic descriptor. */ - s16 status; /* Offset 0. */ - s16 command; /* Offset 2. */ - u32 link; /* struct descriptor * */ +struct descriptor { /* A generic descriptor. */ + s32 cmd_status; /* All command and status fields. */ + u32 link; /* struct descriptor * */ unsigned char params[0]; }; @@ -302,21 +448,34 @@ struct RxFD { /* Receive frame descriptor. */ s32 status; u32 link; /* struct RxFD * */ u32 rx_buf_addr; /* void * */ - u16 count; - u16 size; + u32 count; }; -/* Elements of the RxFD.status word. */ -#define RX_COMPLETE 0x8000 +/* Selected elements of the Tx/RxFD.status word. */ +enum RxFD_bits { + RxComplete=0x8000, RxOK=0x2000, + RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010, + RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002, + TxUnderrun=0x1000, StatusComplete=0x8000, +}; struct TxFD { /* Transmit frame descriptor set. */ s32 status; u32 link; /* void * */ u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ s32 count; /* # of TBD (=1), Tx start thresh., etc. */ - /* This constitutes a single "TBD" entry -- we only use one. */ - u32 tx_buf_addr; /* void *, frame to be transmitted. */ - s32 tx_buf_size; /* Length of Tx frame. */ + /* This constitutes two "TBD" entries -- we only use one. */ + u32 tx_buf_addr0; /* void *, frame to be transmitted. */ + s32 tx_buf_size0; /* Length of Tx frame. */ + u32 tx_buf_addr1; /* void *, frame to be transmitted. */ + s32 tx_buf_size1; /* Length of Tx frame. */ +}; + +/* Multicast filter setting block. --SAW */ +struct speedo_mc_block { + struct speedo_mc_block *next; + unsigned int tx; + struct descriptor frame __attribute__ ((__aligned__(16))); }; /* Elements of the dump_statistics block. This block must be lword aligned. */ @@ -340,47 +499,63 @@ struct speedo_stats { u32 done_marker; }; +enum Rx_ring_state_bits { + RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8, +}; + +/* Do not change the position (alignment) of the first few elements! + The later elements are grouped for cache locality. */ struct speedo_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct device *next_module; struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ + /* The addresses of a Tx/Rx-in-place packets/buffers. */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct descriptor *last_cmd; /* Last command sent. */ - /* Rx descriptor ring & addresses of receive-in-place skbuffs. */ - struct RxFD *rx_ringp[RX_RING_SIZE]; struct sk_buff* rx_skbuff[RX_RING_SIZE]; + struct descriptor *last_cmd; /* Last command sent. */ + unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ + spinlock_t lock; /* Group with Tx control cache line. */ + u32 tx_threshold; /* The value for txdesc.count. */ struct RxFD *last_rxf; /* Last command sent. */ + unsigned int cur_rx, dirty_rx; /* The next free ring entry */ + long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ + const char *product_name; + struct net_device *next_module; + void *priv_addr; /* Unaligned address for kfree */ struct enet_statistics stats; struct speedo_stats lstats; + int chip_id; + unsigned char pci_bus, pci_devfn, acpi_pwr; struct timer_list timer; /* Media selection timer. */ - long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct descriptor config_cmd; /* A configure command, with header... */ - u8 config_cmd_data[22]; /* .. and setup parameters. */ - int mc_setup_frm_len; /* The length of an allocated.. */ - struct descriptor *mc_setup_frm; /* ..multicast setup frame. */ + struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */ + struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */ int in_interrupt; /* Word-aligned dev->interrupt */ char rx_mode; /* Current PROMISC/ALLMULTI setting. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int default_port:1; /* Last dev->if_port value. */ + unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ unsigned int rx_bug:1; /* Work around receiver hang errata. */ unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */ unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */ + unsigned char default_port:8; /* Last dev->if_port value. */ + unsigned char rx_ring_state; /* RX ring status flags. */ unsigned short phy[2]; /* PHY media interfaces available. */ + unsigned short advertising; /* Current PHY advertised caps. */ + unsigned short partner; /* Link partner caps. */ }; /* The parameters for a CmdConfigure operation. There are so many options that it would be difficult to document each bit. We mostly use the default or recommended settings. */ -const char basic_config_cmd[22] = { - 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ +const char i82557_config_cmd[22] = { + 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ 0, 0x2E, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ 0x3f, 0x05, }; +const char i82558_config_cmd[22] = { + 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ + 0, 0x2E, 0, 0x60, 0x08, 0x88, + 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */ + 0x31, 0x05, }; /* PHY media interface chips. */ static const char *phys[] = { @@ -391,65 +566,91 @@ static const char *phys[] = { enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, S80C24, I82555, DP83840A=10, }; static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; +#define EE_READ_CMD (6) -static void speedo_found1(struct device *dev, int ioaddr, int irq, - int card_idx); - -static int read_eeprom(int ioaddr, int location); -static int mdio_read(int ioaddr, int phy_id, int location); -static int mdio_write(int ioaddr, int phy_id, int location, int value); -static int speedo_open(struct device *dev); +static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len); +static int mdio_read(long ioaddr, int phy_id, int location); +static int mdio_write(long ioaddr, int phy_id, int location, int value); +static int speedo_open(struct net_device *dev); +static void speedo_resume(struct net_device *dev); static void speedo_timer(unsigned long data); -static void speedo_init_rx_ring(struct device *dev); -static int speedo_start_xmit(struct sk_buff *skb, struct device *dev); -static int speedo_rx(struct device *dev); +static void speedo_init_rx_ring(struct net_device *dev); +static void speedo_tx_timeout(struct net_device *dev); +static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void speedo_refill_rx_buffers(struct net_device *dev, int force); +static int speedo_rx(struct net_device *dev); +static void speedo_tx_buffer_gc(struct net_device *dev); static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int speedo_close(struct device *dev); -static struct enet_statistics *speedo_get_stats(struct device *dev); -static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct device *dev); +static int speedo_close(struct net_device *dev); +static struct enet_statistics *speedo_get_stats(struct net_device *dev); +static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void set_rx_mode(struct net_device *dev); +static void speedo_show_state(struct net_device *dev); -/* The parameters that may be passed in... */ -/* 'options' is used to pass a transceiver override or full-duplex flag - e.g. "options=16" for FD, "options=32" for 100mbps-only. */ -static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -#ifdef MODULE -static int debug = -1; /* The debug level */ +#ifdef honor_default_port +/* Optional driver feature to allow forcing the transceiver setting. + Not recommended. */ +static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100, + 0x2000, 0x2100, 0x0400, 0x3100}; #endif /* A list of all installed Speedo devices, for removing the driver module. */ -static struct device *root_speedo_dev = NULL; +static struct net_device *root_speedo_dev = NULL; -int eepro100_init(struct device *dev) +int eepro100_init(void) { int cards_found = 0; + int chip_idx; + struct pci_dev *pdev; - if (pcibios_present()) { - static int pci_index = 0; - for (; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency; - int pci_ioaddr; + if (! pcibios_present()) + return cards_found; - unsigned short pci_command, new_command; + for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { + for (; pci_tbl[chip_idx].pci_index < 8; pci_tbl[chip_idx].pci_index++) { + unsigned char pci_bus, pci_device_fn, pci_latency; + unsigned long pciaddr; + long ioaddr; + int irq; - if (pcibios_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82557, - pci_index, &pci_bus, + u16 pci_command, new_command; + + if (pcibios_find_device(pci_tbl[chip_idx].vendor_id, + pci_tbl[chip_idx].device_id, + pci_tbl[chip_idx].pci_index, &pci_bus, &pci_device_fn)) - break; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pci_ioaddr); + break; + { + pdev = pci_find_slot(pci_bus, pci_device_fn); +#ifdef USE_IO + pciaddr = pci_base_address(pdev, 1); /* Use [0] to mem-map */ +#else + pciaddr = pci_base_address(pdev, 0); +#endif + irq = pdev->irq; + } /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; + if (pciaddr & 1) { + ioaddr = pciaddr & ~3UL; + if (check_region(ioaddr, 32)) + continue; + } else { +#ifdef __sparc__ + /* ioremap is hosed in 2.2.x on Sparc. */ + ioaddr = pciaddr & ~0xfUL; +#else + if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx.\n", + pciaddr); + continue; + } +#endif + } if (speedo_debug > 2) - printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n", - (int)pci_ioaddr, pci_irq_line); + printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n", + ioaddr, irq); /* Get and check the bus-master and latency values. */ pcibios_read_config_word(pci_bus, pci_device_fn, @@ -463,7 +664,7 @@ int eepro100_init(struct device *dev) PCI_COMMAND, new_command); } pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 32) { printk(" PCI latency timer (CFLT) is unreasonably low at %d." " Setting to 32 clocks.\n", pci_latency); @@ -472,30 +673,33 @@ int eepro100_init(struct device *dev) } else if (speedo_debug > 1) printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); - speedo_found1(dev, pci_ioaddr, pci_irq_line, cards_found); - dev = NULL; - cards_found++; + if (speedo_found1(pdev, pci_bus, pci_device_fn, ioaddr, chip_idx, cards_found)) + cards_found++; } } return cards_found; } -static void speedo_found1(struct device *dev, int ioaddr, int irq, - int card_idx) +static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int chip_idx, int card_idx) { - static int did_version = 0; /* Already printed version info. */ + struct net_device *dev; struct speedo_private *sp; - char *product; + const char *product; int i, option; - u16 eeprom[0x40]; - + u16 eeprom[0x100]; + int acpi_idle_state = 0; +#ifndef MODULE + static int did_version = 0; /* Already printed version info. */ if (speedo_debug > 0 && did_version++ == 0) printk(version); +#endif - dev = init_etherdev(dev, sizeof(struct speedo_private)); + dev = init_etherdev(NULL, sizeof(struct speedo_private)); - if (dev->mem_start > 0) + if (dev->mem_start > 0) option = dev->mem_start; else if (card_idx >= 0 && options[card_idx] >= 0) option = options[card_idx]; @@ -503,13 +707,30 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, option = 0; /* Read the station address EEPROM before doing the reset. - Perhaps this should even be done before accepting the device, - then we wouldn't have a device name with which to report the error. */ + Nominally his should even be done before accepting the device, but + then we wouldn't have a device name with which to report the error. + The size test is for 6 bit vs. 8 bit address serial EEPROMs. + */ { - u16 sum = 0; + unsigned long iobase; + int read_cmd, ee_size; + u16 sum; int j; - for (j = 0, i = 0; i < 0x40; i++) { - u16 value = read_eeprom(ioaddr, i); + + /* Use IO only to avoid postponed writes and satisfy EEPROM timing + requirements. */ + iobase = pci_base_address(pdev, 1) & ~3UL; + if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000) + == 0xffe0000) { + ee_size = 0x100; + read_cmd = EE_READ_CMD << 24; + } else { + ee_size = 0x40; + read_cmd = EE_READ_CMD << 22; + } + + for (j = 0, i = 0, sum = 0; i < ee_size; i++) { + u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27); eeprom[i] = value; sum += value; if (i < 3) { @@ -522,26 +743,34 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, "check settings before activating this device!\n", dev->name, sum); /* Don't unregister_netdev(dev); as the EEPro may actually be - usable, especially if the MAC address is set later. */ + usable, especially if the MAC address is set later. + On the other hand, it may be unusable if MDI data is corrupted. */ } /* Reset the chip: stop Tx and Rx processes and clear counters. This takes less than 10usec and will easily finish before the next action. */ - outl(0, ioaddr + SCBPort); + outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); + /* Honor PortReset timing. */ + udelay(10); if (eeprom[3] & 0x0100) product = "OEM i82557/i82558 10/100 Ethernet"; else - product = "Intel EtherExpress Pro 10/100"; + product = pci_tbl[chip_idx].name; - printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr); + printk(KERN_INFO "%s: %s, ", dev->name, product); for (i = 0; i < 5; i++) printk("%2.2X:", dev->dev_addr[i]); - printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq); + printk("%2.2X, ", dev->dev_addr[i]); +#ifdef USE_IO + printk("I/O at %#3lx, ", ioaddr); +#endif + printk("IRQ %d.\n", pdev->irq); -#ifndef kernel_bloat +#if 1 || defined(kernel_bloat) /* OK, this is pure kernel bloat. I don't like it when other drivers waste non-pageable kernel space to emit similar messages, but I need them for bug reports. */ @@ -550,7 +779,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, /* The self-test results must be paragraph aligned. */ s32 str[6], *volatile self_test_results; int boguscnt = 16000; /* Timeout for set-test. */ - if (eeprom[3] & 0x03) + if ((eeprom[3] & 0x03) != 0x03) printk(KERN_INFO " Receiver lock-up bug exists -- enabling" " work-around.\n"); printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" @@ -586,7 +815,7 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, self_test_results = (s32*) ((((long) str) + 15) & ~0xf); self_test_results[0] = 0; self_test_results[1] = -1; - outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort); + outl(virt_to_bus(self_test_results) | PortSelfTest, ioaddr + SCBPort); do { udelay(10); } while (self_test_results[1] == -1 && --boguscnt >= 0); @@ -610,21 +839,32 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, } #endif /* kernel_bloat */ - outl(0, ioaddr + SCBPort); + outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); + /* Honor PortReset timing. */ + udelay(10); /* We do a request_region() only to register /proc/ioports info. */ request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet"); dev->base_addr = ioaddr; - dev->irq = irq; + dev->irq = pdev->irq; - if (dev->priv == NULL) - dev->priv = kmalloc(sizeof(*sp), GFP_KERNEL); sp = dev->priv; + if (dev->priv == NULL) { + void *mem = kmalloc(sizeof(*sp), GFP_KERNEL); + dev->priv = sp = mem; /* Cache align here if kmalloc does not. */ + sp->priv_addr = mem; + } memset(sp, 0, sizeof(*sp)); sp->next_module = root_speedo_dev; root_speedo_dev = dev; + sp->pci_bus = pci_bus; + sp->pci_devfn = pci_devfn; + sp->chip_id = chip_idx; + sp->acpi_pwr = acpi_idle_state; + sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) @@ -642,12 +882,16 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, /* The Speedo-specific entries in the device structure. */ dev->open = &speedo_open; dev->hard_start_xmit = &speedo_start_xmit; +#if defined(HAS_NETIF_QUEUE) + dev->tx_timeout = &speedo_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#endif dev->stop = &speedo_close; dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; - return; + return dev; } /* Serial EEPROM section. @@ -656,54 +900,42 @@ static void speedo_found1(struct device *dev, int ioaddr, int irq, #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ #define EE_CS 0x02 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ #define EE_ENB (0x4800 | EE_CS) +#define EE_WRITE_0 0x4802 +#define EE_WRITE_1 0x4806 +#define EE_OFFSET SCBeeprom + +/* The fixes for the code were kindly provided by Dragan Stancevic + <visitor@valinux.com> to strictly follow Intel specifications of EEPROM + access timing. + The publicly available sheet 64486302 (sec. 3.1) specifies 1us access + interval for serial EEPROM. However, it looks like that there is an + additional requirement dictating larger udelay's in the code below. + 2000/05/24 SAW */ +static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len) +{ + unsigned retval = 0; + long ee_addr = ioaddr + SCBeeprom; -/* Delay between EEPROM clock transitions. - This will actually work with no delay on 33Mhz PCI. */ -#define eeprom_delay(nanosec) udelay(1); - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) + io_outw(EE_ENB, ee_addr); udelay(2); + io_outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); -static int read_eeprom(int ioaddr, int location) -{ - int i; - unsigned short retval = 0; - int ee_addr = ioaddr + SCBeeprom; - int read_cmd = location | EE_READ_CMD; - - outw(EE_ENB & ~EE_CS, ee_addr); - outw(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outw(EE_ENB | dataval, ee_addr); - eeprom_delay(100); - outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(150); - } - outw(EE_ENB, ee_addr); - - for (i = 15; i >= 0; i--) { - outw(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(100); - retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); - outw(EE_ENB, ee_addr); - eeprom_delay(100); - } + /* Shift the command bits out. */ + do { + short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; + io_outw(dataval, ee_addr); udelay(2); + io_outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); + retval = (retval << 1) | ((io_inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + } while (--cmd_len >= 0); + io_outw(EE_ENB, ee_addr); udelay(2); /* Terminate the EEPROM access. */ - outw(EE_ENB & ~EE_CS, ee_addr); + io_outw(EE_ENB & ~EE_CS, ee_addr); return retval; } -static int mdio_read(int ioaddr, int phy_id, int location) +static int mdio_read(long ioaddr, int phy_id, int location) { int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); @@ -711,12 +943,13 @@ static int mdio_read(int ioaddr, int phy_id, int location) val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); + break; } } while (! (val & 0x10000000)); return val & 0xffff; } -static int mdio_write(int ioaddr, int phy_id, int location, int value) +static int mdio_write(long ioaddr, int phy_id, int location, int value) { int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x04000000 | (location<<16) | (phy_id<<21) | value, @@ -725,6 +958,7 @@ static int mdio_write(int ioaddr, int phy_id, int location, int value) val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); + break; } } while (! (val & 0x10000000)); return val & 0xffff; @@ -732,86 +966,74 @@ static int mdio_write(int ioaddr, int phy_id, int location, int value) static int -speedo_open(struct device *dev) +speedo_open(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; - -#ifdef notdef - /* We could reset the chip, but should not need to. */ - outl(0, ioaddr + SCBPort); - udelay(10); -#endif + long ioaddr = dev->base_addr; - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, - "Intel EtherExpress Pro 10/100 Ethernet", dev)) { - return -EAGAIN; - } if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); MOD_INC_USE_COUNT; - /* Load the statistics block address. */ - wait_for_cmd_done(ioaddr + SCBCmd); - outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer); - outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); - sp->lstats.done_marker = 0; - - speedo_init_rx_ring(dev); - wait_for_cmd_done(ioaddr + SCBCmd); - outl(0, ioaddr + SCBPointer); - outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); + /* Set up the Tx queue early.. */ + sp->cur_tx = 0; + sp->dirty_tx = 0; + sp->last_cmd = 0; + sp->tx_full = 0; + sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + sp->in_interrupt = 0; - /* Todo: verify that we must wait for previous command completion. */ - wait_for_cmd_done(ioaddr + SCBCmd); - outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer); - outw(INT_MASK | RX_START, ioaddr + SCBCmd); + /* .. we can safely take handler calls during init. */ + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } - /* Fill the first command with our physical address. */ - { - u16 *eaddrs = (u16 *)dev->dev_addr; - u16 *setup_frm = (u16 *)&(sp->tx_ring[0].tx_desc_addr); + dev->if_port = sp->default_port; - /* Avoid a bug(?!) here by marking the command already completed. */ - sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000; - sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1])); - *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; +#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us + /* Retrigger negotiation to reset previous errors. */ + if ((sp->phy[0] & 0x8000) == 0) { + int phy_addr = sp->phy[0] & 0x1f ; + /* Use 0x3300 for restarting NWay, other values to force xcvr: + 0x0000 10-HD + 0x0100 10-FD + 0x2000 100-HD + 0x2100 100-FD + */ +#ifdef honor_default_port + mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); +#else + mdio_write(ioaddr, phy_addr, 0, 0x3300); +#endif } - sp->last_cmd = (struct descriptor *)&sp->tx_ring[0]; - sp->cur_tx = 1; - sp->dirty_tx = 0; - sp->tx_full = 0; +#endif - wait_for_cmd_done(ioaddr + SCBCmd); - outl(0, ioaddr + SCBPointer); - outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd); + speedo_init_rx_ring(dev); - dev->if_port = sp->default_port; + /* Fire up the hardware. */ + outw(SCBMaskAll, ioaddr + SCBCmd); + speedo_resume(dev); - sp->in_interrupt = 0; - dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; - - /* Start the chip's Tx process and unmask interrupts. */ - /* Todo: verify that we must wait for previous command completion. */ - wait_for_cmd_done(ioaddr + SCBCmd); - outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer); - outw(CU_START, ioaddr + SCBCmd); + netif_start_queue(dev); /* Setup the chip and configure the multicast list. */ - sp->mc_setup_frm = NULL; - sp->mc_setup_frm_len = 0; + sp->mc_setup_head = NULL; + sp->mc_setup_tail = NULL; + sp->flow_ctrl = sp->partner = 0; sp->rx_mode = -1; /* Invalid -> always reset the mode. */ set_rx_mode(dev); + if ((sp->phy[0] & 0x8000) == 0) + sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4); if (speedo_debug > 2) { printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", dev->name, inw(ioaddr + SCBStatus)); } + /* Set the timer. The timer serves a dual purpose: 1) to monitor the media interface (e.g. link beat) and perhaps switch to an alternate media type @@ -823,182 +1045,462 @@ speedo_open(struct device *dev) sp->timer.function = &speedo_timer; /* timer handler */ add_timer(&sp->timer); - wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_DUMPSTATS, ioaddr + SCBCmd); + /* No need to wait for the command unit to accept here. */ + if ((sp->phy[0] & 0x8000) == 0) + mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); + return 0; } +/* Start the chip hardware after a full reset. */ +static void speedo_resume(struct net_device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + long ioaddr = dev->base_addr; + + /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ + sp->tx_threshold = 0x01208000; + + /* Set the segment registers to '0'. */ + wait_for_cmd_done(ioaddr + SCBCmd); + outl(0, ioaddr + SCBPointer); + /* impose a delay to avoid a bug */ + inl(ioaddr + SCBPointer); + udelay(10); + outb(RxAddrLoad, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + outb(CUCmdBase, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + /* Load the statistics block and rx ring addresses. */ + outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer); + outb(CUStatsAddr, ioaddr + SCBCmd); + sp->lstats.done_marker = 0; + wait_for_cmd_done(ioaddr + SCBCmd); + + if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) { + if (speedo_debug > 2) + printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n", + dev->name); + } else { + outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), + ioaddr + SCBPointer); + outb(RxStart, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + } + + outb(CUDumpStats, ioaddr + SCBCmd); + + /* Fill the first command with our physical address. */ + { + struct descriptor *ias_cmd; + + ias_cmd = + (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE]; + /* Avoid a bug(?!) here by marking the command already completed. */ + ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000); + ias_cmd->link = + virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + memcpy(ias_cmd->params, dev->dev_addr, 6); + sp->last_cmd = ias_cmd; + } + + /* Start the chip's Tx process and unmask interrupts. */ + wait_for_cmd_done(ioaddr + SCBCmd); + outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + ioaddr + SCBPointer); + /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should + remain masked --Dragan */ + outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); +} + /* Media monitoring and control. */ static void speedo_timer(unsigned long data) { - struct device *dev = (struct device *)data; + struct net_device *dev = (struct net_device *)data; struct speedo_private *sp = (struct speedo_private *)dev->priv; - int tickssofar = jiffies - sp->last_rx_time; + long ioaddr = dev->base_addr; + int phy_num = sp->phy[0] & 0x1f; + /* We have MII and lost link beat. */ + if ((sp->phy[0] & 0x8000) == 0) { + int partner = mdio_read(ioaddr, phy_num, 5); + if (partner != sp->partner) { + int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0; + if (speedo_debug > 2) { + printk(KERN_DEBUG "%s: Link status change.\n", dev->name); + printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", + dev->name, sp->partner, partner, sp->advertising); + } + sp->partner = partner; + if (flow_ctrl != sp->flow_ctrl) { + sp->flow_ctrl = flow_ctrl; + sp->rx_mode = -1; /* Trigger a reload. */ + } + /* Clear sticky bit. */ + mdio_read(ioaddr, phy_num, 1); + /* If link beat has returned... */ + if (mdio_read(ioaddr, phy_num, 1) & 0x0004) + dev->flags |= IFF_RUNNING; + else + dev->flags &= ~IFF_RUNNING; + } + } if (speedo_debug > 3) { - int ioaddr = dev->base_addr; - printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n", + printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); } - if (sp->rx_bug) { - if (tickssofar > 2*HZ || sp->rx_mode < 0) { - /* We haven't received a packet in a Long Time. We might have been - bitten by the receiver hang bug. This can be cleared by sending - a set multicast list command. */ - set_rx_mode(dev); - } - /* We must continue to monitor the media. */ - sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ - add_timer(&sp->timer); + if (sp->rx_mode < 0 || + (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { + /* We haven't received a packet in a Long Time. We might have been + bitten by the receiver hang bug. This can be cleared by sending + a set multicast list command. */ + if (speedo_debug > 2) + printk(KERN_DEBUG "%s: Sending a multicast list set command" + " from a timer routine.\n", dev->name); + set_rx_mode(dev); } + /* We must continue to monitor the media. */ + sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ + add_timer(&sp->timer); +} + +static void speedo_show_state(struct net_device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; +#if 0 + long ioaddr = dev->base_addr; + int phy_num = sp->phy[0] & 0x1f; +#endif + int i; + + /* Print a few items for debugging. */ + if (speedo_debug > 0) { + int i; + printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", dev->name, + sp->cur_tx, sp->dirty_tx); + for (i = 0; i < TX_RING_SIZE; i++) + printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name, + i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ', + i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ', + i, sp->tx_ring[i].status); + } + printk(KERN_DEBUG "%s: Printing Rx ring" + " (next to receive into %u, dirty index %u).\n", + dev->name, sp->cur_rx, sp->dirty_rx); + + for (i = 0; i < RX_RING_SIZE; i++) + printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name, + sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ', + i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ', + i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ', + i, (sp->rx_ringp[i] != NULL) ? + (unsigned)sp->rx_ringp[i]->status : 0); + +#if 0 + for (i = 0; i < 16; i++) { + /* FIXME: what does it mean? --SAW */ + if (i == 6) i = 21; + printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", + dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i)); + } +#endif + } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void -speedo_init_rx_ring(struct device *dev) +speedo_init_rx_ring(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; struct RxFD *rxf, *last_rxf = NULL; int i; sp->cur_rx = 0; - sp->dirty_rx = RX_RING_SIZE - 1; for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC); + skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); sp->rx_skbuff[i] = skb; if (skb == NULL) - break; /* Bad news! */ + break; /* OK. Just initially short of Rx bufs. */ skb->dev = dev; /* Mark as being used by this device. */ - rxf = (struct RxFD *)skb->tail; - skb_reserve(skb, sizeof(struct RxFD)); sp->rx_ringp[i] = rxf; + skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) - last_rxf->link = virt_to_bus(rxf); + last_rxf->link = virt_to_le32desc(rxf); last_rxf = rxf; - rxf->status = 0x00000001; /* '1' is flag value only. */ + rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ - /* This field unused by i82557, we use it as a consistency check. */ - rxf->rx_buf_addr = virt_to_bus(skb->tail); - - rxf->count = 0; - rxf->size = PKT_BUF_SZ; + /* This field unused by i82557. */ + rxf->rx_buf_addr = 0xffffffff; + rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); } + sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ - last_rxf->status = 0xC0000002; /* '2' is flag value only. */ + last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ sp->last_rxf = last_rxf; } -static void speedo_tx_timeout(struct device *dev) +static void speedo_purge_tx(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + int entry; - printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " - "command %4.4x.\n", - dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd)); - - if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) { - printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", - dev->name); - outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), - ioaddr + SCBPointer); - outw(CU_START, ioaddr + SCBCmd); - } else { - outw(DRVR_INT, ioaddr + SCBCmd); + while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { + entry = sp->dirty_tx % TX_RING_SIZE; + if (sp->tx_skbuff[entry]) { + sp->stats.tx_errors++; + dev_free_skb(sp->tx_skbuff[entry]); + sp->tx_skbuff[entry] = 0; + } + sp->dirty_tx++; + } + while (sp->mc_setup_head != NULL) { + struct speedo_mc_block *t; + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); + t = sp->mc_setup_head->next; + kfree(sp->mc_setup_head); + sp->mc_setup_head = t; } + sp->mc_setup_tail = NULL; + sp->tx_full = 0; + netif_wake_queue(dev); +} + +static void reset_mii(struct net_device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + long ioaddr = dev->base_addr; /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { int phy_addr = sp->phy[0] & 0x1f; + int advertising = mdio_read(ioaddr, phy_addr, 4); + int mii_bmcr = mdio_read(ioaddr, phy_addr, 0); mdio_write(ioaddr, phy_addr, 0, 0x0400); mdio_write(ioaddr, phy_addr, 1, 0x0000); mdio_write(ioaddr, phy_addr, 4, 0x0000); mdio_write(ioaddr, phy_addr, 0, 0x8000); +#ifdef honor_default_port + mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); +#else + mdio_read(ioaddr, phy_addr, 0); + mdio_write(ioaddr, phy_addr, 0, mii_bmcr); + mdio_write(ioaddr, phy_addr, 4, advertising); +#endif + } +} + +static void speedo_tx_timeout(struct net_device *dev) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + long ioaddr = dev->base_addr; + int status = inw(ioaddr + SCBStatus); + unsigned long flags; + + printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " + " %4.4x at %d/%d command %8.8x.\n", + dev->name, status, inw(ioaddr + SCBCmd), + sp->dirty_tx, sp->cur_tx, + sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); + + /* Trigger a stats dump to give time before the reset. */ + speedo_get_stats(dev); + + speedo_show_state(dev); +#if 0 + if ((status & 0x00C0) != 0x0080 + && (status & 0x003C) == 0x0010) { + /* Only the command unit has stopped. */ + printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", + dev->name); + outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + ioaddr + SCBPointer); + outw(CUStart, ioaddr + SCBCmd); + reset_mii(dev); + } else { +#else + { +#endif + start_bh_atomic(); + /* Ensure that timer routine doesn't run! */ + del_timer(&sp->timer); + end_bh_atomic(); + /* Reset the Tx and Rx units. */ + outl(PortReset, ioaddr + SCBPort); + /* We may get spurious interrupts here. But I don't think that they + may do much harm. 1999/12/09 SAW */ + udelay(10); + /* Disable interrupts. */ + outw(SCBMaskAll, ioaddr + SCBCmd); + synchronize_irq(); + speedo_tx_buffer_gc(dev); + /* Free as much as possible. + It helps to recover from a hang because of out-of-memory. + It also simplifies speedo_resume() in case TX ring is full or + close-to-be full. */ + speedo_purge_tx(dev); + speedo_refill_rx_buffers(dev, 1); + spin_lock_irqsave(&sp->lock, flags); + speedo_resume(dev); + sp->rx_mode = -1; + dev->trans_start = jiffies; + spin_unlock_irqrestore(&sp->lock, flags); + set_rx_mode(dev); /* it takes the spinlock itself --SAW */ + /* Reset MII transceiver. Do it before starting the timer to serialize + mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */ + reset_mii(dev); + sp->timer.expires = RUN_AT(2*HZ); + add_timer(&sp->timer); } - sp->stats.tx_errors++; - dev->trans_start = jiffies; return; } static int -speedo_start_xmit(struct sk_buff *skb, struct device *dev) +speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - If this ever occurs the queue layer is doing something evil! */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { +#if ! defined(HAS_NETIF_QUEUE) + if (test_bit(0, (void*)&dev->tbusy) != 0) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < TX_TIMEOUT - 2) return 1; if (tickssofar < TX_TIMEOUT) { /* Reap sent packets from the full Tx queue. */ - outw(DRVR_INT, ioaddr + SCBCmd); + unsigned long flags; + /* Take a spinlock to make wait_for_cmd_done and sending the + command atomic. --SAW */ + spin_lock_irqsave(&sp->lock, flags); + wait_for_cmd_done(ioaddr + SCBCmd); + outw(SCBTriggerIntr, ioaddr + SCBCmd); + spin_unlock_irqrestore(&sp->lock, flags); return 1; } speedo_tx_timeout(dev); return 1; } - - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ +#endif { /* Prevent interrupts from changing the Tx ring from underneath us. */ unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&sp->lock, flags); + + /* Check if there are enough space. */ + if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { + printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name); + netif_stop_queue(dev); + sp->tx_full = 1; + spin_unlock_irqrestore(&sp->lock, flags); + return 1; + } + /* Calculate the Tx descriptor entry. */ entry = sp->cur_tx++ % TX_RING_SIZE; sp->tx_skbuff[entry] = skb; - /* Todo: be a little more clever about setting the interrupt bit. */ sp->tx_ring[entry].status = - (CmdSuspend | CmdTx | CmdTxFlex) << 16; + cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex); + if (!(entry & ((TX_RING_SIZE>>2)-1))) + sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr); sp->tx_ring[entry].link = - virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + virt_to_le32desc(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = - virt_to_bus(&sp->tx_ring[entry].tx_buf_addr); - /* The data region is always in one buffer descriptor, Tx FIFO - threshold of 256. */ - sp->tx_ring[entry].count = 0x01208000; - sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data); - sp->tx_ring[entry].tx_buf_size = skb->len; - /* Todo: perhaps leave the interrupt bit set if the Tx queue is more - than half full. Argument against: we should be receiving packets - and scavenging the queue. Argument for: if so, it shouldn't - matter. */ - sp->last_cmd->command &= ~(CmdSuspend | CmdIntr); - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + virt_to_le32desc(&sp->tx_ring[entry].tx_buf_addr0); + /* The data region is always in one buffer descriptor. */ + sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); + sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32desc(skb->data); + sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); /* Trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_RESUME, ioaddr + SCBCmd); - restore_flags(flags); - } + clear_suspend(sp->last_cmd); + /* We want the time window between clearing suspend flag on the previous + command and resuming CU to be as small as possible. + Interrupts in between are very undesired. --SAW */ + outb(CUResume, ioaddr + SCBCmd); + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - /* Leave room for set_rx_mode() to fill two entries. */ - if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3) - sp->tx_full = 1; - else - clear_bit(0, (void*)&dev->tbusy); + /* Leave room for set_rx_mode(). If there is no more space than reserved + for multicast filter mark the ring as full. */ + if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { + netif_stop_queue(dev); + sp->tx_full = 1; + } + + spin_unlock_irqrestore(&sp->lock, flags); + } dev->trans_start = jiffies; return 0; } +static void speedo_tx_buffer_gc(struct net_device *dev) +{ + unsigned int dirty_tx; + struct speedo_private *sp = (struct speedo_private *)dev->priv; + + dirty_tx = sp->dirty_tx; + while ((int)(sp->cur_tx - dirty_tx) > 0) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(sp->tx_ring[entry].status); + + if (speedo_debug > 5) + printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", + entry, status); + if ((status & StatusComplete) == 0) + break; /* It still hasn't been processed. */ + if (status & TxUnderrun) + if (sp->tx_threshold < 0x01e08000) { + if (speedo_debug > 2) + printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n", + dev->name); + sp->tx_threshold += 0x00040000; + } + /* Free the original skb. */ + if (sp->tx_skbuff[entry]) { + sp->stats.tx_packets++; /* Count only user packets. */ + sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; + dev_free_skb(sp->tx_skbuff[entry]); + sp->tx_skbuff[entry] = 0; + } + dirty_tx++; + } + + if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) { + printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," + " full=%d.\n", + dirty_tx, sp->cur_tx, sp->tx_full); + dirty_tx += TX_RING_SIZE; + } + + while (sp->mc_setup_head != NULL + && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) { + struct speedo_mc_block *t; + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); + t = sp->mc_setup_head->next; + kfree(sp->mc_setup_head); + sp->mc_setup_head = t; + } + if (sp->mc_setup_head == NULL) + sp->mc_setup_tail = NULL; + + sp->dirty_tx = dirty_tx; +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct device *dev = (struct device *)dev_instance; + struct net_device *dev = (struct net_device *)dev_instance; struct speedo_private *sp; - int ioaddr, boguscnt = max_interrupt_work; + long ioaddr, boguscnt = max_interrupt_work; unsigned short status; #ifndef final_version @@ -1010,11 +1512,13 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ioaddr = dev->base_addr; sp = (struct speedo_private *)dev->priv; + #ifndef final_version /* A lock to prevent simultaneous entry on SMP machines. */ if (test_and_set_bit(0, (void*)&sp->in_interrupt)) { printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", dev->name); + sp->in_interrupt = 0; /* Avoid halting machine. */ return; } dev->interrupt = 1; @@ -1023,76 +1527,109 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) do { status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ + /* Will change from 0xfc00 to 0xff00 when we start handling + FCP and ER interrupts --Dragan */ outw(status & 0xfc00, ioaddr + SCBStatus); - if (speedo_debug > 4) + if (speedo_debug > 3) printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", dev->name, status); if ((status & 0xfc00) == 0) break; - if (status & 0x4000) /* Packet received. */ + /* Always check if all rx buffers are allocated. --SAW */ + speedo_refill_rx_buffers(dev, 0); + + if ((status & 0x5000) || /* Packet received, or Rx error. */ + (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed) + /* Need to gather the postponed packet. */ speedo_rx(dev); if (status & 0x1000) { - if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */ - outw(RX_RESUMENR, ioaddr + SCBCmd); - else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */ - /* No idea of what went wrong. Restart the receiver. */ + spin_lock(&sp->lock); + if ((status & 0x003c) == 0x0028) { /* No more Rx buffers. */ + struct RxFD *rxf; + printk(KERN_WARNING "%s: card reports no RX buffers.\n", + dev->name); + rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; + if (rxf == NULL) { + if (speedo_debug > 2) + printk(KERN_DEBUG + "%s: NULL cur_rx in speedo_interrupt().\n", + dev->name); + sp->rx_ring_state |= RrNoMem|RrNoResources; + } else if (rxf == sp->last_rxf) { + if (speedo_debug > 2) + printk(KERN_DEBUG + "%s: cur_rx is last in speedo_interrupt().\n", + dev->name); + sp->rx_ring_state |= RrNoMem|RrNoResources; + } else + outb(RxResumeNoResources, ioaddr + SCBCmd); + } else if ((status & 0x003c) == 0x0008) { /* No resources. */ + struct RxFD *rxf; + printk(KERN_WARNING "%s: card reports no resources.\n", + dev->name); + rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; + if (rxf == NULL) { + if (speedo_debug > 2) + printk(KERN_DEBUG + "%s: NULL cur_rx in speedo_interrupt().\n", + dev->name); + sp->rx_ring_state |= RrNoMem|RrNoResources; + } else if (rxf == sp->last_rxf) { + if (speedo_debug > 2) + printk(KERN_DEBUG + "%s: cur_rx is last in speedo_interrupt().\n", + dev->name); + sp->rx_ring_state |= RrNoMem|RrNoResources; + } else { + /* Restart the receiver. */ + outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), + ioaddr + SCBPointer); + outb(RxStart, ioaddr + SCBCmd); + } + } + sp->stats.rx_errors++; + spin_unlock(&sp->lock); + } + + if ((sp->rx_ring_state&(RrNoMem|RrNoResources)) == RrNoResources) { + printk(KERN_WARNING + "%s: restart the receiver after a possible hang.\n", + dev->name); + spin_lock(&sp->lock); + /* Restart the receiver. + I'm not sure if it's always right to restart the receiver + here but I don't know another way to prevent receiver hangs. + 1999/12/25 SAW */ outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), - ioaddr + SCBPointer); - outw(RX_START, ioaddr + SCBCmd); - } - sp->stats.rx_errors++; + ioaddr + SCBPointer); + outb(RxStart, ioaddr + SCBCmd); + sp->rx_ring_state &= ~RrNoResources; + spin_unlock(&sp->lock); } /* User interrupt, Command/Tx unit interrupt or CU not active. */ if (status & 0xA400) { - unsigned int dirty_tx = sp->dirty_tx; - - while (sp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % TX_RING_SIZE; - int status = sp->tx_ring[entry].status; - - if (speedo_debug > 5) - printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", - entry, status); - if ((status & 0x8000) == 0) - break; /* It still hasn't been processed. */ - /* Free the original skb. */ - if (sp->tx_skbuff[entry]) { - sp->stats.tx_packets++; /* Count only user packets. */ - dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE); - sp->tx_skbuff[entry] = 0; - } - dirty_tx++; - } - -#ifndef final_version - if (sp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," - " full=%d.\n", - dirty_tx, sp->cur_tx, sp->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (sp->tx_full && dev->tbusy - && dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) { - /* The ring is no longer full, clear tbusy. */ + spin_lock(&sp->lock); + speedo_tx_buffer_gc(dev); + if (sp->tx_full + && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) { + /* The ring is no longer full. */ sp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */ } - - sp->dirty_tx = dirty_tx; + spin_unlock(&sp->lock); } if (--boguscnt < 0) { printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", dev->name, status); /* Clear all interrupt sources. */ + /* Will change from 0xfc00 to 0xff00 when we start handling + FCP and ER interrupts --Dragan */ outl(0xfc00, ioaddr + SCBStatus); break; } @@ -1107,150 +1644,219 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs) return; } +static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct RxFD *rxf; + struct sk_buff *skb; + /* Get a fresh skbuff to replace the consumed one. */ + skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); + sp->rx_skbuff[entry] = skb; + if (skb == NULL) { + sp->rx_ringp[entry] = NULL; + return NULL; + } + rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; + skb->dev = dev; + skb_reserve(skb, sizeof(struct RxFD)); + rxf->rx_buf_addr = virt_to_bus(skb->tail); + return rxf; +} + +static inline void speedo_rx_link(struct net_device *dev, int entry, + struct RxFD *rxf) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ + rxf->link = 0; /* None yet. */ + rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); + sp->last_rxf->link = virt_to_le32desc(rxf); + sp->last_rxf->status &= cpu_to_le32(~0xC0000000); + sp->last_rxf = rxf; +} + +static int speedo_refill_rx_buf(struct net_device *dev, int force) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + int entry; + struct RxFD *rxf; + + entry = sp->dirty_rx % RX_RING_SIZE; + if (sp->rx_skbuff[entry] == NULL) { + rxf = speedo_rx_alloc(dev, entry); + if (rxf == NULL) { + unsigned int forw; + int forw_entry; + if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) { + printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n", + dev->name, force); + speedo_show_state(dev); + sp->rx_ring_state |= RrOOMReported; + } + if (!force) + return -1; /* Better luck next time! */ + /* Borrow an skb from one of next entries. */ + for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++) + if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL) + break; + if (forw == sp->cur_rx) + return -1; + forw_entry = forw % RX_RING_SIZE; + sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry]; + sp->rx_skbuff[forw_entry] = NULL; + rxf = sp->rx_ringp[forw_entry]; + sp->rx_ringp[forw_entry] = NULL; + sp->rx_ringp[entry] = rxf; + } + } else { + rxf = sp->rx_ringp[entry]; + } + speedo_rx_link(dev, entry, rxf); + sp->dirty_rx++; + sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */ + return 0; +} + +static void speedo_refill_rx_buffers(struct net_device *dev, int force) +{ + struct speedo_private *sp = (struct speedo_private *)dev->priv; + + /* Refill the RX ring. */ + while ((int)(sp->cur_rx - sp->dirty_rx) > 0 && + speedo_refill_rx_buf(dev, force) != -1); +} + static int -speedo_rx(struct device *dev) +speedo_rx(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry = sp->cur_rx % RX_RING_SIZE; int status; + int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; + int alloc_ok = 1; if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) { + while (sp->rx_ringp[entry] != NULL && + (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) { + int pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; + + if (--rx_work_limit < 0) + break; + + /* Check for a rare out-of-memory case: the current buffer is + the last buffer allocated in the RX ring. --SAW */ + if (sp->last_rxf == sp->rx_ringp[entry]) { + /* Postpone the packet. It'll be reaped at an interrupt when this + packet is no longer the last packet in the ring. */ + if (speedo_debug > 2) + printk(KERN_DEBUG "%s: RX packet postponed!\n", + dev->name); + sp->rx_ring_state |= RrPostponed; + break; + } if (speedo_debug > 4) printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, - sp->rx_ringp[entry]->count & 0x3fff); - if (status & 0x0200) { - printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " - "status %8.8x!\n", dev->name, status); - } else if ( ! (status & 0x2000)) { - /* There was a fatal error. This *should* be impossible. */ - sp->stats.rx_errors++; - printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n", - dev->name, status); + pkt_len); + if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) { + if (status & RxErrTooBig) + printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " + "status %8.8x!\n", dev->name, status); + else if (! (status & RxOK)) { + /* There was a fatal error. This *should* be impossible. */ + sp->stats.rx_errors++; + printk(KERN_ERR "%s: Anomalous event in speedo_rx(), " + "status %8.8x.\n", + dev->name, status); + } } else { - /* Malloc up new buffer, compatible with net-2e. */ - int pkt_len = sp->rx_ringp[entry]->count & 0x3fff; struct sk_buff *skb; - int rx_in_place = 0; /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len > rx_copybreak) { - struct sk_buff *newskb; - char *temp; - - /* Pass up the skb already on the Rx ring. */ - skb = sp->rx_skbuff[entry]; - temp = skb_put(skb, pkt_len); - if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" - " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name, - sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp); - /* Get a fresh skbuff to replace the filled one. */ - newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - - if (newskb) { - struct RxFD *rxf; - rx_in_place = 1; - sp->rx_skbuff[entry] = newskb; - newskb->dev = dev; - rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail; - skb_reserve(newskb, sizeof(struct RxFD)); - /* Unused by i82557, consistency check only. */ - rxf->rx_buf_addr = virt_to_bus(newskb->tail); - rxf->status = 0x00000001; - } else /* No memory, drop the packet. */ - skb = 0; - } else - skb = dev_alloc_skb(pkt_len + 2); - if (skb == NULL) { - int i; - printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); - /* Check that at least two ring entries are free. - If not, free one and mark stats->rx_dropped++. */ - /* ToDo: This is not correct!!!! We should count the number - of linked-in Rx buffer to very that we have at least two - remaining. */ - for (i = 0; i < RX_RING_SIZE; i++) - if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status) - & RX_COMPLETE)) - break; - - if (i > RX_RING_SIZE -2) { - sp->stats.rx_dropped++; - sp->rx_ringp[entry]->status = 0; - sp->cur_rx++; - } - break; - } - skb->dev = dev; - if (! rx_in_place) { - skb_reserve(skb, 2); /* 16 byte align the data fields */ -#if defined(__i386) && notyet + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + skb->dev = dev; + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + /* 'skb_put()' points to the start of sk_buff data area. */ +#if !defined(__alpha__) /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), - pkt_len, 0); + eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), - bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len); + memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, + pkt_len); #endif + } else { + /* Pass up the already-filled skbuff. */ + skb = sp->rx_skbuff[entry]; + if (skb == NULL) { + printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", + dev->name); + break; + } + sp->rx_skbuff[entry] = NULL; + skb_put(skb, pkt_len); + sp->rx_ringp[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); sp->stats.rx_packets++; + sp->stats.rx_bytes += pkt_len; } - - /* ToDo: This is better than before, but should be checked. */ - { - struct RxFD *rxf = sp->rx_ringp[entry]; - rxf->status = 0xC0000003; /* '3' for verification only */ - rxf->link = 0; /* None yet. */ - rxf->count = 0; - rxf->size = PKT_BUF_SZ; - sp->last_rxf->link = virt_to_bus(rxf); - sp->last_rxf->status &= ~0xC0000000; - sp->last_rxf = rxf; - entry = (++sp->cur_rx) % RX_RING_SIZE; - } + entry = (++sp->cur_rx) % RX_RING_SIZE; + sp->rx_ring_state &= ~RrPostponed; + /* Refill the recently taken buffers. + Do it one-by-one to handle traffic bursts better. */ + if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1) + alloc_ok = 0; } + /* Try hard to refill the recently taken buffers. */ + speedo_refill_rx_buffers(dev, 1); + sp->last_rx_time = jiffies; + return 0; } static int -speedo_close(struct device *dev) +speedo_close(struct net_device *dev) { - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; struct speedo_private *sp = (struct speedo_private *)dev->priv; int i; dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (speedo_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); /* Shut off the media monitoring timer. */ + start_bh_atomic(); del_timer(&sp->timer); + end_bh_atomic(); - /* Disable interrupts, and stop the chip's Rx process. */ - outw(INT_MASK, ioaddr + SCBCmd); - outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd); + /* Shutting down the chip nicely fails to disable flow control. So.. */ + outl(PortPartialReset, ioaddr + SCBPort); free_irq(dev->irq, dev); - /* Free all the skbuffs in the Rx and Tx queues. */ + /* Print a few items for debugging. */ + if (speedo_debug > 3) + speedo_show_state(dev); + + /* Free all the skbuffs in the Rx and Tx queues. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = sp->rx_skbuff[i]; sp->rx_skbuff[i] = 0; /* Clear the Rx descriptors. */ if (skb) - dev_kfree_skb(skb, FREE_WRITE); + dev_free_skb(skb); } for (i = 0; i < TX_RING_SIZE; i++) { @@ -1258,30 +1864,20 @@ speedo_close(struct device *dev) sp->tx_skbuff[i] = 0; /* Clear the Tx descriptors. */ if (skb) - dev_kfree_skb(skb, FREE_WRITE); - } - if (sp->mc_setup_frm) { - kfree(sp->mc_setup_frm); - sp->mc_setup_frm_len = 0; + dev_free_skb(skb); } - /* Print a few items for debugging. */ - if (speedo_debug > 3) { - int phy_num = sp->phy[0] & 0x1f; - printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n", - dev->name, sp->cur_rx); - - for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_DEBUG " Rx ring entry %d %8.8x.\n", - i, (int)sp->rx_ringp[i]->status); - - for (i = 0; i < 5; i++) - printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n", - phy_num, i, mdio_read(ioaddr, phy_num, i)); - for (i = 21; i < 26; i++) - printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n", - phy_num, i, mdio_read(ioaddr, phy_num, i)); + /* Free multicast setting blocks. */ + for (i = 0; sp->mc_setup_head != NULL; i++) { + struct speedo_mc_block *t; + t = sp->mc_setup_head->next; + kfree(sp->mc_setup_head); + sp->mc_setup_head = t; } + sp->mc_setup_tail = NULL; + if (speedo_debug > 0) + printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i); + MOD_DEC_USE_COUNT; return 0; @@ -1300,36 +1896,42 @@ speedo_close(struct device *dev) Oh, and incoming frames are dropped while executing dump-stats! */ static struct enet_statistics * -speedo_get_stats(struct device *dev) +speedo_get_stats(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; - - if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */ - sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs; - sp->stats.tx_window_errors += sp->lstats.tx_late_colls; - sp->stats.tx_fifo_errors += sp->lstats.tx_underruns; - sp->stats.tx_fifo_errors += sp->lstats.tx_lost_carrier; - /*sp->stats.tx_deferred += sp->lstats.tx_deferred;*/ - sp->stats.collisions += sp->lstats.tx_total_colls; - sp->stats.rx_crc_errors += sp->lstats.rx_crc_errs; - sp->stats.rx_frame_errors += sp->lstats.rx_align_errs; - sp->stats.rx_over_errors += sp->lstats.rx_resource_errs; - sp->stats.rx_fifo_errors += sp->lstats.rx_overrun_errs; - sp->stats.rx_length_errors += sp->lstats.rx_runt_errs; + long ioaddr = dev->base_addr; + + /* Update only if the previous dump finished. */ + if (sp->lstats.done_marker == le32_to_cpu(0xA007)) { + sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats.tx_coll16_errs); + sp->stats.tx_window_errors += le32_to_cpu(sp->lstats.tx_late_colls); + sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_underruns); + sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_lost_carrier); + /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats.tx_deferred);*/ + sp->stats.collisions += le32_to_cpu(sp->lstats.tx_total_colls); + sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats.rx_crc_errs); + sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats.rx_align_errs); + sp->stats.rx_over_errors += le32_to_cpu(sp->lstats.rx_resource_errs); + sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs); + sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs); sp->lstats.done_marker = 0x0000; if (dev->start) { + unsigned long flags; + /* Take a spinlock to make wait_for_cmd_done and sending the + command atomic. --SAW */ + spin_lock_irqsave(&sp->lock, flags); wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_DUMPSTATS, ioaddr + SCBCmd); + outb(CUDumpStats, ioaddr + SCBCmd); + spin_unlock_irqrestore(&sp->lock, flags); } } return &sp->stats; } -static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd) +static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; @@ -1337,12 +1939,20 @@ static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + /* FIXME: these operations need to be serialized with MDIO + access from the timeout handler. + They are currently serialized only with MDIO access from the + timer routine. 2000/05/09 SAW */ + start_bh_atomic(); data[3] = mdio_read(ioaddr, data[0], data[1]); + end_bh_atomic(); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; + start_bh_atomic(); mdio_write(ioaddr, data[0], data[1], data[2]); + end_bh_atomic(); return 0; default: return -EOPNOTSUPP; @@ -1358,11 +1968,11 @@ static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd) loaded the link -- we convert the current command block, normally a Tx command, into a no-op and link it to the new command. */ -static void -set_rx_mode(struct device *dev) +static void set_rx_mode(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; + struct descriptor *last_cmd; char new_rx_mode; unsigned long flags; int entry, i; @@ -1375,68 +1985,75 @@ set_rx_mode(struct device *dev) } else new_rx_mode = 0; - if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) { - /* The Tx ring is full -- don't add anything! Presumably the new mode - is in config_cmd_data and will be added anyway. */ + if (speedo_debug > 3) + printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name, + sp->rx_mode, new_rx_mode); + + if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) { + /* The Tx ring is full -- don't add anything! Hope the mode will be + * set again later. */ sp->rx_mode = -1; return; } if (new_rx_mode != sp->rx_mode) { - /* We must change the configuration. Construct a CmdConfig frame. */ - memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd)); - sp->config_cmd_data[1] = (txfifo << 4) | rxfifo; - sp->config_cmd_data[4] = rxdmacount; - sp->config_cmd_data[5] = txdmacount + 0x80; - sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48; - sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80; - sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; + u8 *config_cmd_data; + + spin_lock_irqsave(&sp->lock, flags); + entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + + sp->tx_skbuff[entry] = 0; /* Redundant. */ + sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure); + sp->tx_ring[entry].link = + virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); + config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr; + /* Construct a full CmdConfig frame. */ + memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd)); + config_cmd_data[1] = (txfifo << 4) | rxfifo; + config_cmd_data[4] = rxdmacount; + config_cmd_data[5] = txdmacount + 0x80; + config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0; + /* 0x80 doesn't disable FC 0x84 does. + Disable Flow control since we are not ACK-ing any FC interrupts + for now. --Dragan */ + config_cmd_data[19] = 0x84; + config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0; + config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ - sp->config_cmd_data[15] |= 0x80; - sp->config_cmd_data[8] = 0; + config_cmd_data[15] |= 0x80; + config_cmd_data[8] = 0; } - save_flags(flags); - cli(); - /* Fill the "real" tx_ring frame with a no-op and point it to us. */ - entry = sp->cur_tx++ % TX_RING_SIZE; - sp->tx_skbuff[entry] = 0; /* Nothing to free. */ - sp->tx_ring[entry].status = CmdNOp << 16; - sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd); - sp->config_cmd.status = 0; - sp->config_cmd.command = CmdSuspend | CmdConfigure; - sp->config_cmd.link = - virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); - sp->last_cmd->command &= ~CmdSuspend; - /* Immediately trigger the command unit resume. */ + /* Trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = &sp->config_cmd; - restore_flags(flags); - if (speedo_debug > 5) { - int i; - printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry); - for(i = 0; i < 32; i++) - printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]); - printk(".\n"); + clear_suspend(last_cmd); + outb(CUResume, ioaddr + SCBCmd); + if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { + netif_stop_queue(dev); + sp->tx_full = 1; } + spin_unlock_irqrestore(&sp->lock, flags); } - if (new_rx_mode == 0 && dev->mc_count < 3) { - /* The simple case of 0-2 multicast list entries occurs often, and + if (new_rx_mode == 0 && dev->mc_count < 4) { + /* The simple case of 0-3 multicast list entries occurs often, and fits within one tx_ring[] entry. */ - u16 *setup_params, *eaddrs; struct dev_mc_list *mclist; + u16 *setup_params, *eaddrs; - save_flags(flags); - cli(); + spin_lock_irqsave(&sp->lock, flags); entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + sp->tx_skbuff[entry] = 0; - sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16; + sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList); sp->tx_ring[entry].link = - virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + virt_to_le32desc(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr; - *setup_params++ = dev->mc_count*6; + *setup_params++ = cpu_to_le16(dev->mc_count*6); /* Fill in the multicast addresses. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; i++, mclist = mclist->next) { @@ -1446,45 +2063,43 @@ set_rx_mode(struct device *dev) *setup_params++ = *eaddrs++; } - sp->last_cmd->command &= ~CmdSuspend; - /* Immediately trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - restore_flags(flags); + clear_suspend(last_cmd); + /* Immediately trigger the command unit resume. */ + outb(CUResume, ioaddr + SCBCmd); + + if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { + netif_stop_queue(dev); + sp->tx_full = 1; + } + spin_unlock_irqrestore(&sp->lock, flags); } else if (new_rx_mode == 0) { - /* This does not work correctly, but why not? */ struct dev_mc_list *mclist; - u16 *eaddrs; - struct descriptor *mc_setup_frm = sp->mc_setup_frm; - u16 *setup_params; + u16 *setup_params, *eaddrs; + struct speedo_mc_block *mc_blk; + struct descriptor *mc_setup_frm; int i; - if (sp->mc_setup_frm_len < 10 + dev->mc_count*6 - || sp->mc_setup_frm == NULL) { - /* Allocate a new frame, 10bytes + addrs, with a few - extra entries for growth. */ - if (sp->mc_setup_frm) - kfree(sp->mc_setup_frm); - sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24; - sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC); - if (sp->mc_setup_frm == NULL) { - printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name); - sp->rx_mode = -1; /* We failed, try again. */ - return; - } + mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6, + GFP_ATOMIC); + if (mc_blk == NULL) { + printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", + dev->name); + sp->rx_mode = -1; /* We failed, try again. */ + return; } - mc_setup_frm = sp->mc_setup_frm; - /* Construct the new setup frame. */ + mc_blk->next = NULL; + mc_setup_frm = &mc_blk->frame; + + /* Fill the setup frame. */ if (speedo_debug > 1) - printk(KERN_DEBUG "%s: Constructing a setup frame at %p, " - "%d bytes.\n", - dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len); - mc_setup_frm->status = 0; - mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList; + printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n", + dev->name, mc_setup_frm); + mc_setup_frm->cmd_status = + cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList); /* Link set below. */ - setup_params = (u16 *)mc_setup_frm->params; - *setup_params++ = dev->mc_count*6; + setup_params = (u16 *)&mc_setup_frm->params; + *setup_params++ = cpu_to_le16(dev->mc_count*6); /* Fill in the multicast addresses. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; i++, mclist = mclist->next) { @@ -1495,32 +2110,42 @@ set_rx_mode(struct device *dev) } /* Disable interrupts while playing with the Tx Cmd list. */ - save_flags(flags); - cli(); - entry = sp->cur_tx++ % TX_RING_SIZE; + spin_lock_irqsave(&sp->lock, flags); - if (speedo_debug > 5) - printk(" CmdMCSetup frame length %d in entry %d.\n", - dev->mc_count, entry); + if (sp->mc_setup_tail) + sp->mc_setup_tail->next = mc_blk; + else + sp->mc_setup_head = mc_blk; + sp->mc_setup_tail = mc_blk; + mc_blk->tx = sp->cur_tx; + + entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = mc_setup_frm; /* Change the command to a NoOp, pointing to the CmdMulti command. */ sp->tx_skbuff[entry] = 0; - sp->tx_ring[entry].status = CmdNOp << 16; - sp->tx_ring[entry].link = virt_to_bus(mc_setup_frm); + sp->tx_ring[entry].status = cpu_to_le32(CmdNOp); + sp->tx_ring[entry].link = virt_to_le32desc(mc_setup_frm); /* Set the link in the setup frame. */ mc_setup_frm->link = - virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); + virt_to_le32desc(&(sp->tx_ring[(entry+1) % TX_RING_SIZE])); - sp->last_cmd->command &= ~CmdSuspend; - /* Immediately trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = mc_setup_frm; - restore_flags(flags); - if (speedo_debug > 1) - printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n", - dev->name, sp->last_cmd, sp->last_cmd->command); + clear_suspend(last_cmd); + /* Immediately trigger the command unit resume. */ + outb(CUResume, ioaddr + SCBCmd); + + if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { + netif_stop_queue(dev); + sp->tx_full = 1; + } + spin_unlock_irqrestore(&sp->lock, flags); + + if (speedo_debug > 5) + printk(" CmdMCSetup frame length %d in entry %d.\n", + dev->mc_count, entry); } sp->rx_mode = new_rx_mode; @@ -1528,41 +2153,54 @@ set_rx_mode(struct device *dev) #ifdef MODULE -int -init_module(void) +int init_module(void) { int cards_found; + if (debug >= 0 && speedo_debug != debug) + printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug); if (debug >= 0) speedo_debug = debug; + /* Always emit the version message. */ if (speedo_debug) printk(KERN_INFO "%s", version); - root_speedo_dev = NULL; - cards_found = eepro100_init(NULL); - return cards_found ? 0 : -ENODEV; + cards_found = eepro100_init(); + if (cards_found <= 0) { + printk(KERN_INFO "eepro100: No cards found, driver not installed.\n"); + return -ENODEV; + } + return 0; } void cleanup_module(void) { - struct device *next_dev; + struct net_device *next_dev; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_speedo_dev) { - next_dev = ((struct speedo_private *)root_speedo_dev->priv)->next_module; + struct speedo_private *sp = (void *)root_speedo_dev->priv; unregister_netdev(root_speedo_dev); release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE); +#ifndef USE_IO + iounmap((char *)root_speedo_dev->base_addr); +#endif + next_dev = sp->next_module; + if (sp->priv_addr) + kfree(sp->priv_addr); kfree(root_speedo_dev); root_speedo_dev = next_dev; } } + #else /* not MODULE */ -int eepro100_probe(struct device *dev) + +int eepro100_probe(void) { int cards_found = 0; - cards_found = eepro100_init(dev); + cards_found = eepro100_init(); if (speedo_debug > 0 && cards_found) printk(version); |