diff -urN linux-2.4.20/drivers/net/3c59x.c linux-2.4.20-3c59x/drivers/net/3c59x.c --- linux-2.4.20/drivers/net/3c59x.c 2002-11-28 18:53:13.000000000 -0500 +++ linux-2.4.20-3c59x/drivers/net/3c59x.c 2002-11-17 15:09:30.000000000 -0500 @@ -1,316 +1,173 @@ /* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ /* - Written 1996-1999 by Donald Becker. + Written 1996-2002 by Donald Becker. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. + 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 the 3Com "Vortex" and "Boomerang" series ethercards. Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597 and the EtherLink XL 3c900 and 3c905 cards. - Problem reports and questions should be directed to - vortex@scyld.com - - The author may be reached as becker@scyld.com, or C/O + The original author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 Annapolis MD 21403 - Linux Kernel Additions: - - 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates - 0.99H+lk1.0 - Jeff Garzik - Remove compatibility defines for kernel versions < 2.2.x. - Update for new 2.3.x module interface - LK1.1.2 (March 19, 2000) - * New PCI interface (jgarzik) - - LK1.1.3 25 April 2000, Andrew Morton - - Merged with 3c575_cb.c - - Don't set RxComplete in boomerang interrupt enable reg - - spinlock in vortex_timer to protect mdio functions - - disable local interrupts around call to vortex_interrupt in - vortex_tx_timeout() (So vortex_interrupt can use spin_lock()) - - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl - - In vortex_start_xmit(), move the lock to _after_ we've altered - vp->cur_tx and vp->tx_full. This defeats the race between - vortex_start_xmit() and vortex_interrupt which was identified - by Bogdan Costescu. - - Merged back support for six new cards from various sources - - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus - insertion oops) - - Tell it that 3c905C has NWAY for 100bT autoneg - - Fix handling of SetStatusEnd in 'Too much work..' code, as - per 2.3.99's 3c575_cb (Dave Hinds). - - Split ISR into two for vortex & boomerang - - Fix MOD_INC/DEC races - - Handle resource allocation failures. - - Fix 3CCFE575CT LED polarity - - Make tx_interrupt_mitigation the default - - LK1.1.4 25 April 2000, Andrew Morton - - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs. - - Put vortex_info_tbl into __devinitdata - - In the vortex_error StatsFull HACK, disable stats in vp->intr_enable as well - as in the hardware. - - Increased the loop counter in issue_and_wait from 2,000 to 4,000. - - LK1.1.5 28 April 2000, andrewm - - Added powerpc defines (John Daniel said these work...) - - Some extra diagnostics - - In vortex_error(), reset the Tx on maxCollisions. Otherwise most - chips usually get a Tx timeout. - - Added extra_reset module parm - - Replaced some inline timer manip with mod_timer - (Franois romieu ) - - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway - (this came across from 3c575_cb). - - LK1.1.6 06 Jun 2000, andrewm - - Backed out the PPC defines. - - Use del_timer_sync(), mod_timer(). - - Fix wrapped ulong comparison in boomerang_rx() - - Add IS_TORNADO, use it to suppress 3c905C checksum error msg - (Donald Becker, I Lee Hetherington ) - - Replace union wn3_config with BFINS/BFEXT manipulation for - sparc64 (Pete Zaitcev, Peter Jones) - - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex): - do a netif_wake_queue() to better recover from errors. (Anders Pedersen, - Donald Becker) - - Print a warning on out-of-memory (rate limited to 1 per 10 secs) - - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) - - LK1.1.7 2 Jul 2000 andrewm - - Better handling of shared IRQs - - Reset the transmitter on a Tx reclaim error - - Fixed crash under OOM during vortex_open() (Mark Hemment) - - Fix Rx cessation problem during OOM (help from Mark Hemment) - - The spinlocks around the mdio access were blocking interrupts for 300uS. - Fix all this to use spin_lock_bh() within mdio_read/write - - Only write to TxFreeThreshold if it's a boomerang - other NICs don't - have one. - - Added 802.3x MAC-layer flow control support - - LK1.1.8 13 Aug 2000 andrewm - - Ignore request_region() return value - already reserved if Cardbus. - - Merged some additional Cardbus flags from Don's 0.99Qk - - Some fixes for 3c556 (Fred Maciel) - - Fix for EISA initialisation (Jan Rekorajski) - - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers - - Fixed MII_XCVR_PWR for 3CCFE575CT - - Added INVERT_LED_PWR, used it. - - Backed out the extra_reset stuff - - LK1.1.9 12 Sep 2000 andrewm - - Backed out the tx_reset_resume flags. It was a no-op. - - In vortex_error, don't reset the Tx on txReclaim errors - - In vortex_error, don't reset the Tx on maxCollisions errors. - Hence backed out all the DownListPtr logic here. - - In vortex_error, give Tornado cards a partial TxReset on - maxCollisions (David Hinds). Defined MAX_COLLISION_RESET for this. - - Redid some driver flags and device names based on pcmcia_cs-3.1.20. - - Fixed a bug where, if vp->tx_full is set when the interface - is downed, it remains set when the interface is upped. Bad - things happen. - - LK1.1.10 17 Sep 2000 andrewm - - Added EEPROM_8BIT for 3c555 (Fred Maciel) - - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg) - - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO" - - LK1.1.11 13 Nov 2000 andrewm - - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER - - LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1) - - Call pci_enable_device before we request our IRQ (Tobias Ringstrom) - - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra) - - Added extended issue_and_wait for the 3c905CX. - - Look for an MII on PHY index 24 first (3c905CX oddity). - - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) - - Don't free skbs we don't own on oom path in vortex_open(). - - LK1.1.13 27 Jan 2001 - - Added explicit `medialock' flag so we can truly - lock the media type down with `options'. - - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo ) - - Added and used EEPROM_NORESET for 3c556B PM resumes. - - Fixed leakage of vp->rx_ring. - - Break out separate HAS_HWCKSM device capability flag. - - Kill vp->tx_full (ANK) - - Merge zerocopy fragment handling (ANK?) - - LK1.1.14 15 Feb 2001 - - Enable WOL. Can be turned on with `enable_wol' module option. - - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul) - - If a device's internalconfig register reports it has NWAY, - use it, even if autoselect is enabled. - - LK1.1.15 6 June 2001 akpm - - Prevent double counting of received bytes (Lars Christensen) - - Add ethtool support (jgarzik) - - Add module parm descriptions (Andrzej M. Krzysztofowicz) - - Implemented alloc_etherdev() API - - Special-case the 'Tx error 82' message. - - LK1.1.16 18 July 2001 akpm - - Make NETIF_F_SG dependent upon nr_free_highpages(), not on CONFIG_HIGHMEM - - Lessen verbosity of bootup messages - - Fix WOL - use new PM API functions. - - Use netif_running() instead of vp->open in suspend/resume. - - Don't reset the interface logic on open/close/rmmod. It upsets - autonegotiation, and hence DHCP (from 0.99T). - - Back out EEPROM_NORESET flag because of the above (we do it for all - NICs). - - Correct 3c982 identification string - - Rename wait_for_completion() to issue_and_wait() to avoid completion.h - clash. - - - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - - Also see Documentation/networking/vortex.txt + Support information and updates are available at + http://www.scyld.com/network/vortex.html */ -/* - * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamachi.c implementation - * as well as other drivers - * - * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k - * due to dead code elimination. There will be some performance benefits from this due to - * elimination of all the tests and reduced cache footprint. - */ - - -#define DRV_NAME "3c59x" -#define DRV_VERSION "LK1.1.16" -#define DRV_RELDATE "19 July 2001" - - +static const char versionA[] = +"3c59x.c:v0.99Xf 11/17/2002 Donald Becker, becker@scyld.com\n"; +static const char versionB[] = +" http://www.scyld.com/network/vortex.html\n"; + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ + +/* This driver uses 'options' to pass the media type, full-duplex flag, etc. + See media_tbl[] and the web page for the possible types. + There is no limit on card count, MAX_UNITS limits only module options. */ +#define MAX_UNITS 8 +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}; -/* A few values that may be tweaked. */ -/* Keep the ring sizes a power of two for efficiency. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; -/* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ -#ifndef __arm__ static const int rx_copybreak = 200; -#else -/* ARM systems perform better by disregarding the bus-master - transfer capability of these cards. -- rmk */ -static const int rx_copybreak = 1513; -#endif -/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ +/* Allow setting MTU to a larger size, bypassing the normal Ethernet setup. */ static const int mtu = 1500; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; -/* Tx timeout interval (millisecs) */ -static int watchdog = 5000; - -/* Allow aggregation of Tx interrupts. Saves CPU load at the cost - * of possible Tx stalls if the system is blocking interrupts - * somewhere else. Undefine this to disable. +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + The Tornados have a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 64; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + Do not increase the Tx ring beyond 256. + 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 32 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (6*HZ) + +/* Allocation size of Rx buffers with normal sized Ethernet frames. + Do not change this value without good reason. The 1536 value is not + a limit, or directly related to MTU, but rather a way to keep a + consistent allocation size among drivers. */ -#define tx_interrupt_mitigation 1 +#define PKT_BUF_SZ 1536 -/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ -#define vortex_debug debug -#ifdef VORTEX_DEBUG -static int vortex_debug = VORTEX_DEBUG; -#else -static int vortex_debug = 1; +#ifndef __KERNEL__ +#define __KERNEL__ #endif - -#ifndef __OPTIMIZE__ -#error You must compile this file with the correct options! -#error See the last lines of the source file. +#if !defined(__OPTIMIZE__) +#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 +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif +#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) +#define MODVERSIONS +#endif + +#include +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) #include +#include +#else +#include +#include +#endif + #include -#include #include #include #include -#include #include +#if LINUX_VERSION_CODE >= 0x20400 #include +#else +#include +#endif #include #include -#include -#include #include #include #include -#include -#include -#include /* For NR_IRQS only. */ +#include +#include #include #include -#include - -/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. - This is only in the support-all-kernels source code. */ -#define RUN_AT(x) (jiffies + (x)) +#ifdef INLINE_PCISCAN +#include "k_compat.h" +#else +#include "pci-scan.h" +#include "kern_compat.h" +#endif -#include +/* Condensed operations for readability. + Compatibility defines are now in kern_compat.h */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) -static char version[] __devinitdata = -DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n"; +#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE) +char kernel_version[] = UTS_RELEASE; +#endif MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver " - DRV_VERSION " " DRV_RELDATE); +MODULE_DESCRIPTION("3Com EtherLink XL (3c590/3c900 series) driver"); MODULE_LICENSE("GPL"); - MODULE_PARM(debug, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(compaq_ioaddr, "i"); -MODULE_PARM(compaq_irq, "i"); -MODULE_PARM(compaq_device_id, "i"); -MODULE_PARM(watchdog, "i"); -MODULE_PARM_DESC(debug, "3c59x debug level (0-6)"); -MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex"); -MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)"); -MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)"); -MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)"); -MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)"); -MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt"); -MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)"); -MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)"); -MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)"); -MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds"); +MODULE_PARM(multicast_filter_limit, "i"); +#ifdef MODULE_PARM_DESC +MODULE_PARM_DESC(debug, "3c59x message level (0-31)"); +MODULE_PARM_DESC(options, "3c59x force fixed media type"); +MODULE_PARM_DESC(full_duplex, + "3c59x set to 1 to force full duplex (not recommended)"); +MODULE_PARM_DESC(rx_copybreak, + "3c59x copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(max_interrupt_work, + "3c59x maximum events handled per interrupt"); +MODULE_PARM_DESC(multicast_filter_limit, + "3c59x breakpoint for switching to Rx-all-multicast"); +#endif /* Operational parameter that usually are not changed. */ -/* The Vortex size is twice that of the original EtherLinkIII series: the - runtime register window, window 1, is now always mapped in. - The Boomerang size is twice as large as the Vortex -- it has additional - bus master control registers. */ -#define VORTEX_TOTAL_SIZE 0x20 -#define BOOMERANG_TOTAL_SIZE 0x40 - /* Set iff a MII transceiver on any interface requires mdio preamble. This only set with the original DP83840 on older 3c905 boards, so the extra code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required; - -#define PFX DRV_NAME ": " - +static char mii_preamble_required = 0; +/* Performance and path-coverage information. */ +static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; /* Theory of Operation @@ -320,11 +177,10 @@ This device driver is designed for the 3Com FastEtherLink and FastEtherLink XL, 3Com's PCI to 10/100baseT adapters. It also works with the 10Mbs versions of the FastEtherLink cards. The supported product IDs are - 3c590, 3c592, 3c595, 3c597, 3c900, 3c905 +in the pci_tbl[] list. The related ISA 3c515 is supported with a separate driver, 3c515.c, included -with the kernel source or available from - cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html +with the kernel source. II. Board-specific settings @@ -369,6 +225,7 @@ passing the full-sized skbuff to the queue layer for all frames vs. the copying cost of copying a frame to a correctly-sized skbuff. + IIIC. 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 @@ -383,202 +240,147 @@ the EISA version is called "Demon". According to Terry these names come from rides at the local amusement park. -The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes! -This driver only supports ethernet packets because of the skbuff allocation -limit of 4K. +The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes. +This driver only supports ethernet packets on some kernels because of the +skbuff allocation limit of 4K. */ -/* 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. -*/ -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 { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ - HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, - INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, - EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000 }; - -enum vortex_chips { - CH_3C590 = 0, - CH_3C592, - CH_3C597, - CH_3C595_1, - CH_3C595_2, - - CH_3C595_3, - CH_3C900_1, - CH_3C900_2, - CH_3C900_3, - CH_3C900_4, - - CH_3C900_5, - CH_3C900B_FL, - CH_3C905_1, - CH_3C905_2, - CH_3C905B_1, - - CH_3C905B_2, - CH_3C905B_FX, - CH_3C905C, - CH_3C980, - CH_3C9805, - - CH_3CSOHO100_TX, - CH_3C555, - CH_3C556, - CH_3C556B, - CH_3C575, - - CH_3C575_1, - CH_3CCFE575, - CH_3CCFE575CT, - CH_3CCFE656, - CH_3CCFEM656, - - CH_3CCFEM656_1, - CH_3C450, -}; - - -/* note: this array directly indexed by above enums, and MUST - * be kept in sync with both the enums above, and the PCI device - * table below - */ -static struct vortex_chip_info { - const char *name; - int flags; - int drv_flags; - int io_size; -} vortex_info_tbl[] __devinitdata = { -#define EISA_TBL_OFFSET 0 /* Offset of this entry for vortex_eisa_init */ - {"3c590 Vortex 10Mbps", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c595 Vortex 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - - {"3c595 Vortex 100base-MII", - PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, - {"3c900 Boomerang 10baseT", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {"3c900 Boomerang 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, - {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c900 Cyclone 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - - {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c900B-FL Cyclone 10base-FL", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c905 Boomerang 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3c905 Boomerang 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, - {"3c905B Cyclone 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - - {"3c905B Cyclone 10/100/BNC", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c905B-FX Cyclone 100baseFx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c905C Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c980 Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - {"3c982 Dual Port Server Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, - - {"3cSOHO100-TX Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, - {"3c555 Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, - {"3c556 Laptop Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR| - HAS_HWCKSM, 128, }, - {"3c556B Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| - HAS_HWCKSM, 128, }, - {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, - - {"3c575 Boomerang CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, - {"3CCFE575BT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - {"3CCFE575CT Tornado CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| - MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, - {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - {"3CCFEM656B Cyclone+Winmodem CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| - INVERT_LED_PWR|HAS_HWCKSM, 128, }, - - {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| - MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, - {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - {0,}, /* 0 terminated list. */ -}; - - -static struct pci_device_id vortex_pci_tbl[] __devinitdata = { - { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 }, - { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 }, - { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 }, - { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 }, - { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 }, - - { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 }, - { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 }, - { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 }, - { 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 }, - { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 }, - - { 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 }, - { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL }, - { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 }, - { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 }, - { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 }, - - { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 }, - { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX }, - { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C }, - { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 }, - { 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 }, - - { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX }, - { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 }, - { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 }, - { 0x10B7, 0x6056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556B }, - { 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 }, - - { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 }, - { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 }, - { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT }, - { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 }, - { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 }, - - { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 }, - { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 }, - {0,} /* 0 terminated list. */ -}; -MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); +/* The Vortex size is twice that of the original EtherLinkIII series: the + runtime register window, window 1, is now always mapped in. + The Boomerang size is twice as large as the Vortex -- it has additional + bus master control registers. */ +#define VORTEX_SIZE 0x20 +#define BOOMERANG_SIZE 0x40 +#define CYCLONE_SIZE 0x80 +enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=0x804, IS_TORNADO=0x08, + HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, + EEPROM_8BIT=0x200, INVERT_LED_PWR=0x400, MII_XCVR_PWR=0x4000, + HAS_V2_TX=0x800, WN0_XCVR_PWR=0x1000, +}; +/* Base feature sets for the generations. */ +#define FEATURE_BOOMERANG (HAS_MII) /* 905 */ +#define FEATURE_CYCLONE (IS_CYCLONE|HAS_V2_TX) /* 905B */ +#define FEATURE_TORNADO (IS_TORNADO|HAS_NWAY|HAS_V2_TX) /* 905C */ + +static void *vortex_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_idx, int find_cnt); +static int pwr_event(void *dev_instance, int event); +#ifdef USE_MEM_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#endif +static struct pci_id_info pci_tbl[] = { + {"3c590 Vortex 10Mbps", { 0x590010B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"3c595 Vortex 100baseTx", { 0x595010B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"3c595 Vortex 100baseT4", { 0x595110B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"3c595 Vortex 100base-MII",{ 0x595210B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + /* Change EISA_scan if these move from index 4 and 5. */ + {"3c592 EISA Vortex", { 0x592010B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"3c597 EISA Vortex", { 0x597010B7, 0xffffffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"Vortex (unknown)", { 0x590010B7, 0xff00ffff }, + PCI_IOTYPE, VORTEX_SIZE, IS_VORTEX, }, + {"3c900 Boomerang 10baseT", { 0x900010B7, 0xffffffff }, + PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG, }, + {"3c900 Boomerang 10Mbps Combo", { 0x900110B7, 0xffffffff }, + PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG, }, + {"3c900 Cyclone 10Mbps TPO", { 0x900410B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, }, + {"3c900 Cyclone 10Mbps Combo", { 0x900510B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, }, + {"3c900 Cyclone 10Mbps TPC", { 0x900610B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, }, + {"3c900B-FL Cyclone 10base-FL",{ 0x900A10B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, }, + {"3c905 Boomerang 100baseTx",{ 0x905010B7, 0xffffffff }, + PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, }, + {"3c905 Boomerang 100baseT4",{ 0x905110B7, 0xffffffff }, + PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, }, + {"3c905B Cyclone 100baseTx",{ 0x905510B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE|HAS_NWAY, }, + {"3c905B Cyclone 10/100/BNC",{ 0x905810B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE|HAS_NWAY, }, + {"3c905B-FX Cyclone 100baseFx",{ 0x905A10B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, IS_CYCLONE, }, + {"3c905C Tornado",{ 0x920010B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, }, + {"3c982 Server Tornado",{ 0x980510B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, }, + {"3c980 Cyclone",{ 0x980010B7, 0xfff0ffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE|HAS_NWAY, }, + {"3cSOHO100-TX Hurricane", { 0x764610B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE, }, + {"3c555 Laptop Hurricane", { 0x505510B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_CYCLONE, }, + {"3c556 Laptop Tornado",{ 0x605510B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO|EEPROM_8BIT, }, + {"3c556 series Laptop Tornado",{ 0x605510B7, 0xf0ffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO|EEPROM_8BIT, }, + {"3c1556B-5 mini-PCI",{ 0x605610B7, 0xffffffff, 0x655610b7, 0xffffffff, }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_TORNADO|EEPROM_8BIT|INVERT_LED_PWR|WN0_XCVR_PWR, }, + {"3c1556B mini-PCI",{ 0x605610B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_TORNADO|EEPROM_8BIT|HAS_CB_FNS|INVERT_LED_PWR|MII_XCVR_PWR, }, + {"3c1556B series mini-PCI",{ 0x605610B7, 0xf0ffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_TORNADO|EEPROM_8BIT|HAS_CB_FNS|INVERT_LED_PWR|MII_XCVR_PWR, }, + {"3c575 Boomerang CardBus", { 0x505710B7, 0xffffffff }, + PCI_IOTYPE,BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, }, + {"3CCFE575BT Cyclone CardBus",{ 0x515710B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_CYCLONE | HAS_CB_FNS | EEPROM_8BIT | INVERT_LED_PWR, }, + {"3CCFE575CT Tornado CardBus",{ 0x525710B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_TORNADO|HAS_CB_FNS|EEPROM_8BIT|MII_XCVR_PWR, }, + {"3CCFE656 Cyclone CardBus",{ 0x656010B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + IS_CYCLONE|HAS_NWAY|HAS_CB_FNS| INVERT_LED_PWR | MII_XCVR_PWR, }, + {"3CCFE656B Cyclone+Winmodem CardBus",{ 0x656210B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + FEATURE_CYCLONE/*|HAS_NWAY*/ |HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR|MII_XCVR_PWR, }, + {"3CCFE656C Tornado+Winmodem CardBus",{ 0x656410B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, + (FEATURE_TORNADO & ~HAS_NWAY)|HAS_CB_FNS|EEPROM_8BIT | MII_XCVR_PWR, }, + {"3c450 HomePNA Tornado",{ 0x450010B7, 0xffffffff }, + PCI_IOTYPE, CYCLONE_SIZE, FEATURE_TORNADO, }, + {"3c575 series CardBus (unknown version)", {0x505710B7, 0xf0ffffff }, + PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG|HAS_MII, }, + {"3Com Boomerang (unknown version)",{ 0x900010B7, 0xff00ffff }, + PCI_IOTYPE, BOOMERANG_SIZE, IS_BOOMERANG, }, + {0,}, /* 0 terminated list. */ +}; + +struct drv_id_info vortex_drv_id = { + "vortex", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl, + vortex_probe1, pwr_event }; + +/* This driver was written to use I/O operations. + However there are performance benefits to using memory operations, so + that mode is now an options. + Compiling for memory ops turns off EISA support. +*/ +#ifdef USE_MEM_OPS +#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 /* Operational definitions. These are not used by other compilation units and thus are not @@ -635,11 +437,7 @@ Wn0EepromData = 12, /* Window 0: EEPROM results register. */ IntrStatus=0x0E, /* Valid in all windows. */ }; -enum Win0_EEPROM_bits { - EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, - EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ - EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ -}; + /* EEPROM locations. */ enum eeprom_offset { PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3, @@ -651,24 +449,9 @@ Wn2_ResetOptions=12, }; enum Window3 { /* Window 3: MAC/config bits. */ - Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, + Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; -#define BFEXT(value, offset, bitcount) \ - ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1)) - -#define BFINS(lhs, rhs, offset, bitcount) \ - (((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) | \ - (((rhs) & ((1 << (bitcount)) - 1)) << (offset))) - -#define RAM_SIZE(v) BFEXT(v, 0, 3) -#define RAM_WIDTH(v) BFEXT(v, 3, 1) -#define RAM_SPEED(v) BFEXT(v, 4, 2) -#define ROM_SIZE(v) BFEXT(v, 6, 2) -#define RAM_SPLIT(v) BFEXT(v, 16, 2) -#define XCVR(v) BFEXT(v, 20, 4) -#define AUTOSELECT(v) BFEXT(v, 24, 1) - enum Window4 { /* Window 4: Xcvr/media bits. */ Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, }; @@ -678,20 +461,24 @@ Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ Media_LnkBeat = 0x0800, }; -enum Window7 { /* Window 7: Bus Master control. */ +enum Window7 { + /* Bus Master control on Vortex. */ Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, + /* On Cyclone and later, VLAN and PowerMgt control. */ + Wn7_VLAN_Mask = 0, Wn7_VLAN_EtherType = 4, Wn7_PwrMgmtEvent = 12, }; + /* Boomerang bus master control registers. */ enum MasterCtrl { PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c, - TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38, + DownPollRate = 0x2d, TxFreeThreshold = 0x2f, + UpPktStatus = 0x30, UpListPtr = 0x38, }; /* The Rx and Tx descriptor lists. Caution Alpha hackers: these types are 32 bits! Note also the 8 byte alignment contraint on tx_ring[] and rx_ring[]. */ -#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ -#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ +#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ struct boom_rx_desc { u32 next; /* Last entry points to 0. */ s32 status; @@ -706,90 +493,74 @@ IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31, }; -#ifdef MAX_SKB_FRAGS -#define DO_ZEROCOPY 1 -#else -#define DO_ZEROCOPY 0 -#endif - struct boom_tx_desc { u32 next; /* Last entry points to 0. */ s32 status; /* bits 0:12 length, others see below. */ -#if DO_ZEROCOPY - struct { - u32 addr; - s32 length; - } frag[1+MAX_SKB_FRAGS]; -#else - u32 addr; - s32 length; -#endif + u32 addr; + s32 length; }; /* Values for the Tx status entry. */ enum tx_desc_status { - CRCDisable=0x2000, TxDComplete=0x8000, + CRCDisable=0x2000, TxIntrDnComplete=0x8000, TxDownComplete=0x10000, AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000, + TxNoRoundup=0x10000000, /* HAS_V2_TX should not word-pad packet. */ TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */ }; /* Chip features we care about in vp->capabilities, read from the EEPROM. */ -enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; +enum ChipCaps { CapBusMaster=0x20, CapNoTxLength=0x0200, CapPwrMgmt=0x2000 }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ - struct boom_rx_desc* rx_ring; - struct boom_tx_desc* tx_ring; - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; + struct boom_rx_desc rx_ring[RX_RING_SIZE]; + struct boom_tx_desc tx_ring[TX_RING_SIZE]; /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct net_device *next_module; /* NULL if PCI device */ - 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 net_device_stats stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */ + struct net_device *next_module; + void *priv_addr; + /* Keep the Rx and Tx variables grouped on their own cache lines. */ + struct boom_rx_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + int rx_copybreak; + + struct boom_tx_desc *tx_desc_tail; + unsigned int cur_tx, dirty_tx; + struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ - /* PCI configuration space information. */ - struct pci_dev *pdev; - char *cb_fn_base; /* CardBus function status addr space. */ - - /* Some values here only for performance evaluation and path-coverage */ - int rx_nocopy, rx_copy, queued_packet, rx_csumhits; - int card_idx; + long last_reset; + spinlock_t window_lock; + struct net_device_stats stats; + char *cb_fn_base; /* CardBus function status addr space. */ + int msg_level; + int chip_id, drv_flags; + struct pci_dev *pci_dev; /* PCI configuration space information. */ /* The remainder are related to chip state, mostly media selection. */ - struct timer_list timer; /* Media selection timer. */ - struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:4, /* Passed-in media type. */ + int multicast_filter_limit; + int max_interrupt_work; + int rx_mode; + struct timer_list timer; /* Media selection timer. */ + int options; /* User-settable misc. driver options. */ + unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ + full_duplex:1, medialock:1, autoselect:1, + bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ - partner_flow_ctrl:1, /* Partner supports flow control */ - has_nway:1, - enable_wol:1, /* Wake-on-LAN is enabled */ - pm_state_valid:1, /* power_state[] has sane contents */ - open:1, - medialock:1, - must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ - int drv_flags; + hw_csums:1, /* Has hardware checksums. */ + tx_full:1, restart_tx:1, + restore_intr_mask:1, + polling:1; u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ + u16 wn3_mac_ctrl; /* Current settings. */ u16 capabilities, info1, info2; /* Various, from EEPROM. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */ - u16 deferred; /* Resend these interrupts when we - * bale from the ISR */ - u16 io_size; /* Size of PCI region (for release_region) */ - spinlock_t lock; /* Serialise access to device & its vortex_private */ - spinlock_t mdio_lock; /* Serialise access to mdio hardware */ - u32 power_state[16]; }; /* The action to take with a media selection timer tick. @@ -803,9 +574,9 @@ static struct media_table { char *name; unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ - mask:8, /* The transceiver-present bit in Wn3_Config.*/ - next:8; /* The media type to try next. */ - int wait; /* Time before we check media status. */ + mask:8, /* The transceiver-present bit in Wn3_Config.*/ + next:8; /* The media type to try next. */ + int wait; /* Time before we check media status. */ } media_tbl[] = { { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, @@ -820,319 +591,311 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chip_idx, int card_idx); -static void vortex_up(struct net_device *dev); -static void vortex_down(struct net_device *dev); +#if ! defined(CARDBUS) && ! defined(USE_MEM_OPS) +static int eisa_scan(struct net_device *dev); +#endif static int vortex_open(struct net_device *dev); +static void set_media_type(struct net_device *dev); +static void activate_xcvr(struct net_device *dev); +static void start_operation(struct net_device *dev); +static void start_operation1(struct net_device *dev); static void mdio_sync(long ioaddr, int bits); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *vp, int phy_id, int location, int value); +static int mdio_read(long ioaddr, int phy_id, int location); +static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); -static void rx_oom_timer(unsigned long arg); +static void vortex_tx_timeout(struct net_device *dev); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int vortex_close(struct net_device *dev); -static void dump_tx_ring(struct net_device *dev); static void update_stats(long ioaddr, struct net_device *dev); static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void vortex_tx_timeout(struct net_device *dev); +#if defined(NO_PCI) +#define acpi_set_WOL(dev) do {} while(0); +#define acpi_wake(pci_dev) do {} while(0); +#define acpi_set_pwr_state(pci_dev, state) do {} while(0); +#else static void acpi_set_WOL(struct net_device *dev); +#endif -/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ -/* Option count limit only -- unlimited interfaces are supported. */ -#define MAX_UNITS 8 -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}; -static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* #define dev_alloc_skb dev_alloc_skb_debug */ -/* A list of all installed Vortex EISA devices, for removing the driver module. */ -static struct net_device *root_vortex_eisa_dev; +/* A list of all installed Vortex devices, for removing the driver module. */ +static struct net_device *root_vortex_dev = NULL; -/* Variables to work-around the Compaq PCI BIOS32 problem. */ -static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900; -static int vortex_cards_found; +#ifdef MODULE +#ifdef CARDBUS -#ifdef CONFIG_PM +#include -static int vortex_suspend (struct pci_dev *pdev, u32 state) +static dev_node_t *vortex_attach(dev_locator_t *loc) { - struct net_device *dev = pci_get_drvdata(pdev); + u32 io, pci_id; + u8 bus, devfn, irq; + struct net_device *dev; + int chip_idx; - if (dev && dev->priv) { - if (netif_running(dev)) { - netif_device_detach(dev); - vortex_down(dev); - } + if (loc->bus != LOC_PCI) return NULL; + bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; + pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); + pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &pci_id); + printk(KERN_INFO "vortex_attach(bus %d, function %d, device %8.8x)\n", + bus, devfn, pci_id); + io &= ~3; + if (io == 0 || irq == 0) { + printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " + "assigned an %s.\n" KERN_ERR " It will not be activated.\n", + io == 0 ? "I/O address" : "IRQ"); + return NULL; + } + for (chip_idx = 0; pci_tbl[chip_idx].id.pci; chip_idx++) + if ((pci_id & pci_tbl[chip_idx].id.pci_mask) == + pci_tbl[chip_idx].id.pci) + break; + if (pci_tbl[chip_idx].id.pci == 0) { /* Compiled out! */ + printk(KERN_INFO "Unable to match chip type %8.8x in " + "vortex_attach().\n", pci_id); + return NULL; } - return 0; + dev = vortex_probe1(pci_find_slot(bus, devfn), NULL, io, irq, chip_idx, MAX_UNITS+1); + if (dev) { + dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); + strcpy(node->dev_name, dev->name); + node->major = node->minor = 0; + node->next = NULL; + MOD_INC_USE_COUNT; + return node; + } + return NULL; } -static int vortex_resume (struct pci_dev *pdev) +static void vortex_detach(dev_node_t *node) { - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev && dev->priv) { - if (netif_running(dev)) { - vortex_up(dev); - netif_device_attach(dev); - } + struct net_device **devp, **next; + printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name); + for (devp = &root_vortex_dev; *devp; devp = next) { + next = &((struct vortex_private *)(*devp)->priv)->next_module; + if (strcmp((*devp)->name, node->dev_name) == 0) break; + } + if (*devp) { + struct net_device *dev = *devp; + struct vortex_private *vp = dev->priv; + if (dev->flags & IFF_UP) + dev_close(dev); + dev->flags &= ~(IFF_UP|IFF_RUNNING); + unregister_netdev(dev); + if (vp->cb_fn_base) iounmap(vp->cb_fn_base); + kfree(dev); + *devp = *next; + kfree(vp->priv_addr); + kfree(node); + MOD_DEC_USE_COUNT; } - return 0; } -#endif /* CONFIG_PM */ - -/* returns count found (>= 0), or negative on error */ -static int __init vortex_eisa_init (void) -{ - long ioaddr; - int rc; - int orig_cards_found = vortex_cards_found; +struct driver_operations vortex_ops = { + "3c575_cb", vortex_attach, NULL, NULL, vortex_detach +}; - /* Now check all slots of the EISA bus. */ - if (!EISA_bus) - return 0; +#endif /* Cardbus support */ - for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - int device_id; - if (request_region(ioaddr, VORTEX_TOTAL_SIZE, DRV_NAME) == NULL) - continue; +int init_module(void) +{ + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); +#ifdef CARDBUS + register_driver(&vortex_ops); + return 0; +#else +#ifndef USE_MEM_OPS + /* This is not quite correct, but both EISA and PCI cards is unlikely. */ + if (eisa_scan(0) >= 0) + return 0; +#if defined(NO_PCI) + return 0; +#endif +#endif - /* Check the standard EISA ID register for an encoded '3Com'. */ - if (inw(ioaddr + 0xC80) != 0x6d50) { - release_region (ioaddr, VORTEX_TOTAL_SIZE); - continue; - } + return pci_drv_register(&vortex_drv_id, NULL); +#endif +} - /* Check for a product that we support, 3c59{2,7} any rev. */ - device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); - if ((device_id & 0xFF00) != 0x5900) { - release_region (ioaddr, VORTEX_TOTAL_SIZE); - continue; - } +#else +int tc59x_probe(struct net_device *dev) +{ + int retval = -ENODEV; - rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, - EISA_TBL_OFFSET, vortex_cards_found); - if (rc == 0) - vortex_cards_found++; - else - release_region (ioaddr, VORTEX_TOTAL_SIZE); + /* Allow an EISA-only driver. */ +#if ! defined(NO_PCI) + if (pci_drv_register(&vortex_drv_id, dev) >= 0) { + retval = 0; + dev = 0; } +#endif +#ifndef USE_MEM_OPS + if (eisa_scan(dev) >= 0) + retval = 0; +#endif + if (retval >= 0) + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + return retval; +} +#endif /* not MODULE */ - /* Special code to work-around the Compaq PCI BIOS32 problem. */ - if (compaq_ioaddr) { - vortex_probe1(NULL, compaq_ioaddr, compaq_irq, - compaq_device_id, vortex_cards_found++); +#if ! defined(CARDBUS) && ! defined(USE_MEM_OPS) +static int eisa_scan(struct net_device *dev) +{ + int cards_found = 0; + + /* Check the slots of the EISA bus. */ + if (EISA_bus) { + static long ioaddr = 0x1000; + for ( ; ioaddr < 0x9000; ioaddr += 0x1000) { + int device_id; + if (check_region(ioaddr, VORTEX_SIZE)) + continue; + /* Check the standard EISA ID register for an encoded '3Com'. */ + if (inw(ioaddr + 0xC80) != 0x6d50) + continue; + /* Check for a product that we support, 3c59{2,7} any rev. */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) != 0x5900) + continue; + vortex_probe1(0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12, + (device_id & 0xfff0) == 0x5970 ? 5 : 4, cards_found); + dev = 0; + cards_found++; + } } - return vortex_cards_found - orig_cards_found; + return cards_found ? 0 : -ENODEV; } +#endif /* ! Cardbus */ -/* returns count (>= 0), or negative on error */ -static int __devinit vortex_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int do_eeprom_op(long ioaddr, int ee_cmd) { - int rc; + int timer; - /* wake up and enable device */ - if (pci_enable_device (pdev)) { - rc = -EIO; - } else { - rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq, - ent->driver_data, vortex_cards_found); - if (rc == 0) - vortex_cards_found++; + outw(ee_cmd, ioaddr + Wn0EepromCmd); + /* Wait for the read to take place, worst-case 162 us. */ + for (timer = 1620; timer >= 0; timer--) { + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; } - return rc; + return inw(ioaddr + Wn0EepromData); } -/* - * Start up the PCI device which is described by *pdev. - * Return 0 on success. - * - * NOTE: pdev can be NULL, for the case of an EISA driver - */ -static int __devinit vortex_probe1(struct pci_dev *pdev, - long ioaddr, int irq, - int chip_idx, int card_idx) +static void *vortex_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_idx, int find_cnt) { + struct net_device *dev; struct vortex_private *vp; + void *priv_mem; int option; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i, step; - struct net_device *dev; - static int printed_version; - int retval, print_info; - struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx]; - char *print_name; - - if (!printed_version) { - printk (version); - printed_version = 1; - } - - print_name = pdev ? pdev->slot_name : "3c59x"; - - dev = alloc_etherdev(sizeof(*vp)); - retval = -ENOMEM; - if (!dev) { - printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); - goto out; - } - SET_MODULE_OWNER(dev); - vp = dev->priv; + int ee_read_cmd; + int drv_flags = pci_tbl[chip_idx].drv_flags; + int i; - /* The lower four bits are the media type. */ - if (dev->mem_start) { - /* - * The 'options' param is passed in as the third arg to the - * LILO 'ether=' argument for non-modular use - */ - option = dev->mem_start; + dev = init_etherdev(init_dev, 0); + if (!dev) + return NULL; + +#if ! defined(NO_PCI) + /* Check the PCI latency value. On the 3c590 series the latency timer + must be set to the maximum value to avoid data corruption that occurs + when the timer expires during a transfer. This bug exists the Vortex + chip only. */ + if (pdev) { + u8 pci_latency; + u8 new_latency = (drv_flags & IS_VORTEX) ? 248 : 32; + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < new_latency) { + printk(KERN_INFO "%s: Overriding PCI latency" + " timer (CFLT) setting of %d, new value is %d.\n", + dev->name, pci_latency, new_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); + } } - else if (card_idx < MAX_UNITS) - option = options[card_idx]; - else - option = -1; +#endif + + printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", + dev->name, pci_tbl[chip_idx].name, ioaddr); - if (option > 0) { - if (option & 0x8000) - vortex_debug = 7; - if (option & 0x4000) - vortex_debug = 2; - if (option & 0x0400) - vp->enable_wol = 1; - } - - print_info = (vortex_debug > 1); - if (print_info) - printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); - - printk(KERN_INFO "%s: 3Com %s %s at 0x%lx. Vers " DRV_VERSION "\n", - print_name, - pdev ? "PCI" : "EISA", - vci->name, - ioaddr); + /* Make certain elements e.g. descriptor lists are aligned. */ + priv_mem = kmalloc(sizeof(*vp) + PRIV_ALIGN, GFP_KERNEL); + /* Check for the very unlikely case of no memory. */ + if (priv_mem == NULL) { + printk(" INTERFACE MEMORY ALLOCATION FAILURE.\n"); + return NULL; + } dev->base_addr = ioaddr; dev->irq = irq; dev->mtu = mtu; - vp->drv_flags = vci->drv_flags; - vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; - vp->io_size = vci->io_size; - vp->card_idx = card_idx; - - /* module list only for EISA devices */ - if (pdev == NULL) { - vp->next_module = root_vortex_eisa_dev; - root_vortex_eisa_dev = dev; - } - /* PCI-only startup logic */ - if (pdev) { - /* EISA resources already marked, so only PCI needs to do this here */ - /* Ignore return value, because Cardbus drivers already allocate for us */ - if (request_region(ioaddr, vci->io_size, print_name) != NULL) - vp->must_free_region = 1; - - /* enable bus-mastering if necessary */ - if (vci->flags & PCI_USES_MASTER) - pci_set_master (pdev); - - if (vci->drv_flags & IS_VORTEX) { - u8 pci_latency; - u8 new_latency = 248; - - /* Check the PCI latency value. On the 3c590 series the latency timer - must be set to the maximum value to avoid data corruption that occurs - when the timer expires during a transfer. This bug exists the Vortex - chip only. */ - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - print_name, pci_latency, new_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); - } - } - } + dev->priv = vp = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN); + memset(vp, 0, sizeof(*vp)); + vp->priv_addr = priv_mem; + + vp->next_module = root_vortex_dev; + root_vortex_dev = dev; + + vp->chip_id = chip_idx; + vp->pci_dev = pdev; + vp->drv_flags = drv_flags; + vp->msg_level = (1 << debug) - 1; + vp->rx_copybreak = rx_copybreak; + vp->max_interrupt_work = max_interrupt_work; + vp->multicast_filter_limit = multicast_filter_limit; - spin_lock_init(&vp->lock); - spin_lock_init(&vp->mdio_lock); - vp->pdev = pdev; - - /* Makes sure rings are at least 16 byte aligned. */ - vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - &vp->rx_ring_dma); - retval = -ENOMEM; - if (vp->rx_ring == 0) - goto free_region; - - vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); - vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; - - /* if we are a PCI driver, we store info in pdev->driver_data - * instead of a module list */ - if (pdev) - pci_set_drvdata(pdev, dev); + /* The lower four bits are the media type. */ + if (dev->mem_start) + option = dev->mem_start; + else if (find_cnt < MAX_UNITS) + option = options[find_cnt]; + else + option = -1; - vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; - if (vp->media_override != 7) - vp->medialock = 1; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; + } else { + vp->media_override = 7; + vp->full_duplex = 0; + vp->bus_master = 0; } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + vp->full_duplex = 1; - if (card_idx < MAX_UNITS) { - if (full_duplex[card_idx] > 0) - vp->full_duplex = 1; - if (flow_ctrl[card_idx] > 0) - vp->flow_ctrl = 1; - if (enable_wol[card_idx] > 0) - vp->enable_wol = 1; - } - - vp->force_fd = vp->full_duplex; vp->options = option; + /* Read the station address from the EEPROM. */ EL3WINDOW(0); - { - int base; + /* Figure out the size and offset of the EEPROM table. + This is complicated by potential discontiguous address bits. */ - if (vci->drv_flags & EEPROM_8BIT) - base = 0x230; - else if (vci->drv_flags & EEPROM_OFFSET) - base = EEPROM_Read + 0x30; - else - base = EEPROM_Read; - - for (i = 0; i < 0x40; i++) { - int timer; - outw(base + i, ioaddr + Wn0EepromCmd); - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 10; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; - } - eeprom[i] = inw(ioaddr + Wn0EepromData); + /* Locate the opcode bits, 0xC0 or 0x300. */ + outw(0x5555, ioaddr + Wn0EepromData); + ee_read_cmd = do_eeprom_op(ioaddr, 0x80) == 0x5555 ? 0x200 : 0x80; + /* Locate the table base for CardBus cards. */ + if (do_eeprom_op(ioaddr, ee_read_cmd + 0x37) == 0x6d50) + ee_read_cmd += 0x30; + + for (i = 0; i < 0x40; i++) { + int cmd_and_addr = ee_read_cmd + i; + if (ee_read_cmd == 0xB0) { /* Correct for discontinuity. */ + int offset = 0x30 + i; + cmd_and_addr = 0x80 + (offset & 0x3f) + ((offset<<2) & 0x0f00); } + eeprom[i] = do_eeprom_op(ioaddr, cmd_and_addr); } for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; @@ -1142,134 +905,89 @@ checksum ^= eeprom[i++]; checksum = (checksum ^ (checksum >> 8)) & 0xff; } - if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) + if (checksum != 0x00 && !(drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); + for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); - if (print_info) { - for (i = 0; i < 6; i++) - printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); - } + for (i = 0; i < 6; i++) + printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); -#ifdef __sparc__ - if (print_info) - printk(", IRQ %s\n", __irq_itoa(dev->irq)); -#else - if (print_info) - printk(", IRQ %d\n", dev->irq); + printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ - if (dev->irq <= 0 || dev->irq >= NR_IRQS) + if (dev->irq <= 0) printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); -#endif - - EL3WINDOW(4); - step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; - if (print_info) { - printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" - "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], - step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); - } - - if (pdev && vci->drv_flags & HAS_CB_FNS) { - unsigned long fn_st_addr; /* Cardbus function status space */ - unsigned short n; - - fn_st_addr = pci_resource_start (pdev, 2); - if (fn_st_addr) { - vp->cb_fn_base = ioremap(fn_st_addr, 128); - retval = -ENOMEM; - if (!vp->cb_fn_base) - goto free_ring; - } - if (print_info) { - printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", - print_name, fn_st_addr, vp->cb_fn_base); - } - EL3WINDOW(2); - - n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; - if (vp->drv_flags & INVERT_LED_PWR) - n |= 0x10; - if (vp->drv_flags & INVERT_MII_PWR) - n |= 0x4000; - outw(n, ioaddr + Wn2_ResetOptions); +#if ! defined(NO_PCI) + if (drv_flags & HAS_CB_FNS) { + u32 fn_st_addr; /* Cardbus function status space */ + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &fn_st_addr); + if (fn_st_addr) + vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128); + printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p.\n", + dev->name, fn_st_addr, vp->cb_fn_base); } +#endif /* Extract our information from the EEPROM data. */ vp->info1 = eeprom[13]; vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) { + if (vp->info1 & 0x8000) vp->full_duplex = 1; - if (print_info) - printk(KERN_INFO "Full duplex capable\n"); - } + if (vp->full_duplex) + vp->medialock = 1; + + /* Turn on the transceiver. */ + activate_xcvr(dev); { - static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - unsigned int config; + char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + int i_cfg; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */ vp->available_media = 0x40; - config = inl(ioaddr + Wn3_Config); - if (print_info) { - printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config, inw(ioaddr + Wn3_Options)); - printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << RAM_SIZE(config), - RAM_WIDTH(config) ? "word" : "byte", - ram_split[RAM_SPLIT(config)], - AUTOSELECT(config) ? "autoselect/" : "", - XCVR(config) > XCVR_ExtMII ? "" : - media_tbl[XCVR(config)].name); - } - vp->default_media = XCVR(config); - if (vp->default_media == XCVR_NWAY) - vp->has_nway = 1; - vp->autoselect = AUTOSELECT(config); + i_cfg = inl(ioaddr + Wn3_Config); /* Internal Configuration */ + vp->default_media = (i_cfg >> 20) & 15; + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG " Internal config register is %8.8x, " + "transceivers %#x.\n", i_cfg, inw(ioaddr + Wn3_Options)); + printk(KERN_INFO " %dK buffer %s Rx:Tx split, %s%s interface.\n", + 8 << (i_cfg & 7), + ram_split[(i_cfg >> 16) & 3], + i_cfg & 0x01000000 ? "autoselect/" : "", + vp->default_media > XCVR_ExtMII ? "" : + media_tbl[vp->default_media].name); + vp->autoselect = i_cfg & 0x01000000 ? 1 : 0; } if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver type %d (%s).\n", - print_name, vp->media_override, - media_tbl[vp->media_override].name); + printk(KERN_INFO " Media override to transceiver type %d (%s).\n", + vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else dev->if_port = vp->default_media; - if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { + if ((vp->available_media & 0x41) || (drv_flags & HAS_NWAY) || + dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int phy, phy_idx = 0; EL3WINDOW(4); mii_preamble_required++; - mii_preamble_required++; - mdio_read(dev, 24, 1); - for (phy = 0; phy < 32 && phy_idx < 1; phy++) { - int mii_status, phyx; - - /* - * For the 3c905CX we look at index 24 first, because it bogusly - * reports an external PHY at all indices - */ - if (phy == 0) - phyx = 24; - else if (phy <= 24) - phyx = phy - 1; - else - phyx = phy; - mii_status = mdio_read(dev, phyx, 1); - if (mii_status && mii_status != 0xffff) { + mdio_sync(ioaddr, 32); + mdio_read(ioaddr, 24, 1); + for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { + int mii_status, phyx = phy & 0x1f; + mii_status = mdio_read(ioaddr, phyx, 1); + if ((mii_status & 0xf800) && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; - if (print_info) { - printk(KERN_INFO " MII transceiver found at address %d," - " status %4x.\n", phyx, mii_status); - } + printk(KERN_INFO " MII transceiver found at address %d," + " status %4x.\n", phyx, mii_status); if ((mii_status & 0x0040) == 0) mii_preamble_required++; } @@ -1279,237 +997,108 @@ printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { - vp->advertising = mdio_read(dev, vp->phys[0], 4); + if (mii_preamble_required == 0 && + mdio_read(ioaddr, vp->phys[0], 1) == 0) { + printk(KERN_INFO "%s: MII transceiver has preamble bug.\n", + dev->name); + mii_preamble_required = 1; + } + vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; - mdio_write(dev, vp->phys[0], 4, vp->advertising); + mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); } } + } else { + /* We will emulate MII management. */ + vp->phys[0] = 32; } if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; - if (print_info) { - printk(KERN_INFO " Enabling bus-master transmits and %s receives.\n", - (vp->info2 & 1) ? "early" : "whole-frame" ); - } + printk(KERN_INFO" Using bus-master transmits and %s receives.\n", + (vp->info2 & 1) ? "early" : "whole-frame" ); vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; - vp->bus_master = 0; /* AKPM: vortex only */ - } - - /* The 3c59x-specific entries in the device structure. */ - dev->open = vortex_open; - if (vp->full_bus_master_tx) { - dev->hard_start_xmit = boomerang_start_xmit; - /* Actually, it still should work with iommu. */ - dev->features |= NETIF_F_SG; - if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) || - (hw_checksums[card_idx] == 1)) { - dev->features |= NETIF_F_IP_CSUM; - } - } else { - dev->hard_start_xmit = vortex_start_xmit; - } - - if (print_info) { - printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", - print_name, - (dev->features & NETIF_F_SG) ? "en":"dis", - (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); - } - - dev->stop = vortex_close; - dev->get_stats = vortex_get_stats; - dev->do_ioctl = vortex_ioctl; - dev->set_multicast_list = set_rx_mode; - dev->tx_timeout = vortex_tx_timeout; - dev->watchdog_timeo = (watchdog * HZ) / 1000; - if (pdev && vp->enable_wol) { - vp->pm_state_valid = 1; - pci_save_state(vp->pdev, vp->power_state); - acpi_set_WOL(dev); } - retval = register_netdev(dev); - if (retval == 0) - return 0; -free_ring: - pci_free_consistent(pdev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, - vp->rx_ring_dma); -free_region: - if (vp->must_free_region) - release_region(ioaddr, vci->io_size); - kfree (dev); - printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); -out: - return retval; -} + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); -static void -issue_and_wait(struct net_device *dev, int cmd) -{ - int i; + /* The 3c59x-specific entries in the device structure. */ + dev->open = &vortex_open; + dev->hard_start_xmit = &vortex_start_xmit; + dev->stop = &vortex_close; + dev->get_stats = &vortex_get_stats; + dev->do_ioctl = &vortex_ioctl; + dev->set_multicast_list = &set_rx_mode; - outw(cmd, dev->base_addr + EL3_CMD); - for (i = 0; i < 2000; i++) { - if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) - return; - } - - /* OK, that didn't work. Do it the slow way. One second */ - for (i = 0; i < 100000; i++) { - if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { - if (vortex_debug > 1) - printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", - dev->name, cmd, i * 10); - return; - } - udelay(10); - } - printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", - dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); + return dev; } -static void -vortex_up(struct net_device *dev) + +static int vortex_open(struct net_device *dev) { - long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; - unsigned int config; + long ioaddr = dev->base_addr; int i; - if (vp->pdev && vp->enable_wol) { - pci_set_power_state(vp->pdev, 0); /* Go active */ - pci_restore_state(vp->pdev, vp->power_state); - } + MOD_INC_USE_COUNT; - /* Before initializing select the active media port. */ - EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); + acpi_wake(vp->pci_dev); + vp->window_lock = SPIN_LOCK_UNLOCKED; + activate_xcvr(dev); + /* Before initializing select the active media port. */ if (vp->media_override != 7) { - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + dev->name, vp->media_override, + media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { - if (vp->has_nway) { - if (vortex_debug > 1) - printk(KERN_INFO "%s: using NWAY device table, not %d\n", - dev->name, dev->if_port); + if (vp->drv_flags & HAS_NWAY) dev->if_port = XCVR_NWAY; - } else { + else { /* Find first available media type, starting with 100baseTx. */ dev->if_port = XCVR_100baseTx; while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; - if (vortex_debug > 1) - printk(KERN_INFO "%s: first available media type: %s\n", - dev->name, media_tbl[dev->if_port].name); } - } else { + } else dev->if_port = vp->default_media; - if (vortex_debug > 1) - printk(KERN_INFO "%s: using default media %s\n", - dev->name, media_tbl[dev->if_port].name); - } - - init_timer(&vp->timer); - vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - vp->timer.data = (unsigned long)dev; - vp->timer.function = vortex_timer; /* timer handler */ - add_timer(&vp->timer); - init_timer(&vp->rx_oom_timer); - vp->rx_oom_timer.data = (unsigned long)dev; - vp->rx_oom_timer.function = rx_oom_timer; - - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - - vp->full_duplex = vp->force_fd; - config = BFINS(config, dev->if_port, 20, 4); - if (vortex_debug > 6) - printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); - outl(config, ioaddr + Wn3_Config); + if (! vp->medialock) + vp->full_duplex = 0; - if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { - int mii_reg1, mii_reg5; - EL3WINDOW(4); - /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(dev, vp->phys[0], 1); - mii_reg5 = mdio_read(dev, vp->phys[0], 5); - if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) { - netif_carrier_off(dev); /* No MII device or no link partner report */ - } else { - if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ - || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ - vp->full_duplex = 1; - netif_carrier_on(dev); - } - vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); - if (vortex_debug > 1) - printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " info1 %04x, setting %s-duplex.\n", - dev->name, vp->phys[0], - mii_reg1, mii_reg5, - vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half"); - EL3WINDOW(3); - } + vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete| + (vp->full_bus_master_tx ? DownComplete : TxAvailable) | + (vp->full_bus_master_rx ? UpComplete : RxComplete) | + (vp->bus_master ? DMADone : 0); + vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete | + StatsFull | HostError | TxComplete | IntReq + | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; - /* Set the full-duplex bit. */ - outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - - if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", - dev->name, config); - } - - issue_and_wait(dev, TxReset); - /* - * Don't reset the PHY - that upsets autonegotiation during DHCP operations. - */ - issue_and_wait(dev, RxReset|0x04); + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG "%s: Initial media type %s %s-duplex.\n", + dev->name, media_tbl[dev->if_port].name, + vp->full_duplex ? "full":"half"); - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); + set_media_type(dev); + start_operation(dev); - if (vortex_debug > 1) { - EL3WINDOW(4); - printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); + /* Use the now-standard shared IRQ implementation. */ + if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; } - /* Set the station address and mask in window 2 each time opened. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - for (; i < 12; i+=2) - outw(0, ioaddr + i); - - if (vp->cb_fn_base) { - unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; - if (vp->drv_flags & INVERT_LED_PWR) - n |= 0x10; - if (vp->drv_flags & INVERT_MII_PWR) - n |= 0x4000; - outw(n, ioaddr + Wn2_ResetOptions); - } + spin_lock(&vp->window_lock); - if (dev->if_port == XCVR_10base2) - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - if (dev->if_port != XCVR_NWAY) { + if (vp->msg_level & NETIF_MSG_IFUP) { EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n", + dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } /* Switch to the stats window, and clear all stats by reading. */ @@ -1527,110 +1116,223 @@ /* Switch to register set 7 for normal use. */ EL3WINDOW(7); +#if defined(CONFIG_VLAN) + /* If this value is set no MTU adjustment is needed for 802.1Q. */ + outw(0x8100, ioaddr + Wn7_VLAN_EtherType); +#endif + spin_unlock(&vp->window_lock); if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; + /* Use 1518/+18 if the CRC is transferred. */ + vp->rx_buf_sz = dev->mtu + 14; + if (vp->rx_buf_sz < PKT_BUF_SZ) + vp->rx_buf_sz = PKT_BUF_SZ; + /* Initialize the RxEarly register as recommended. */ outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); outl(0x0020, ioaddr + PktStatus); - outl(vp->rx_ring_dma, ioaddr + UpListPtr); + for (i = 0; i < RX_RING_SIZE; i++) { + vp->rx_ring[i].length = cpu_to_le32(vp->rx_buf_sz | LAST_FRAG); + vp->rx_ring[i].status = 0; + vp->rx_ring[i].next = virt_to_le32desc(&vp->rx_ring[i+1]); + vp->rx_skbuff[i] = 0; + } + /* Wrap the ring. */ + vp->rx_head_desc = &vp->rx_ring[0]; + vp->rx_ring[i-1].next = virt_to_le32desc(&vp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(vp->rx_buf_sz); + vp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + vp->rx_ring[i].addr = virt_to_le32desc(skb->tail); + } + outl(virt_to_bus(vp->rx_head_desc), ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ + dev->hard_start_xmit = &boomerang_start_xmit; vp->cur_tx = vp->dirty_tx = 0; - if (vp->drv_flags & IS_BOOMERANG) - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ - /* Clear the Rx, Tx rings. */ - for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ - vp->rx_ring[i].status = 0; + vp->tx_desc_tail = &vp->tx_ring[TX_RING_SIZE - 1]; + if (vp->drv_flags & IS_BOOMERANG) { + /* Room for a packet, to avoid long DownStall delays. */ + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + } else if (vp->drv_flags & HAS_V2_TX) + outb(20, ioaddr + DownPollRate); + + /* Clear the Tx ring. */ for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); + vp->restart_tx = 1; } /* Set receiver mode: presumably accept b-case and phys addr only. */ + vp->rx_mode = 0; set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ -// issue_and_wait(dev, SetTxStart|0x07ff); - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete| - (vp->full_bus_master_tx ? DownComplete : TxAvailable) | - (vp->full_bus_master_rx ? UpComplete : RxComplete) | - (vp->bus_master ? DMADone : 0); - vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | - (vp->full_bus_master_rx ? 0 : RxComplete) | - StatsFull | HostError | TxComplete | IntReq - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; - outw(vp->status_enable, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(vp->intr_enable, ioaddr + EL3_CMD); - if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); - netif_start_queue (dev); + start_operation1(dev); + + init_timer(&vp->timer); + vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; + vp->timer.data = (unsigned long)dev; + vp->timer.function = &vortex_timer; /* timer handler */ + add_timer(&vp->timer); + + return 0; } -static int -vortex_open(struct net_device *dev) +static void set_media_type(struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int i; - int retval; + long ioaddr = dev->base_addr; + int i_cfg; - /* Use the now-standard shared IRQ implementation. */ - if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? - &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { - printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); - goto out; + EL3WINDOW(3); + i_cfg = inl(ioaddr + Wn3_Config); + i_cfg &= ~0x00f00000; + if (vp->drv_flags & HAS_NWAY) + outl(i_cfg | 0x00800000, ioaddr + Wn3_Config); + else + outl(i_cfg | (dev->if_port << 20), ioaddr + Wn3_Config); + + if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { + int mii_reg1, mii_reg5; + EL3WINDOW(4); + /* Read BMSR (reg1) only to clear old status. */ + mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); + mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) + ; /* No MII device or no link partner report */ + else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ + || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ + vp->full_duplex = 1; + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," + " setting %s-duplex.\n", dev->name, vp->phys[0], + mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); + EL3WINDOW(3); + } + if (dev->if_port == XCVR_10base2) + /* Start the thinnet transceiver. We should really wait 50ms...*/ + outw(StartCoax, ioaddr + EL3_CMD); + EL3WINDOW(4); + if (dev->if_port != XCVR_NWAY) { + outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); } + /* Do we require link beat to transmit? */ + if (vp->info1 & 0x4000) + outw(inw(ioaddr + Wn4_Media) & ~Media_Lnk, ioaddr + Wn4_Media); - if (vp->full_bus_master_rx) { /* Boomerang bus master. */ - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); - vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); - skb = dev_alloc_skb(PKT_BUF_SZ); - vp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* Bad news! */ - skb->dev = dev; /* Mark as being used by this device. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); - } - if (i != RX_RING_SIZE) { - int j; - printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); - for (j = 0; j < i; j++) { - if (vp->rx_skbuff[j]) { - dev_kfree_skb(vp->rx_skbuff[j]); - vp->rx_skbuff[j] = 0; - } - } - retval = -ENOMEM; - goto out_free_irq; + /* Set the full-duplex and oversized frame bits. */ + EL3WINDOW(3); + + vp->wn3_mac_ctrl = vp->full_duplex ? 0x0120 : 0; + if (dev->mtu > 1500) + vp->wn3_mac_ctrl |= (dev->mtu == 1504 ? 0x0400 : 0x0040); + outb(vp->wn3_mac_ctrl, ioaddr + Wn3_MAC_Ctrl); + + if (vp->drv_flags & HAS_V2_TX) + outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize); +} + +static void activate_xcvr(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + int reset_opts; + + /* Correct some magic bits. */ + EL3WINDOW(2); + reset_opts = inw(ioaddr + Wn2_ResetOptions); + if (vp->drv_flags & INVERT_LED_PWR) + reset_opts |= 0x0010; + if (vp->drv_flags & MII_XCVR_PWR) + reset_opts |= 0x4000; + outw(reset_opts, ioaddr + Wn2_ResetOptions); + if (vp->drv_flags & WN0_XCVR_PWR) { + EL3WINDOW(0); + outw(0x0900, ioaddr); + } +} + +static void start_operation(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + outw(TxReset, ioaddr + EL3_CMD); + for (i = 2000; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + + outw(RxReset | 0x04, ioaddr + EL3_CMD); + /* Wait a few ticks for the RxReset command to complete. */ + for (i = 0; i < 200000; i++) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + if (i >= 200 && (vp->msg_level & NETIF_MSG_DRV)) + printk(KERN_DEBUG "%s: Rx Reset took an unexpectedly long time" + " to finish, %d ticks.\n", + dev->name, i); + + outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); + /* Handle VLANs and jumbo frames. */ + if ((vp->drv_flags & HAS_V2_TX) && dev->mtu > 1500) { + EL3WINDOW(3); + outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize); + if (dev->mtu > 2033) { + outl(inl(ioaddr + Wn3_Config) | 0x0000C000, ioaddr + Wn3_Config); + outw(SetTxStart + (2000>>2), ioaddr + EL3_CMD); } - /* Wrap the ring. */ - vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); } + /* Reset the station address and mask. */ + EL3WINDOW(2); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + for (; i < 12; i+=2) + outw(0, ioaddr + i); + if (vp->drv_flags & IS_BOOMERANG) { + /* Room for a packet, to avoid long DownStall delays. */ + outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + } else if (vp->drv_flags & HAS_V2_TX) { + outb(20, ioaddr + DownPollRate); + vp->restart_tx = 1; + } +} - vortex_up(dev); - return 0; +static void start_operation1(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; -out_free_irq: - free_irq(dev->irq, dev); -out: - if (vortex_debug > 1) - printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval); - return retval; + if (vp->full_bus_master_rx) { /* post-Vortex bus master. */ + /* Initialize the RxEarly register as recommended. */ + outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); + outl(0x0020, ioaddr + PktStatus); + outl(virt_to_bus(&vp->rx_ring[vp->cur_rx % RX_RING_SIZE]), + ioaddr + UpListPtr); + } + + outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + /* Allow status bits to be seen. */ + outw(vp->status_enable, ioaddr + EL3_CMD); + /* Ack all pending events, and set active indicator mask. */ + outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + ioaddr + EL3_CMD); + outw(vp->intr_enable, ioaddr + EL3_CMD); + if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ + writel(0x8000, vp->cb_fn_base + 4); + netif_start_tx_queue(dev); } -static void -vortex_timer(unsigned long data) +static void vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; @@ -1639,14 +1341,36 @@ int ok = 0; int media_status, mii_status, old_window; - if (vortex_debug > 2) { - printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", - dev->name, media_tbl[dev->if_port].name); - printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); + if (vp->msg_level & NETIF_MSG_TIMER) + printk(KERN_DEBUG "%s: Media selection timer tick happened, " + "%s %s duplex.\n", + dev->name, media_tbl[dev->if_port].name, + vp->full_duplex ? "full" : "half"); + + /* This only works with bus-master (non-3c590) chips. */ + if (vp->cur_tx - vp->dirty_tx > 1 && + (jiffies - dev->trans_start) > TX_TIMEOUT) { + /* Check for blocked interrupts. */ + if (inw(ioaddr + EL3_STATUS) & IntLatch) { + /* We have a blocked IRQ line. This should never happen, but + we recover as best we can.*/ + if ( ! vp->polling) { + if (jiffies - vp->last_reset > 10*HZ) { + printk(KERN_ERR "%s: IRQ %d is physically blocked! " + "Failing back to low-rate polling.\n", + dev->name, dev->irq); + vp->last_reset = jiffies; + } + vp->polling = 1; + } + vortex_interrupt(dev->irq, dev, 0); + next_tick = jiffies + 2; + } else { + vortex_tx_timeout(dev); + vp->last_reset = jiffies; + } } - if (vp->medialock) - goto leave_media_alone; disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1654,72 +1378,64 @@ switch (dev->if_port) { case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { - netif_carrier_on(dev); ok = 1; - if (vortex_debug > 1) + if (vp->msg_level & NETIF_MSG_LINK) printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); - } else if (vortex_debug > 1) { - netif_carrier_off(dev); - printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n", + } else if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); - } break; case XCVR_MII: case XCVR_NWAY: - { - mii_status = mdio_read(dev, vp->phys[0], 1); - ok = 1; - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", - dev->name, mii_status); - if (mii_status & BMSR_LSTATUS) { - int mii_reg5 = mdio_read(dev, vp->phys[0], 5); - if (! vp->force_fd && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || - (mii_reg5 & 0x01C0) == 0x0040; - if (vp->full_duplex != duplex) { - vp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII " - "#%d link partner capability of %4.4x.\n", - dev->name, vp->full_duplex ? "full" : "half", - vp->phys[0], mii_reg5); - /* Set the full-duplex bit. */ - EL3WINDOW(3); - outw( (vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - if (vortex_debug > 1) - printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n"); - /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ - } - } - netif_carrier_on(dev); - } else { - netif_carrier_off(dev); - } - } - break; - default: /* Other media types handled by Tx timeouts. */ - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n", - dev->name, media_tbl[dev->if_port].name, media_status); + mii_status = mdio_read(ioaddr, vp->phys[0], 1); + ok = 1; + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", + dev->name, mii_status); + if (mii_status & 0x0004) { + int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); + if (! vp->medialock && mii_reg5 != 0xffff) { + int duplex = (mii_reg5&0x0100) || + (mii_reg5 & 0x01C0) == 0x0040; + if (vp->full_duplex != duplex) { + vp->full_duplex = duplex; + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_INFO "%s: Setting %s-duplex based on " + "MII #%d link partner capability of %4.4x.\n", + dev->name, vp->full_duplex ? "full" : "half", + vp->phys[0], mii_reg5); + /* Set the full-duplex bit. */ + EL3WINDOW(3); + if (duplex) + vp->wn3_mac_ctrl |= 0x120; + else + vp->wn3_mac_ctrl &= ~0x120; + outb(vp->wn3_mac_ctrl, ioaddr + Wn3_MAC_Ctrl); + } + next_tick = 60*HZ; + } + } + break; + default: /* Other media types handled by Tx timeouts. */ + if (vp->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } if ( ! ok) { - unsigned int config; + int i_cfg; do { dev->if_port = media_tbl[dev->if_port].next; } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); if (dev->if_port == XCVR_Default) { /* Go back to default. */ dev->if_port = vp->default_media; - if (vortex_debug > 1) + if (vp->msg_level & NETIF_MSG_LINK) printk(KERN_DEBUG "%s: Media selection failing, using default " "%s port.\n", dev->name, media_tbl[dev->if_port].name); } else { - if (vortex_debug > 1) + if (vp->msg_level & NETIF_MSG_LINK) printk(KERN_DEBUG "%s: Media selection failed, now trying " "%s port.\n", dev->name, media_tbl[dev->if_port].name); @@ -1729,27 +1445,25 @@ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); - config = BFINS(config, dev->if_port, 20, 4); - outl(config, ioaddr + Wn3_Config); + i_cfg = inl(ioaddr + Wn3_Config); + i_cfg &= ~0x00f00000; + i_cfg |= (dev->if_port << 20); + outl(i_cfg, ioaddr + Wn3_Config); outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); - if (vortex_debug > 1) - printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); - /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ } EL3WINDOW(old_window); enable_irq(dev->irq); + if (vp->restore_intr_mask) + outw(FakeIntr, ioaddr + EL3_CMD); -leave_media_alone: - if (vortex_debug > 2) + if (vp->msg_level & NETIF_MSG_TIMER) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); - mod_timer(&vp->timer, RUN_AT(next_tick)); - if (vp->deferred) - outw(FakeIntr, ioaddr + EL3_CMD); + vp->timer.expires = jiffies + next_tick; + add_timer(&vp->timer); return; } @@ -1757,61 +1471,81 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; + int tx_status = inb(ioaddr + TxStatus); + int intr_status = inw(ioaddr + EL3_STATUS); + int j; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); - EL3WINDOW(4); - printk(KERN_ERR " diagnostics: net %04x media %04x dma %8.8x.\n", - inw(ioaddr + Wn4_NetDiag), inw(ioaddr + Wn4_Media), - inl(ioaddr + PktStatus)); + dev->name, tx_status, intr_status); /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) + if ((tx_status & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); - if (inw(ioaddr + EL3_STATUS) & IntLatch) { + if (intr_status & IntLatch) { printk(KERN_ERR "%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); - /* Bad idea here.. but we might as well handle a few events. */ - { - /* - * Block interrupts because vortex_interrupt does a bare spin_lock() - */ - unsigned long flags; - local_irq_save(flags); - if (vp->full_bus_master_tx) - boomerang_interrupt(dev->irq, dev, 0); - else - vortex_interrupt(dev->irq, dev, 0); - local_irq_restore(flags); - } + /* Race condition possible, but we handle a few events. */ + vortex_interrupt(dev->irq, dev, 0); } - if (vortex_debug > 0) - dump_tx_ring(dev); - - issue_and_wait(dev, TxReset); +#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300 + if (vp->full_bus_master_tx) { + int i; + printk(KERN_DEBUG " Flags: bus-master %d full %d dirty %d " + "current %d restart_tx %d.\n", + vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx, + vp->restart_tx); + printk(KERN_DEBUG " Transmit list %8.8x vs. %p, packet ID %2.2x.\n", + (int)inl(ioaddr + DownListPtr), + &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE], inb(ioaddr + 0x18)); + for (i = 0; i < TX_RING_SIZE; i++) { + printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, + &vp->tx_ring[i], + le32_to_cpu(vp->tx_ring[i].length), + le32_to_cpu(vp->tx_ring[i].status)); + } + } +#endif + outw(TxReset, ioaddr + EL3_CMD); + for (j = 200; j >= 0 ; j--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; vp->stats.tx_errors++; + if (vp->full_bus_master_tx) { - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); + if (vp->drv_flags & HAS_V2_TX) + outb(20, ioaddr + DownPollRate); + if (vp->msg_level & NETIF_MSG_TX_ERR) + printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", + dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) - outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), + outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]), ioaddr + DownListPtr); - if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) - netif_wake_queue (dev); - if (vp->drv_flags & IS_BOOMERANG) + else + vp->restart_tx = 1; + if (vp->drv_flags & IS_BOOMERANG) { + /* Room for a packet, to avoid long DownStall delays. */ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); + outw(DownUnstall, ioaddr + EL3_CMD); + } else { + if (dev->mtu > 2033) + outw(SetTxStart + (2000>>2), ioaddr + EL3_CMD); + } + + if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_QUEUE_LEN - 1)) { + vp->tx_full = 0; + netif_unpause_tx_queue(dev); + } } else { + netif_unpause_tx_queue(dev); vp->stats.tx_dropped++; - netif_wake_queue(dev); } - + /* Issue Tx Enable */ outw(TxEnable, ioaddr + EL3_CMD); dev->trans_start = jiffies; - + /* Switch to register set 7 for normal use. */ EL3WINDOW(7); } @@ -1825,46 +1559,32 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int do_tx_reset = 0, reset_mask = 0; - unsigned char tx_status = 0; - - if (vortex_debug > 2) { - printk(KERN_ERR "%s: vortex_error(), status=0x%x\n", dev->name, status); - } + int do_tx_reset = 0; + int i; if (status & TxComplete) { /* Really "TxError" for us. */ - tx_status = inb(ioaddr + TxStatus); + unsigned char tx_status = inb(ioaddr + TxStatus); /* Presumably a tx-timeout. We must merely re-enable. */ - if (vortex_debug > 2 - || (tx_status != 0x88 && vortex_debug > 0)) { - printk(KERN_ERR "%s: Transmit error, Tx status register %2.2x.\n", + if (vp->msg_level & NETIF_MSG_TX_ERR) + printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n", dev->name, tx_status); - if (tx_status == 0x82) { - printk(KERN_ERR "Probably a duplex mismatch. See " - "Documentation/networking/vortex.txt\n"); - } - dump_tx_ring(dev); - } if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; outb(0, ioaddr + TxStatus); - if (tx_status & 0x30) { /* txJabber or txUnderrun */ - do_tx_reset = 1; - } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ + if (tx_status & 0x30) do_tx_reset = 1; - reset_mask = 0x0108; /* Reset interface logic, but not download logic */ - } else { /* Merely re-enable the transmitter. */ + else { /* Merely re-enable the transmitter. */ outw(TxEnable, ioaddr + EL3_CMD); + vp->restart_tx = 1; } } - if (status & RxEarly) { /* Rx early is unused. */ vortex_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & StatsFull) { /* Empty statistics. */ - static int DoneDidThat; - if (vortex_debug > 4) + static int DoneDidThat = 0; + if (vp->msg_level & NETIF_MSG_MISC) printk(KERN_DEBUG "%s: Updating stats.\n", dev->name); update_stats(ioaddr, dev); /* HACK: Disable statistics as an interrupt source. */ @@ -1875,7 +1595,6 @@ "stats as an interrupt source.\n", dev->name); EL3WINDOW(5); outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); - vp->intr_enable &= ~StatsFull; EL3WINDOW(7); DoneDidThat++; } @@ -1883,73 +1602,99 @@ if (status & IntReq) { /* Restore all interrupt sources. */ outw(vp->status_enable, ioaddr + EL3_CMD); outw(vp->intr_enable, ioaddr + EL3_CMD); + vp->restore_intr_mask = 0; } if (status & HostError) { u16 fifo_diag; EL3WINDOW(4); fifo_diag = inw(ioaddr + Wn4_FIFODiag); - printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", - dev->name, fifo_diag); + if (vp->msg_level & NETIF_MSG_DRV) + printk(KERN_ERR "%s: Host error, status %x, FIFO diagnostic " + "register %4.4x.\n", + dev->name, status, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { int bus_status = inl(ioaddr + PktStatus); /* 0x80000000 PCI master abort. */ /* 0x40000000 PCI target abort. */ - if (vortex_debug) - printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status); - - /* In this case, blow the card away */ - vortex_down(dev); - issue_and_wait(dev, TotalReset | 0xff); - vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */ + outw(TotalReset | 0xff, ioaddr + EL3_CMD); + for (i = 2000; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + if (vp->msg_level & NETIF_MSG_DRV) + printk(KERN_ERR "%s: PCI bus error, bus status %8.8x, reset " + "had %d tick left.\n", + dev->name, bus_status, i); + /* Re-enable the receiver. */ + outw(RxEnable, ioaddr + EL3_CMD); + outw(TxEnable, ioaddr + EL3_CMD); + vp->restart_tx = 1; } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { - /* Reset Rx fifo and upload logic */ - issue_and_wait(dev, RxReset|0x07); + outw(RxReset | 7, ioaddr + EL3_CMD); + for (i = 200000; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + if ((vp->drv_flags & HAS_V2_TX) && dev->mtu > 1500) { + EL3WINDOW(3); + outw(dev->mtu + 14, ioaddr + Wn3_MaxPktSize); + } /* Set the Rx filter to the current state. */ + vp->rx_mode = 0; set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ outw(AckIntr | HostError, ioaddr + EL3_CMD); } } - if (do_tx_reset) { - issue_and_wait(dev, TxReset|reset_mask); + int j; + outw(TxReset, ioaddr + EL3_CMD); + for (j = 200; j >= 0 ; j--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; outw(TxEnable, ioaddr + EL3_CMD); - if (!vp->full_bus_master_tx) - netif_wake_queue(dev); + vp->restart_tx = 1; } + } + static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; + /* Block a timer-based transmit from overlapping. This happens when + packets are presumed lost, and we use this check the Tx status. */ + if (netif_pause_tx_queue(dev) != 0) { + /* This watchdog code is redundant with the media monitor timer. */ + if (jiffies - dev->trans_start > TX_TIMEOUT) + vortex_tx_timeout(dev); + return 1; + } + /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ - int len = (skb->len + 3) & ~3; - outl( vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), - ioaddr + Wn7_MasterAddr); - outw(len, ioaddr + Wn7_MasterLen); + outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); + outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); - /* netif_wake_queue() will be called at the DMADone interrupt. */ + netif_stop_tx_queue(dev); + /* Tx busy will be cleared at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb); - if (inw(ioaddr + TxFree) > 1536) { - netif_start_queue (dev); /* AKPM: redundant? */ - } else { + dev_free_skb(skb); + if (inw(ioaddr + TxFree) <= 1536) { /* Interrupt us when the FIFO has room for max-sized packet. */ - netif_stop_queue(dev); outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - } + netif_stop_tx_queue(dev); + } else + netif_unpause_tx_queue(dev); /* Typical path */ } dev->trans_start = jiffies; @@ -1961,15 +1706,20 @@ while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ - if (vortex_debug > 2) + if (vp->msg_level & NETIF_MSG_TX_ERR) printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n", dev->name, tx_status); if (tx_status & 0x04) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; if (tx_status & 0x30) { - issue_and_wait(dev, TxReset); + int j; + outw(TxReset, ioaddr + EL3_CMD); + for (j = 200; j >= 0 ; j--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; } outw(TxEnable, ioaddr + EL3_CMD); + vp->restart_tx = 1; } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } @@ -1982,248 +1732,122 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - /* Calculate the next Tx descriptor entry. */ - int entry = vp->cur_tx % TX_RING_SIZE; - struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; + int entry; + struct boom_tx_desc *prev_entry; unsigned long flags; + int i; - if (vortex_debug > 6) { - printk(KERN_DEBUG "boomerang_start_xmit()\n"); - if (vortex_debug > 3) - printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n", - dev->name, vp->cur_tx); + if (netif_pause_tx_queue(dev) != 0) { + /* This watchdog code is redundant with the media monitor timer. */ + if (jiffies - dev->trans_start > TX_TIMEOUT) + vortex_tx_timeout(dev); + return 1; } - if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { - if (vortex_debug > 0) - printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n", - dev->name); - netif_stop_queue(dev); + /* Calculate the next Tx descriptor entry. */ + entry = vp->cur_tx % TX_RING_SIZE; + prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; + + if (vp->msg_level & NETIF_MSG_TX_QUEUED) + printk(KERN_DEBUG "%s: Queuing Tx packet, index %d.\n", + dev->name, vp->cur_tx); + /* Impossible error. */ + if (vp->tx_full) { + printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", + dev->name); return 1; } - vp->tx_skbuff[entry] = skb; - vp->tx_ring[entry].next = 0; -#if DO_ZEROCOPY - if (skb->ip_summed != CHECKSUM_HW) - vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); + vp->tx_ring[entry].addr = virt_to_le32desc(skb->data); + vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); + if (vp->capabilities & CapNoTxLength) + vp->tx_ring[entry].status = + cpu_to_le32(TxNoRoundup | TxIntrUploaded | (entry << 2)); else - vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum); + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); - if (!skb_shinfo(skb)->nr_frags) { - vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG); + if (vp->drv_flags & IS_BOOMERANG) { + save_flags(flags); + cli(); + outw(DownStall, ioaddr + EL3_CMD); + /* Wait for the stall to complete. */ + for (i = 600; i >= 0 ; i--) + if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) + break; + vp->tx_desc_tail->next = virt_to_le32desc(&vp->tx_ring[entry]); + vp->tx_desc_tail = &vp->tx_ring[entry]; + if (inl(ioaddr + DownListPtr) == 0) { + outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); + queued_packet++; + } + outw(DownUnstall, ioaddr + EL3_CMD); + restore_flags(flags); } else { - int i; - - vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, - skb->len-skb->data_len, PCI_DMA_TODEVICE)); - vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len-skb->data_len); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - vp->tx_ring[entry].frag[i+1].addr = - cpu_to_le32(pci_map_single(vp->pdev, - (void*)page_address(frag->page) + frag->page_offset, - frag->size, PCI_DMA_TODEVICE)); - - if (i == skb_shinfo(skb)->nr_frags-1) - vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size|LAST_FRAG); - else - vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size); + vp->tx_desc_tail->next = virt_to_le32desc(&vp->tx_ring[entry]); + vp->tx_desc_tail = &vp->tx_ring[entry]; + if (vp->restart_tx) { + outl(virt_to_bus(vp->tx_desc_tail), ioaddr + DownListPtr); + vp->restart_tx = 0; + queued_packet++; } } -#else - vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); - vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); - vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); -#endif - - spin_lock_irqsave(&vp->lock, flags); - /* Wait for the stall to complete. */ - issue_and_wait(dev, DownStall); - prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); - if (inl(ioaddr + DownListPtr) == 0) { - outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - vp->queued_packet++; - } - vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { - netif_stop_queue (dev); + if (vp->cur_tx - vp->dirty_tx >= TX_QUEUE_LEN) { + vp->tx_full = 1; + /* Check for a just-cleared queue. */ + if (vp->cur_tx - (volatile unsigned int)vp->dirty_tx + < TX_QUEUE_LEN - 2) { + vp->tx_full = 0; + netif_unpause_tx_queue(dev); + } else + netif_stop_tx_queue(dev); } else { /* Clear previous interrupt enable. */ #if defined(tx_interrupt_mitigation) - /* Dubious. If in boomeang_interrupt "faster" cyclone ifdef - * were selected, this would corrupt DN_COMPLETE. No? - */ prev_entry->status &= cpu_to_le32(~TxIntrUploaded); #endif + netif_unpause_tx_queue(dev); /* Typical path */ } - outw(DownUnstall, ioaddr + EL3_CMD); - spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; return 0; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ - -/* - * This is the ISR for the vortex series chips. - * full_bus_master_tx == 0 && full_bus_master_rx == 0 - */ - static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr; - int status; - int work_done = max_interrupt_work; - - ioaddr = dev->base_addr; - spin_lock(&vp->lock); + int latency, status; + int work_done = vp->max_interrupt_work; + ioaddr = dev->base_addr; + latency = inb(ioaddr + Timer); status = inw(ioaddr + EL3_STATUS); - if (vortex_debug > 6) - printk("vortex_interrupt(). status=0x%4x\n", status); - - if ((status & IntLatch) == 0) - goto handler_exit; /* No interrupt: shared IRQs cause this */ - - if (status & IntReq) { - status |= vp->deferred; - vp->deferred = 0; - } - - if (status == 0xffff) /* h/w no longer present (hotplug)? */ + if (status == 0xffff) goto handler_exit; - - if (vortex_debug > 4) + if (vp->msg_level & NETIF_MSG_INTR) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, inb(ioaddr + Timer)); - + dev->name, status, latency); do { - if (vortex_debug > 5) + if (vp->msg_level & NETIF_MSG_INTR) printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & RxComplete) vortex_rx(dev); + if (status & UpComplete) { + outw(AckIntr | UpComplete, ioaddr + EL3_CMD); + boomerang_rx(dev); + } if (status & TxAvailable) { - if (vortex_debug > 5) + if (vp->msg_level & NETIF_MSG_TX_DONE) printk(KERN_DEBUG " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue (dev); - } - - if (status & DMADone) { - if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */ - if (inw(ioaddr + TxFree) > 1536) { - /* - * AKPM: FIXME: I don't think we need this. If the queue was stopped due to - * insufficient FIFO room, the TxAvailable test will succeed and call - * netif_wake_queue() - */ - netif_wake_queue(dev); - } else { /* Interrupt when FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - netif_stop_queue(dev); - } - } - } - /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { - if (status == 0xffff) - break; - vortex_error(dev, status); - } - - if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); - /* Disable all pending interrupts. */ - do { - vp->deferred |= status; - outw(SetStatusEnb | (~vp->deferred & vp->status_enable), - ioaddr + EL3_CMD); - outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); - /* The timer will reenable interrupts. */ - mod_timer(&vp->timer, jiffies + 1*HZ); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); - - if (vortex_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", - dev->name, status); -handler_exit: - spin_unlock(&vp->lock); -} - -/* - * This is the ISR for the boomerang series chips. - * full_bus_master_tx == 1 && full_bus_master_rx == 1 - */ - -static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr; - int status; - int work_done = max_interrupt_work; - - ioaddr = dev->base_addr; - - /* - * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout - * and boomerang_start_xmit - */ - spin_lock(&vp->lock); - - status = inw(ioaddr + EL3_STATUS); - - if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); - - if ((status & IntLatch) == 0) - goto handler_exit; /* No interrupt: shared IRQs can cause this */ - - if (status == 0xffff) { /* h/w no longer present (hotplug)? */ - if (vortex_debug > 1) - printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); - goto handler_exit; - } - - if (status & IntReq) { - status |= vp->deferred; - vp->deferred = 0; - } - - if (vortex_debug > 4) - printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, inb(ioaddr + Timer)); - do { - if (vortex_debug > 5) - printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", - dev->name, status); - if (status & UpComplete) { - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); - if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n"); - boomerang_rx(dev); + netif_resume_tx_queue(dev); } if (status & DownComplete) { @@ -2232,74 +1856,76 @@ outw(AckIntr | DownComplete, ioaddr + EL3_CMD); while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; -#if 1 /* AKPM: the latter is faster, but cyclone-only */ - if (inl(ioaddr + DownListPtr) == - vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) - break; /* It still hasn't been processed. */ -#else - if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0) + int tx_status = le32_to_cpu(vp->tx_ring[entry].status); + if (vp->capabilities & CapNoTxLength) { + if ( ! (tx_status & TxDownComplete)) + break; + } else if (inl(ioaddr + DownListPtr) == + virt_to_bus(&vp->tx_ring[entry])) break; /* It still hasn't been processed. */ -#endif - + if (vp->msg_level & NETIF_MSG_TX_DONE) + printk(KERN_DEBUG "%s: Transmit done, Tx status %8.8x.\n", + dev->name, tx_status); if (vp->tx_skbuff[entry]) { - struct sk_buff *skb = vp->tx_skbuff[entry]; -#if DO_ZEROCOPY - int i; - for (i=0; i<=skb_shinfo(skb)->nr_frags; i++) - pci_unmap_single(vp->pdev, - le32_to_cpu(vp->tx_ring[entry].frag[i].addr), - le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF, - PCI_DMA_TODEVICE); -#else - pci_unmap_single(vp->pdev, - le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); -#endif - dev_kfree_skb_irq(skb); + dev_free_skb_irq(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; - } else { - printk(KERN_DEBUG "boomerang_interrupt: no skb!\n"); } /* vp->stats.tx_packets++; Counted below. */ dirty_tx++; } vp->dirty_tx = dirty_tx; - if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) { - if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt: wake queue\n"); - netif_wake_queue (dev); + /* 4 entry hysteresis before marking the queue non-full. */ + if (vp->tx_full && (vp->cur_tx - dirty_tx < TX_QUEUE_LEN - 4)) { + vp->tx_full = 0; + netif_resume_tx_queue(dev); + } + } + if (status & DMADone) { + if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { + outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + /* Release the transfered buffer */ + dev_free_skb_irq(vp->tx_skb); + if (inw(ioaddr + TxFree) > 1536) { + netif_resume_tx_queue(dev); + } else /* Interrupt when FIFO has room for max-sized packet. */ + outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); } } - /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) + if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { + if (status == 0xffff) + break; vortex_error(dev, status); + } if (--work_done < 0) { - printk(KERN_WARNING "%s: Too much work in interrupt, status " - "%4.4x.\n", dev->name, status); - /* Disable all pending interrupts. */ - do { - vp->deferred |= status; - outw(SetStatusEnb | (~vp->deferred & vp->status_enable), - ioaddr + EL3_CMD); - outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); - /* The timer will reenable interrupts. */ - mod_timer(&vp->timer, jiffies + 1*HZ); - break; + if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) { + /* Just ack these and return. */ + outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD); + } else { + printk(KERN_WARNING "%s: Too much work in interrupt, status " + "%4.4x. Temporarily disabling functions (%4.4x).\n", + dev->name, status, SetStatusEnb | ((~status) & 0x7FE)); + /* Disable all pending interrupts. */ + outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); + outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); + /* The timer will reenable interrupts. */ + vp->restore_intr_mask = 1; + break; + } } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch); + } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); - if (vortex_debug > 4) + if (vp->msg_level & NETIF_MSG_INTR) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: - spin_unlock(&vp->lock); + return; } static int vortex_rx(struct net_device *dev) @@ -2309,13 +1935,13 @@ int i; short rx_status; - if (vortex_debug > 5) - printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n", + if (vp->msg_level & NETIF_MSG_RX_STATUS) + printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); while ((rx_status = inw(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsigned char rx_error = inb(ioaddr + RxErrors); - if (vortex_debug > 2) + if (vp->msg_level & NETIF_MSG_RX_ERR) printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); vp->stats.rx_errors++; if (rx_error & 0x01) vp->stats.rx_over_errors++; @@ -2329,7 +1955,7 @@ struct sk_buff *skb; skb = dev_alloc_skb(pkt_len + 5); - if (vortex_debug > 4) + if (vp->msg_level & NETIF_MSG_RX_STATUS) printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { @@ -2338,14 +1964,12 @@ /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master && ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { - dma_addr_t dma = pci_map_single(vp->pdev, skb_put(skb, pkt_len), - pkt_len, PCI_DMA_FROMDEVICE); - outl(dma, ioaddr + Wn7_MasterAddr); + outl(virt_to_bus(skb_put(skb, pkt_len)), + ioaddr + Wn7_MasterAddr); outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); outw(StartDMAUp, ioaddr + EL3_CMD); while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) ; - pci_unmap_single(vp->pdev, dma, pkt_len, PCI_DMA_FROMDEVICE); } else { insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), (pkt_len + 3) >> 2); @@ -2355,17 +1979,24 @@ netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + vp->stats.rx_bytes += pkt_len; +#endif /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; continue; - } else if (vortex_debug > 0) + } else if (vp->msg_level & NETIF_MSG_RX_ERR) printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); } + outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; - issue_and_wait(dev, RxDiscard); + /* Wait a limited time to skip this packet. */ + for (i = 200; i >= 0; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; } return 0; @@ -2380,15 +2011,16 @@ int rx_status; int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; - if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", inw(ioaddr+EL3_STATUS)); - + if (vp->msg_level & NETIF_MSG_RX_STATUS) + printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status " + "%8.8x.\n", + inw(ioaddr+EL3_STATUS), (int)inl(ioaddr+UpPktStatus)); while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ if (--rx_work_limit < 0) break; if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; - if (vortex_debug > 2) + if (vp->msg_level & NETIF_MSG_RX_ERR) printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); vp->stats.rx_errors++; if (rx_error & 0x01) vp->stats.rx_over_errors++; @@ -2400,30 +2032,34 @@ /* The packet length: up to 4.5K!. */ int pkt_len = rx_status & 0x1fff; struct sk_buff *skb; - dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr); - if (vortex_debug > 4) + if (vp->msg_level & NETIF_MSG_RX_STATUS) printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + if (pkt_len < vp->rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - vp->rx_skbuff[entry]->tail, - pkt_len); - vp->rx_copy++; + le32desc_to_virt(vp->rx_ring[entry].addr), pkt_len); + rx_copy++; } else { + void *temp; /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; vp->rx_skbuff[entry] = NULL; - skb_put(skb, pkt_len); - pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - vp->rx_nocopy++; + temp = skb_put(skb, pkt_len); + /* Remove this checking code for final release. */ + if (le32desc_to_virt(vp->rx_ring[entry].addr) != temp) + printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" + " in boomerang_rx: %p vs. %p.\n", dev->name, + bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), + temp); + rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); { /* Use hardware checksum info. */ @@ -2432,12 +2068,15 @@ (csum_bits == (IPChksumValid | TCPChksumValid) || csum_bits == (IPChksumValid | UDPChksumValid))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - vp->rx_csumhits++; + rx_csumhits++; } } netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + vp->stats.rx_bytes += pkt_len; +#endif } entry = (++vp->cur_rx) % RX_RING_SIZE; } @@ -2446,20 +2085,12 @@ struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) { - static unsigned long last_jif; - if ((jiffies - last_jif) > 10 * HZ) { - printk(KERN_WARNING "%s: memory shortage\n", dev->name); - last_jif = jiffies; - } - if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) - mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); + skb = dev_alloc_skb(vp->rx_buf_sz); + if (skb == NULL) break; /* Bad news! */ - } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); + vp->rx_ring[entry].addr = virt_to_le32desc(skb->tail); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ @@ -2468,37 +2099,12 @@ return 0; } -/* - * If we've hit a total OOM refilling the Rx ring we poll once a second - * for some memory. Otherwise there is no way to restart the rx process. - */ -static void -rx_oom_timer(unsigned long arg) -{ - struct net_device *dev = (struct net_device *)arg; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - - spin_lock_irq(&vp->lock); - if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ - boomerang_rx(dev); - if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, - ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); - } - spin_unlock_irq(&vp->lock); -} - static void vortex_down(struct net_device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - netif_stop_queue (dev); - - del_timer_sync(&vp->rx_oom_timer); - del_timer_sync(&vp->timer); - /* Turn off statistics ASAP. We update vp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -2517,11 +2123,6 @@ outl(0, ioaddr + UpListPtr); if (vp->full_bus_master_tx) outl(0, ioaddr + DownListPtr); - - if (vp->pdev && vp->enable_wol) { - pci_save_state(vp->pdev, vp->power_state); - acpi_set_WOL(dev); - } } static int @@ -2531,94 +2132,42 @@ long ioaddr = dev->base_addr; int i; - if (netif_device_present(dev)) - vortex_down(dev); + netif_stop_tx_queue(dev); - if (vortex_debug > 1) { + if (vp->msg_level & NETIF_MSG_IFDOWN) { printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); + dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); } -#if DO_ZEROCOPY - if ( vp->rx_csumhits && - ((vp->drv_flags & HAS_HWCKSM) == 0) && - (hw_checksums[vp->card_idx] == -1)) { - printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name); - printk(KERN_WARNING "Please see http://www.uow.edu.au/~andrewm/zerocopy.html\n"); - } -#endif - + del_timer(&vp->timer); + vortex_down(dev); free_irq(dev->irq, dev); + outw(TotalReset | 0x34, ioaddr + EL3_CMD); if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { - pci_unmap_single( vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - dev_kfree_skb(vp->rx_skbuff[i]); +#if LINUX_VERSION_CODE < 0x20100 + vp->rx_skbuff[i]->free = 1; +#endif + dev_free_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) { + for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - struct sk_buff *skb = vp->tx_skbuff[i]; -#if DO_ZEROCOPY - int k; - - for (k=0; k<=skb_shinfo(skb)->nr_frags; k++) - pci_unmap_single(vp->pdev, - le32_to_cpu(vp->tx_ring[i].frag[k].addr), - le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF, - PCI_DMA_TODEVICE); -#else - pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); -#endif - dev_kfree_skb(skb); + dev_free_skb(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } - } } - return 0; -} - -static void -dump_tx_ring(struct net_device *dev) -{ - if (vortex_debug > 0) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (vp->full_bus_master_tx) { - int i; - int stalled = inl(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ + MOD_DEC_USE_COUNT; - printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", - vp->full_bus_master_tx, - vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, - vp->cur_tx, vp->cur_tx % TX_RING_SIZE); - printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", - inl(ioaddr + DownListPtr), - &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); - issue_and_wait(dev, DownStall); - for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, - &vp->tx_ring[i], -#if DO_ZEROCOPY - le32_to_cpu(vp->tx_ring[i].frag[0].length), -#else - le32_to_cpu(vp->tx_ring[i].length), -#endif - le32_to_cpu(vp->tx_ring[i].status)); - } - if (!stalled) - outw(DownUnstall, ioaddr + EL3_CMD); - } - } + return 0; } static struct net_device_stats *vortex_get_stats(struct net_device *dev) @@ -2626,10 +2175,11 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ - spin_lock_irqsave (&vp->lock, flags); + if (netif_running(dev)) { + save_flags(flags); + cli(); update_stats(dev->base_addr, dev); - spin_unlock_irqrestore (&vp->lock, flags); + restore_flags(flags); } return &vp->stats; } @@ -2664,90 +2214,111 @@ /* Don't bother with register 9, an extension of registers 6&7. If we do use the 6&7 values the atomic update assumption above is invalid. */ - vp->stats.rx_bytes += inw(ioaddr + 10); + /* Rx Bytes is unreliable */ inw(ioaddr + 10); +#if LINUX_VERSION_CODE > 0x020119 vp->stats.tx_bytes += inw(ioaddr + 12); +#else + inw(ioaddr + 10); + inw(ioaddr + 12); +#endif /* New: On the Vortex we must also clear the BadSSD counter. */ EL3WINDOW(4); inb(ioaddr + 12); - { - u8 up = inb(ioaddr + 13); - vp->stats.rx_bytes += (up & 0x0f) << 16; - vp->stats.tx_bytes += (up & 0xf0) << 12; - } - + /* We change back to window 7 (not 1) with the Vortex. */ EL3WINDOW(old_window >> 13); return; } - -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) -{ - struct vortex_private *vp = dev->priv; - u32 ethcmd; - - if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) - return -EFAULT; - - switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; - strcpy(info.driver, DRV_NAME); - strcpy(info.version, DRV_VERSION); - if (vp->pdev) - strcpy(info.bus_info, vp->pdev->slot_name); - else - sprintf(info.bus_info, "EISA 0x%lx %d", - dev->base_addr, dev->irq); - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; - } - - } - - return -EOPNOTSUPP; -} - static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; - int phy = vp->phys[0] & 0x1f; - int retval; + u16 *data = (u16 *)&rq->ifr_data; + u32 *data32 = (void *)&rq->ifr_data; + int phy = vp->phys[0]; switch(cmd) { - case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ - data->phy_id = phy; - - case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + case 0x8947: case 0x89F0: + /* SIOCGMIIPHY: Get the address of the PHY in use. */ + data[0] = phy; + /* Fall Through */ + case 0x8948: case 0x89F1: + /* SIOCGMIIREG: Read the specified MII register. */ + if (data[0] == 32) { /* Emulate MII for 3c59*, 3c900. */ + data[3] = 0; + switch (data[1]) { + case 0: + if (dev->if_port == XCVR_100baseTx) data[3] |= 0x2000; + if (vp->full_duplex) data[3] |= 0x0100; + break; + case 1: + if (vp->available_media & 0x02) data[3] |= 0x6000; + if (vp->available_media & 0x08) data[3] |= 0x1800; + spin_lock(&vp->window_lock); + EL3WINDOW(4); + if (inw(ioaddr + Wn4_Media) & Media_LnkBeat) data[3] |= 0x0004; + spin_unlock(&vp->window_lock); + break; + case 2: data[3] = 0x0280; break; /* OUI 00:a0:24 */ + case 3: data[3] = 0x9000; break; + default: break; + } + return 0; + } + spin_lock(&vp->window_lock); EL3WINDOW(4); - data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); - retval = 0; - break; - - case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ - if (!capable(CAP_NET_ADMIN)) { - retval = -EPERM; - } else { - EL3WINDOW(4); - mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); - retval = 0; + data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + spin_unlock(&vp->window_lock); + return 0; + case 0x8949: case 0x89F2: + /* SIOCSMIIREG: Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data[0] == vp->phys[0]) { + u16 value = data[2]; + if (vp->phys[0] == 32) { + if (data[1] == 0) { + vp->media_override = (value & 0x2000) ? + XCVR_100baseTx : XCVR_10baseT; + vp->full_duplex = (value & 0x0100) ? 1 : 0; + vp->medialock = 1; + } + return 0; + } + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + vp->medialock = (value & 0x9000) ? 0 : 1; + if (vp->medialock) + vp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: vp->advertising = value; break; + } + /* Perhaps check_duplex(dev), depending on chip semantics. */ } - break; + spin_lock(&vp->window_lock); + EL3WINDOW(4); + mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + spin_unlock(&vp->window_lock); + return 0; + case SIOCGPARAMS: + data32[0] = vp->msg_level; + data32[1] = vp->multicast_filter_limit; + data32[2] = vp->max_interrupt_work; + data32[3] = vp->rx_copybreak; + return 0; + case SIOCSPARAMS: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + vp->msg_level = data32[0]; + vp->multicast_filter_limit = data32[1]; + vp->max_interrupt_work = data32[2]; + vp->rx_copybreak = data32[3]; + return 0; default: - retval = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; } - - return retval; } /* Pre-Cyclone chips have no documented multicast filter, so the only @@ -2755,21 +2326,26 @@ the chip has a very clean way to set the mode, unlike many others. */ static void set_rx_mode(struct net_device *dev) { + struct vortex_private *vp = (void *)dev->priv; long ioaddr = dev->base_addr; int new_mode; if (dev->flags & IFF_PROMISC) { - if (vortex_debug > 0) - printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name); + /* Unconditionally log a net tap. */ + printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name); new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; } else new_mode = SetRxFilter | RxStation | RxBroadcast; - outw(new_mode, ioaddr + EL3_CMD); + if (vp->rx_mode != new_mode) { + vp->rx_mode = new_mode; + outw(new_mode, ioaddr + EL3_CMD); + } } + /* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet @@ -2802,17 +2378,13 @@ } } -static int mdio_read(struct net_device *dev, int phy_id, int location) +static int mdio_read(long ioaddr, int phy_id, int location) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; int i; - long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; - spin_lock_bh(&vp->mdio_lock); - if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2824,28 +2396,23 @@ outw(dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { + /* Read the two transition and 16 data bits. */ + for (i = 18; i > 0; i--) { outw(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - spin_unlock_bh(&vp->mdio_lock); - return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; + return retval & 0x10000 ? 0xffff : retval & 0xffff; } -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +static void mdio_write(long ioaddr, int phy_id, int location, int value) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; - long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; - spin_lock_bh(&vp->mdio_lock); - if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2858,16 +2425,12 @@ mdio_delay(); } /* Leave the interface idle. */ - for (i = 1; i >= 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - spin_unlock_bh(&vp->mdio_lock); + mdio_sync(ioaddr, 32); + return; } +#if ! defined(NO_PCI) /* ACPI: Advanced Configuration and Power Interface. */ /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ static void acpi_set_WOL(struct net_device *dev) @@ -2881,121 +2444,118 @@ /* The RxFilter must accept the WOL frames. */ outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); outw(RxEnable, ioaddr + EL3_CMD); - /* Change the power state to D3; RxEnable doesn't take effect. */ - pci_enable_wake(vp->pdev, 0, 1); - pci_set_power_state(vp->pdev, 3); -} - - -static void __devexit vortex_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct vortex_private *vp; - - if (!dev) { - printk("vortex_remove_one called for EISA device!\n"); - BUG(); - } - - vp = dev->priv; - - /* AKPM: FIXME: we should have - * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - * here - */ - unregister_netdev(dev); - /* Should really use issue_and_wait() here */ - outw(TotalReset|0x14, dev->base_addr + EL3_CMD); - - if (vp->pdev && vp->enable_wol) { - pci_set_power_state(vp->pdev, 0); /* Go active */ - if (vp->pm_state_valid) - pci_restore_state(vp->pdev, vp->power_state); - } - - pci_free_consistent(pdev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, - vp->rx_ring_dma); - if (vp->must_free_region) - release_region(dev->base_addr, vp->io_size); - kfree(dev); + pci_write_config_word(vp->pci_dev, 0xe0, 0x8103); } - - -static struct pci_driver vortex_driver = { - name: "3c59x", - probe: vortex_init_one, - remove: __devexit_p(vortex_remove_one), - id_table: vortex_pci_tbl, -#ifdef CONFIG_PM - suspend: vortex_suspend, - resume: vortex_resume, #endif -}; - - -static int vortex_have_pci; -static int vortex_have_eisa; - -static int __init vortex_init (void) +static int pwr_event(void *dev_instance, int event) { - int pci_rc, eisa_rc; - - pci_rc = pci_module_init(&vortex_driver); - eisa_rc = vortex_eisa_init(); - - if (pci_rc == 0) - vortex_have_pci = 1; - if (eisa_rc > 0) - vortex_have_eisa = 1; + struct net_device *dev = dev_instance; + struct vortex_private *np = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; - return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV; + if (np->msg_level & NETIF_MSG_LINK) + printk(KERN_DEBUG "%s: Handling power event %d.\n", dev->name, event); + switch(event) { + case DRV_ATTACH: + MOD_INC_USE_COUNT; + break; + case DRV_SUSPEND: + vortex_down(dev); + netif_stop_tx_queue(dev); + if (np->capabilities & CapPwrMgmt) + acpi_set_WOL(dev); + break; + case DRV_RESUME: + /* This is incomplete: the actions are very chip specific. */ + activate_xcvr(dev); + set_media_type(dev); + start_operation(dev); + np->rx_mode = 0; + set_rx_mode(dev); + start_operation1(dev); + break; + case DRV_DETACH: { + struct net_device **devp, **next; + if (dev->flags & IFF_UP) { + dev_close(dev); + dev->flags &= ~(IFF_UP|IFF_RUNNING); + } + unregister_netdev(dev); + release_region(dev->base_addr, pci_tbl[np->chip_id].io_size); +#ifndef USE_IO_OPS + iounmap((char *)dev->base_addr); +#endif + for (devp = &root_vortex_dev; *devp; devp = next) { + next = &((struct vortex_private *)(*devp)->priv)->next_module; + if (*devp == dev) { + *devp = *next; + break; + } + } + if (np->priv_addr) + kfree(np->priv_addr); + kfree(dev); + MOD_DEC_USE_COUNT; + break; + } + case DRV_PWR_WakeOn: + if ( ! (np->capabilities & CapPwrMgmt)) + return -1; + EL3WINDOW(7); + /* Power up on: 1=Downloaded Filter, 2=Magic Packets, 4=Link Status.*/ + outw(2, ioaddr + 12); + /* This RxEnable doesn't take effect if we immediately change to D3. */ + outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + outw(RxEnable, ioaddr + EL3_CMD); + acpi_set_pwr_state(np->pci_dev, ACPI_D3); + break; + } + return 0; } - -static void __exit vortex_eisa_cleanup (void) + +#ifdef MODULE +void cleanup_module(void) { - struct net_device *dev, *tmp; - struct vortex_private *vp; - long ioaddr; + struct net_device *next_dev; - dev = root_vortex_eisa_dev; - - while (dev) { - vp = dev->priv; - ioaddr = dev->base_addr; - - unregister_netdev (dev); - outw (TotalReset, ioaddr + EL3_CMD); - release_region (ioaddr, VORTEX_TOTAL_SIZE); - - tmp = dev; - dev = vp->next_module; +#ifdef CARDBUS + unregister_driver(&vortex_ops); +#elif ! defined(NO_PCI) + pci_drv_unregister(&vortex_drv_id); +#endif - kfree (tmp); + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_vortex_dev) { + struct vortex_private *vp=(void *)(root_vortex_dev->priv); + unregister_netdev(root_vortex_dev); + outw(TotalReset | 0x14, root_vortex_dev->base_addr + EL3_CMD); + if (vp->capabilities & CapPwrMgmt) + acpi_set_WOL(root_vortex_dev); +#ifdef USE_MEM_OPS + iounmap((char *)root_vortex_dev->base_addr); +#else + release_region(root_vortex_dev->base_addr, + pci_tbl[vp->chip_id].io_size); +#endif + next_dev = vp->next_module; + if (vp->priv_addr) + kfree(vp->priv_addr); + kfree(root_vortex_dev); + root_vortex_dev = next_dev; } } - -static void __exit vortex_cleanup (void) -{ - if (vortex_have_pci) - pci_unregister_driver (&vortex_driver); - if (vortex_have_eisa) - vortex_eisa_cleanup (); -} - - -module_init(vortex_init); -module_exit(vortex_cleanup); - +#endif /* MODULE */ /* * Local variables: + * compile-command: "make KERNVER=`uname -r` 3c59x.o" + * compile-cmd: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c 3c59x.c" + * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia/include/" + * eisa-only-compile: "gcc -DNO_PCI -DMODULE -O6 -c 3c59x.c -o 3c597.o" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -urN linux-2.4.20/drivers/net/kern_compat.h linux-2.4.20-3c59x/drivers/net/kern_compat.h --- linux-2.4.20/drivers/net/kern_compat.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.20-3c59x/drivers/net/kern_compat.h 2002-12-12 18:46:52.000000000 -0500 @@ -0,0 +1,284 @@ +#ifndef _KERN_COMPAT_H +#define _KERN_COMPAT_H +/* kern_compat.h: Linux PCI network adapter backward compatibility code. */ +/* + $Revision: 1.17 $ $Date: 2002/11/17 17:37:00 $ + + Kernel compatibility defines. + This file provides macros to mask the difference between kernel versions. + It is designed primarily to allow device drivers to be written so that + they work with a range of kernel versions. + + Written 1999-2002 Donald Becker, Scyld Computing Corporation + This software may be used and distributed according to the terms + of the GNU General Public License (GPL), incorporated herein by + reference. Drivers interacting with these functions are derivative + works and thus are covered the GPL. They must include an explicit + GPL notice. + + This code also provides inline scan and activate functions for PCI network + interfaces. It has an interface identical to pci-scan.c, but is + intended as an include file to simplify using updated drivers with older + kernel versions. + This code version matches pci-scan.c:v0.05 9/16/99 + + The author may be reached as becker@scyld.com, or + Donald Becker + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Other contributers: + +*/ + +/* We try to use defined values to decide when an interface has changed or + added features, but we must have the kernel version number for a few. */ +#if ! defined(LINUX_VERSION_CODE) || (LINUX_VERSION_CODE < 0x10000) +#include +#endif +/* Older kernel versions didn't include modversions automatically. */ +#if LINUX_VERSION_CODE < 0x20300 && defined(MODVERSIONS) +#include +#endif + +/* There was no support for PCI address space mapping in 2.0, but the + Alpha needed it. See the 2.2 documentation. */ +#if LINUX_VERSION_CODE < 0x20100 && ! defined(__alpha__) +#define ioremap(a,b)\ + (((unsigned long)(a) >= 0x100000) ? vremap(a,b) : (void*)(a)) +#define iounmap(v)\ + do { if ((unsigned long)(v) >= 0x100000) vfree(v);} while (0) +#endif + +/* Support for adding info about the purpose of and parameters for kernel + modules was added in 2.1. */ +#if LINUX_VERSION_CODE < 0x20115 +#define MODULE_AUTHOR(name) extern int nonesuch +#define MODULE_DESCRIPTION(string) extern int nonesuch +#define MODULE_PARM(varname, typestring) extern int nonesuch +#define MODULE_PARM_DESC(var,desc) extern int nonesuch +#endif +#if !defined(MODULE_LICENSE) +#define MODULE_LICENSE(license) \ +static const char __module_license[] __attribute__((section(".modinfo"))) = \ +"license=" license +#endif +#if !defined(MODULE_PARM_DESC) +#define MODULE_PARM_DESC(var,desc) \ +const char __module_parm_desc_##var[] \ +__attribute__((section(".modinfo"))) = \ +"parm_desc_" __MODULE_STRING(var) "=" desc +#endif + +/* SMP and better multiarchitecture support were added. + Using an older kernel means we assume a little-endian uniprocessor. +*/ +#if LINUX_VERSION_CODE < 0x20123 +#define hard_smp_processor_id() smp_processor_id() +#define test_and_set_bit(val, addr) set_bit(val, addr) +#define cpu_to_le16(val) (val) +#define cpu_to_le32(val) (val) +#define le16_to_cpu(val) (val) +#define le16_to_cpus(val) /* In-place conversion. */ +#define le32_to_cpu(val) (val) +#define cpu_to_be16(val) ((((val) & 0xff) << 8) + (((val) >> 8) & 0xff)) +#define cpu_to_be32(val) ((cpu_to_be16(val) << 16) + cpu_to_be16((val) >> 16)) +typedef long spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 +#define spin_lock(lock) +#define spin_unlock(lock) +#define spin_lock_irqsave(lock, flags) do {save_flags(flags); cli();} while(0) +#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) +#endif + +#if LINUX_VERSION_CODE <= 0x20139 +#define net_device_stats enet_statistics +#else +#define NETSTATS_VER2 +#endif + +/* These are used by the netdrivers to report values from the + MII (Media Indpendent Interface) management registers. +*/ +#ifndef SIOCGMIIPHY +#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ +#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */ +#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register. */ +#endif +#ifndef SIOCGPARAMS +#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters. */ +#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters. */ +#endif + +#if !defined(HAVE_NETIF_MSG) +enum { + NETIF_MSG_DRV = 0x0001, + NETIF_MSG_PROBE = 0x0002, + NETIF_MSG_LINK = 0x0004, + NETIF_MSG_TIMER = 0x0008, + NETIF_MSG_IFDOWN = 0x0010, + NETIF_MSG_IFUP = 0x0020, + NETIF_MSG_RX_ERR = 0x0040, + NETIF_MSG_TX_ERR = 0x0080, + NETIF_MSG_TX_QUEUED = 0x0100, + NETIF_MSG_INTR = 0x0200, + NETIF_MSG_TX_DONE = 0x0400, + NETIF_MSG_RX_STATUS = 0x0800, + NETIF_MSG_PKTDATA = 0x1000, + /* 2000 is reserved. */ + NETIF_MSG_WOL = 0x4000, + NETIF_MSG_MISC = 0x8000, + NETIF_MSG_RXFILTER = 0x10000, +}; +#define NETIF_MSG_MAX 0x10000 +#endif + +#if !defined(NETIF_MSG_MAX) || NETIF_MSG_MAX < 0x8000 +#define NETIF_MSG_MISC 0x8000 +#endif +#if !defined(NETIF_MSG_MAX) || NETIF_MSG_MAX < 0x10000 +#define NETIF_MSG_RXFILTER 0x10000 +#endif + +#if LINUX_VERSION_CODE < 0x20155 +#include +#define PCI_SUPPORT_VER1 +/* A minimal version of the 2.2.* PCI support that handles configuration + space access. + Drivers that actually use pci_dev fields must do explicit compatibility. + Note that the struct pci_dev * "pointer" is actually a byte mapped integer! +*/ +#if LINUX_VERSION_CODE < 0x20014 +struct pci_dev { int not_used; }; +#endif + +#define pci_find_slot(bus, devfn) (struct pci_dev*)((bus<<8) | devfn | 0xf0000) +#define bus_number(pci_dev) ((((int)(pci_dev))>>8) & 0xff) +#define devfn_number(pci_dev) (((int)(pci_dev)) & 0xff) +#define pci_bus_number(pci_dev) ((((int)(pci_dev))>>8) & 0xff) +#define pci_devfn(pci_dev) (((int)(pci_dev)) & 0xff) + +#ifndef CONFIG_PCI +extern inline int pci_present(void) { return 0; } +#else +#define pci_present pcibios_present +#endif + +#define pci_read_config_byte(pdev, where, valp)\ + pcibios_read_config_byte(bus_number(pdev), devfn_number(pdev), where, valp) +#define pci_read_config_word(pdev, where, valp)\ + pcibios_read_config_word(bus_number(pdev), devfn_number(pdev), where, valp) +#define pci_read_config_dword(pdev, where, valp)\ + pcibios_read_config_dword(bus_number(pdev), devfn_number(pdev), where, valp) +#define pci_write_config_byte(pdev, where, val)\ + pcibios_write_config_byte(bus_number(pdev), devfn_number(pdev), where, val) +#define pci_write_config_word(pdev, where, val)\ + pcibios_write_config_word(bus_number(pdev), devfn_number(pdev), where, val) +#define pci_write_config_dword(pdev, where, val)\ + pcibios_write_config_dword(bus_number(pdev), devfn_number(pdev), where, val) +#else +#define PCI_SUPPORT_VER2 +#define pci_bus_number(pci_dev) ((pci_dev)->bus->number) +#define pci_devfn(pci_dev) ((pci_dev)->devfn) +#endif + +/* The arg count changed, but function name did not. + We cover that bad choice by defining a new name. +*/ +#if LINUX_VERSION_CODE < 0x20159 +#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE) +#define dev_free_skb_irq(skb) dev_kfree_skb(skb, FREE_WRITE) +#elif LINUX_VERSION_CODE < 0x20400 +#define dev_free_skb(skb) dev_kfree_skb(skb) +#define dev_free_skb_irq(skb) dev_kfree_skb(skb) +#else +#define dev_free_skb(skb) dev_kfree_skb(skb) +#define dev_free_skb_irq(skb) dev_kfree_skb_irq(skb) +#endif + +/* Added at the suggestion of Jes Sorensen. */ +#if LINUX_VERSION_CODE > 0x20153 +#include +#else +#define __init +#define __initdata +#define __initfunc(__arginit) __arginit +#endif + +/* The old 'struct device' used a too-generic name. */ +#if LINUX_VERSION_CODE < 0x2030d +#define net_device device +#endif + +/* More changes for the 2.4 kernel, some in the zillion 2.3.99 releases. */ +#if LINUX_VERSION_CODE < 0x20363 +#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX; +#define down_write(semaphore_p) down(semaphore_p) +#define down_read(semaphore_p) down(semaphore_p) +#define up_write(semaphore_p) up(semaphore_p) +#define up_read(semaphore_p) up(semaphore_p) +#define get_free_page get_zeroed_page +/* Note that the kernel version has a broken time_before()! */ +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_before(a,b) ((long)(a) - (long)(b) < 0) +#endif + +/* The 2.2 kernels added the start of capability-based security for operations + that formerally could only be done by root. +*/ +#if ! defined(CAP_NET_ADMIN) +#define capable(CAP_XXX) (suser()) +#endif + +#if ! defined(HAVE_NETIF_QUEUE) +#define netif_wake_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); mark_bh(NET_BH); } while (0) +#define netif_start_tx_queue(dev) do { (dev)->tbusy = 0; dev->start = 1; } while (0) +#define netif_stop_tx_queue(dev) do { (dev)->tbusy = 1; dev->start = 0; } while (0) +#define netif_queue_paused(dev) ((dev)->tbusy != 0) +/* Splitting these lines exposes a bug in some preprocessors. */ +#define netif_pause_tx_queue(dev) (test_and_set_bit( 0, (void*)&(dev)->tbusy)) +#define netif_unpause_tx_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); } while (0) +#define netif_resume_tx_queue(dev) do { clear_bit( 0, (void*)&(dev)->tbusy); mark_bh(NET_BH); } while (0) + +#define netif_running(dev) ((dev)->start != 0) +#define netif_device_attach(dev) do {; } while (0) +#define netif_device_detach(dev) do {; } while (0) +#define netif_device_present(dev) (1) +#define netif_set_tx_timeout(dev, func, deltajiffs) do {; } while (0) +#define netif_link_down(dev) (dev)->flags &= ~IFF_RUNNING +#define netif_link_up(dev) (dev)->flags |= IFF_RUNNING + +#else + +#define netif_start_tx_queue(dev) netif_start_queue(dev) +#define netif_stop_tx_queue(dev) netif_stop_queue(dev) +#define netif_queue_paused(dev) netif_queue_stopped(dev) +#define netif_resume_tx_queue(dev) netif_wake_queue(dev) +/* Only used in transmit path. No function in 2.4. */ +#define netif_pause_tx_queue(dev) 0 +#define netif_unpause_tx_queue(dev) do {; } while (0) + +#ifdef __LINK_STATE_NOCARRIER +#define netif_link_down(dev) netif_carrier_off(dev) +#define netif_link_up(dev) netif_carrier_on(dev) +#else +#define netif_link_down(dev) (dev)->flags &= ~IFF_RUNNING +#define netif_link_up(dev) (dev)->flags |= IFF_RUNNING +#endif + +#endif +#ifndef PCI_DMA_BUS_IS_PHYS +#define pci_dma_sync_single(pci_dev, base_addr, extent, tofrom) do {; } while (0) +#define pci_map_single(pci_dev, base_addr, extent, dir) virt_to_bus(base_addr) +#define pci_unmap_single(pci_dev, base_addr, extent, dir) do {; } while (0) +#endif + +#endif +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -urN linux-2.4.20/drivers/net/Makefile linux-2.4.20-3c59x/drivers/net/Makefile --- linux-2.4.20/drivers/net/Makefile 2002-11-28 18:53:13.000000000 -0500 +++ linux-2.4.20-3c59x/drivers/net/Makefile 2002-12-12 18:44:25.000000000 -0500 @@ -69,7 +69,7 @@ obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_RCPCI) += rcpci.o -obj-$(CONFIG_VORTEX) += 3c59x.o mii.o +obj-$(CONFIG_VORTEX) += 3c59x.o pci-scan.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o mii.o obj-$(CONFIG_EEPRO100) += eepro100.o mii.o diff -urN linux-2.4.20/drivers/net/pci-scan.c linux-2.4.20-3c59x/drivers/net/pci-scan.c --- linux-2.4.20/drivers/net/pci-scan.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.20-3c59x/drivers/net/pci-scan.c 2002-09-24 00:08:48.000000000 -0400 @@ -0,0 +1,658 @@ +/* pci-scan.c: Linux PCI network adapter support code. */ +/* + Originally written 1999-2002 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 interacting with these functions are derivative + works and thus are covered the GPL. They must include an explicit + GPL notice. + + This code provides common scan and activate functions for PCI network + interfaces. + + The author may be reached as becker@scyld.com, or + Donald Becker + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Other contributers: +*/ +static const char version[] = +"pci-scan.c:v1.11 8/31/2002 Donald Becker " +" http://www.scyld.com/linux/drivers.html\n"; + +/* A few user-configurable values that may be modified when a module. */ + +static int msg_level = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int min_pci_latency = 32; + +#if ! defined(__KERNEL__) +#define __KERNEL__ 1 +#endif +#if !defined(__OPTIMIZE__) +#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 the proper options, including "-O". +#endif + +#if defined(MODULE) && ! defined(EXPORT_SYMTAB) +#define EXPORT_SYMTAB +#endif + +#include +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif +#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) +#define MODVERSIONS +#endif + +#include +#include +#if LINUX_VERSION_CODE < 0x20500 && defined(MODVERSIONS) +/* Another interface semantics screw-up. */ +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= 0x20300 +/* Bogus change in the middle of a "stable" kernel series. + Also, in 2.4.7+ slab must come before interrupt.h to avoid breakage. */ +#include +#else +#include +#endif +#include +#include "pci-scan.h" +#include "kern_compat.h" +#if defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 +#include +#endif +#ifdef CONFIG_PM +/* New in 2.4 kernels, pointlessly incompatible with earlier APM. */ +#include +#endif + +#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE) +char kernel_version[] = UTS_RELEASE; +#endif +#if (LINUX_VERSION_CODE < 0x20100) +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#endif + +int (*register_hotswap_hook)(struct drv_id_info *did); +void (*unregister_hotswap_hook)(struct drv_id_info *did); + +#if LINUX_VERSION_CODE > 0x20118 && defined(MODULE) +MODULE_LICENSE("GPL"); +MODULE_PARM(msg_level, "i"); +MODULE_PARM(min_pci_latency, "i"); +MODULE_PARM_DESC(msg_level, "Enable additional status messages (0-7)"); +MODULE_PARM_DESC(min_pci_latency, + "Minimum value for the PCI Latency Timer settings"); +#if defined(EXPORT_SYMTAB) +EXPORT_SYMBOL_NOVERS(pci_drv_register); +EXPORT_SYMBOL_NOVERS(pci_drv_unregister); +EXPORT_SYMBOL_NOVERS(acpi_wake); +EXPORT_SYMBOL_NOVERS(acpi_set_pwr_state); +EXPORT_SYMBOL_NOVERS(register_hotswap_hook); +EXPORT_SYMBOL_NOVERS(unregister_hotswap_hook); +#endif +#endif + +/* List of registered drivers. */ +static struct drv_id_info *drv_list; +/* List of detected PCI devices, for APM events. */ +static struct dev_info { + struct dev_info *next; + void *dev; + struct drv_id_info *drv_id; + int flags; +} *dev_list; + +/* + This code is not intended to support every configuration. + It is intended to minimize duplicated code by providing the functions + needed in almost every PCI driver. + + The "no kitchen sink" policy: + Additional features and code will be added to this module only if more + than half of the drivers for common hardware would benefit from the feature. +*/ + +/* + Ideally we would detect and number all cards of a type (e.g. network) in + PCI slot order. + But that does not work with hot-swap card, CardBus cards and added drivers. + So instead we detect just the each chip table in slot order. + + This routine takes a PCI ID table, scans the PCI bus, and calls the + associated attach/probe1 routine with the hardware already activated and + single I/O or memory address already mapped. + + This routine will later be supplemented with CardBus and hot-swap PCI + support using the same table. Thus the pci_chip_tbl[] should not be + marked as __initdata. +*/ + +#if LINUX_VERSION_CODE >= 0x20200 +/* Grrrr.. complex abstaction layers with negative benefit. */ +int pci_drv_register(struct drv_id_info *drv_id, void *initial_device) +{ + int chip_idx, cards_found = 0; + struct pci_dev *pdev = NULL; + struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl; + struct drv_id_info *drv; + void *newdev; + + + /* Ignore a double-register attempt. */ + for (drv = drv_list; drv; drv = drv->next) + if (drv == drv_id) + return -EBUSY; + + while ((pdev = pci_find_class(drv_id->pci_class, pdev)) != 0) { + u32 pci_id, pci_subsys_id, pci_class_rev; + u16 pci_command, new_command; + int pci_flags; + long pciaddr; /* Bus address. */ + long ioaddr; /* Mapped address for this processor. */ + + pci_read_config_dword(pdev, PCI_VENDOR_ID, &pci_id); + /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */ + pci_read_config_dword(pdev, 0x2c, &pci_subsys_id); + pci_read_config_dword(pdev, PCI_REVISION_ID, &pci_class_rev); + + if (msg_level > 3) + printk(KERN_DEBUG "PCI ID %8.8x subsystem ID is %8.8x.\n", + pci_id, pci_subsys_id); + for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { + struct pci_id_info *chip = &pci_tbl[chip_idx]; + if ((pci_id & chip->id.pci_mask) == chip->id.pci + && (pci_subsys_id&chip->id.subsystem_mask) == chip->id.subsystem + && (pci_class_rev&chip->id.revision_mask) == chip->id.revision) + break; + } + if (pci_tbl[chip_idx].name == 0) /* Compiled out! */ + continue; + + pci_flags = pci_tbl[chip_idx].pci_flags; +#if LINUX_VERSION_CODE >= 0x2030C + /* Wow. A oversized, hard-to-use abstraction. Bogus. */ + pciaddr = pdev->resource[(pci_flags >> 4) & 7].start; +#else + pciaddr = pdev->base_address[(pci_flags >> 4) & 7]; +#if defined(__alpha__) /* Really any machine with 64 bit addressing. */ + if (pci_flags & PCI_ADDR_64BITS) + pciaddr |= ((long)pdev->base_address[((pci_flags>>4)&7)+ 1]) << 32; +#endif +#endif + if (msg_level > 2) + printk(KERN_INFO "Found %s at PCI address %#lx, mapped IRQ %d.\n", + pci_tbl[chip_idx].name, pciaddr, pdev->irq); + + if ( ! (pci_flags & PCI_UNUSED_IRQ) && + (pdev->irq == 0 || pdev->irq == 255)) { + if (pdev->bus->number == 32) /* Broken CardBus activation. */ + printk(KERN_WARNING "Resources for CardBus device '%s' have" + " not been allocated.\n" + KERN_WARNING "Activation has been delayed.\n", + pci_tbl[chip_idx].name); + else + printk(KERN_WARNING "PCI device '%s' was not assigned an " + "IRQ.\n" + KERN_WARNING "It will not be activated.\n", + pci_tbl[chip_idx].name); + continue; + } + if ((pci_flags & PCI_BASE_ADDRESS_SPACE_IO)) { + ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK; + if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK, + pci_tbl[chip_idx].io_size)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx for device " + "'%s'.\n", pciaddr, pci_tbl[chip_idx].name); + continue; + } + if ( ! (pci_flags & PCI_NO_ACPI_WAKE)) + acpi_wake(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", + pdev->bus->number, pdev->devfn, pci_command, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); + } + + newdev = drv_id->probe1(pdev, initial_device, + ioaddr, pdev->irq, chip_idx, cards_found); + if (newdev == NULL) + continue; + initial_device = 0; + cards_found++; + if (pci_flags & PCI_COMMAND_MASTER) { + pci_set_master(pdev); + if ( ! (pci_flags & PCI_NO_MIN_LATENCY)) { + u8 pci_latency; + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < min_pci_latency) { + printk(KERN_INFO " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to %d clocks.\n", + pci_latency, min_pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + min_pci_latency); + } + } + } + { + struct dev_info *devp = + kmalloc(sizeof(struct dev_info), GFP_KERNEL); + if (devp == 0) + continue; + devp->next = dev_list; + devp->dev = newdev; + devp->drv_id = drv_id; + dev_list = devp; + } + } + + if (((drv_id->flags & PCI_HOTSWAP) + && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0) + || cards_found) { + MOD_INC_USE_COUNT; + drv_id->next = drv_list; + drv_list = drv_id; + return 0; + } else + return -ENODEV; +} +#else +int pci_drv_register(struct drv_id_info *drv_id, void *initial_device) +{ + int pci_index, cards_found = 0; + unsigned char pci_bus, pci_device_fn; + struct pci_dev *pdev; + struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl; + void *newdev; + + if ( ! pcibios_present()) + return -ENODEV; + + for (pci_index = 0; pci_index < 0xff; pci_index++) { + u32 pci_id, subsys_id, pci_class_rev; + u16 pci_command, new_command; + int chip_idx, irq, pci_flags; + long pciaddr; + long ioaddr; + u32 pci_busaddr; + u8 pci_irq_line; + + if (pcibios_find_class (drv_id->pci_class, pci_index, + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &pci_id); + /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */ + pcibios_read_config_dword(pci_bus, pci_device_fn, 0x2c, &subsys_id); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_REVISION_ID, &pci_class_rev); + + for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { + struct pci_id_info *chip = &pci_tbl[chip_idx]; + if ((pci_id & chip->id.pci_mask) == chip->id.pci + && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem + && (pci_class_rev&chip->id.revision_mask) == chip->id.revision) + break; + } + if (pci_tbl[chip_idx].name == 0) /* Compiled out! */ + continue; + + pci_flags = pci_tbl[chip_idx].pci_flags; + pdev = pci_find_slot(pci_bus, pci_device_fn); + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + irq = pci_irq_line; + pcibios_read_config_dword(pci_bus, pci_device_fn, + ((pci_flags >> 2) & 0x1C) + 0x10, + &pci_busaddr); + pciaddr = pci_busaddr; +#if defined(__alpha__) + if (pci_flags & PCI_ADDR_64BITS) { + pcibios_read_config_dword(pci_bus, pci_device_fn, + ((pci_flags >> 2) & 0x1C) + 0x14, + &pci_busaddr); + pciaddr |= ((long)pci_busaddr)<<32; + } +#endif + + if (msg_level > 2) + printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", + pci_tbl[chip_idx].name, pciaddr, irq); + + if ( ! (pci_flags & PCI_UNUSED_IRQ) && + (irq == 0 || irq == 255)) { + if (pci_bus == 32) /* Broken CardBus activation. */ + printk(KERN_WARNING "Resources for CardBus device '%s' have" + " not been allocated.\n" + KERN_WARNING "It will not be activated.\n", + pci_tbl[chip_idx].name); + else + printk(KERN_WARNING "PCI device '%s' was not assigned an " + "IRQ.\n" + KERN_WARNING "It will not be activated.\n", + pci_tbl[chip_idx].name); + continue; + } + + if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) { + ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK; + if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK, + pci_tbl[chip_idx].io_size)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx.\n", + pciaddr); + continue; + } + + if ( ! (pci_flags & PCI_NO_ACPI_WAKE)) + acpi_wake(pdev); + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", + pci_bus, pci_device_fn, pci_command, new_command); + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + + newdev = drv_id->probe1(pdev, initial_device, + ioaddr, irq, chip_idx, cards_found); + + if (newdev && (pci_flags & PCI_COMMAND_MASTER) && + ! (pci_flags & PCI_NO_MIN_LATENCY)) { + u8 pci_latency; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < min_pci_latency) { + printk(KERN_INFO " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to %d clocks.\n", + pci_latency, min_pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, min_pci_latency); + } + } + if (newdev) { + struct dev_info *devp = + kmalloc(sizeof(struct dev_info), GFP_KERNEL); + if (devp) { + devp->next = dev_list; + devp->dev = newdev; + devp->drv_id = drv_id; + dev_list = devp; + } + } + initial_device = 0; + cards_found++; + } + + if (((drv_id->flags & PCI_HOTSWAP) + && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0) + || cards_found) { + MOD_INC_USE_COUNT; + drv_id->next = drv_list; + drv_list = drv_id; + return 0; + } else + return cards_found ? 0 : -ENODEV; +} +#endif + +void pci_drv_unregister(struct drv_id_info *drv_id) +{ + struct drv_id_info **drvp; + struct dev_info **devip = &dev_list; + + if (unregister_hotswap_hook) + (*unregister_hotswap_hook)(drv_id); + + for (drvp = &drv_list; *drvp; drvp = &(*drvp)->next) + if (*drvp == drv_id) { + *drvp = (*drvp)->next; + MOD_DEC_USE_COUNT; + break; + } + while (*devip) { + struct dev_info *thisdevi = *devip; + if (thisdevi->drv_id == drv_id) { + *devip = thisdevi->next; + kfree(thisdevi); + } else + devip = &(*devip)->next; + } + + return; +} + +#if LINUX_VERSION_CODE < 0x20400 +/* + Search PCI configuration space for the specified capability registers. + Return the index, or 0 on failure. + The 2.4 kernel now includes this function. +*/ +int pci_find_capability(struct pci_dev *pdev, int findtype) +{ + u16 pci_status, cap_type; + u8 pci_cap_idx; + int cap_idx; + + pci_read_config_word(pdev, PCI_STATUS, &pci_status); + if ( ! (pci_status & PCI_STATUS_CAP_LIST)) + return 0; + pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pci_cap_idx); + cap_idx = pci_cap_idx; + for (cap_idx = pci_cap_idx; cap_idx; cap_idx = (cap_type >> 8) & 0xff) { + pci_read_config_word(pdev, cap_idx, &cap_type); + if ((cap_type & 0xff) == findtype) + return cap_idx; + } + return 0; +} +#endif + +/* Change a device from D3 (sleep) to D0 (active). + Return the old power state. + This is more complicated than you might first expect since most cards + forget all PCI config info during the transition! */ +int acpi_wake(struct pci_dev *pdev) +{ + u32 base[5], romaddr; + u16 pci_command, pwr_command; + u8 pci_latency, pci_cacheline, irq; + int i, pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); + + if (pwr_cmd_idx == 0) + return 0; + pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); + if ((pwr_command & 3) == 0) + return 0; + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + for (i = 0; i < 5; i++) + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, + &base[i]); + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); + pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); + + pci_write_config_word(pdev, pwr_cmd_idx + 4, 0x0000); + for (i = 0; i < 5; i++) + if (base[i]) + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, + base[i]); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); + pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); + pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); + pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); + pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); + return pwr_command & 3; +} + +int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state) +{ + u16 pwr_command; + int pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); + + if (pwr_cmd_idx == 0) + return 0; + pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); + if ((pwr_command & 3) == ACPI_D3 && new_state != ACPI_D3) + acpi_wake(pdev); /* The complicated sequence. */ + pci_write_config_word(pdev, pwr_cmd_idx + 4, + (pwr_command & ~3) | new_state); + return pwr_command & 3; +} + +#if defined(CONFIG_PM) +static int handle_pm_event(struct pm_dev *dev, int event, void *data) +{ + static int down = 0; + struct dev_info *devi; + int pwr_cmd = -1; + + if (msg_level > 1) + printk(KERN_DEBUG "pci-scan: Handling power event %d for driver " + "list %s...\n", + event, drv_list->name); + switch (event) { + case PM_SUSPEND: + if (down) { + printk(KERN_DEBUG "pci-scan: Received extra suspend event\n"); + break; + } + down = 1; + for (devi = dev_list; devi; devi = devi->next) + if (devi->drv_id->pwr_event) + devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND); + break; + case PM_RESUME: + if (!down) { + printk(KERN_DEBUG "pci-scan: Received bogus resume event\n"); + break; + } + for (devi = dev_list; devi; devi = devi->next) { + if (devi->drv_id->pwr_event) { + if (msg_level > 3) + printk(KERN_DEBUG "pci-scan: Calling resume for %s " + "device.\n", devi->drv_id->name); + devi->drv_id->pwr_event(devi->dev, DRV_RESUME); + } + } + down = 0; + break; + case PM_SET_WAKEUP: pwr_cmd = DRV_PWR_WakeOn; break; + case PM_EJECT: pwr_cmd = DRV_DETACH; break; + default: + printk(KERN_DEBUG "pci-scan: Unknown power management event %d.\n", + event); + } + if (pwr_cmd >= 0) + for (devi = dev_list; devi; devi = devi->next) + if (devi->drv_id->pwr_event) + devi->drv_id->pwr_event(devi->dev, pwr_cmd); + + return 0; +} + +#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + struct dev_info *devi; + + if (msg_level > 1) + printk(KERN_DEBUG "pci-scan: Handling APM event %d for driver " + "list %s...\n", + event, drv_list->name); + return 0; + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "pci-scan: Received extra suspend event\n"); + break; + } + down = 1; + for (devi = dev_list; devi; devi = devi->next) + if (devi->drv_id->pwr_event) + devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND); + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "pci-scan: Received bogus resume event\n"); + break; + } + for (devi = dev_list; devi; devi = devi->next) + if (devi->drv_id->pwr_event) + devi->drv_id->pwr_event(devi->dev, DRV_RESUME); + down = 0; + break; + } + return 0; +} +#endif /* CONFIG_APM */ + +#ifdef MODULE +int init_module(void) +{ + if (msg_level) /* Emit version even if no cards detected. */ + printk(KERN_INFO "%s", version); + +#if defined(CONFIG_PM) + pm_register(PM_PCI_DEV, 0, &handle_pm_event); +#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 + apm_register_callback(&handle_apm_event); +#endif + return 0; +} +void cleanup_module(void) +{ +#if defined(CONFIG_PM) + pm_unregister_all(&handle_pm_event); +#elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 + apm_unregister_callback(&handle_apm_event); +#endif + if (dev_list != NULL) + printk(KERN_WARNING "pci-scan: Unfreed device references.\n"); + return; +} +#endif + + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O6 -c pci-scan.c" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -urN linux-2.4.20/drivers/net/pci-scan.h linux-2.4.20-3c59x/drivers/net/pci-scan.h --- linux-2.4.20/drivers/net/pci-scan.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.4.20-3c59x/drivers/net/pci-scan.h 2001-03-18 16:35:59.000000000 -0500 @@ -0,0 +1,90 @@ +#ifndef _PCI_SCAN_H +#define _PCI_SCAN_H +/* + version 1.02 $Version:$ $Date: 2001/03/18 21:35:59 $ + Copyright 1999-2001 Donald Becker / Scyld Computing Corporation + This software is part of the Linux kernel. It may be used and + distributed according to the terms of the GNU Public License, + incorporated herein by reference. +*/ + +/* + These are the structures in the table that drives the PCI probe routines. + Note the matching code uses a bitmask: more specific table entries should + be placed before "catch-all" entries. + + The table must be zero terminated. +*/ +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, + PCI_UNUSED_IRQ=0x800, +}; + +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ +}; + +enum drv_id_flags { + PCI_HOTSWAP=1, /* Leave module loaded for Cardbus-like chips. */ +}; +enum drv_pwr_action { + DRV_NOOP, /* No action. */ + DRV_ATTACH, /* The driver may expect power ops. */ + DRV_SUSPEND, /* Machine suspending, next event RESUME or DETACH. */ + DRV_RESUME, /* Resume from previous SUSPEND */ + DRV_DETACH, /* Card will-be/is gone. Valid from SUSPEND! */ + DRV_PWR_WakeOn, /* Put device in e.g. Wake-On-LAN mode. */ + DRV_PWR_DOWN, /* Go to lowest power mode. */ + DRV_PWR_UP, /* Go to normal power mode. */ +}; + +struct drv_id_info { + const char *name; /* Single-word driver name. */ + int flags; + int pci_class; /* Typically PCI_CLASS_NETWORK_ETHERNET<<8. */ + struct pci_id_info *pci_dev_tbl; + void *(*probe1)(struct pci_dev *pdev, void *dev_ptr, + long ioaddr, int irq, int table_idx, int fnd_cnt); + /* Optional, called for suspend, resume and detach. */ + int (*pwr_event)(void *dev, int event); + /* Internal values. */ + struct drv_id_info *next; + void *cb_ops; +}; + +/* PCI scan and activate. + Scan PCI-like hardware, calling probe1(..,dev,..) on devices that match. + Returns -ENODEV, a negative number, if no cards are found. */ + +extern int pci_drv_register(struct drv_id_info *drv_id, void *initial_device); +extern void pci_drv_unregister(struct drv_id_info *drv_id); + + +/* ACPI routines. + Wake (change to ACPI D0 state) or set the ACPI power level of a sleeping + ACPI device. Returns the old power state. */ + +int acpi_wake(struct pci_dev *pdev); +enum acpi_pwr_state {ACPI_D0, ACPI_D1, ACPI_D2, ACPI_D3}; +int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state state); + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ +#endif