patch-2.3.99-pre6 linux/drivers/net/3c59x.c
Next file: linux/drivers/net/8139too.c
Previous file: linux/drivers/net/3c515.c
Back to the patch index
Back to the overall index
- Lines: 2355
- Date:
Mon Apr 24 15:17:06 2000
- Orig file:
v2.3.99-pre5/linux/drivers/net/3c59x.c
- Orig date:
Mon Mar 27 08:08:25 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
@@ -1,6 +1,6 @@
-/* 3c59x.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
/*
- Written 1996-1998 by Donald Becker.
+ Written 1996-1999 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -13,14 +13,51 @@
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- Version history:
- 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
- Remove compatibility defines for kernel versions < 2.2.x.
- Update for new 2.3.x module interface
-
+ Linux Kernel Additions:
+
+ LK1.1.2 (March 19, 2000)
+ * New PCI interface (jgarzik)
+
+*/
+
+/*
+ 22Apr00, Andrew Morton <andrewm@uow.edu.au>
+ - 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
+ - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
+ - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
+*/
+
+/*
+ * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamaci.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.
*/
+static char *version =
+"3c59x.c:v0.99L+LK1.1.2+AKPM 24 Apr 2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -29,7 +66,13 @@
/* 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 = 20;
+static int max_interrupt_work = 32;
+
+/* 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.
+ */
+#define tx_interrupt_mitigation 1
/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
#define vortex_debug debug
@@ -52,8 +95,12 @@
#define RX_RING_SIZE 32
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-#include <linux/config.h>
-#include <linux/version.h>
+#ifndef __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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -61,11 +108,11 @@
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/in.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -80,14 +127,8 @@
#include <linux/delay.h>
-#define PCI_SUPPORT_VER2
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-
-static char *version __initdata =
-"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
+MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
MODULE_PARM(debug, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
@@ -111,6 +152,10 @@
code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;
+#define PFX "3c59x: "
+
+
+
/*
Theory of Operation
@@ -168,7 +213,6 @@
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
@@ -195,68 +239,163 @@
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
+
+enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
+ EEPROM_230=8, /* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */
+ HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+
+
+enum vortex_chips {
+ CH_3C590 = 0,
+ CH_3C592,
+ CH_3C597,
+ CH_3C595_1,
+ CH_3C595_2,
+
+ CH_3C595_3,
+ CH_VORTEX,
+ 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_3CSOHO100_TX,
+ CH_3C555,
+ CH_3C575_1,
+ CH_3CCFE575,
+ CH_3CCFE575CT,
+
+ CH_3CCFE656,
+ CH_3CCFEM656,
+ 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;
- u16 vendor_id, device_id, device_id_mask, flags;
- int drv_flags, io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
- HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, int dev_id, int card_idx);
-
-static struct pci_id_info pci_tbl[] = {
- {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3Com Vortex", 0x10B7, 0x5900, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905C Tornado", 0x10B7, 0x9200, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+ int flags;
+ int drv_flags;
+ int io_size;
+} vortex_info_tbl[] = {
+ {"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, },
+#define EISA_TBL_OFFSET 6 /* Offset of this entry for vortex_eisa_init */
+ {"3Com Vortex",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"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, 128, },
+
+ {"3c900 Cyclone 10Mbps Combo",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c900B-FL Cyclone 10base-FL",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 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, 128, },
+ {"3c905B Cyclone 10/100/BNC",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c905B-FX Cyclone 100baseFx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c905C Tornado",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c980 Cyclone",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+
+ {"3cSOHO100-TX Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c555 Laptop Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c575 Boomerang CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 64, },
+ {"3CCFE575 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ {"3CCFE575CT Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+
+ {"3CCFE656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ {"3CCFEM656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ {"3c450 Cyclone/unknown", /* AKPM: from Don's 0.99N */
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 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, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
+ { 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, 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, 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, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
{0,}, /* 0 terminated list. */
};
+MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
+
/* Operational definitions.
These are not used by other compilation units and thus are not
@@ -392,7 +531,7 @@
};
/* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20 };
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
struct vortex_private {
/* The Rx and Tx rings should be quad-word-aligned. */
@@ -403,36 +542,38 @@
/* 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;
+ 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 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. */
/* PCI configuration space information. */
- u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */
+ struct pci_dev *pdev;
char *cb_fn_base; /* CardBus function status addr space. */
int chip_id;
- struct pci_dev *pdev; /* Device for DMA mapping */
/* The remainder are related to chip state, mostly media selection. */
- unsigned long in_interrupt;
- struct timer_list timer; /* Media selection timer. */
- int options; /* User-settable misc. driver options. */
- unsigned int media_override:3, /* Passed-in media type. */
+ 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. */
+ bus_master:1, /* Vortex can only do a fragment bus-m. */
full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- hw_csums:1, /* Has hardware checksums. */
- tx_full:1;
+ hw_csums:1, /* Has hardware checksums. */
+ tx_full:1,
+ open:1;
u16 status_enable;
u16 intr_enable;
u16 available_media; /* From Wn3_Options. */
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 */
+ spinlock_t lock;
};
/* The action to take with a media selection timer tick.
@@ -446,9 +587,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},
@@ -463,329 +604,245 @@
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[]);
-#endif
+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);
static int vortex_open(struct net_device *dev);
static void mdio_sync(long ioaddr, int bits);
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 int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void vortex_tx_timeout(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 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);
+static void acpi_set_WOL(struct net_device *dev);
-
/* 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};
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
-#ifndef CARDBUS
+
+/* A list of all installed Vortex EISA devices, for removing the driver module. */
+static struct net_device *root_vortex_eisa_dev = NULL;
+
/* Variables to work-around the Compaq PCI BIOS32 problem. */
static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
-#ifdef CARDBUS
+static int vortex_cards_found = 0;
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *vortex_attach(dev_locator_t *loc)
+static void vortex_suspend (struct pci_dev *pdev)
{
- u16 dev_id, vendor_id;
- u32 io;
- u8 irq;
- struct net_device *dev;
- struct pci_dev *pdev;
- int chip_idx;
+ struct net_device *dev = pdev->driver_data;
- if (loc->bus != LOC_PCI) return NULL;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) return NULL;
- io = pdev->resource[0].start;
- irq = pdev->irq;
- vendor_id = pdev->vendor;
- dev_id = pdev->device;
- printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
- pdev->bus->number, pdev->devfn, dev_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].vendor_id; chip_idx++)
- if (vendor_id == pci_tbl[chip_idx].vendor_id
- && (dev_id & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */
- printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
- "vortex_attach().\n", vendor_id, dev_id);
- return NULL;
- }
- dev = vortex_probe1(pdev, 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;
-}
+ printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
-static void vortex_detach(dev_node_t *node)
-{
- struct net_device **devp, **next;
- printk(KERN_INFO "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)
- vortex_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);
- kfree(node);
- MOD_DEC_USE_COUNT;
+ if (dev && dev->priv) {
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ if (vp->open) {
+ netif_device_detach(dev);
+ vortex_down(dev);
+ }
}
}
-struct driver_operations vortex_ops = {
- "3c575_cb", vortex_attach, NULL, NULL, vortex_detach
-};
-
-#endif /* Cardbus support */
+static void vortex_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
-static int __init vortex_init_module (void)
-{
- if (vortex_debug)
- printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
- register_driver(&vortex_ops);
- return 0;
-#else
- return vortex_scan(pci_tbl);
-#endif
+ if (dev && dev->priv) {
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ if (vp->open) {
+ vortex_up(dev);
+ netif_device_attach(dev);
+ }
+ }
}
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[])
+/* returns count found (>= 0), or negative on error */
+static int __init vortex_eisa_init (void)
{
- int cards_found = 0;
- struct net_device *dev;
-
- /* Allow an EISA-only driver. */
-#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
- /* Ideally we would detect all cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well with the current structure. So instead we detect 3Com cards
- in slot order. */
- if (pci_present()) {
- static int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
-
- for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command, pwr_cmd;
- int chip_idx, irq;
- long ioaddr;
- struct pci_dev *pdev;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- if (!pdev) continue;
- vendor = pdev->vendor;
- device = pdev->device;
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == pci_tbl[chip_idx].vendor_id
- && (device & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- {
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
- }
-
- /* Power-up the card. */
- pci_read_config_word(pdev, 0xe0, &pwr_cmd);
-
- if (pwr_cmd & 0x3) {
- /* Save the ioaddr and IRQ info! */
- printk(KERN_INFO " A 3Com network adapter is powered down!"
- " Setting the power state %4.4x->%4.4x.\n",
- pwr_cmd, pwr_cmd & ~3);
- pci_write_config_word(pdev, 0xe0, pwr_cmd & ~3);
- printk(KERN_INFO " Setting the IRQ to %d, IOADDR to %#lx.\n",
- irq, ioaddr);
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ioaddr);
- }
-
- if (ioaddr == 0) {
- printk(KERN_WARNING " A 3Com network adapter has been found, "
- "however it has not been assigned an I/O address.\n"
- " You may need to power-cycle the machine for this "
- "device to work!\n");
- continue;
- }
-
- if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
- continue;
-
- /* Activate the card. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ long ioaddr;
+ int rc;
+ int orig_cards_found = vortex_cards_found;
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- 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);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
+ /* Now check all slots of the EISA bus. */
+ if (!EISA_bus)
+ return 0;
- dev = vortex_probe1(pdev, ioaddr, irq,
- chip_idx, cards_found);
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int device_id;
- if (dev) {
- /* Get and check the latency values. 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 -- a bug in the Vortex chip only. */
- u8 pci_latency;
- u8 new_latency = (device & 0xff00) == 0x5900 ? 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);
- }
- dev = 0;
- cards_found++;
- }
- }
- }
-#endif /* NO_PCI */
+ if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+ continue;
- /* Now check all 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_TOTAL_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(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
- 4, cards_found);
- cards_found++;
- }
+ /* Check the standard EISA ID register for an encoded '3Com'. */
+ if (inw(ioaddr + 0xC80) != 0x6d50) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ 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) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
+ }
+
+ 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);
}
/* Special code to work-around the Compaq PCI BIOS32 problem. */
if (compaq_ioaddr) {
vortex_probe1(NULL, compaq_ioaddr, compaq_irq,
- compaq_device_id, cards_found++);
- dev = 0;
+ compaq_device_id, vortex_cards_found++);
}
- return cards_found ? 0 : -ENODEV;
+ return vortex_cards_found - orig_cards_found;
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int __devinit vortex_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
+ ent->driver_data, vortex_cards_found);
+ if (rc == 0)
+ vortex_cards_found++;
+ return rc;
}
-#endif /* ! Cardbus */
/*
- * vortex_probe1 - initialize one vortex board, after probing
- * has located one during bus scan.
+ * Start up the PCI device which is described by *pdev.
+ * Return 0 on success.
*
- * NOTE: pdev==NULL is a valid condition, indicating
- * non-PCI (generally EISA) bus device
+ * NOTE: pdev can be NULL, for the case of an EISA driver
*/
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
- long ioaddr, int irq,
- int chip_idx, int card_idx)
+static int __devinit vortex_probe1(struct pci_dev *pdev,
+ long ioaddr, int irq,
+ int chip_idx, int card_idx)
{
struct vortex_private *vp;
int option;
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
struct net_device *dev;
+ static int printed_version = 0;
+ int retval;
- dev = init_etherdev(NULL, 0);
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
- printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
- dev->name, pci_tbl[chip_idx].name, ioaddr);
+ dev = init_etherdev(NULL, sizeof(*vp));
+ if (!dev) {
+ printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
+ dev->name,
+ pdev ? "PCI" : "EISA",
+ vortex_info_tbl[chip_idx].name,
+ ioaddr);
+ /* private struct aligned and zeroed by init_etherdev */
+ vp = dev->priv;
dev->base_addr = ioaddr;
dev->irq = irq;
dev->mtu = mtu;
- /* Make certain the descriptor lists are aligned. */
- vp = kmalloc(sizeof(*vp), GFP_KERNEL);
-
- memset(vp, 0, sizeof(*vp));
- dev->priv = vp;
-
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
+ /* 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 */
+ if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
+ dev->name)) {
+ printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+ dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+ retval = -EBUSY;
+ goto free_dev;
+ }
+
+ /* wake up and enable device */
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
+ retval = -EIO;
+ goto free_region;
+ }
+
+ /* enable bus-mastering if necessary */
+ if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+ pci_set_master (pdev);
+ }
+ vp->lock = SPIN_LOCK_UNLOCKED;
vp->chip_id = chip_idx;
- vp->pci_bus = pdev == NULL ? 0 : pdev->bus->number;
- vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn;
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);
+ if (vp->rx_ring == 0)
+ {
+ retval = -ENOMEM;
+ 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)
+ pdev->driver_data = dev;
+
/* The lower four bits are the media type. */
if (dev->mem_start)
+ { /*
+ * AKPM: ewww.. The 'options' param is passed in as the third arg to the
+ * LILO 'ether=' argument for non-modular use
+ */
option = dev->mem_start;
+ }
else if (card_idx < MAX_UNITS)
option = options[card_idx];
else
option = -1;
if (option >= 0) {
- vp->media_override = ((option & 7) == 2) ? 0 : option & 7;
- vp->full_duplex = (option & 8) ? 1 : 0;
+ vp->media_override = ((option & 7) == 2) ? 0 : option & 15;
+ vp->full_duplex = (option & 0x200) ? 1 : 0;
vp->bus_master = (option & 16) ? 1 : 0;
} else {
vp->media_override = 7;
@@ -797,23 +854,21 @@
vp->force_fd = vp->full_duplex;
vp->options = option;
-
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
- for (i = 0; i < 0x40; i++) {
- int timer;
-#ifdef CARDBUS
- outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
- outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-#endif
- /* 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;
+ {
+ int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230 : 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);
}
- eeprom[i] = inw(ioaddr + Wn0EepromData);
}
for (i = 0; i < 0x18; i++)
checksum ^= eeprom[i];
@@ -825,11 +880,14 @@
}
if (checksum != 0x00)
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-
for (i = 0; i < 3; i++)
((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
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__
printk(", IRQ %s\n", __irq_itoa(dev->irq));
#else
@@ -840,15 +898,19 @@
dev->irq);
#endif
- if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+ if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
u32 fn_st_addr; /* Cardbus function status space */
- fn_st_addr = pdev == NULL ? 0 : pdev->resource[2].start;
+ fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
- vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
- printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
- " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
- EL3WINDOW(2);
- outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+ vp->cb_fn_base = ioremap(fn_st_addr, 128);
+ printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
+ dev->name, fn_st_addr, vp->cb_fn_base);
+#if 0 /* AKPM */
+ if (vortex_pci_tbl[vp->chip_id].device != 0x5257) {
+ EL3WINDOW(2);
+ outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+ }
+#endif
}
/* Extract our information from the EEPROM data. */
@@ -857,10 +919,13 @@
vp->capabilities = eeprom[16];
if (vp->info1 & 0x8000)
+ {
vp->full_duplex = 1;
+ printk(KERN_INFO "Full duplex capable\n");
+ }
{
- char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
union wn3_config config;
EL3WINDOW(3);
vp->available_media = inw(ioaddr + Wn3_Options);
@@ -919,38 +984,65 @@
}
}
+ if (vp->capabilities & CapPwrMgmt)
+ acpi_set_WOL(dev);
+
if (vp->capabilities & CapBusMaster) {
vp->full_bus_master_tx = 1;
printk(KERN_INFO" Enabling 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 */
}
- /* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
/* The 3c59x-specific entries in the device structure. */
dev->open = &vortex_open;
dev->hard_start_xmit = &vortex_start_xmit;
- dev->tx_timeout = &vortex_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
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 = TX_TIMEOUT;
+
+ return 0;
- return dev;
+free_region:
+ release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+free_dev:
+ kfree (dev);
+ printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval);
+out:
+ return retval;
}
-
-static int
-vortex_open(struct net_device *dev)
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+ int i = 2000;
+
+ outw(cmd, dev->base_addr + EL3_CMD);
+ while (--i > 0)
+ {
+ if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+ return;
+ }
+ printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+ dev->name, cmd, inw(dev->base_addr + EL3_STATUS));
+}
+
+static void
+vortex_up(struct net_device *dev)
{
long ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
union wn3_config config;
- int i;
+ int i, device_id;
+ if (vp->pdev)
+ device_id = vp->pdev->device;
+ else
+ device_id = 0x5900; /* EISA */
+
/* Before initializing select the active media port. */
EL3WINDOW(3);
config.i = inl(ioaddr + Wn3_Config);
@@ -961,15 +1053,24 @@
dev->name, vp->media_override,
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
- } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
- dev->if_port = XCVR_NWAY;
} else if (vp->autoselect) {
- /* 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;
- } else
+ if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
+ printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name);
+ dev->if_port = XCVR_NWAY;
+ } 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;
+ printk(KERN_INFO "%s: first avaialble mdeia type: %s\n",
+ dev->name,
+ media_tbl[dev->if_port].name);
+ }
+ } else {
dev->if_port = vp->default_media;
+ 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);
@@ -983,7 +1084,13 @@
vp->full_duplex = vp->force_fd;
config.u.xcvr = dev->if_port;
- outl(config.i, ioaddr + Wn3_Config);
+ if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+ {
+ if (vortex_debug > 6)
+ printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n",
+ config.i);
+ outl(config.i, ioaddr + Wn3_Config);
+ }
if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
int mii_reg1, mii_reg5;
@@ -1008,31 +1115,18 @@
(dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
if (vortex_debug > 1) {
- printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
+ printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
dev->name, config.i);
}
- outw(TxReset, ioaddr + EL3_CMD);
- for (i = 2000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-
- outw(RxReset, ioaddr + EL3_CMD);
- /* Wait a few ticks for the RxReset command to complete. */
- for (i = 2000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, TxReset);
+ wait_for_completion(dev, RxReset);
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
- /* Use the now-standard shared IRQ implementation. */
- if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
- return -EAGAIN;
- }
-
if (vortex_debug > 1) {
EL3WINDOW(4);
- printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
+ printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n",
dev->name, dev->irq, inw(ioaddr + Wn4_Media));
}
@@ -1042,6 +1136,19 @@
outb(dev->dev_addr[i], ioaddr + i);
for (; i < 12; i+=2)
outw(0, ioaddr + i);
+ if (vp->cb_fn_base) {
+ u_short n = inw(ioaddr + Wn2_ResetOptions);
+#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */
+ /* Inverted LED polarity */
+ if (device_id != 0x5257)
+ n |= 0x0010;
+#endif
+ /* Inverted polarity of MII power bit */
+ if ((device_id == 0x6560) || (device_id == 0x6562) ||
+ (device_id == 0x5257))
+ n |= 0x4000;
+ outw(n, ioaddr + Wn2_ResetOptions);
+ }
if (dev->if_port == XCVR_10base2)
/* Start the thinnet transceiver. We should really wait 50ms...*/
@@ -1073,39 +1180,24 @@
/* Initialize the RxEarly register as recommended. */
outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
outl(0x0020, ioaddr + PktStatus);
- 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));
- }
- /* Wrap the ring. */
- vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
- outl(vp->rx_ring_dma, ioaddr + UpListPtr);
+ outl(virt_to_bus(&vp->rx_ring[0]), 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;
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
- /* Clear the Tx ring. */
+ /* 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;
for (i = 0; i < TX_RING_SIZE; i++)
vp->tx_skbuff[i] = 0;
outl(0, ioaddr + DownListPtr);
}
- /* Set reciever mode: presumably accept b-case and phys addr only. */
+ /* Set receiver mode: presumably accept b-case and phys addr only. */
set_rx_mode(dev);
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
- vp->in_interrupt = 0;
+ netif_start_queue (dev);
outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -1114,7 +1206,8 @@
(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 |
+ 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);
@@ -1125,11 +1218,55 @@
if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
writel(0x8000, vp->cb_fn_base + 4);
- netif_start_queue(dev);
+ /* AKPM: unjam the 3CCFE575CT */
+ wait_for_completion(dev, TxReset);
+ outw(TxEnable, ioaddr + EL3_CMD);
+}
+
+static int
+vortex_open(struct net_device *dev)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int i;
+ int retval;
MOD_INC_USE_COUNT;
+ /* Use the now-standard shared IRQ implementation. */
+ if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt,
+ SA_SHIRQ, dev->name, dev)) {
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ 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(virt_to_bus(&vp->rx_ring[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(virt_to_bus(skb->tail));
+ }
+ /* Wrap the ring. */
+ vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
+ }
+
+ vortex_up(dev);
+ vp->open = 1;
return 0;
+out:
+ MOD_DEC_USE_COUNT;
+ if (vortex_debug > 1)
+ printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval);
+ return retval;
}
static void vortex_timer(unsigned long data)
@@ -1137,7 +1274,7 @@
struct net_device *dev = (struct net_device *)data;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- int next_tick = 0;
+ int next_tick = 60*HZ;
int ok = 0;
int media_status, mii_status, old_window;
@@ -1152,43 +1289,50 @@
switch (dev->if_port) {
case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx:
if (media_status & Media_LnkBeat) {
- ok = 1;
- if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
- dev->name, media_tbl[dev->if_port].name, media_status);
+ ok = 1;
+ if (vortex_debug > 1)
+ 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)
- printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
+ 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(ioaddr, vp->phys[0], 1);
- ok = 1;
- if (debug > 1)
- 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->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. */
- outb((vp->full_duplex ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0),
- ioaddr + Wn3_MAC_Ctrl);
- }
- next_tick = 60*HZ;
- }
- }
- break;
+ case XCVR_MII: case XCVR_NWAY:
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */
+
+ mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+ ok = 1;
+ if (vortex_debug > 1)
+ 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->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); /* AKPM: this was missing from 2.3.99 3c59x.c! */
+ outb((vp->full_duplex ? 0x20 : 0) |
+ (dev->mtu > 1500 ? 0x40 : 0),
+ ioaddr + Wn3_MAC_Ctrl);
+ }
+ next_tick = 60*HZ;
+ }
+ }
+ spin_unlock_irqrestore(&vp->lock, flags);
+ }
+ break;
default: /* Other media types handled by Tx timeouts. */
if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
+ printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
ok = 1;
}
@@ -1205,11 +1349,11 @@
"%s port.\n",
dev->name, media_tbl[dev->if_port].name);
} else {
- if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: Media selection failed, now trying "
- "%s port.\n",
- dev->name, media_tbl[dev->if_port].name);
- next_tick = media_tbl[dev->if_port].wait;
+ if (vortex_debug > 1)
+ printk(KERN_DEBUG "%s: Media selection failed, now trying "
+ "%s port.\n",
+ dev->name, media_tbl[dev->if_port].name);
+ next_tick = media_tbl[dev->if_port].wait;
}
outw((media_status & ~(Media_10TP|Media_SQE)) |
media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1225,14 +1369,14 @@
EL3WINDOW(old_window);
enable_irq(dev->irq);
- if (vortex_debug > 2)
+ if (vortex_debug > 1)
printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
- if (next_tick) {
- vp->timer.expires = RUN_AT(next_tick);
- add_timer(&vp->timer);
- }
+ vp->timer.expires = RUN_AT(next_tick);
+ add_timer(&vp->timer);
+ if (vp->deferred)
+ outw(FakeIntr, ioaddr + EL3_CMD);
return;
}
@@ -1240,7 +1384,6 @@
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- int j;
printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
dev->name, inb(ioaddr + TxStatus),
@@ -1253,30 +1396,41 @@
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. */
- vortex_interrupt(dev->irq, dev, 0);
+ {
+ /*
+ * AKPM: 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);
+ }
}
- outw(TxReset, ioaddr + EL3_CMD);
- for (j = 200; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
-#if ! defined(final_version)
- if (vp->full_bus_master_tx) {
- int i;
- printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d "
- "current %d.\n",
- vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
- printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n",
- inl(ioaddr + DownListPtr),
- &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
- 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));
+ if (vortex_debug > 0) {
+ if (vp->full_bus_master_tx) {
+ int i;
+ printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d "
+ "current %d.\n",
+ vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+ printk(KERN_DEBUG " Transmit list %8.8x vs. %p.\n",
+ inl(ioaddr + DownListPtr),
+ &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+ 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
+
+ wait_for_completion(dev, TxReset);
+
vp->stats.tx_errors++;
if (vp->full_bus_master_tx) {
if (vortex_debug > 0)
@@ -1287,8 +1441,10 @@
ioaddr + DownListPtr);
if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
vp->tx_full = 0;
- netif_wake_queue(dev);
+ netif_start_queue (dev);
}
+ if (vp->tx_full)
+ netif_stop_queue (dev);
outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
outw(DownUnstall, ioaddr + EL3_CMD);
} else
@@ -1312,7 +1468,9 @@
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
int do_tx_reset = 0;
- int i;
+
+ if (vortex_debug > 2)
+ printk(KERN_DEBUG "%s: vortex_error(), status=0x%x\n", dev->name, status);
if (status & TxComplete) { /* Really "TxError" for us. */
unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1358,25 +1516,18 @@
u16 fifo_diag;
EL3WINDOW(4);
fifo_diag = inw(ioaddr + Wn4_FIFODiag);
- if (vortex_debug > 0)
- printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
- dev->name, fifo_diag);
+ printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+ dev->name, fifo_diag);
/* Adapter failure requires Tx/Rx reset and reinit. */
if (vp->full_bus_master_tx) {
- outw(TotalReset | 0xff, ioaddr + EL3_CMD);
- for (i = 2000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
- /* Re-enable the receiver. */
- outw(RxEnable, ioaddr + EL3_CMD);
- outw(TxEnable, ioaddr + EL3_CMD);
+ /* In this case, blow the card away */
+ vortex_down(dev);
+ wait_for_completion(dev, TotalReset | 0xff);
+ vortex_up(dev);
} else if (fifo_diag & 0x0400)
do_tx_reset = 1;
if (fifo_diag & 0x3000) {
- outw(RxReset, ioaddr + EL3_CMD);
- for (i = 2000; i >= 0 ; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, RxReset);
/* Set the Rx filter to the current state. */
set_rx_mode(dev);
outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1384,40 +1535,37 @@
}
}
if (do_tx_reset) {
- int j;
- outw(TxReset, ioaddr + EL3_CMD);
- for (j = 200; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, TxReset);
outw(TxEnable, ioaddr + EL3_CMD);
}
}
-
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;
- netif_stop_queue(dev);
-
+ netif_stop_queue (dev);
+
/* 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);
+ outl( vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE),
+ ioaddr + Wn7_MasterAddr);
outw(len, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
outw(StartDMADown, ioaddr + EL3_CMD);
+ /* dev->tbusy 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_FREE_SKB(skb);
+ dev_kfree_skb (skb);
if (inw(ioaddr + TxFree) > 1536) {
- netif_wake_queue(dev);
+ netif_start_queue (dev);
} else
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1438,18 +1586,13 @@
if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
- int j;
- outw(TxReset, ioaddr + EL3_CMD);
- for (j = 200; j >= 0 ; j--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, TxReset);
}
outw(TxEnable, ioaddr + EL3_CMD);
}
outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- vp->stats.tx_bytes += skb->len;
return 0;
}
@@ -1459,21 +1602,22 @@
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- netif_stop_queue(dev);
+ if (vortex_debug > 6)
+ printk(KERN_DEBUG "boomerang_start_xmit()\n");
- if (1) {
+ netif_stop_queue (dev);
+ {
/* 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];
unsigned long flags;
- int i;
if (vortex_debug > 3)
printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
dev->name, vp->cur_tx);
if (vp->tx_full) {
- if (vortex_debug >0)
+ if (vortex_debug > 0)
printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
dev->name);
return 1;
@@ -1484,37 +1628,40 @@
vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
- /* Hmm... And some poor people try to use it on SMP machines 8) */
- save_flags(flags);
- cli();
- outw(DownStall, ioaddr + EL3_CMD);
+ spin_lock_irqsave(&vp->lock, flags);
/* Wait for the stall to complete. */
- for (i = 600; i >= 0 ; i--)
- if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
- break;
+ wait_for_completion(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);
queued_packet++;
}
- outw(DownUnstall, ioaddr + EL3_CMD);
- restore_flags(flags);
vp->cur_tx++;
if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
vp->tx_full = 1;
+ netif_stop_queue (dev);
} else { /* Clear previous interrupt enable. */
+#if defined(tx_interrupt_mitigation)
prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
- netif_wake_queue(dev);
+#endif
+ netif_start_queue (dev);
}
+ outw(DownUnstall, ioaddr + EL3_CMD);
+ spin_unlock_irqrestore(&vp->lock, flags);
dev->trans_start = jiffies;
- vp->stats.tx_bytes += skb->len;
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;
@@ -1523,10 +1670,23 @@
int latency, status;
int work_done = max_interrupt_work;
+ spin_lock(&vp->lock);
+
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
status = inw(ioaddr + EL3_STATUS);
+ if (vortex_debug > 6)
+ printk("AKPM: vortex_interrupt. status=0x%4x\n", status);
+
+ if (status & IntReq) {
+ status |= vp->deferred;
+ vp->deferred = 0;
+ }
+
+ if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */
+ goto handler_exit;
+
if (vortex_debug > 4)
printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
dev->name, status, latency);
@@ -1536,22 +1696,117 @@
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)
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);
+ 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 transfered buffer */
+ if (inw(ioaddr + TxFree) > 1536) {
+ 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); /* AKPM: This is new */
+ }
+ }
+ }
+ /* 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. */
+ del_timer(&vp->timer);
+ vp->timer.expires = RUN_AT(1);
+ add_timer(&vp->timer);
+ 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 | 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 latency, status;
+ int work_done = max_interrupt_work;
+
+ spin_lock(&vp->lock);
+
+ ioaddr = dev->base_addr;
+ latency = inb(ioaddr + Timer);
+ status = inw(ioaddr + EL3_STATUS);
+
+ if (vortex_debug > 6)
+ printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
+
+ if (status & IntReq) {
+ status |= vp->deferred;
+ vp->deferred = 0;
+ }
+
+ if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */
+ {
+ if (vortex_debug > 1)
+ printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
+ goto handler_exit;
+ }
+
+ if (vortex_debug > 4)
+ printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+ dev->name, status, latency);
+ 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);
}
if (status & DownComplete) {
unsigned int dirty_tx = vp->dirty_tx;
+ outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
while (vp->cur_tx - dirty_tx > 0) {
int entry = dirty_tx % TX_RING_SIZE;
if (inl(ioaddr + DownListPtr) ==
@@ -1560,31 +1815,27 @@
if (vp->tx_skbuff[entry]) {
struct sk_buff *skb = vp->tx_skbuff[entry];
- pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(vp->tx_skbuff[entry]);
+ pci_unmap_single(vp->pdev,
+ le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
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;
- outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
- vp->tx_full= 0;
- 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 transfered buffer */
- if (inw(ioaddr + TxFree) > 1536) {
- netif_wake_queue(dev);
- } else /* Interrupt when FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+ if (vortex_debug > 6)
+ printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n");
+ vp->tx_full = 0;
+ netif_wake_queue (dev);
}
}
+ if (vp->tx_full)
+ netif_stop_queue (dev);
+
/* Check for all uncommon interrupts at once. */
if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
if (status == 0xffff)
@@ -1593,19 +1844,20 @@
}
if (--work_done < 0) {
- 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. */
- break;
- }
+ 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. */
+ del_timer(&vp->timer);
+ vp->timer.expires = RUN_AT(1);
+ add_timer(&vp->timer);
+ break;
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
@@ -1617,8 +1869,8 @@
if (vortex_debug > 4)
printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
dev->name, status);
-
- return;
+handler_exit:
+ spin_unlock(&vp->lock);
}
static int vortex_rx(struct net_device *dev)
@@ -1629,7 +1881,7 @@
short rx_status;
if (vortex_debug > 5)
- printk(KERN_DEBUG" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+ printk(KERN_DEBUG "vortex_rx(): 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. */
@@ -1674,22 +1926,17 @@
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
- vp->stats.rx_bytes += skb->len;
/* 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)
+ } else if (vortex_debug > 0)
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++;
- /* Wait a limited time to skip this packet. */
- for (i = 200; i >= 0; i--)
- if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
- break;
+ wait_for_completion(dev, RxDiscard);
}
return 0;
@@ -1705,7 +1952,7 @@
int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
if (vortex_debug > 5)
- printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status "
+ printk(KERN_DEBUG "boomerang_rx(): status %4.4x, rx_status "
"%4.4x.\n",
inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
@@ -1787,22 +2034,13 @@
return 0;
}
-static int
-vortex_close(struct net_device *dev)
+static void
+vortex_down(struct net_device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
long ioaddr = dev->base_addr;
- int i;
-
- netif_stop_queue(dev);
- if (vortex_debug > 1) {
- 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, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
- }
+ netif_stop_queue (dev);
del_timer(&vp->timer);
@@ -1817,34 +2055,60 @@
/* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD);
- free_irq(dev->irq, dev);
-
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
update_stats(ioaddr, dev);
- if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+ if (vp->full_bus_master_rx)
outl(0, ioaddr + UpListPtr);
+ if (vp->full_bus_master_tx)
+ outl(0, ioaddr + DownListPtr);
+
+ if (vp->capabilities & CapPwrMgmt)
+ acpi_set_WOL(dev);
+}
+
+static int
+vortex_close(struct net_device *dev)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int i;
+
+ if (netif_device_present(dev))
+ vortex_down(dev);
+
+ if (vortex_debug > 1) {
+ 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, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
+ }
+
+ free_irq(dev->irq, dev);
+
+ 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_FREE_SKB(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]);
vp->rx_skbuff[i] = 0;
}
}
if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
- outl(0, ioaddr + DownListPtr);
for (i = 0; i < TX_RING_SIZE; i++)
if (vp->tx_skbuff[i]) {
struct sk_buff *skb = vp->tx_skbuff[i];
pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
- DEV_FREE_SKB(skb);
+ dev_kfree_skb(skb);
vp->tx_skbuff[i] = 0;
}
}
MOD_DEC_USE_COUNT;
-
+ vp->open = 0;
return 0;
}
@@ -1853,11 +2117,10 @@
struct vortex_private *vp = (struct vortex_private *)dev->priv;
unsigned long flags;
- if (netif_running(dev)) {
- save_flags(flags);
- cli();
+ if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */
+ spin_lock_irqsave (&vp->lock, flags);
update_stats(dev->base_addr, dev);
- restore_flags(flags);
+ spin_unlock_irqrestore (&vp->lock, flags);
}
return &vp->stats;
}
@@ -1872,7 +2135,10 @@
static void update_stats(long ioaddr, struct net_device *dev)
{
struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int old_window = inw(ioaddr + EL3_CMD);
+ if (old_window == 0xffff) /* Chip suspended or ejected. */
+ return;
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
@@ -1889,14 +2155,21 @@
/* 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. */
- inw(ioaddr + 10); /* Total Rx and Tx octets. */
- inw(ioaddr + 12);
+ vp->stats.rx_bytes += inw(ioaddr + 10);
+ vp->stats.tx_bytes += inw(ioaddr + 12);
/* 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(7);
+ /* AKPM: the previous comment is obsolete - we switch back to the old window */
+ EL3WINDOW(old_window >> 13);
return;
}
@@ -1906,6 +2179,10 @@
long ioaddr = dev->base_addr;
u16 *data = (u16 *)&rq->ifr_data;
int phy = vp->phys[0] & 0x1f;
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
@@ -1913,16 +2190,24 @@
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
EL3WINDOW(4);
data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
- return 0;
+ retval = 0;
+ break;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- EL3WINDOW(4);
- mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- return 0;
+ if (!capable(CAP_NET_ADMIN)) {
+ retval = -EPERM;
+ } else {
+ EL3WINDOW(4);
+ mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ retval = 0;
+ }
+ break;
default:
- return -EOPNOTSUPP;
+ retval = -EOPNOTSUPP;
+ break;
}
+
+ spin_unlock_irqrestore(&vp->lock, flags);
+ return retval;
}
/* Pre-Cyclone chips have no documented multicast filter, so the only
@@ -1945,7 +2230,6 @@
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
@@ -2004,11 +2288,7 @@
outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
-#if 0
- return (retval>>1) & 0x1ffff;
-#else
return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-#endif
}
static void mdio_write(long ioaddr, int phy_id, int location, int value)
@@ -2038,42 +2318,131 @@
return;
}
+
+/* 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)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ /* AKPM: This kills the 905 */
+ if (vortex_debug > 0) {
+ printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n");
+ }
+ return;
+
+ /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+ EL3WINDOW(7);
+ outw(2, ioaddr + 0x0c);
+ /* 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_write_config_word(vp->pdev, 0xe0, 0x8103);
+}
-static void __exit vortex_cleanup_module (void)
+static void __devexit vortex_remove_one (struct pci_dev *pdev)
{
- struct net_device *next_dev;
+ struct net_device *dev = pdev->driver_data;
+ struct vortex_private *vp;
-#ifdef CARDBUS
- unregister_driver(&vortex_ops);
-#endif
+ if (!dev)
+ return;
+
+ vp = (void *)(dev->priv);
/* 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);
- next_dev = vp->next_module;
- unregister_netdev(root_vortex_dev);
- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr,
- pci_tbl[vp->chip_id].io_size);
- kfree(root_vortex_dev);
- pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
- + sizeof(struct boom_tx_desc) * TX_RING_SIZE
- + 15, vp->rx_ring, vp->rx_ring_dma);
- kfree(vp);
- root_vortex_dev = next_dev;
+ unregister_netdev(dev);
+ outw(TotalReset, dev->base_addr + EL3_CMD);
+ release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+ kfree(dev);
+}
+
+
+static struct pci_driver vortex_driver = {
+ name: "3c575_cb",
+ probe: vortex_init_one,
+ remove: vortex_remove_one,
+ suspend: vortex_suspend,
+ resume: vortex_resume,
+ id_table: vortex_pci_tbl,
+};
+
+
+static int vortex_have_pci = 0;
+static int vortex_have_eisa = 0;
+
+
+static int __init vortex_init (void)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&vortex_driver);
+ if (rc < 0)
+ goto out;
+
+ if (rc >= 0) /* AKPM: had "> 0" */
+ vortex_have_pci = 1;
+
+ rc = vortex_eisa_init ();
+ if (rc < 0)
+ goto out;
+
+ if (rc > 0)
+ vortex_have_eisa = 1;
+
+out:
+ MOD_DEC_USE_COUNT;
+ return rc;
+}
+
+
+static void __exit vortex_eisa_cleanup (void)
+{
+ struct net_device *dev, *tmp;
+ struct vortex_private *vp;
+ long ioaddr;
+
+ 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;
+
+ kfree (tmp);
}
}
-module_init(vortex_init_module);
-module_exit(vortex_cleanup_module);
+
+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);
+
+
+
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
+ * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)