summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
commitb9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch)
tree42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/net
parent7406b0a326f2d70ade2671c37d1beef62249db97 (diff)
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/3c509.c10
-rw-r--r--drivers/net/3c515.c9
-rw-r--r--drivers/net/3c59x.c1621
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/82596.c993
-rw-r--r--drivers/net/8390.c12
-rw-r--r--drivers/net/Space.c40
-rw-r--r--drivers/net/acenic.c2
-rw-r--r--drivers/net/am79c961a.c300
-rw-r--r--drivers/net/am79c961a.h17
-rw-r--r--drivers/net/appletalk/ltpc.c4
-rw-r--r--drivers/net/arcnet/arcnet.c2
-rw-r--r--drivers/net/arcnet/com90io.c2
-rw-r--r--drivers/net/cs89x0.c82
-rw-r--r--drivers/net/de4x5.c2
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c3
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hp100.c12
-rw-r--r--drivers/net/ne2k-pci.c6
-rw-r--r--drivers/net/pcmcia/3c575_cb.c2159
-rw-r--r--drivers/net/pcmcia/Config.in2
-rw-r--r--drivers/net/pcmcia/Makefile1
-rw-r--r--drivers/net/pcmcia/ray_cs.c7
-rw-r--r--drivers/net/pcmcia/xircom_tulip_cb.c3
-rw-r--r--drivers/net/plip.c8
-rw-r--r--drivers/net/ppp_async.c1
-rw-r--r--drivers/net/ppp_generic.c45
-rw-r--r--drivers/net/ppp_synctty.c1
-rw-r--r--drivers/net/rrunner.c5
-rw-r--r--drivers/net/rtl8129.c1
-rw-r--r--drivers/net/setup.c4
-rw-r--r--drivers/net/shaper.c53
-rw-r--r--drivers/net/starfire.c1
-rw-r--r--drivers/net/tulip/21142.c11
-rw-r--r--drivers/net/tulip/timer.c15
-rw-r--r--drivers/net/tulip/tulip.h49
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/via-rhine.c25
-rw-r--r--drivers/net/wan/Config.in6
-rw-r--r--drivers/net/wan/Makefile15
-rw-r--r--drivers/net/wan/comx.c55
-rw-r--r--drivers/net/wan/comx.h2
-rw-r--r--drivers/net/wan/cosa.c3
-rw-r--r--drivers/net/wan/lmc/.cvsignore2
-rw-r--r--drivers/net/wan/lmc/Makefile39
-rw-r--r--drivers/net/wan/lmc/lmc.h32
-rw-r--r--drivers/net/wan/lmc/lmc_debug.c87
-rw-r--r--drivers/net/wan/lmc/lmc_debug.h52
-rw-r--r--drivers/net/wan/lmc/lmc_ioctl.h257
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2486
-rw-r--r--drivers/net/wan/lmc/lmc_media.c1258
-rw-r--r--drivers/net/wan/lmc/lmc_media.h64
-rw-r--r--drivers/net/wan/lmc/lmc_prot.h14
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c270
-rw-r--r--drivers/net/wan/lmc/lmc_proto.h15
-rw-r--r--drivers/net/wan/lmc/lmc_proto_raw.h4
-rw-r--r--drivers/net/wan/lmc/lmc_var.h590
-rw-r--r--drivers/net/wan/lmc/lmc_ver.h123
-rw-r--r--drivers/net/wan/sdla_chdlc.c5
-rw-r--r--drivers/net/wan/sdla_fr.c9
-rw-r--r--drivers/net/wan/sdla_ppp.c5
-rw-r--r--drivers/net/wan/sdladrv.c2
-rw-r--r--drivers/net/wan/sdlamain.c6
-rw-r--r--drivers/net/wan/syncppp.c12
-rw-r--r--drivers/net/wan/z85230.c6
-rw-r--r--drivers/net/yellowfin.c1
67 files changed, 7354 insertions, 3582 deletions
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index da4e4bfe4..00c1c6e60 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -168,7 +168,7 @@ struct el3_mca_adapters_struct el3_mca_adapters[] = {
};
#endif
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
struct el3_isapnp_adapters_struct {
unsigned short vendor, function;
char *name;
@@ -187,7 +187,7 @@ u16 el3_isapnp_phys_addr[8][3] = {
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
};
#endif /* CONFIG_ISAPNP */
-#if defined(CONFIG_ISAPNP) || defined(MODULE)
+#if defined(__ISAPNP__) || defined(MODULE)
static int nopnp = 0;
#endif
@@ -198,7 +198,7 @@ int el3_probe(struct net_device *dev)
u16 phys_addr[3];
static int current_tag = 0;
int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
static int pnp_cards = 0;
#endif
@@ -294,7 +294,7 @@ int el3_probe(struct net_device *dev)
}
#endif
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if (nopnp == 1)
goto no_pnp;
@@ -376,7 +376,7 @@ no_pnp:
phys_addr[i] = htons(id_read_eeprom(i));
}
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if (nopnp == 0) {
/* The ISA PnP 3c509 cards respond to the ID sequence.
This check is needed in order not to register them twice. */
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 4aeee0a2e..f5c8ef1b0 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -46,7 +46,6 @@ static int max_interrupt_work = 20;
#define RX_RING_SIZE 16
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/isapnp.h>
@@ -353,7 +352,7 @@ static struct media_table {
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
struct corkscrew_isapnp_adapters_struct {
unsigned short vendor, function;
char *name;
@@ -445,7 +444,7 @@ static int corkscrew_scan(struct net_device *dev)
static int ioaddr;
static int pnp_cards = 0;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if(nopnp == 1)
goto no_pnp;
for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
@@ -503,12 +502,12 @@ static int corkscrew_scan(struct net_device *dev)
}
}
no_pnp:
-#endif /* not CONFIG_ISAPNP */
+#endif /* not __ISAPNP__ */
/* Check all locations on the ISA bus -- evil! */
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
int irq;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
/* Make sure this was not already picked up by isapnp */
if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue;
if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index ebaeb68ba..92da42e6d 100644
--- a/drivers/net/3c59x.c
+++ b/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 @@ static const int rx_copybreak = 200;
/* 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 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#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 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#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 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#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 @@ MODULE_PARM(compaq_device_id, "i");
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 @@ the copying breakpoint: it is chosen to trade-off the memory wasted by
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 @@ enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
+
+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);
+ 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. */
};
-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},
+
+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 @@ enum tx_desc_status {
};
/* 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 @@ struct vortex_private {
/* 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 @@ enum xcvr_types {
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 @@ static struct media_table {
{ "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
-#include <pcmcia/driver_ops.h>
+static int vortex_cards_found = 0;
-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;
-
- 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;
-}
+ struct net_device *dev = pdev->driver_data;
-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;
+ printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
+
+ 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;
- }
+ long ioaddr;
+ int rc;
+ int orig_cards_found = vortex_cards_found;
- if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
- continue;
+ /* Now check all slots of the EISA bus. */
+ if (!EISA_bus)
+ return 0;
- /* Activate the card. */
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int device_id;
- 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);
- }
+ if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+ continue;
- dev = vortex_probe1(pdev, ioaddr, irq,
- chip_idx, cards_found);
-
- 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++;
- }
+ /* Check the standard EISA ID register for an encoded '3Com'. */
+ if (inw(ioaddr + 0xC80) != 0x6d50) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
}
- }
-#endif /* NO_PCI */
- /* 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 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);
-
- printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
- dev->name, pci_tbl[chip_idx].name, ioaddr);
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
+ 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);
+ /* 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;
+ }
- memset(vp, 0, sizeof(*vp));
- dev->priv = vp;
+ /* 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;
+ }
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
+ /* 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 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
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 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
}
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 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
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 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
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 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
}
}
+ 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 dev;
+ return 0;
+
+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 @@ vortex_open(struct net_device *dev)
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 @@ vortex_open(struct net_device *dev)
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 @@ vortex_open(struct net_device *dev)
(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 @@ vortex_open(struct net_device *dev)
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 @@ vortex_open(struct net_device *dev)
/* 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 @@ vortex_open(struct net_device *dev)
(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 @@ vortex_open(struct net_device *dev)
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 @@ static void vortex_timer(unsigned long data)
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 @@ static void vortex_timer(unsigned long data)
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 @@ static void vortex_timer(unsigned long data)
"%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 @@ static void vortex_timer(unsigned long data)
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 @@ static void vortex_tx_timeout(struct net_device *dev)
{
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 @@ static void vortex_tx_timeout(struct net_device *dev)
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 @@ static void vortex_tx_timeout(struct net_device *dev)
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 @@ vortex_error(struct net_device *dev, int status)
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 @@ vortex_error(struct net_device *dev, int status)
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 @@ vortex_error(struct net_device *dev, int status)
}
}
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 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
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 @@ boomerang_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);
+ 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 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
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 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static int vortex_rx(struct net_device *dev)
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 @@ static int vortex_rx(struct net_device *dev)
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 @@ boomerang_rx(struct net_device *dev)
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 @@ boomerang_rx(struct net_device *dev)
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 @@ vortex_close(struct net_device *dev)
/* 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 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev)
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 struct net_device_stats *vortex_get_stats(struct net_device *dev)
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 @@ static void update_stats(long ioaddr, struct net_device *dev)
/* 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 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
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 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
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 @@ static void set_rx_mode(struct net_device *dev)
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 @@ static int mdio_read(long ioaddr, int phy_id, int location)
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 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value)
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
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 336a66949..ce573e312 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -439,7 +439,7 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
u8 tmp8;
int rc;
u32 pio_start, pio_end, pio_flags, pio_len;
- u32 mmio_start, mmio_end, mmio_flags, mmio_len;
+ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
DPRINTK ("ENTER\n");
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 55c85bbd1..673da178d 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -40,7 +40,7 @@
*/
-static const char *version = "82596.c:v1.0 15/07/98\n";
+static const char *version = "82596.c $Revision: 1.4 $\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -63,6 +63,32 @@ static const char *version = "82596.c:v1.0 15/07/98\n";
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT 0x0001
+#define DEB_PROBE 0x0002
+#define DEB_SERIOUS 0x0004
+#define DEB_ERRORS 0x0008
+#define DEB_MULTI 0x0010
+#define DEB_TDR 0x0020
+#define DEB_OPEN 0x0040
+#define DEB_RESET 0x0080
+#define DEB_ADDCMD 0x0100
+#define DEB_STATUS 0x0200
+#define DEB_STARTTX 0x0400
+#define DEB_RXADDR 0x0800
+#define DEB_TXADDR 0x1000
+#define DEB_RXFRAME 0x2000
+#define DEB_INTS 0x4000
+#define DEB_STRUCT 0x8000
+#define DEB_ANY 0xffff
+
+
+#define DEB(x,y) if (i596_debug & (x)) y
+
#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
#define ENABLE_MVME16x_NET
@@ -97,13 +123,13 @@ static const char *version = "82596.c:v1.0 15/07/98\n";
#define ISCP_BUSY 0x00010000
#define MACH_IS_APRICOT 0
#else
-#define WSWAPrfd(x) x
-#define WSWAPrbd(x) ((struct i596_rbd *)(x))
-#define WSWAPiscp(x) ((struct i596_iscp *)(x))
-#define WSWAPscb(x) ((struct i596_scb *)(x))
-#define WSWAPcmd(x) x
-#define WSWAPtbd(x) x
-#define WSWAPchar(x) ((char *)(x))
+#define WSWAPrfd(x) ((struct i596_rfd *)(x))
+#define WSWAPrbd(x) ((struct i596_rbd *)(x))
+#define WSWAPiscp(x) ((struct i596_iscp *)(x))
+#define WSWAPscb(x) ((struct i596_scb *)(x))
+#define WSWAPcmd(x) ((struct i596_cmd *)(x))
+#define WSWAPtbd(x) ((struct i596_tbd *)(x))
+#define WSWAPchar(x) ((char *)(x))
#define ISCP_BUSY 0x0001
#define MACH_IS_APRICOT 1
#endif
@@ -119,13 +145,12 @@ static const char *version = "82596.c:v1.0 15/07/98\n";
#define PORT_ALTSCP 0x02 /* alternate SCB address */
#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-#define I82596_DEBUG 1
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_PARM(i596_debug, "i");
-#ifdef I82596_DEBUG
-int i596_debug = I82596_DEBUG;
-#else
-int i596_debug = 1;
-#endif
/* Copy frames shorter than rx_copybreak, otherwise pass on up in
* a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
@@ -137,7 +162,7 @@ static int rx_copybreak = 100;
#define I596_TOTAL_SIZE 17
-#define I596_NULL -1
+#define I596_NULL ((void *)0xffffffff)
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
@@ -164,7 +189,8 @@ enum commands {
#define RX_SUSPEND 0x0030
#define RX_ABORT 0x0040
-#define TX_TIMEOUT 5
+#define TX_TIMEOUT 5
+
struct i596_reg {
unsigned short porthi;
@@ -172,12 +198,6 @@ struct i596_reg {
unsigned long ca;
};
-struct i596_cmd {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *next;
-};
-
#define EOF 0x8000
#define SIZE_MASK 0x3fff
@@ -188,6 +208,23 @@ struct i596_tbd {
char *data;
};
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596. The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next. It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+ struct i596_cmd *v_next; /* Address from CPUs viewpoint */
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *b_next; /* Address from i596 viewpoint */
+};
+
struct tx_cmd {
struct i596_cmd cmd;
struct i596_tbd *tbd;
@@ -196,26 +233,53 @@ struct tx_cmd {
struct sk_buff *skb; /* So we can free it after tx */
};
+struct tdr_cmd {
+ struct i596_cmd cmd;
+ unsigned short status;
+ unsigned short pad;
+};
+
+struct mc_cmd {
+ struct i596_cmd cmd;
+ short mc_cnt;
+ char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+ struct i596_cmd cmd;
+ char eth_addr[8];
+};
+
+struct cf_cmd {
+ struct i596_cmd cmd;
+ char i596_config[16];
+};
+
struct i596_rfd {
unsigned short stat;
unsigned short cmd;
- struct i596_rfd *next;
+ struct i596_rfd *b_next; /* Address from i596 viewpoint */
struct i596_rbd *rbd;
unsigned short count;
unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
};
struct i596_rbd {
unsigned short count;
unsigned short zero1;
- struct i596_rbd *next;
- char *data;
+ struct i596_rbd *b_next;
+ unsigned char *b_data; /* Address from i596 viewpoint */
unsigned short size;
unsigned short zero2;
struct sk_buff *skb;
+ struct i596_rbd *v_next;
+ struct i596_rbd *b_addr; /* This rbd addr from i596 view */
+ unsigned char *v_data; /* Address from CPUs viewpoint */
};
-#define TX_RING_SIZE 16
+#define TX_RING_SIZE 64
#define RX_RING_SIZE 16
struct i596_scb {
@@ -248,17 +312,14 @@ struct i596_private {
volatile struct i596_scp scp;
volatile struct i596_iscp iscp;
volatile struct i596_scb scb;
- struct i596_cmd set_add;
- char eth_addr[8];
- struct i596_cmd set_conf;
- char i596_config[16];
- struct i596_cmd tdr;
- struct i596_cmd mc_cmd; /* Keep these three together!!! */
- short mc_cnt; /* Keep these three together!!! */
- char mc_addrs[MAX_MC_CNT*6]; /* Keep these three together!!! */
+ struct sa_cmd sa_cmd;
+ struct cf_cmd cf_cmd;
+ struct tdr_cmd tdr_cmd;
+ struct mc_cmd mc_cmd;
unsigned long stat;
int last_restart __attribute__((aligned(4)));
- struct i596_rfd *rx_tail;
+ struct i596_rfd *rfd_head;
+ struct i596_rbd *rbd_head;
struct i596_cmd *cmd_tail;
struct i596_cmd *cmd_head;
int cmd_backlog;
@@ -300,13 +361,13 @@ static int i596_close(struct net_device *dev);
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(char *);
+static void print_eth(unsigned char *buf, char *str);
static void set_multicast_list(struct net_device *dev);
static int rx_ring_size = RX_RING_SIZE;
static int ticks_limit = 25;
-static int max_cmd_backlog = 16;
-
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
static inline void CA(struct net_device *dev)
{
@@ -317,7 +378,9 @@ static inline void CA(struct net_device *dev)
#endif
#ifdef ENABLE_BVME6000_NET
if (MACH_IS_BVME6000) {
- volatile u32 i = *(volatile u32 *) (dev->base_addr);
+ volatile u32 i;
+
+ i = *(volatile u32 *) (dev->base_addr);
}
#endif
#ifdef ENABLE_APRICOT
@@ -349,29 +412,88 @@ static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
}
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->iscp.stat)
+ udelay(10);
+ if (!delcnt) {
+ printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->scb.command)
+ udelay(10);
+ if (!delcnt) {
+ printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+ &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+ printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+ &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+ printk("scb at %p, scb.status = %04x, .command = %04x,"
+ " .cmd = %p, .rfd = %p\n",
+ &lp->scb, lp->scb.status, lp->scb.command,
+ lp->scb.cmd, lp->scb.rfd);
+ printk(" errors: crc %lx, align %lx, resource %lx,"
+ " over %lx, rcvdt %lx, short %lx\n",
+ lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+ lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+ cmd = lp->cmd_head;
+ while (cmd != I596_NULL) {
+ printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+ cmd, cmd->status, cmd->command, cmd->b_next);
+ cmd = cmd->v_next;
+ }
+ rfd = lp->rfd_head;
+ printk("rfd_head = %p\n", rfd);
+ do {
+ printk (" %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+ " count %04x\n",
+ rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+ rfd->count);
+ rfd = rfd->v_next;
+ } while (rfd != lp->rfd_head);
+ rbd = lp->rbd_head;
+ printk("rbd_head = %p\n", rbd);
+ do {
+ printk(" %p .count %04x, b_next %p, b_data %p, size %04x\n",
+ rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+ rbd = rbd->v_next;
+ } while (rbd != lp->rbd_head);
+}
+
+
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
- struct i596_cmd *cmd;
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
- struct i596_private *lp = (struct i596_private *) dev->priv;
- printk("i596_error: lp = 0x%08x\n", (u32) lp);
- printk("scp at %08x, .sysbus = %08x, .iscp = %08x\n",
- (u32) & lp->scp, (u32) lp->scp.sysbus, (u32) lp->scp.iscp);
- printk("iscp at %08x, .stat = %08x, .scb = %08x\n",
- (u32) & lp->iscp, (u32) lp->iscp.stat, (u32) lp->iscp.scb);
- printk("scb at %08x, .status = %04x, .command = %04x\n",
- (u32) & lp->scb, lp->scb.status, lp->scb.command);
- printk(" .cmd = %08x, .rfd = %08x\n", (u32) lp->scb.cmd,
- (u32) lp->scb.rfd);
- cmd = WSWAPcmd(lp->scb.cmd);
- while (cmd && (u32) cmd < 0x1000000) {
- printk("cmd at %08x, .status = %04x, .command = %04x, .next = %08x\n",
- (u32) cmd, cmd->status, cmd->command, (u32) cmd->next);
- cmd = WSWAPcmd(cmd->next);
- }
- while (1);
+ pcc2[0x28] = 1;
+ pcc2[0x2b] = 0x1d;
+ printk("%s: Error interrupt\n", dev->name);
+ i596_display_data(dev);
}
#endif
@@ -382,9 +504,6 @@ static inline void init_rx_bufs(struct net_device *dev)
struct i596_rfd *rfd;
struct i596_rbd *rbd;
- if (i596_debug > 1)
- printk ("%s: init_rx_bufs %d.\n", dev->name, rx_ring_size);
-
/* First build the Receive Buffer Descriptor List */
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
@@ -393,28 +512,39 @@ static inline void init_rx_bufs(struct net_device *dev)
if (skb == NULL)
panic("82596: alloc_skb() failed");
skb->dev = dev;
- rbd->next = WSWAPrbd(rbd+1);
+ rbd->v_next = rbd+1;
+ rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
+ rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
rbd->skb = skb;
- rbd->data = WSWAPchar(skb->tail);
+ rbd->v_data = skb->tail;
+ rbd->b_data = WSWAPchar(virt_to_bus(skb->tail));
rbd->size = PKT_BUF_SZ;
#ifdef __mc68000__
cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
#endif
}
- lp->rbds[rx_ring_size-1].next = WSWAPrbd(lp->rbds);
+ lp->rbd_head = lp->rbds;
+ rbd = lp->rbds + rx_ring_size - 1;
+ rbd->v_next = lp->rbds;
+ rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
/* Now build the Receive Frame Descriptor List */
for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
- rfd->rbd = (struct i596_rbd *)I596_NULL;
- rfd->next = WSWAPrfd(rfd+1);
+ rfd->rbd = I596_NULL;
+ rfd->v_next = rfd+1;
+ rfd->v_prev = rfd-1;
+ rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
rfd->cmd = CMD_FLEX;
}
- lp->scb.rfd = WSWAPrfd(lp->rfds);
- lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ rfd = lp->rfds;
+ rfd->rbd = lp->rbd_head;
+ rfd->v_prev = lp->rfds + rx_ring_size - 1;
rfd = lp->rfds + rx_ring_size - 1;
- lp->rx_tail = rfd;
- rfd->next = WSWAPrfd(lp->rfds);
+ rfd->v_next = lp->rfds;
+ rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
rfd->cmd = CMD_EOL|CMD_FLEX;
}
@@ -431,15 +561,37 @@ static inline void remove_rx_bufs(struct net_device *dev)
}
}
-static inline void init_i596_mem(struct net_device *dev)
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int i;
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+
+ for (i = 0; i < rx_ring_size; i++) {
+ lp->rfds[i].rbd = I596_NULL;
+ lp->rfds[i].cmd = CMD_FLEX;
+ }
+ lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ lp->rbd_head = lp->rbds;
+ lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
short ioaddr = dev->base_addr;
#endif
- int boguscnt = 100000;
unsigned long flags;
- int i;
+
+ MPU_PORT(dev, PORT_RESET, 0);
+
+ udelay(100); /* Wait 100us - seems to help */
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
#ifdef ENABLE_MVME16x_NET
@@ -448,12 +600,12 @@ static inline void init_i596_mem(struct net_device *dev)
/* Disable all ints for now */
pcc2[0x28] = 1;
- pcc2[0x2a] = 0x40;
+ pcc2[0x2a] = 0x48;
/* Following disables snooping. Snooping is not required
* as we make appropriate use of non-cached pages for
* shared data, and cache_push/cache_clear.
*/
- pcc2[0x2b] = 0x00;
+ pcc2[0x2b] = 0x08;
}
#endif
#ifdef ENABLE_BVME6000_NET
@@ -464,22 +616,22 @@ static inline void init_i596_mem(struct net_device *dev)
}
#endif
- MPU_PORT(dev, PORT_RESET, 0);
-
- udelay(100); /* Wait 100us - seems to help */
-
/* change the scp address */
- MPU_PORT(dev, PORT_ALTSCP, &lp->scp);
+ MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
#elif defined(ENABLE_APRICOT)
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr + 0xf);
- outw(((((int) &lp->scp) & 0xffff) | 2), ioaddr);
- outw((((int) &lp->scp) >> 16) & 0xffff, ioaddr);
+ {
+ u32 scp = virt_to_bus(&lp->scp);
+
+ /* change the scp address */
+ outw(0, ioaddr);
+ outw(0, ioaddr);
+ outb(4, ioaddr + 0xf);
+ outw(scp | 2, ioaddr);
+ outw(scp >> 16, ioaddr);
+ }
#endif
lp->last_cmd = jiffies;
@@ -497,15 +649,14 @@ static inline void init_i596_mem(struct net_device *dev)
lp->scp.sysbus = 0x00440000;
#endif
- lp->scp.iscp = WSWAPiscp(&(lp->iscp));
- lp->iscp.scb = WSWAPscb(&(lp->scb));
+ lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
+ lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
lp->iscp.stat = ISCP_BUSY;
lp->cmd_backlog = 0;
- lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+ lp->cmd_head = lp->scb.cmd = I596_NULL;
- if (i596_debug > 1)
- printk("%s: starting i82596.\n", dev->name);
+ DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
#if defined(ENABLE_APRICOT)
(void) inb(ioaddr + 0x10);
@@ -513,25 +664,12 @@ static inline void init_i596_mem(struct net_device *dev)
#endif
CA(dev);
- while (lp->iscp.stat)
- if (--boguscnt == 0) {
- printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ if (wait_istat(dev,lp,1000,"initialization timed out"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name));
/* Ensure rx frame/buffer descriptors are tidy */
- /* Bit naff doing this here as well as in init_rx_bufs() */
-
- for (i = 0; i < rx_ring_size; i++) {
- lp->rfds[i].rbd = (struct i596_rbd *)I596_NULL;
- lp->rfds[i].cmd = CMD_FLEX;
- }
- lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
- lp->scb.rfd = WSWAPrfd(lp->rfds);
- lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
- lp->rx_tail = lp->rfds + rx_ring_size - 1;
-
+ rebuild_rx_bufs(dev);
lp->scb.command = 0;
#ifdef ENABLE_MVME16x_NET
@@ -539,9 +677,8 @@ static inline void init_i596_mem(struct net_device *dev)
volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
/* Enable ints, etc. now */
- pcc2[0x2a] = 0x08;
pcc2[0x2a] = 0x55; /* Edge sensitive */
- pcc2[0x2b] = 0x55;
+ pcc2[0x2b] = 0x15;
}
#endif
#ifdef ENABLE_BVME6000_NET
@@ -552,40 +689,40 @@ static inline void init_i596_mem(struct net_device *dev)
}
#endif
- memcpy(lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
- memcpy(lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdSASetup;
- i596_add_cmd(dev, &lp->set_add);
+ DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name));
+ memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr);
+ DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name));
+ memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+ lp->sa_cmd.cmd.command = CmdSASetup;
+ i596_add_cmd(dev, &lp->sa_cmd.cmd);
- boguscnt = 200000;
+ DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name));
+ lp->tdr_cmd.cmd.command = CmdTDR;
+ i596_add_cmd(dev, &lp->tdr_cmd.cmd);
spin_lock_irqsave (&lp->lock, flags);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name));
lp->scb.command = RX_START;
CA(dev);
spin_unlock_irqrestore (&lp->lock, flags);
- boguscnt = 2000;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- return;
+ if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name));
+ return 0;
+
+failed:
+ printk("%s: Failed to initialise 82596\n", dev->name);
+ MPU_PORT(dev, PORT_RESET, 0);
+ return -1;
}
static inline int i596_rx(struct net_device *dev)
@@ -595,23 +732,31 @@ static inline int i596_rx(struct net_device *dev)
struct i596_rbd *rbd;
int frames = 0;
- if (i596_debug > 3)
- printk ("i596_rx()\n");
+ DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n",
+ lp->rfd_head, lp->rbd_head));
- rfd = WSWAPrfd(lp->scb.rfd); /* Ref next frame to check */
+ rfd = lp->rfd_head; /* Ref next frame to check */
- while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
- rbd = WSWAPrbd(rfd->rbd); /* Ref associated buffer desc */
-
- if (i596_debug >2)
- print_eth(WSWAPchar(rbd->data));
-
- if ((rfd->stat) & STAT_OK) {
+ while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
+ if (rfd->rbd == I596_NULL)
+ rbd = I596_NULL;
+ else if (rfd->rbd == lp->rbd_head->b_addr)
+ rbd = lp->rbd_head;
+ else {
+ printk("%s: rbd chain broken!\n", dev->name);
+ /* XXX Now what? */
+ rbd = I596_NULL;
+ }
+ DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+
+ if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
/* a good frame */
int pkt_len = rbd->count & 0x3fff;
struct sk_buff *skb = rbd->skb;
int rx_in_place = 0;
+ DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
frames++;
/* Check if the packet is long enough to just accept
@@ -620,7 +765,6 @@ static inline int i596_rx(struct net_device *dev)
if (pkt_len > rx_copybreak) {
struct sk_buff *newskb;
- char *temp;
/* Get fresh skbuff to replace filled one. */
newskb = dev_alloc_skb(PKT_BUF_SZ);
@@ -629,17 +773,12 @@ static inline int i596_rx(struct net_device *dev)
goto memory_squeeze;
}
/* Pass up the skb already on the Rx ring. */
- temp = skb_put(skb, pkt_len);
- if (WSWAPchar(rbd->data) != temp)
- printk(KERN_ERR "%s: Internal consistency error "
- "-- the skbuff addresses do not match"
- " in i596_rx: %p vs. %p / %p.\n", dev->name,
- WSWAPchar(rbd->data),
- skb->head, temp);
+ skb_put(skb, pkt_len);
rx_in_place = 1;
rbd->skb = newskb;
newskb->dev = dev;
- rbd->data = WSWAPchar(newskb->tail);
+ rbd->v_data = newskb->tail;
+ rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));
#ifdef __mc68000__
cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
#endif
@@ -657,8 +796,7 @@ memory_squeeze:
if (!rx_in_place) {
/* 16 byte align the data fields */
skb_reserve(skb, 2);
- memcpy(skb_put(skb,pkt_len),
- WSWAPchar(rbd->data), pkt_len);
+ memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
}
skb->protocol=eth_type_trans(skb,dev);
skb->len = pkt_len;
@@ -672,6 +810,8 @@ memory_squeeze:
}
}
else {
+ DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
+ dev->name, rfd->stat));
lp->stats.rx_errors++;
if ((rfd->stat) & 0x0001)
lp->stats.collisions++;
@@ -691,52 +831,42 @@ memory_squeeze:
/* Clear the buffer descriptor count and EOF + F flags */
- if (rbd != (struct i596_rbd *)I596_NULL)
- rbd->count=0;
- else
- printk("%s: Null rbd - oops!\n", dev->name);
+ if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+ rbd->count = 0;
+ lp->rbd_head = rbd->v_next;
+ }
/* Tidy the frame descriptor, marking it as end of list */
- rfd->rbd = (struct i596_rbd *)I596_NULL;
+ rfd->rbd = I596_NULL;
rfd->stat = 0;
rfd->cmd = CMD_EOL|CMD_FLEX;
rfd->count = 0;
/* Remove end-of-list from old end descriptor */
- lp->rx_tail->cmd = CMD_FLEX;
-
- /* Update last frame descriptor to reference the one just
- * processed */
-
- lp->rx_tail = rfd;
+ rfd->v_prev->cmd = CMD_FLEX;
/* Update record of next frame descriptor to process */
- lp->scb.rfd = rfd->next;
- rfd = WSWAPrfd(lp->scb.rfd); /* Next frame desc. to check */
+ lp->scb.rfd = rfd->b_next;
+ lp->rfd_head = rfd->v_next;
+ rfd = lp->rfd_head;
}
- if (i596_debug > 3)
- printk ("frames %d\n", frames);
+ DEB(DEB_RXFRAME,printk ("frames %d\n", frames));
return 0;
}
-static inline void i596_cleanup_cmd(struct i596_private *lp)
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
{
struct i596_cmd *ptr;
- int boguscnt = 1000;
-
- if (i596_debug > 4)
- printk("i596_cleanup_cmd\n");
- while (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
+ while (lp->cmd_head != I596_NULL) {
ptr = lp->cmd_head;
-
- lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ lp->cmd_head = ptr->v_next;
lp->cmd_backlog--;
switch ((ptr->command) & 0x7) {
@@ -750,45 +880,28 @@ static inline void i596_cleanup_cmd(struct i596_private *lp)
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
- ptr->next = (struct i596_cmd *) I596_NULL;
+ ptr->v_next = ptr->b_next = I596_NULL;
tx_cmd->cmd.command = 0; /* Mark as free */
break;
}
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- break;
- }
default:
- ptr->next = (struct i596_cmd *) I596_NULL;
+ ptr->v_next = ptr->b_next = I596_NULL;
}
}
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+ wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+ lp->scb.cmd = I596_NULL;
}
static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
{
- int boguscnt = 1000;
unsigned long flags;
- if (i596_debug > 1)
- printk("i596_reset\n");
+ DEB(DEB_RESET,printk("i596_reset\n"));
spin_lock_irqsave (&lp->lock, flags);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596_reset timed out");
netif_stop_queue(dev);
@@ -796,17 +909,10 @@ static inline void i596_reset(struct net_device *dev, struct i596_private *lp, i
CA(dev);
/* wait for shutdown */
- boguscnt = 4000;
-
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
spin_unlock_irqrestore (&lp->lock, flags);
- i596_cleanup_cmd(lp);
+ i596_cleanup_cmd(dev,lp);
i596_rx(dev);
netif_start_queue(dev);
@@ -818,46 +924,28 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
struct i596_private *lp = (struct i596_private *) dev->priv;
int ioaddr = dev->base_addr;
unsigned long flags;
- int boguscnt = 1000;
- if (i596_debug > 4)
- printk("i596_add_cmd\n");
+ DEB(DEB_ADDCMD,printk("i596_add_cmd\n"));
cmd->status = 0;
cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->next = (struct i596_cmd *) I596_NULL;
+ cmd->v_next = cmd->b_next = I596_NULL;
spin_lock_irqsave (&lp->lock, flags);
- /*
- * RGH 300597: Looks to me like there could be a race condition
- * here. Just because we havn't picked up all the command items
- * yet, doesn't mean that the 82596 hasn't finished processing
- * them. So, we may need to do a CUC_START anyway.
- * Maybe not. If it interrupts saying the CU is idle when there
- * is still something in the cmd queue, the int handler with restart
- * the CU.
- */
-
- if (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
- lp->cmd_tail->next = WSWAPcmd(cmd);
+ if (lp->cmd_head != I596_NULL) {
+ lp->cmd_tail->v_next = cmd;
+ lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
} else {
lp->cmd_head = cmd;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.cmd = WSWAPcmd(cmd);
+ wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
lp->scb.command = CUC_START;
CA(dev);
}
lp->cmd_tail = cmd;
lp->cmd_backlog++;
- lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */
-
spin_unlock_irqrestore (&lp->lock, flags);
if (lp->cmd_backlog > max_cmd_backlog) {
@@ -874,11 +962,14 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
static int i596_open(struct net_device *dev)
{
- if (i596_debug > 1)
- printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+ int res = 0;
- if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev))
+ DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+ if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+ printk("%s: IRQ %d not free\n", dev->name, dev->irq);
return -EAGAIN;
+ }
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
if (request_irq(0x56, &i596_error, 0, "i82596_error", dev))
@@ -892,9 +983,12 @@ static int i596_open(struct net_device *dev)
MOD_INC_USE_COUNT;
/* Initialize the 82596 memory */
- init_i596_mem(dev);
+ if (init_i596_mem(dev)) {
+ res = -EAGAIN;
+ free_irq(dev->irq, dev);
+ }
- return 0; /* Always succeed */
+ return res;
}
static void i596_tx_timeout (struct net_device *dev)
@@ -903,21 +997,19 @@ static void i596_tx_timeout (struct net_device *dev)
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
- printk ("%s: transmit timed out, status resetting.\n", dev->name);
+ DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
+ dev->name));
lp->stats.tx_errors++;
/* Try to restart the adaptor */
if (lp->last_restart == lp->stats.tx_packets) {
- if (i596_debug > 1)
- printk ("Resetting board.\n");
-
+ DEB(DEB_ERRORS,printk ("Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp, ioaddr);
} else {
/* Issue a channel attention signal */
- if (i596_debug > 1)
- printk ("Kicking board.\n");
+ DEB(DEB_ERRORS,printk ("Kicking board.\n"));
lp->scb.command = CUC_START | RX_START;
CA (dev);
lp->last_restart = lp->stats.tx_packets;
@@ -933,55 +1025,47 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct i596_private *lp = (struct i596_private *) dev->priv;
struct tx_cmd *tx_cmd;
struct i596_tbd *tbd;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ dev->trans_start = jiffies;
- if (i596_debug > 2)
- printk("%s: 82596 start xmit\n", dev->name);
-
- if (i596_debug > 3)
- printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
- skb->len, (unsigned int)skb->data);
+ DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
+ skb->len, (unsigned int)skb->data));
netif_stop_queue(dev);
-
- {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- dev->trans_start = jiffies;
- tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
- tbd = lp->tbds + lp->next_tx_cmd;
+ tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+ tbd = lp->tbds + lp->next_tx_cmd;
- if (tx_cmd->cmd.command) {
- printk ("%s: xmit ring full, dropping packet.\n",
- dev->name);
- lp->stats.tx_dropped++;
+ if (tx_cmd->cmd.command) {
+ DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n",
+ dev->name));
+ lp->stats.tx_dropped++;
- dev_kfree_skb(skb);
- } else {
- if (++lp->next_tx_cmd == TX_RING_SIZE)
- lp->next_tx_cmd = 0;
- tx_cmd->tbd = WSWAPtbd(tbd);
- tbd->next = (struct i596_tbd *) I596_NULL;
+ dev_kfree_skb(skb);
+ } else {
+ if (++lp->next_tx_cmd == TX_RING_SIZE)
+ lp->next_tx_cmd = 0;
+ tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
+ tbd->next = I596_NULL;
- tx_cmd->cmd.command = CMD_FLEX | CmdTx;
- tx_cmd->skb = skb;
+ tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+ tx_cmd->skb = skb;
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tbd->pad = 0;
- tbd->size = EOF | length;
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = EOF | length;
- tbd->data = WSWAPchar(skb->data);
+ tbd->data = WSWAPchar(virt_to_bus(skb->data));
#ifdef __mc68000__
- cache_push(virt_to_phys(skb->data), length);
+ cache_push(virt_to_phys(skb->data), length);
#endif
- if (i596_debug > 3)
- print_eth(skb->data);
- i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+ i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
- }
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += length;
}
netif_start_queue(dev);
@@ -989,21 +1073,17 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static void print_eth(char *add)
+static void print_eth(unsigned char *add, char *str)
{
int i;
- printk("print_eth(%08x)\n", (unsigned int) add);
- printk("Dest ");
+ printk("i596 0x%p, ", add);
for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i]);
- printk("\n");
-
- printk("Source");
+ printk(" %02X", add[i + 6]);
+ printk(" -->");
for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i + 6]);
- printk("\n");
- printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+ printk(" %02X", add[i]);
+ printk(" %02X%02X, %s\n", add[12], add[13], str);
}
int __init i82596_probe(struct net_device *dev)
@@ -1011,19 +1091,17 @@ int __init i82596_probe(struct net_device *dev)
int i;
struct i596_private *lp;
char eth_addr[6];
+ static int probed = 0;
+ if (probed)
+ return -ENODEV;
+ probed++;
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
- static int probed = 0;
-#ifdef XXX_FIXME
if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
printk("Ethernet probe disabled - chip not present\n");
- return ENODEV;
+ return -ENODEV;
}
-#endif
- if (probed)
- return ENODEV;
- probed++;
memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
dev->base_addr = MVME_I596_BASE;
dev->irq = (unsigned) MVME16x_IRQ_I596;
@@ -1044,48 +1122,59 @@ int __init i82596_probe(struct net_device *dev)
}
#endif
#ifdef ENABLE_APRICOT
- int checksum = 0;
- int ioaddr = 0x300;
+ {
+ int checksum = 0;
+ int ioaddr = 0x300;
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
+ /* this is easy the ethernet interface can only be at 0x300 */
+ /* first check nothing is already registered here */
- if (check_region(ioaddr, I596_TOTAL_SIZE))
- return ENODEV;
+ if (check_region(ioaddr, I596_TOTAL_SIZE)) {
+ printk("82596: IO address 0x%04x in use\n", ioaddr);
+ return -ENODEV;
+ }
- for (i = 0; i < 8; i++) {
- eth_addr[i] = inb(ioaddr + 8 + i);
- checksum += eth_addr[i];
- }
+ for (i = 0; i < 8; i++) {
+ eth_addr[i] = inb(ioaddr + 8 + i);
+ checksum += eth_addr[i];
+ }
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum */
+ /* checksum is a multiple of 0x100, got this wrong first time
+ some machines have 0x100, some 0x200. The DOS driver doesn't
+ even bother with the checksum */
- if (checksum % 0x100)
- return ENODEV;
+ if (checksum % 0x100)
+ return -ENODEV;
- /* Some other boards trip the checksum.. but then appear as ether
- address 0. Trap these - AC */
+ /* Some other boards trip the checksum.. but then appear as
+ * ether address 0. Trap these - AC */
- if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
- return ENODEV;
+ if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
+ return -ENODEV;
- request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+ request_region(ioaddr, I596_TOTAL_SIZE, "i596");
- dev->base_addr = ioaddr;
- dev->irq = 10;
+ dev->base_addr = ioaddr;
+ dev->irq = 10;
+ }
+#endif
+ dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+ if (!dev->mem_start) {
+#ifdef ENABLE_APRICOT
+ release_region(dev->base_addr, I596_TOTAL_SIZE);
#endif
+ return -ENOMEM;
+ }
+
ether_setup(dev);
- printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr);
+ DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr));
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+ DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
- printk(" IRQ %d.\n", dev->irq);
+ DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
- if (i596_debug > 0)
- printk(version);
+ DEB(DEB_PROBE,printk(version));
/* The 82596-specific entries in the device structure. */
dev->open = i596_open;
@@ -1095,16 +1184,13 @@ int __init i82596_probe(struct net_device *dev)
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
dev->priv = (void *)(dev->mem_start);
lp = (struct i596_private *) dev->priv;
- if (i596_debug)
- printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+ DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
dev->name, (unsigned long)lp,
- sizeof(struct i596_private), (unsigned long)&lp->scb);
+ sizeof(struct i596_private), (unsigned long)&lp->scb));
memset((void *) lp, 0, sizeof(struct i596_private));
#ifdef __mc68000__
@@ -1113,8 +1199,8 @@ int __init i82596_probe(struct net_device *dev)
kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
#endif
lp->scb.command = 0;
- lp->scb.cmd = (struct i596_cmd *) I596_NULL;
- lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+ lp->scb.cmd = I596_NULL;
+ lp->scb.rfd = I596_NULL;
lp->lock = SPIN_LOCK_UNLOCKED;
return 0;
@@ -1125,7 +1211,6 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = dev_id;
struct i596_private *lp;
short ioaddr;
- int boguscnt = 2000;
unsigned short status, ack_cmd = 0;
#ifdef ENABLE_BVME6000_NET
@@ -1140,145 +1225,116 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk("i596_interrupt(): irq %d for unknown device.\n", irq);
return;
}
- if (i596_debug > 3)
- printk("%s: i596_interrupt(): irq %d\n", dev->name, irq);
ioaddr = dev->base_addr;
lp = (struct i596_private *) dev->priv;
-
+
spin_lock (&lp->lock);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
status = lp->scb.status;
- if (i596_debug > 4)
- printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
+ DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+ dev->name, irq, status));
ack_cmd = status & 0xf000;
if ((status & 0x8000) || (status & 0x2000)) {
struct i596_cmd *ptr;
- if ((i596_debug > 4) && (status & 0x8000))
- printk("%s: i596 interrupt completed command.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x2000))
- printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
+ if ((status & 0x8000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name));
+ if ((status & 0x2000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
- while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+ while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
ptr = lp->cmd_head;
- if (i596_debug > 2)
- printk("cmd_head->status = %04x, ->command = %04x\n",
- lp->cmd_head->status, lp->cmd_head->command);
- lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n",
+ lp->cmd_head->status, lp->cmd_head->command));
+ lp->cmd_head = ptr->v_next;
lp->cmd_backlog--;
switch ((ptr->command) & 0x7) {
case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- if ((ptr->status) & STAT_OK) {
- if (i596_debug > 2)
- print_eth(skb->data);
- } else {
- lp->stats.tx_errors++;
- if ((ptr->status) & 0x0020)
- lp->stats.collisions++;
- if (!((ptr->status) & 0x0040))
- lp->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400)
- lp->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800)
- lp->stats.collisions++;
- if ((ptr->status) & 0x1000)
- lp->stats.tx_aborted_errors++;
- }
-
- dev_kfree_skb(skb);
-
- ptr->next = (struct i596_cmd *) I596_NULL;
- tx_cmd->cmd.command = 0; /* Mark free */
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- break;
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if ((ptr->status) & STAT_OK) {
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+ } else {
+ lp->stats.tx_errors++;
+ if ((ptr->status) & 0x0020)
+ lp->stats.collisions++;
+ if (!((ptr->status) & 0x0040))
+ lp->stats.tx_heartbeat_errors++;
+ if ((ptr->status) & 0x0400)
+ lp->stats.tx_carrier_errors++;
+ if ((ptr->status) & 0x0800)
+ lp->stats.collisions++;
+ if ((ptr->status) & 0x1000)
+ lp->stats.tx_aborted_errors++;
}
+
+ dev_kfree_skb_irq(skb);
+
+ tx_cmd->cmd.command = 0; /* Mark free */
+ break;
+ }
case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (ptr + 1));
-
- if (status & 0x8000) {
- if (i596_debug > 3)
- printk("%s: link ok.\n", dev->name);
- } else {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n", dev->name);
-
- if (i596_debug > 1)
- printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
- }
- break;
+ {
+ unsigned short status = ((struct tdr_cmd *)ptr)->status;
+
+ if (status & 0x8000) {
+ DEB(DEB_ANY,printk("%s: link ok.\n", dev->name));
+ } else {
+ if (status & 0x4000)
+ printk("%s: Transceiver problem.\n", dev->name);
+ if (status & 0x2000)
+ printk("%s: Termination problem.\n", dev->name);
+ if (status & 0x1000)
+ printk("%s: Short circuit.\n", dev->name);
+
+ DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff));
}
+ break;
+ }
case CmdConfigure:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- /* Zap command so set_multicast_list() knows it is free */
- ptr->command = 0;
- break;
- }
- default:
- ptr->next = (struct i596_cmd *) I596_NULL;
+ /* Zap command so set_multicast_list() knows it is free */
+ ptr->command = 0;
+ break;
}
+ ptr->v_next = ptr->b_next = I596_NULL;
lp->last_cmd = jiffies;
}
ptr = lp->cmd_head;
- while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) {
+ while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
ptr->command &= 0x1fff;
- ptr = WSWAPcmd(ptr->next);
+ ptr = ptr->v_next;
}
- if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) &&
- netif_running(dev))
+ if ((lp->cmd_head != I596_NULL))
ack_cmd |= CUC_START;
- lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
}
if ((status & 0x1000) || (status & 0x4000)) {
- if ((i596_debug > 4) && (status & 0x4000))
- printk("%s: i596 interrupt received a frame.\n", dev->name);
+ if ((status & 0x4000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name));
+ i596_rx(dev);
/* Only RX_START if stopped - RGH 07-07-96 */
if (status & 0x1000) {
- if (netif_running(dev))
+ if (netif_running(dev)) {
+ DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
ack_cmd |= RX_START;
- if (i596_debug > 1)
- printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ rebuild_rx_bufs(dev);
+ }
}
- i596_rx(dev);
}
- /* acknowledge the interrupt */
-
-/* COMMENTED OUT <<<<<
- if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start))
- ack_cmd |= CUC_START;
- */
- boguscnt = 1000;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
lp->scb.command = ack_cmd;
#ifdef ENABLE_MVME16x_NET
@@ -1304,49 +1360,33 @@ static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
CA(dev);
- if (i596_debug > 4)
- printk("%s: exiting interrupt.\n", dev->name);
+ DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name));
spin_unlock (&lp->lock);
-
return;
}
static int i596_close(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
- int boguscnt = 2000;
unsigned long flags;
netif_stop_queue(dev);
- if (i596_debug > 1)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
+ DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, lp->scb.status));
save_flags(flags);
cli();
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"close1 timed out");
lp->scb.command = CUC_ABORT | RX_ABORT;
CA(dev);
- boguscnt = 2000;
-
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"close2 timed out");
restore_flags(flags);
-
- i596_cleanup_cmd(lp);
+ DEB(DEB_STRUCT,i596_display_data(dev));
+ i596_cleanup_cmd(dev,lp);
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
@@ -1388,35 +1428,33 @@ static struct net_device_stats *
static void set_multicast_list(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
- struct i596_cmd *cmd;
int config = 0, cnt;
- if (i596_debug > 1)
- printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF");
+ DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
- if ((dev->flags & IFF_PROMISC) && !(lp->i596_config[8] & 0x01)) {
- lp->i596_config[8] |= 0x01;
+ if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] |= 0x01;
config = 1;
}
- if (!(dev->flags & IFF_PROMISC) && (lp->i596_config[8] & 0x01)) {
- lp->i596_config[8] &= ~0x01;
+ if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] &= ~0x01;
config = 1;
}
- if ((dev->flags & IFF_ALLMULTI) && (lp->i596_config[11] & 0x20)) {
- lp->i596_config[11] &= ~0x20;
+ if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] &= ~0x20;
config = 1;
}
- if (!(dev->flags & IFF_ALLMULTI) && !(lp->i596_config[11] & 0x20)) {
- lp->i596_config[11] |= 0x20;
+ if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] |= 0x20;
config = 1;
}
if (config) {
- if (lp->set_conf.command)
+ if (lp->cf_cmd.cmd.command)
printk("%s: config change request already queued\n",
dev->name);
else {
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
}
}
@@ -1431,20 +1469,19 @@ static void set_multicast_list(struct net_device *dev)
if (dev->mc_count > 0) {
struct dev_mc_list *dmi;
unsigned char *cp;
+ struct mc_cmd *cmd;
cmd = &lp->mc_cmd;
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
- cp = ((unsigned char *) (cmd + 1)) + 2;
- for(dmi=dev->mc_list;cnt && dmi!=NULL;dmi=dmi->next,cnt--) {
+ cmd->cmd.command = CmdMulticastList;
+ cmd->mc_cnt = dev->mc_count * 6;
+ cp = cmd->mc_addrs;
+ for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
memcpy(cp, dmi->dmi_addr, 6);
if (i596_debug > 1)
- printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5));
- cp += 6;
+ DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
}
- if (i596_debug > 2)
- print_eth(((char *) (cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
+ i596_add_cmd(dev, &cmd->cmd);
}
}
@@ -1495,7 +1532,7 @@ void cleanup_module(void)
* XXX which may be invalid (CONFIG_060_WRITETHROUGH)
*/
- kernel_set_cachemode((u32)(dev_82596.mem_start), 4096,
+ kernel_set_cachemode((void *)(dev_82596.mem_start), 4096,
IOMAP_FULL_CACHING);
#endif
free_page ((u32)(dev_82596.mem_start));
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 3097345c8..416e9ce94 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -181,7 +181,7 @@ int ei_open(struct net_device *dev)
* ei_close - shut down network device
* @dev: network device to close
*
- * Opposite of ei_open. Only used when "ifconfig <devname> down" is done.
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
*/
int ei_close(struct net_device *dev)
{
@@ -416,7 +416,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* the 8390 via the card specific functions and fire them at the networking
* stack. We also handle transmit completions and wake the transmit path if
* neccessary. We also update the counters and do other housekeeping as
- * needed
+ * needed.
*/
void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
@@ -530,7 +530,7 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* is a much better solution as it avoids kernel based Tx timeouts, and
* an unnecessary card reset.
*
- * Called with lock held
+ * Called with lock held.
*/
static void ei_tx_err(struct net_device *dev)
@@ -573,7 +573,7 @@ static void ei_tx_err(struct net_device *dev)
* @dev: network device for which tx intr is handled
*
* We have finished a transmit: check for errors and then trigger the next
- * packet to be sent. Called with lock held
+ * packet to be sent. Called with lock held.
*/
static void ei_tx_intr(struct net_device *dev)
@@ -665,7 +665,7 @@ static void ei_tx_intr(struct net_device *dev)
* @dev: network device with which receive will be run
*
* We have a good packet(s), get it/them out of the buffers.
- * Called with lock held
+ * Called with lock held.
*/
static void ei_receive(struct net_device *dev)
@@ -801,7 +801,7 @@ static void ei_receive(struct net_device *dev)
* This includes causing "the NIC to defer indefinitely when it is stopped
* on a busy network." Ugh.
* Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10mS or so.
+ * computer will hate you - it takes 10ms or so.
*/
static void ei_rx_overrun(struct net_device *dev)
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 6cc44eac9..ee728a86c 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -679,6 +679,46 @@ static struct net_device tr0_dev = {
#define NEXT_DEV (&sbni0_dev)
#endif
+/* S/390 channels */
+#ifdef CONFIG_CTC
+ extern int ctc_probe(struct net_device *dev);
+ static struct net_device ctc7_dev =
+ {"ctc7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, ctc_probe};
+ static struct net_device ctc6_dev =
+ {"ctc6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc7_dev, ctc_probe};
+ static struct net_device ctc5_dev =
+ {"ctc5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc6_dev, ctc_probe};
+ static struct net_device ctc4_dev =
+ {"ctc4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc5_dev, ctc_probe};
+ static struct net_device ctc3_dev =
+ {"ctc3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc4_dev, ctc_probe};
+ static struct net_device ctc2_dev =
+ {"ctc2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc3_dev, ctc_probe};
+ static struct net_device ctc1_dev =
+ {"ctc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc2_dev, ctc_probe};
+ static struct net_device ctc0_dev =
+ {"ctc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc1_dev, ctc_probe};
+
+ static struct net_device escon7_dev =
+ {"escon7", 0, 0, 0, 0, 0, 0, 0, 0, 0, &ctc0_dev, ctc_probe};
+ static struct net_device escon6_dev =
+ {"escon6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon7_dev, ctc_probe};
+ static struct net_device escon5_dev =
+ {"escon5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon6_dev, ctc_probe};
+ static struct net_device escon4_dev =
+ {"escon4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon5_dev, ctc_probe};
+ static struct net_device escon3_dev =
+ {"escon3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon4_dev, ctc_probe};
+ static struct net_device escon2_dev =
+ {"escon2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon3_dev, ctc_probe};
+ static struct net_device escon1_dev =
+ {"escon1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon2_dev, ctc_probe};
+ static struct net_device escon0_dev =
+ {"escon0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &escon1_dev, ctc_probe};
+
+#undef NEXT_DEV
+#define NEXT_DEV (&escon0_dev)
+#endif
/*
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 9969bcbde..8fa454af9 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2949,6 +2949,6 @@ static int __init read_eeprom_byte(struct net_device *dev,
/*
* Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
* End:
*/
diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
index 9c00c4cbd..c7e7f2fe5 100644
--- a/drivers/net/am79c961a.c
+++ b/drivers/net/am79c961a.c
@@ -33,40 +33,49 @@
#include "am79c961a.h"
+static int am79c961_probe1 (struct net_device *dev);
+static int am79c961_open (struct net_device *dev);
+static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
+static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
+static int am79c961_close (struct net_device *dev);
+static struct enet_statistics *am79c961_getstats (struct net_device *dev);
+static void am79c961_setmulticastlist (struct net_device *dev);
+static void am79c961_timeout(struct net_device *dev);
+
static unsigned int net_debug = NET_DEBUG;
static void
am79c961_setmulticastlist (struct net_device *dev);
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
+static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n";
#define FUNC_PROLOGUE \
struct dev_priv *priv = (struct dev_priv *)dev->priv
/* --------------------------------------------------------------------------- */
+#ifdef __arm__
static void
write_rreg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #-4] @ NET_RDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ str%?h %0, [%2, #-4] @ NET_RDP
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
static inline void
write_ireg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #8] @ NET_RDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ str%?h %0, [%2, #8] @ NET_RDP
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
#define am_writeword(dev,off,val)\
- __asm__("\
- strh %0, [%1]\
- " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+ __asm__("str%?h %0, [%1]" : : \
+ "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
static inline void
am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
@@ -74,30 +83,28 @@ am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf,
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
if ((int)buf & 2) {
- __asm__ __volatile__("
- strh %2, [%0], #4
- " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ __asm__ __volatile__("str%?h %2, [%0], #4"
+ : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
}
while (length > 8) {
unsigned int tmp, tmp2;
__asm__ __volatile__("
- ldmia %1!, {%2, %3}
- strh %2, [%0], #4
- mov %2, %2, lsr #16
- strh %2, [%0], #4
- strh %3, [%0], #4
- mov %3, %3, lsr #16
- strh %3, [%0], #4
+ ldm%?ia %1!, {%2, %3}
+ str%?h %2, [%0], #4
+ mov%? %2, %2, lsr #16
+ str%?h %2, [%0], #4
+ str%?h %3, [%0], #4
+ mov%? %3, %3, lsr #16
+ str%?h %3, [%0], #4
" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
: "0" (offset), "1" (buf));
length -= 8;
}
while (length > 0) {
- __asm__ __volatile__("
- strh %2, [%0], #4
- " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ __asm__ __volatile__("str%?h %2, [%0], #4"
+ : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
}
@@ -107,9 +114,8 @@ static inline unsigned short
read_rreg (unsigned int base_addr, unsigned int reg)
{
unsigned short v;
- __asm__("
- strh %1, [%2] @ NET_RAP
- ldrh %0, [%2, #-4] @ NET_IDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ ldr%?h %0, [%2, #-4] @ NET_IDP
" : "=r" (v): "r" (reg), "r" (0xf0000464));
return v;
}
@@ -120,9 +126,7 @@ am_readword (struct net_device *dev, unsigned long off)
unsigned long address = 0xe0000000 + (off << 1);
unsigned short val;
- __asm__("
- ldrh %0, [%1]
- " : "=r" (val): "r" (address));
+ __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address));
return val;
}
@@ -134,23 +138,23 @@ am_readbuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, u
if ((int)buf & 2) {
unsigned int tmp;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- strb %2, [%1], #1
- mov %2, %2, lsr #8
- strb %2, [%1], #1
+ ldr%?h %2, [%0], #4
+ str%?b %2, [%1], #1
+ mov%? %2, %2, lsr #8
+ str%?b %2, [%1], #1
" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
length -= 2;
}
while (length > 8) {
unsigned int tmp, tmp2, tmp3;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- ldrh %3, [%0], #4
- orr %2, %2, %3, lsl #16
- ldrh %3, [%0], #4
- ldrh %4, [%0], #4
- orr %3, %3, %4, lsl #16
- stmia %1!, {%2, %3}
+ ldr%?h %2, [%0], #4
+ ldr%?h %3, [%0], #4
+ orr%? %2, %2, %3, lsl #16
+ ldr%?h %3, [%0], #4
+ ldr%?h %4, [%0], #4
+ orr%? %3, %3, %4, lsl #16
+ stm%?ia %1!, {%2, %3}
" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
: "0" (offset), "1" (buf));
length -= 8;
@@ -158,14 +162,17 @@ am_readbuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, u
while (length > 0) {
unsigned int tmp;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- strb %2, [%1], #1
- mov %2, %2, lsr #8
- strb %2, [%1], #1
+ ldr%?h %2, [%0], #4
+ str%?b %2, [%1], #1
+ mov%? %2, %2, lsr #8
+ str%?b %2, [%1], #1
" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
length -= 2;
}
}
+#else
+#error Not compatable
+#endif
static int
am79c961_ramtest(struct net_device *dev, unsigned int val)
@@ -259,7 +266,7 @@ am79c961_init_for_open(struct net_device *dev)
write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
- write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
+ write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
}
@@ -304,7 +311,7 @@ am79c961_probe1(struct net_device *dev)
/*
* The PNP initialisation should have been done by the ether bootp loader.
*/
- inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */
+ inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */
udelay (5);
@@ -343,6 +350,7 @@ am79c961_probe1(struct net_device *dev)
dev->hard_start_xmit = am79c961_sendpacket;
dev->get_stats = am79c961_getstats;
dev->set_multicast_list = am79c961_setmulticastlist;
+ dev->tx_timeout = am79c961_timeout;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
@@ -382,14 +390,15 @@ am79c961_open(struct net_device *dev)
memset (&priv->stats, 0, sizeof (priv->stats));
- if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
+ if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) {
+ MOD_DEC_USE_COUNT;
return -EAGAIN;
+ }
am79c961_init_for_open(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
+
return 0;
}
@@ -399,8 +408,7 @@ am79c961_open(struct net_device *dev)
static int
am79c961_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
am79c961_init(dev);
@@ -420,26 +428,116 @@ static struct enet_statistics *am79c961_getstats (struct net_device *dev)
return &priv->stats;
}
+static inline u32 update_crc(u32 crc, u8 byte)
+{
+ int i;
+
+ for (i = 8; i != 0; i--) {
+ byte ^= crc & 1;
+ crc >>= 1;
+
+ if (byte & 1)
+ crc ^= 0xedb88320;
+
+ byte >>= 1;
+ }
+
+ return crc;
+}
+
+static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
+{
+ if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
+ int i, idx, bit;
+ u32 crc;
+
+ crc = 0xffffffff;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ crc = update_crc(crc, dmi->dmi_addr[i]);
+
+ idx = crc >> 30;
+ bit = (crc >> 26) & 15;
+
+ hash[idx] |= 1 << bit;
+ }
+}
+
/*
* Set or clear promiscuous/multicast mode filter for this adaptor.
- *
- * We don't attempt any packet filtering. The card may have a SEEQ 8004
- * in which does not have the other ethernet address registers present...
*/
static void am79c961_setmulticastlist (struct net_device *dev)
{
unsigned long flags;
- int i;
+ unsigned short multi_hash[4], mode;
+ int i, stopped;
- dev->flags &= ~IFF_ALLMULTI;
+ mode = MODE_PORT0;
- i = MODE_PORT0;
- if (dev->flags & IFF_PROMISC)
- i |= MODE_PROMISC;
+ if (dev->flags & IFF_PROMISC) {
+ mode |= MODE_PROMISC;
+ } else if (dev->flags & IFF_ALLMULTI) {
+ memset(multi_hash, 0xff, sizeof(multi_hash));
+ } else {
+ struct dev_mc_list *dmi;
- save_flags_cli (flags);
- write_rreg (dev->base_addr, MODE, i);
- restore_flags (flags);
+ memset(multi_hash, 0x00, sizeof(multi_hash));
+
+ for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ am79c961_mc_hash(dmi, multi_hash);
+ }
+
+ save_flags_cli(flags);
+
+ stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
+
+ if (!stopped) {
+ /*
+ * Put the chip into suspend mode
+ */
+ write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
+
+ /*
+ * Spin waiting for chip to report suspend mode
+ */
+ while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
+ restore_flags(flags);
+ nop();
+ save_flags_cli(flags);
+ }
+ }
+
+ /*
+ * Update the multicast hash table
+ */
+ for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+ write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
+
+ /*
+ * Write the mode register
+ */
+ write_rreg(dev->base_addr, MODE, mode);
+
+ if (!stopped) {
+ /*
+ * Put the chip back into running mode
+ */
+ write_rreg(dev->base_addr, CTRL1, 0);
+ }
+
+ restore_flags(flags);
+}
+
+static void am79c961_timeout(struct net_device *dev)
+{
+ printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
+ dev->name);
+
+ /*
+ * ought to do some setup of the tx side here
+ */
+
+ netif_wake_queue(dev);
}
/*
@@ -449,46 +547,34 @@ static int
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned int hdraddr, bufaddr;
+ unsigned int head;
+ unsigned long flags;
- if (!dev->tbusy) {
-again:
- if (!test_and_set_bit(0, (void*)&dev->tbusy)) {
- unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned int hdraddr, bufaddr;
- unsigned long flags;
-
- hdraddr = priv->txhdr + (priv->txhead << 3);
- bufaddr = priv->txbuffer[priv->txhead];
- priv->txhead ++;
- if (priv->txhead >= TX_BUFFERS)
- priv->txhead = 0;
-
- am_writebuffer (dev, bufaddr, skb->data, length);
- am_writeword (dev, hdraddr + 4, -length);
- am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
-
- save_flags_cli (flags);
- write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
- dev->trans_start = jiffies;
- restore_flags (flags);
-
- if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
- dev->tbusy = 0;
- dev_kfree_skb (skb);
- return 0;
- } else
- printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- } else {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
- /* Try to restart the adaptor. */
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- goto again;
- }
+ head = priv->txhead;
+ hdraddr = priv->txhdr + (head << 3);
+ bufaddr = priv->txbuffer[head];
+ head += 1;
+ if (head >= TX_BUFFERS)
+ head = 0;
+
+ am_writebuffer (dev, bufaddr, skb->data, length);
+ am_writeword (dev, hdraddr + 4, -length);
+ am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+ priv->txhead = head;
+
+ save_flags_cli (flags);
+ write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
+ dev->trans_start = jiffies;
+ restore_flags (flags);
+
+ if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
+ netif_stop_queue(dev);
+
+ dev_kfree_skb(skb);
+
+ return 0;
}
static void
@@ -503,8 +589,6 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_DEBUG "am79c961irq: %d ", irq);
#endif
- dev->interrupt = 1;
-
status = read_rreg (dev->base_addr, CSR0);
write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
@@ -515,8 +599,6 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & CSR0_MISS)
priv->stats.rx_dropped ++;
- dev->interrupt = 0;
-
#if NET_DEBUG > 1
if(net_debug & DEBUG_INT)
printk("done\n");
@@ -613,7 +695,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
am_writeword (dev, hdraddr + 6, 0);
if (status2 & TST_RTRY)
- priv->stats.collisions += 1;
+ priv->stats.collisions += 16;
if (status2 & TST_LCOL)
priv->stats.tx_window_errors ++;
if (status2 & TST_LCAR)
@@ -625,7 +707,5 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
priv->stats.tx_packets ++;
} while (priv->txtail != priv->txhead);
- dev->tbusy = 0;
- mark_bh (NET_BH);
+ netif_wake_queue(dev);
}
-
diff --git a/drivers/net/am79c961a.h b/drivers/net/am79c961a.h
index 24bcd24fa..377c1b5d1 100644
--- a/drivers/net/am79c961a.h
+++ b/drivers/net/am79c961a.h
@@ -45,6 +45,7 @@
#define CSR3_EMBA 0x0008
#define CSR3_DXMT2PD 0x0010
#define CSR3_LAPPEN 0x0020
+#define CSR3_DXSUFLO 0x0040
#define CSR3_IDONM 0x0100
#define CSR3_TINTM 0x0200
#define CSR3_RINTM 0x0400
@@ -53,6 +54,9 @@
#define CSR3_BABLM 0x4000
#define CSR3_MASKALL 0x5F00
+#define CTRL1 5
+#define CTRL1_SPND 0x0001
+
#define LADRL 8
#define LADRM1 9
#define LADRM2 10
@@ -97,8 +101,8 @@
#define TMD_ERR 0x4000
#define TMD_OWN 0x8000
-#define TST_RTRY 0x0200
-#define TST_LCAR 0x0400
+#define TST_RTRY 0x0400
+#define TST_LCAR 0x0800
#define TST_LCOL 0x1000
#define TST_UFLO 0x4000
@@ -115,14 +119,5 @@ struct dev_priv {
};
extern int am79c961_probe (struct net_device *dev);
-static int am79c961_probe1 (struct net_device *dev);
-static int am79c961_open (struct net_device *dev);
-static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
-static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
-static int am79c961_close (struct net_device *dev);
-static struct enet_statistics *am79c961_getstats (struct net_device *dev);
-static void am79c961_setmulticastlist (struct net_device *dev);
#endif
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 2728d63c0..da5afb2ad 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1253,17 +1253,15 @@ static int __init ltpc_setup(char *str)
/* usage message */
printk (KERN_ERR
"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
+ return 0;
}
- return 1;
} else {
io = ints[1];
if (ints[0] > 1) {
irq = ints[2];
- return 1;
}
if (ints[0] > 2) {
dma = ints[3];
- return 1;
}
/* ignore any other paramters */
}
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 1608b8bdd..789123124 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -107,7 +107,7 @@ static int go_tx(struct net_device *dev);
void __init arcnet_init(void)
{
- static int arcnet_inited __initdata = 0;
+ static int arcnet_inited = 0;
int count;
if (arcnet_inited++)
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 79800883f..e7db72e15 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -426,7 +426,7 @@ static int __init com90io_setup(char *s)
s = get_options(s, 4, ints);
if (!ints[0])
- return 1;
+ return 0;
dev = alloc_bootmem(sizeof(struct net_device) + 10);
memset(dev, 0, sizeof(struct net_device) + 10);
dev->name = (char *) (dev + 1);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 5ef42cf9c..9fd9a275e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -48,10 +48,23 @@
: Don't call netif_wake_queue() in net_send_packet()
: Fixed an out-of-mem bug in dma_rx()
: Updated Documentation/cs89x0.txt
+
+ Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre1
+ : Use skb_reserve to longword align IP header (two places)
+ : Remove a delay loop from dma_rx()
+ : Replace '100' with HZ
+ : Clean up a couple of skb API abuses
+ : Added 'cs89x0_dma=N' kernel boot option
+ : Correctly initialise lp->lock in non-module compile
+
+ Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1
+ : MOD_INC/DEC race fix (see
+ : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
+
*/
static char *version =
-"cs89x0.c: (kernel 2.3.48) Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+"cs89x0.c: v2.3.99-pre1-2 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
/* ======================= end of configuration ======================= */
@@ -121,7 +134,7 @@ static unsigned int netcard_portlist[] __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
#if DEBUGGING
-static unsigned int net_debug = 5;
+static unsigned int net_debug = DEBUGGING;
#else
#define net_debug 0 /* gcc will remove all the debug code for us */
#endif
@@ -190,6 +203,21 @@ static void release_dma_buff(struct net_local *lp);
/* Example routines you must write ;->. */
#define tx_done(dev) 1
+/*
+ * Permit 'cs89x0_dma=N' in the kernel boot environment
+ */
+#if !defined(MODULE) && (ALLOW_DMA != 0)
+static int g_cs89x0_dma;
+
+static int __init dma_fn(char *str)
+{
+ g_cs89x0_dma = simple_strtol(str,NULL,0);
+ return 1;
+}
+
+__setup("cs89x0_dma=", dma_fn);
+#endif /* !defined(MODULE) && (ALLOW_DMA != 0) */
+
/* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations.
@@ -318,7 +346,17 @@ cs89x0_probe1(struct net_device *dev, int ioaddr)
retval = ENOMEM;
goto out;
}
- memset(dev->priv, 0, sizeof(struct net_local));
+ lp = (struct net_local *)dev->priv;
+ memset(lp, 0, sizeof(*lp));
+ spin_lock_init(&lp->lock);
+#if !defined(MODULE) && (ALLOW_DMA != 0)
+ if (g_cs89x0_dma)
+ {
+ lp->use_dma = 1;
+ lp->dma = g_cs89x0_dma;
+ lp->dmasize = 16; /* Could make this an option... */
+ }
+#endif
}
lp = (struct net_local *)dev->priv;
@@ -612,12 +650,6 @@ dma_rx(struct net_device *dev)
int status, length;
unsigned char *bp = lp->rx_dma_ptr;
- {
- int i;
- for (i = 0; i < 1000; i++)
- ;
- }
-
status = bp[0] + (bp[1]<<8);
length = bp[2] + (bp[3]<<8);
bp += 4;
@@ -632,7 +664,7 @@ dma_rx(struct net_device *dev)
}
/* Malloc up new buffer. */
- skb = alloc_skb(length, GFP_ATOMIC);
+ skb = dev_alloc_skb(length + 2);
if (skb == NULL) {
if (net_debug) /* I don't think we want to do this to a stressed system */
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
@@ -645,8 +677,7 @@ skip_this_frame:
lp->rx_dma_ptr = bp;
return;
}
-
- skb->len = length;
+ skb_reserve(skb, 2); /* longword align L3 header */
skb->dev = dev;
if (bp + length > lp->end_dma_buff) {
@@ -720,7 +751,7 @@ control_dc_dc(struct net_device *dev, int on_not_off)
writereg(dev, PP_SelfCTL, selfcontrol);
/* Wait for the DC/DC converter to power up - 500ms */
- while (jiffies - timenow < 100)
+ while (jiffies - timenow < HZ)
;
}
@@ -914,6 +945,9 @@ net_open(struct net_device *dev)
struct net_local *lp = (struct net_local *)dev->priv;
int result = 0;
int i;
+ int ret;
+
+ MOD_INC_USE_COUNT;
if (dev->irq < 2) {
/* Allow interrupts to be generated by the chip */
@@ -938,13 +972,15 @@ net_open(struct net_device *dev)
writereg(dev, PP_BusCTL, 0); /* disable interrupts. */
if (net_debug)
printk("cs89x0: can't get an interrupt\n");
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto bad_out;
}
} else {
if (((1 << dev->irq) & lp->irq_map) == 0) {
printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
dev->name, dev->irq, lp->irq_map);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto bad_out;
}
/* FIXME: Cirrus' release had this: */
writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );
@@ -956,7 +992,8 @@ net_open(struct net_device *dev)
if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {
if (net_debug)
printk("cs89x0: request_irq(%d) failed\n", dev->irq);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto bad_out;
}
}
@@ -1032,7 +1069,8 @@ net_open(struct net_device *dev)
#endif
writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
free_irq(dev->irq, dev);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto bad_out;
}
/* set the hardware to the configured choice */
@@ -1125,11 +1163,13 @@ net_open(struct net_device *dev)
| dma_busctl(dev)
#endif
);
- MOD_INC_USE_COUNT;
netif_start_queue(dev);
if (net_debug)
printk("cs89x0: net_open() succeeded\n");
return 0;
+bad_out:
+ MOD_DEC_USE_COUNT;
+ return ret;
}
static void net_timeout(struct net_device *dev)
@@ -1317,7 +1357,7 @@ net_rx(struct net_device *dev)
}
/* Malloc up new buffer. */
- skb = alloc_skb(length, GFP_ATOMIC);
+ skb = dev_alloc_skb(length + 2);
if (skb == NULL) {
#if 0 /* Again, this seems a cruel thing to do */
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
@@ -1325,10 +1365,10 @@ net_rx(struct net_device *dev)
lp->stats.rx_dropped++;
return;
}
- skb->len = length;
+ skb_reserve(skb, 2); /* longword align L3 header */
skb->dev = dev;
- insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1);
+ insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1);
if (length & 1)
skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT);
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 81e0dbdae..4d738e579 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -5923,9 +5923,7 @@ insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_devi
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
*
- * Delete -D__SMP__ below if you didn't define this in your kernel
* Delete -DMODVERSIONS below if you didn't define this in your kernel
*
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index c9e7beaca..6549f10c7 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1614,6 +1614,8 @@ init_module(void)
if (register_netdev(d) == 0)
n_eepro++;
+ else
+ break;
}
return n_eepro ? 0 : -ENODEV;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 128128bcb..b8e5acd66 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1285,7 +1285,7 @@ static void speedo_tx_timeout(struct net_device *dev)
del_timer(&sp->timer);
end_bh_atomic();
#else /* LINUX_VERSION_CODE */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
del_timer_sync(&sp->timer);
#else /* SMP */
del_timer(&sp->timer);
@@ -2258,7 +2258,6 @@ module_exit(eepro100_cleanup_module);
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index e770baacf..8ffc4fd41 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -1509,7 +1509,7 @@ module_exit(cleanup_baycomepp);
static int __init baycom_epp_setup(char *str)
{
- static unsigned __initdata nr_dev = 0;
+ static unsigned __initlocaldata nr_dev = 0;
int ints[2];
if (nr_dev >= NR_PORTS)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 85270f707..a0cb27045 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1800,9 +1800,9 @@ static void hp100_clean_txring( struct net_device *dev )
donecount);
#endif
#ifdef LINUX_2_1
- dev_kfree_skb( lp->txrhead->skb );
+ dev_kfree_skb_any( lp->txrhead->skb );
#else
- dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+ dev_kfree_skb_any( lp->txrhead->skb, FREE_WRITE );
#endif
lp->txrhead->skb=(void *)NULL;
lp->txrhead=lp->txrhead->next;
@@ -1960,9 +1960,9 @@ static int hp100_start_xmit( struct sk_buff *skb, struct net_device *dev )
hp100_ints_on();
#ifdef LINUX_2_1
- dev_kfree_skb( skb );
+ dev_kfree_skb_any( skb );
#else
- dev_kfree_skb( skb, FREE_WRITE );
+ dev_kfree_skb_any( skb, FREE_WRITE );
#endif
#ifdef HP100_DEBUG_TX
@@ -2198,9 +2198,9 @@ static void hp100_rx_bm( struct net_device *dev )
#endif
if(ptr->skb!=NULL)
#ifdef LINUX_2_1
- dev_kfree_skb( ptr->skb );
+ dev_kfree_skb_any( ptr->skb );
#else
- dev_kfree_skb( ptr->skb, FREE_READ );
+ dev_kfree_skb_any( ptr->skb, FREE_READ );
#endif
lp->stats.rx_errors++;
}
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 743812346..2ecbdee2d 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -188,9 +188,10 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
return -ENODEV;
}
- if (pci_enable_device (pdev)) {
+ i = pci_enable_device (pdev);
+ if (i) {
printk (KERN_ERR "ne2k-pci: cannot enable device\n");
- return -EIO;
+ return i;
}
if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
@@ -292,6 +293,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
/* Set up the rest of the parameters. */
dev->irq = irq;
dev->base_addr = ioaddr;
+ pdev->driver_data = dev;
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c
deleted file mode 100644
index bff7bc9ed..000000000
--- a/drivers/net/pcmcia/3c575_cb.c
+++ /dev/null
@@ -1,2159 +0,0 @@
-/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
-/*
- Written 1996-1999 by Donald Becker.
-
- This software may be used and distributed according to the terms
- of the GNU Public License, incorporated herein by reference.
-
- This driver is for the 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.
-
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
- Center of Excellence in Space Data and Information Sciences
- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
- Linux Kernel Additions:
-
- LK1.1.2 (March 19, 2000)
- * New PCI interface (jgarzik)
-
-*/
-
-static char *version =
-"3c575_cb.c:v0.99L+LK1.1.2 3/19/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.
- Setting to > 1512 effectively disables this feature. */
-static const int rx_copybreak = 200;
-/* 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;
-
-/* 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;
-#endif
-
-/* Some values here only for performance evaluation and path-coverage
- debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-
-/* A few values that may be tweaked. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((400*HZ)/1000)
-
-/* 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.*/
-
-#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>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/in.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>
-#include <asm/irq.h> /* For NR_IRQS only. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/* 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))
-
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-
-/* 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 = 0;
-
-#define PFX "3c575_cb: "
-
-
-
-/*
- Theory of Operation
-
-I. Board Compatibility
-
-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
-
-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
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-The EEPROM settings for media type and forced-full-duplex are observed.
-The EEPROM media type should be left at the default "autoselect" unless using
-10base2 or AUI connections which cannot be reliably detected.
-
-III. Driver operation
-
-The 3c59x series use an interface that's very similar to the previous 3c5x9
-series. The primary interface is two programmed-I/O FIFOs, with an
-alternate single-contiguous-region bus-master transfer (see next).
-
-The 3c900 "Boomerang" series uses a full-bus-master interface with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3. The first chip version retains a compatible
-programmed-I/O interface that has been removed in 'B' and subsequent board
-revisions.
-
-One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters. On the Vortex chip this capability was
-only for a single contiguous region making it far less useful than the full
-bus master capability. There is a significant performance impact of taking
-an extra interrupt or polling for the completion of each transfer, as well
-as difficulty sharing the single transfer engine between the transmit and
-receive threads. Using DMA transfers is a win only with large blocks or
-with the flawed versions of the Intel Orion motherboard PCI controller.
-
-The Boomerang chip's full-bus-master interface is useful, and has the
-currently-unused advantages over other similar chips that queued transmit
-packets may be reordered and receive buffer groups are associated with a
-single frame.
-
-With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Rather than a fixed intermediate receive buffer, this scheme allocates
-full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as
-the copying breakpoint: it is chosen to trade-off the memory wasted by
-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
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
-3c590, 3c595, and 3c900 boards.
-The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
-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.
-*/
-
-/* 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,
- HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-
-
-enum vortex_chips {
- CH_3C590 = 0,
- CH_3C595_1,
- CH_3C595_2,
- CH_3C595_3,
- CH_VORTEX,
- CH_3C900_1,
- CH_3C900_2,
- CH_3C900_3,
- 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_3C575_2,
- CH_BOOMERANG,
-};
-
-
-/* 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[] = {
- {"3c590 Vortex 10Mbps",
- 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, },
- {"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 Combo",
- 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, 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, 64, },
- {"3CCFE575 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
- {"3CCFE575CT Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
- {"3CCFE656 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
- {"3CCFEM656 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
- {"3c575 series CardBus (unknown version)",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
- {"3Com Boomerang (unknown version)",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
- {0,}, /* 0 terminated list. */
-};
-
-
-static struct pci_device_id vortex_pci_tbl[] __devinit = {
- { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
- { 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, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
- { 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, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 },
- { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG },
- {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
- exported in a ".h" file.
-
- First the windows. There are eight register windows, with the command
- and status registers available in each.
- */
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable.
- Note that 11 parameters bits was fine for ethernet, but the new chip
- can handle FDDI length frames (~4500 octets) and now parameters count
- 32-bit 'Dwords' rather than octets. */
-
-enum vortex_cmd {
- TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
- RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
- UpStall = 6<<11, UpUnstall = (6<<11)+1,
- DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
- RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
- FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11, SetTxStart = 19<<11,
- StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
- StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
- RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Bits in the general status register. */
-enum vortex_status {
- IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
- TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
- IntReq = 0x0040, StatsFull = 0x0080,
- DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
- DMAInProgress = 1<<11, /* DMA controller is still busy.*/
- CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/
-};
-
-/* Register window 1 offsets, the window used in normal operation.
- On the Vortex this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
- TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
- RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B,
- TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
- Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
- 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,
- EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
- NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
- DriverTune=13, Checksum=15};
-
-enum Window2 { /* Window 2. */
- Wn2_ResetOptions=12,
-};
-enum Window3 { /* Window 3: MAC/config bits. */
- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-union wn3_config {
- int i;
- struct w3_config_fields {
- unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
- int pad8:8;
- unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
- int pad24:7;
- } u;
-};
-
-enum Window4 { /* Window 4: Xcvr/media bits. */
- Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-enum Win4_Media_bits {
- Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
- Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
- Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
- Media_LnkBeat = 0x0800,
-};
-enum Window7 { /* Window 7: Bus Master control. */
- Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
-};
-/* Boomerang bus master control registers. */
-enum MasterCtrl {
- PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
- 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. */
-struct boom_rx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status;
- u32 addr; /* Up to 63 addr/len pairs possible. */
- s32 length; /* Set LAST_FRAG to indicate last pair. */
-};
-/* Values for the Rx status entry. */
-enum rx_desc_status {
- RxDComplete=0x00008000, RxDError=0x4000,
- /* See boomerang_rx() for actual error bits */
- IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
- IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
-};
-
-struct boom_tx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status; /* bits 0:12 length, others see below. */
- u32 addr;
- s32 length;
-};
-
-/* Values for the Tx status entry. */
-enum tx_desc_status {
- CRCDisable=0x2000, TxDComplete=0x8000,
- AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
- 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 };
-
-struct vortex_private {
- /* The Rx and Tx rings should be quad-word-aligned. */
- 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 */
- void *priv_addr;
- 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. */
-
- /* PCI configuration space information. */
- struct pci_dev *pdev;
- char *cb_fn_base; /* CardBus function status addr space. */
- int chip_id;
-
- /* 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: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_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- hw_csums:1, /* Has hardware checksums. */
- tx_full:1,
- open:1,
- reap: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;
- spinlock_t lock;
-};
-
-/* The action to take with a media selection timer tick.
- Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
- XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
- XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
-};
-
-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. */
-} media_tbl[] = {
- { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
- { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
- { "MII", 0, 0x41, XCVR_10baseT, 3*HZ },
- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
- { "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ},
- { "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ },
- { "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);
-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 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 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 EISA devices, for removing the driver module. */
-static struct net_device *root_vortex_eisa_dev = NULL;
-
-static int vortex_cards_found = 0;
-
-
-
-
-static void vortex_suspend (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
-
- printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
-
- if (dev && dev->priv) {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) {
- netif_device_detach(dev);
- vortex_down(dev);
- }
- }
-}
-
-
-static void vortex_resume (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
-
- printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
-
- if (dev && dev->priv) {
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) {
- vortex_up(dev);
- netif_device_attach(dev);
- }
- }
-}
-
-
-/* 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;
-
- /* Now check all slots of the EISA bus. */
- if (!EISA_bus)
- return 0;
-
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- int device_id;
-
- if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
- continue;
-
- /* 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,
- 4, /* XXX is 4 correct eisa idx? */
- vortex_cards_found);
- if (rc == 0)
- vortex_cards_found++;
- else
- release_region (ioaddr, VORTEX_TOTAL_SIZE);
- }
-
- 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;
-}
-
-
-/* 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)
-{
- 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;
-
- if (!printed_version) {
- printk (KERN_INFO "%s", version);
- printed_version = 1;
- }
-
- dev = init_etherdev(NULL, sizeof(*vp));
- if (!dev) {
- printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
- return -ENOMEM;
- }
-
- 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;
- vp->priv_addr = vp;
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->mtu = mtu;
-
- /* 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);
- kfree (dev);
- return -EBUSY;
- }
-
- /* wake up and enable device */
- if (pci_enable_device (pdev)) {
- printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
- release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
- kfree (dev);
- return -EIO;
- }
-
- /* 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->pdev = pdev;
-
- /* 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)
- 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 & 15;
- 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 (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- vp->full_duplex = 1;
-
- 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;
-#if 1 /* 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;
- }
- eeprom[i] = inw(ioaddr + Wn0EepromData);
- }
- for (i = 0; i < 0x18; i++)
- checksum ^= eeprom[i];
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */
- while (i < 0x21)
- checksum ^= eeprom[i++];
- checksum = (checksum ^ (checksum >> 8)) & 0xff;
- }
- 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
- printk(", IRQ %d\n", dev->irq);
- /* Tell them about an invalid IRQ. */
- if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
- printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
- dev->irq);
-#endif
-
- if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
- u32 fn_st_addr; /* Cardbus function status space */
- fn_st_addr = pci_resource_start (pdev, 2);
- if (fn_st_addr)
- 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);
- }
-
- /* Extract our information from the EEPROM data. */
- vp->info1 = eeprom[13];
- vp->info2 = eeprom[15];
- vp->capabilities = eeprom[16];
-
- if (vp->info1 & 0x8000)
- vp->full_duplex = 1;
-
- {
- char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- union wn3_config config;
- EL3WINDOW(3);
- vp->available_media = inw(ioaddr + Wn3_Options);
- if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */
- vp->available_media = 0x40;
- config.i = inl(ioaddr + Wn3_Config);
- if (vortex_debug > 1)
- printk(KERN_DEBUG " Internal config register is %4.4x, "
- "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
- printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
- 8 << config.u.ram_size,
- config.u.ram_width ? "word" : "byte",
- ram_split[config.u.ram_split],
- config.u.autoselect ? "autoselect/" : "",
- config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
- media_tbl[config.u.xcvr].name);
- vp->default_media = config.u.xcvr;
- vp->autoselect = config.u.autoselect;
- }
-
- if (vp->media_override != 7) {
- 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) {
- int phy, phy_idx = 0;
- EL3WINDOW(4);
- mii_preamble_required++;
- mii_preamble_required++;
- 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 && mii_status != 0xffff) {
- vp->phys[phy_idx++] = phyx;
- printk(KERN_INFO " MII transceiver found at address %d,"
- " status %4x.\n", phyx, mii_status);
- if ((mii_status & 0x0040) == 0)
- mii_preamble_required++;
- }
- }
- mii_preamble_required--;
- if (phy_idx == 0) {
- printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
- vp->phys[0] = 24;
- } else {
- vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
- if (vp->full_duplex) {
- /* Only advertise the FD media types. */
- vp->advertising &= ~0x02A0;
- mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
- }
- }
- }
-
- 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;
- }
-
- /* 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;
- dev->tx_timeout = &vortex_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- return 0;
-}
-
-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))
- break;
- if (i == 0)
- printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
- dev->name, cmd);
-}
-
-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, 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);
-
- if (vp->media_override != 7) {
- if (vortex_debug > 1)
- 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 (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)
- 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;
- }
- } else
- dev->if_port = vp->default_media;
-
- 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);
-
- 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.u.xcvr = dev->if_port;
- if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
- outl(config.i, 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 (vortex_debug > 1)
- 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);
- }
-
- /* Set the full-duplex bit. */
- outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
-
- if (vortex_debug > 1) {
- printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
- dev->name, config.i);
- }
-
- wait_for_completion(dev, TxReset);
- wait_for_completion(dev, RxReset);
-
- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
- if (vortex_debug > 1) {
- EL3WINDOW(4);
- printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
- dev->name, dev->irq, inw(ioaddr + Wn4_Media));
- }
-
- /* 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) {
- u_short n = inw(ioaddr + Wn2_ResetOptions);
- /* Inverted LED polarity */
- if (device_id != 0x5257)
- n |= 0x0010;
- /* 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...*/
- outw(StartCoax, ioaddr + EL3_CMD);
- if (dev->if_port != XCVR_NWAY) {
- EL3WINDOW(4);
- outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
- media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
- }
-
- /* Switch to the stats window, and clear all stats by reading. */
- outw(StatsDisable, ioaddr + EL3_CMD);
- EL3WINDOW(6);
- for (i = 0; i < 10; i++)
- inb(ioaddr + i);
- inw(ioaddr + 10);
- inw(ioaddr + 12);
- /* New: On the Vortex we must also clear the BadSSD counter. */
- EL3WINDOW(4);
- inb(ioaddr + 12);
- /* ..and on the Boomerang we enable the extra statistics bits. */
- outw(0x0040, ioaddr + Wn4_NetDiag);
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
-
- if (vp->full_bus_master_rx) { /* Boomerang bus master. */
- vp->cur_rx = vp->dirty_rx = 0;
- /* Initialize the RxEarly register as recommended. */
- outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
- outl(0x0020, ioaddr + PktStatus);
- 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 Rx, Tx rings. */
- for (i = 0; i < RX_RING_SIZE; i++)
- vp->rx_ring[i].status = 0;
- for (i = 0; i < TX_RING_SIZE; i++)
- vp->tx_skbuff[i] = 0;
- outl(0, ioaddr + DownListPtr);
- }
- /* 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. */
- /* 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 | 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);
-}
-
-static int
-vortex_open(struct net_device *dev)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int i;
-
-#ifdef CARDBUS
- if (vp->reap)
- return -ENODEV;
-#endif
- /* Use the now-standard shared IRQ implementation. */
- if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
- return -EAGAIN;
- }
-
- 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]));
- }
- if (vp->full_bus_master_tx)
- dev->hard_start_xmit = &boomerang_start_xmit;
-
- vortex_up(dev);
- vp->open = 1;
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-
-static void vortex_timer(unsigned long data)
-{
- 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 = 60*HZ;
- int ok = 0;
- int media_status, mii_status, old_window;
-
- if (vortex_debug > 1)
- printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- disable_irq(dev->irq);
- old_window = inw(ioaddr + EL3_CMD) >> 13;
- EL3WINDOW(4);
- media_status = inw(ioaddr + Wn4_Media);
- 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);
- } else if (vortex_debug > 1)
- 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. */
- EL3WINDOW(3);
- outb((vp->full_duplex ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0),
- ioaddr + Wn3_MAC_Ctrl);
- }
- next_tick = 60*HZ;
- }
- }
- 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",
- dev->name, media_tbl[dev->if_port].name, media_status);
- ok = 1;
- }
- if ( ! ok) {
- union wn3_config config;
-
- 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)
- 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)
- 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);
-
- EL3WINDOW(3);
- config.i = inl(ioaddr + Wn3_Config);
- config.u.xcvr = dev->if_port;
- outl(config.i, ioaddr + Wn3_Config);
-
- outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
- ioaddr + EL3_CMD);
- }
- EL3WINDOW(old_window);
- enable_irq(dev->irq);
-
- if (vortex_debug > 2)
- printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
- dev->name, media_tbl[dev->if_port].name);
-
- vp->timer.expires = RUN_AT(next_tick);
- add_timer(&vp->timer);
- if (vp->deferred)
- outw(FakeIntr, ioaddr + EL3_CMD);
- return;
-}
-
-static void vortex_tx_timeout(struct net_device *dev)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
- printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus),
- inw(ioaddr + EL3_STATUS));
- /* Slight code bloat to be user friendly. */
- if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
- printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
- " network cable problem?\n", dev->name);
- if (inw(ioaddr + EL3_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. */
- vortex_interrupt(dev->irq, dev, 0);
- }
-
-#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));
- }
- }
-#endif
- wait_for_completion(dev, TxReset);
-
- vp->stats.tx_errors++;
- if (vp->full_bus_master_tx) {
- if (vortex_debug > 0)
- 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(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
- ioaddr + DownListPtr);
- if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
- vp->tx_full = 0;
- 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
- vp->stats.tx_dropped++;
-
- /* Issue Tx Enable */
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
-
- /* Switch to register set 7 for normal use. */
- EL3WINDOW(7);
-}
-
-/*
- * Handle uncommon interrupt sources. This is a separate routine to minimize
- * the cache impact.
- */
-static void
-vortex_error(struct net_device *dev, int status)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int do_tx_reset = 0;
-
- if (status & TxComplete) { /* Really "TxError" for us. */
- 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_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
- dev->name, tx_status);
- 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)
- do_tx_reset = 1;
- else /* Merely re-enable the transmitter. */
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- if (status & RxEarly) { /* Rx early is unused. */
- vortex_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
- if (status & StatsFull) { /* Empty statistics. */
- static int DoneDidThat = 0;
- if (vortex_debug > 4)
- printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
- update_stats(ioaddr, dev);
- /* HACK: Disable statistics as an interrupt source. */
- /* This occurs when we have the wrong media type! */
- if (DoneDidThat == 0 &&
- inw(ioaddr + EL3_STATUS) & StatsFull) {
- printk(KERN_WARNING "%s: Updating statistics failed, disabling "
- "stats as an interrupt source.\n", dev->name);
- EL3WINDOW(5);
- outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
- EL3WINDOW(7);
- DoneDidThat++;
- }
- }
- if (status & IntReq) { /* Restore all interrupt sources. */
- outw(vp->status_enable, ioaddr + EL3_CMD);
- outw(vp->intr_enable, ioaddr + EL3_CMD);
- }
- 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);
- /* Adapter failure requires Tx/Rx reset and reinit. */
- if (vp->full_bus_master_tx) {
- /* 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) {
- 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. */
- outw(AckIntr | HostError, ioaddr + EL3_CMD);
- }
- }
- if (do_tx_reset) {
- 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);
-
- /* Put out the doubleword header... */
- outl(skb->len, ioaddr + TX_FIFO);
- if (vp->bus_master) {
- /* Set the bus-master controller to transfer the packet. */
- 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);
- /* 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_kfree_skb (skb);
- if (inw(ioaddr + TxFree) > 1536) {
- netif_start_queue (dev);
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
- }
-
- dev->trans_start = jiffies;
-
- /* Clear the Tx status stack. */
- {
- int tx_status;
- int i = 32;
-
- while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
- if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
- if (vortex_debug > 2)
- 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) {
- wait_for_completion(dev, TxReset);
- }
- outw(TxEnable, ioaddr + EL3_CMD);
- }
- outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
- }
- }
- return 0;
-}
-
-static int
-boomerang_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);
- if (1) {
- /* 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;
-
- 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)
- 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;
- vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
- vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
- vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-
- spin_lock_irqsave(&vp->lock, flags);
- /* Wait for the stall to complete. */
- wait_for_completion(dev, DownStall);
- prev_entry->next = cpu_to_le32(virt_to_bus(&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);
- spin_unlock_irqrestore(&vp->lock, 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);
-#endif
- netif_start_queue (dev);
- }
- dev->trans_start = jiffies;
- return 0;
- }
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-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 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 (status & IntReq) {
- status |= vp->deferred;
- vp->deferred = 0;
- }
-
- if (status == 0xffff)
- 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 & 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);
- }
-
- 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) ==
- virt_to_bus(&vp->tx_ring[entry]))
- break; /* It still hasn't been processed. */
- if (vp->tx_skbuff[entry]) {
- dev_kfree_skb_irq(vp->tx_skbuff[entry]);
- vp->tx_skbuff[entry] = 0;
- }
- /* vp->stats.tx_packets++; Counted below. */
- dirty_tx++;
- }
- vp->dirty_tx = dirty_tx;
- if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
- vp->tx_full = 0;
- netif_wake_queue (dev);
- }
- }
- if (vp->tx_full)
- netif_stop_queue (dev);
- if (status & DMADone) {
- if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- 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);
- }
- }
- }
- /* 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);
-}
-
-static int vortex_rx(struct net_device *dev)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int i;
- short rx_status;
-
- if (vortex_debug > 5)
- 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)
- printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- int pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(pkt_len + 5);
- if (vortex_debug > 4)
- printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
- pkt_len, rx_status);
- if (skb != NULL) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- if (vp->bus_master &&
- ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
- 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)
- ;
- } else {
- insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
- (pkt_len + 3) >> 2);
- }
- outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- vp->stats.rx_packets++;
- /* 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)
- printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
- "size %d.\n", dev->name, pkt_len);
- }
- vp->stats.rx_dropped++;
- wait_for_completion(dev, RxDiscard);
- }
-
- return 0;
-}
-
-static int
-boomerang_rx(struct net_device *dev)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int entry = vp->cur_rx % RX_RING_SIZE;
- long ioaddr = dev->base_addr;
- int rx_status;
- 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 "
- "%4.4x.\n",
- inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
- 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)
- printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
- vp->stats.rx_errors++;
- if (rx_error & 0x01) vp->stats.rx_over_errors++;
- if (rx_error & 0x02) vp->stats.rx_length_errors++;
- if (rx_error & 0x04) vp->stats.rx_frame_errors++;
- if (rx_error & 0x08) vp->stats.rx_crc_errors++;
- if (rx_error & 0x10) vp->stats.rx_length_errors++;
- } else {
- /* The packet length: up to 4.5K!. */
- int pkt_len = rx_status & 0x1fff;
- struct sk_buff *skb;
-
- if (vortex_debug > 4)
- 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) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- /* 'skb_put()' points to the start of sk_buff data area. */
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(le32_to_cpu(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;
- temp = skb_put(skb, pkt_len);
- /* Remove this checking code for final release. */
- if (bus_to_virt(le32_to_cpu(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. */
- int csum_bits = rx_status & 0xee000000;
- if (csum_bits &&
- (csum_bits == (IPChksumValid | TCPChksumValid) ||
- csum_bits == (IPChksumValid | UDPChksumValid))) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- rx_csumhits++;
- }
- }
- netif_rx(skb);
- dev->last_rx = jiffies;
- vp->stats.rx_packets++;
- }
- entry = (++vp->cur_rx) % RX_RING_SIZE;
- }
- /* Refill the Rx ring buffers. */
- for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
- 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)
- 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(virt_to_bus(skb->tail));
- vp->rx_skbuff[entry] = skb;
- }
- vp->rx_ring[entry].status = 0; /* Clear complete bit. */
- outw(UpUnstall, ioaddr + EL3_CMD);
- }
- return 0;
-}
-
-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(&vp->timer);
-
- /* Turn off statistics ASAP. We update vp->stats below. */
- outw(StatsDisable, ioaddr + EL3_CMD);
-
- /* Disable the receiver and transmitter. */
- outw(RxDisable, ioaddr + EL3_CMD);
- outw(TxDisable, ioaddr + EL3_CMD);
-
- if (dev->if_port == XCVR_10base2)
- /* Turn off thinnet power. Green! */
- outw(StopCoax, ioaddr + EL3_CMD);
-
- outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
- update_stats(ioaddr, dev);
- 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]) {
- dev_kfree_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++)
- if (vp->tx_skbuff[i]) {
- dev_kfree_skb(vp->tx_skbuff[i]);
- vp->tx_skbuff[i] = 0;
- }
- }
-
- MOD_DEC_USE_COUNT;
- vp->open = 0;
- return 0;
-}
-
-static struct net_device_stats *vortex_get_stats(struct net_device *dev)
-{
- struct vortex_private *vp = (struct vortex_private *)dev->priv;
- unsigned long flags;
-
- if (netif_device_present(dev)) {
- spin_lock_irqsave (&vp->lock, flags);
- update_stats(dev->base_addr, dev);
- spin_unlock_irqrestore (&vp->lock, flags);
- }
- return &vp->stats;
-}
-
-/* Update statistics.
- Unlike with the EL3 we need not worry about interrupts changing
- the window setting from underneath us, but we must still guard
- against a race condition with a StatsUpdate interrupt updating the
- table. This is done by checking that the ASM (!) code generated uses
- atomic updates with '+='.
- */
-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);
- vp->stats.tx_carrier_errors += inb(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
- /* Multiple collisions. */ inb(ioaddr + 2);
- vp->stats.collisions += inb(ioaddr + 3);
- vp->stats.tx_window_errors += inb(ioaddr + 4);
- vp->stats.rx_fifo_errors += inb(ioaddr + 5);
- vp->stats.tx_packets += inb(ioaddr + 6);
- vp->stats.tx_packets += (inb(ioaddr + 9)&0x30) << 4;
- /* Rx packets */ inb(ioaddr + 7); /* Must read to clear */
- /* Tx deferrals */ inb(ioaddr + 8);
- /* 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);
- 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(old_window >> 13);
- return;
-}
-
-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;
- u16 *data = (u16 *)&rq->ifr_data;
- int phy = vp->phys[0] & 0x1f;
-
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- data[0] = phy;
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- EL3WINDOW(4);
- data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
- return 0;
- 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;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/* Pre-Cyclone chips have no documented multicast filter, so the only
- multicast setting is to receive all multicast frames. At least
- the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
- 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);
- 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);
-}
-
-/* MII transceiver control section.
- Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details. */
-
-/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues. */
-#define mdio_delay() inl(mdio_addr)
-
-#define MDIO_SHIFT_CLK 0x01
-#define MDIO_DIR_WRITE 0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ 0x02
-#define MDIO_ENB_IN 0x00
-
-/* Generate the preamble required for initial synchronization and
- a few older transceivers. */
-static void mdio_sync(long ioaddr, int bits)
-{
- long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- /* Establish sync by sending at least 32 logic ones. */
- while (-- bits >= 0) {
- outw(MDIO_DATA_WRITE1, mdio_addr);
- mdio_delay();
- outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
-}
-
-static int mdio_read(long ioaddr, int phy_id, int location)
-{
- int i;
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- unsigned int retval = 0;
- long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the read command bits out. */
- for (i = 14; i >= 0; i--) {
- int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- mdio_delay();
- 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--) {
- 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();
- }
- return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-}
-
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
-{
- int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
- long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
- int i;
-
- if (mii_preamble_required)
- mdio_sync(ioaddr, 32);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outw(dataval, mdio_addr);
- mdio_delay();
- outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- 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();
- }
-
- 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;
-
- /* 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 __devexit vortex_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
- struct vortex_private *vp;
-
- if (!dev)
- return;
-
- vp = (void *)(dev->priv);
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- 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)
- 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);
- }
-}
-
-
-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 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c"
- * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.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
- * End:
- */
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 9530440e3..5a83c521c 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -18,7 +18,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
if [ "$CONFIG_CARDBUS" = "y" ]; then
- dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
+ comment ' 3Com 3c575 moved to Ethernet 10/100 menu'
tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
fi
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index ddefee51d..4f6463c22 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -36,7 +36,6 @@ obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
# Cardbus client drivers
-obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o
obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o
obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o
diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
index 3c088df36..ba58883c2 100644
--- a/drivers/net/pcmcia/ray_cs.c
+++ b/drivers/net/pcmcia/ray_cs.c
@@ -1494,16 +1494,19 @@ static int ray_open(struct net_device *dev)
dev_link_t *link;
ray_dev_t *local = (ray_dev_t *)dev->priv;
+ MOD_INC_USE_COUNT;
+
DEBUG(1, "ray_open('%s')\n", dev->name);
for (link = dev_list; link; link = link->next)
if (link->priv == dev) break;
- if (!DEV_OK(link))
+ if (!DEV_OK(link)) {
+ MOD_DEC_USE_COUNT;
return -ENODEV;
+ }
if (link->open == 0) local->num_multi = 0;
link->open++;
- MOD_INC_USE_COUNT;
if (sniffer) netif_stop_queue(dev);
else netif_start_queue(dev);
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
index c1cb7629f..bf71f29fd 100644
--- a/drivers/net/pcmcia/xircom_tulip_cb.c
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -3132,7 +3132,7 @@ static int __init tulip_init(void)
return 0;
}
-static __exit void tulip_exit(void)
+static void __exit tulip_exit(void)
{
pci_unregister_driver(&tulip_ops);
}
@@ -3143,7 +3143,6 @@ module_exit(tulip_exit)
/*
* Local variables:
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
* c-indent-level: 4
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 6508c56c2..877407590 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -687,11 +687,12 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
return ERROR;
}
/* Malloc up new buffer. */
- rcv->skb = dev_alloc_skb(rcv->length.h);
+ rcv->skb = dev_alloc_skb(rcv->length.h + 2);
if (rcv->skb == NULL) {
printk(KERN_ERR "%s: Memory squeeze.\n", dev->name);
return ERROR;
}
+ skb_reserve(rcv->skb, 2); /* Align IP on 16 byte boundaries */
skb_put(rcv->skb,rcv->length.h);
rcv->skb->dev = dev;
rcv->state = PLIP_PK_DATA;
@@ -989,7 +990,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
switch (nl->connection) {
case PLIP_CN_CLOSING:
- netif_start_queue (dev);
+ netif_wake_queue (dev);
case PLIP_CN_NONE:
case PLIP_CN_SEND:
dev->last_rx = jiffies;
@@ -1035,7 +1036,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->len > dev->mtu + dev->hard_header_len) {
printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);
netif_start_queue (dev);
- return 0;
+ return 1;
}
if (net_debug > 2)
@@ -1054,7 +1055,6 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
mark_bh(IMMEDIATE_BH);
spin_unlock_irq(&nl->lock);
- netif_start_queue (dev);
return 0;
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index c3eb74c37..d6b2c47f3 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -290,6 +290,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
return err;
}
+/* No kernel lock - fine */
static unsigned int
ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
{
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index a70c1a8db..4a7454d3f 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -19,7 +19,7 @@
* PPP driver, written by Michael Callahan and Al Longyear, and
* subsequently hacked by Paul Mackerras.
*
- * ==FILEVERSION 20000406==
+ * ==FILEVERSION 20000417==
*/
#include <linux/config.h>
@@ -206,7 +206,7 @@ static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf,
size_t count);
static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
unsigned int cmd, unsigned long arg);
-static void ppp_xmit_process(struct ppp *ppp, int wakeup);
+static void ppp_xmit_process(struct ppp *ppp);
static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
static void ppp_push(struct ppp *ppp);
static void ppp_channel_push(struct channel *pch);
@@ -427,7 +427,7 @@ static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf,
switch (pf->kind) {
case INTERFACE:
- ppp_xmit_process(PF_TO_PPP(pf), 0);
+ ppp_xmit_process(PF_TO_PPP(pf));
break;
case CHANNEL:
ppp_channel_push(PF_TO_CHANNEL(pf));
@@ -440,6 +440,7 @@ static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf,
return ret;
}
+/* No kernel lock - fine */
static unsigned int ppp_poll(struct file *file, poll_table *wait)
{
struct ppp_file *pf = (struct ppp_file *) file->private_data;
@@ -774,7 +775,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
skb_queue_tail(&ppp->file.xq, skb);
- ppp_xmit_process(ppp, 0);
+ ppp_xmit_process(ppp);
return 0;
outf:
@@ -860,13 +861,12 @@ ppp_net_init(struct net_device *dev)
* that can now be done.
*/
static void
-ppp_xmit_process(struct ppp *ppp, int wakeup)
+ppp_xmit_process(struct ppp *ppp)
{
struct sk_buff *skb;
ppp_xmit_lock(ppp);
- if (wakeup)
- ppp_push(ppp);
+ ppp_push(ppp);
while (ppp->xmit_pending == 0
&& (skb = skb_dequeue(&ppp->file.xq)) != 0)
ppp_send_frame(ppp, skb);
@@ -1018,14 +1018,12 @@ ppp_push(struct ppp *ppp)
spin_lock_bh(&pch->downl);
if (pch->chan) {
if (pch->chan->ops->start_xmit(pch->chan, skb))
- skb = 0;
+ ppp->xmit_pending = 0;
} else {
/* channel got unregistered */
kfree_skb(skb);
- skb = 0;
- }
- if (skb_queue_len(&pch->file.xq) == 0 && skb == 0)
ppp->xmit_pending = 0;
+ }
spin_unlock_bh(&pch->downl);
return;
}
@@ -1196,6 +1194,7 @@ static void
ppp_channel_push(struct channel *pch)
{
struct sk_buff *skb;
+ struct ppp *ppp;
spin_lock_bh(&pch->downl);
if (pch->chan != 0) {
@@ -1212,6 +1211,14 @@ ppp_channel_push(struct channel *pch)
skb_queue_purge(&pch->file.xq);
}
spin_unlock_bh(&pch->downl);
+ /* see if there is anything from the attached unit to be sent */
+ if (skb_queue_len(&pch->file.xq) == 0) {
+ read_lock_bh(&pch->upl);
+ ppp = pch->ppp;
+ if (ppp != 0)
+ ppp_xmit_process(ppp);
+ read_unlock_bh(&pch->upl);
+ }
}
/*
@@ -1792,18 +1799,10 @@ void
ppp_output_wakeup(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
- struct ppp *ppp;
if (pch == 0)
return;
ppp_channel_push(pch);
- if (skb_queue_len(&pch->file.xq) == 0) {
- read_lock_bh(&pch->upl);
- ppp = pch->ppp;
- if (ppp != 0)
- ppp_xmit_process(ppp, 1);
- read_unlock_bh(&pch->upl);
- }
}
/*
@@ -1830,6 +1829,7 @@ ppp_channel_write(struct ppp_channel *chan, const char *buf, size_t count)
return ppp_file_write(&pch->file, buf, count);
}
+/* No kernel lock - fine */
unsigned int
ppp_channel_poll(struct ppp_channel *chan, struct file *file, poll_table *wait)
{
@@ -2376,6 +2376,7 @@ ppp_disconnect_channel(struct channel *pch)
{
struct ppp *ppp;
int err = -EINVAL;
+ int dead;
write_lock_bh(&pch->upl);
ppp = pch->ppp;
@@ -2385,12 +2386,12 @@ ppp_disconnect_channel(struct channel *pch)
ppp_lock(ppp);
list_del(&pch->clist);
--ppp->n_channels;
- if (ppp->dev == 0 && ppp->n_channels == 0)
+ dead = ppp->dev == 0 && ppp->n_channels == 0;
+ ppp_unlock(ppp);
+ if (dead)
/* Last disconnect from a ppp unit
that is already dead: free it. */
kfree(ppp);
- else
- ppp_unlock(ppp);
err = 0;
}
write_unlock_bh(&pch->upl);
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index e049ab4bd..d84f05956 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -329,6 +329,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
return err;
}
+/* No kernel lock - fine */
static unsigned int
ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
{
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 8ad1a2a16..dbd12bdb9 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -25,6 +25,7 @@
#define RX_DMA_SKBUFF 1
#define PKT_COPY_THRESHOLD 512
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
@@ -166,7 +167,7 @@ int __init rr_hippi_probe (struct net_device *dev)
rrpriv = (struct rr_private *)dev->priv;
memset(rrpriv, 0, sizeof(*rrpriv));
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_lock_init(&rrpriv->lock);
#endif
sprintf(rrpriv->name, "RoadRunner serial HIPPI");
@@ -1650,6 +1651,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/*
* Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
+ * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
* End:
*/
diff --git a/drivers/net/rtl8129.c b/drivers/net/rtl8129.c
index b60a62608..725f16a4a 100644
--- a/drivers/net/rtl8129.c
+++ b/drivers/net/rtl8129.c
@@ -1460,7 +1460,6 @@ module_exit(rtl8129_cleanup);
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/setup.c b/drivers/net/setup.c
index 12e51e458..7e01e3f83 100644
--- a/drivers/net/setup.c
+++ b/drivers/net/setup.c
@@ -28,6 +28,7 @@ extern int lapbeth_init(void);
extern int sdla_setup(void);
extern int sdla_c_setup(void);
extern int comx_init(void);
+extern int lmc_setup(void);
extern int abyss_probe(void);
extern int madgemc_probe(void);
@@ -81,6 +82,9 @@ struct net_probe pci_probes[] __initdata = {
* SLHC if present needs attaching so other people see it
* even if not opened.
*/
+#if defined(CONFIG_LANMEDIA)
+ {lmc_setup, 0},
+#endif
#ifdef CONFIG_INET
#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 41e15ff36..133483614 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -64,6 +64,9 @@
* Device statistics (tx_pakets, tx_bytes,
* tx_drops: queue_over_time and collisions: max_queue_exceded)
* 1999/06/18 Jordi Murgo <savage@apostols.org>
+ *
+ * Use skb->cb for private data.
+ * 2000/03 Andi Kleen
*/
#include <linux/config.h>
@@ -85,6 +88,15 @@
#include <net/arp.h>
#include <linux/if_shaper.h>
+struct shaper_cb {
+ __u32 shapelatency; /* Latency on frame */
+ __u32 shapeclock; /* Time it should go out */
+ __u32 shapelen; /* Frame length in clocks */
+ __u32 shapestamp; /* Stamp for shaper */
+ __u16 shapepend; /* Pending */
+};
+#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
+
int sh_debug; /* Debug flag */
#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
@@ -149,7 +161,7 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
{
struct sk_buff *ptr;
-
+
/*
* Get ready to work on this shaper. Lock may fail if its
* an interrupt and locked.
@@ -163,25 +175,25 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
* Set up our packet details
*/
- skb->shapelatency=0;
- skb->shapeclock=shaper->recovery;
- if(time_before(skb->shapeclock, jiffies))
- skb->shapeclock=jiffies;
+ SHAPERCB(skb)->shapelatency=0;
+ SHAPERCB(skb)->shapeclock=shaper->recovery;
+ if(time_before(SHAPERCB(skb)->shapeclock, jiffies))
+ SHAPERCB(skb)->shapeclock=jiffies;
skb->priority=0; /* short term bug fix */
- skb->shapestamp=jiffies;
+ SHAPERCB(skb)->shapestamp=jiffies;
/*
* Time slots for this packet.
*/
- skb->shapelen= shaper_clocks(shaper,skb);
+ SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
#ifdef SHAPER_COMPLEX /* and broken.. */
while(ptr && ptr!=(struct sk_buff *)&shaper->sendq)
{
if(ptr->pri<skb->pri
- && jiffies - ptr->shapeclock < SHAPER_MAXSLIP)
+ && jiffies - SHAPERCB(ptr)->shapeclock < SHAPER_MAXSLIP)
{
struct sk_buff *tmp=ptr->prev;
@@ -190,14 +202,14 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
* of the new frame.
*/
- ptr->shapeclock+=skb->shapelen;
- ptr->shapelatency+=skb->shapelen;
+ SHAPERCB(ptr)->shapeclock+=SHAPERCB(skb)->shapelen;
+ SHAPERCB(ptr)->shapelatency+=SHAPERCB(skb)->shapelen;
/*
* The packet may have slipped so far back it
* fell off.
*/
- if(ptr->shapelatency > SHAPER_LATENCY)
+ if(SHAPERCB(ptr)->shapelatency > SHAPER_LATENCY)
{
skb_unlink(ptr);
dev_kfree_skb(ptr);
@@ -218,7 +230,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
* this loop.
*/
for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next)
- skb->shapeclock+=tmp->shapelen;
+ SHAPERCB(skb)->shapeclock+=tmp->shapelen;
skb_append(ptr,skb);
}
#else
@@ -230,11 +242,11 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
*/
for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
- skb->shapeclock+=tmp->shapelen;
+ SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen;
/*
* Queue over time. Spill packet.
*/
- if(skb->shapeclock-jiffies > SHAPER_LATENCY) {
+ if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) {
dev_kfree_skb(skb);
shaper->stats.tx_dropped++;
} else
@@ -325,22 +337,23 @@ static void shaper_kick(struct shaper *shaper)
*/
if(sh_debug)
- printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
- if(time_before_eq(skb->shapeclock - jiffies, SHAPER_BURST))
+ printk("Clock = %d, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies);
+ if(time_before_eq(SHAPERCB(skb)->shapeclock - jiffies, SHAPER_BURST))
{
/*
* Pull the frame and get interrupts back on.
*/
skb_unlink(skb);
- if (shaper->recovery < skb->shapeclock + skb->shapelen)
- shaper->recovery = skb->shapeclock + skb->shapelen;
+ if (shaper->recovery <
+ SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
+ shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
/*
* Pass on to the physical target device via
* our low level packet thrower.
*/
- skb->shapepend=0;
+ SHAPERCB(skb)->shapepend=0;
shaper_queue_xmit(shaper, skb); /* Fire */
}
else
@@ -352,7 +365,7 @@ static void shaper_kick(struct shaper *shaper)
*/
if(skb!=NULL)
- mod_timer(&shaper->timer, skb->shapeclock);
+ mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
clear_bit(0, &shaper->locked);
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 5036b01af..43b093a12 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1375,7 +1375,6 @@ module_exit(starfire_cleanup);
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c"
* c-indent-level: 4
* c-basic-offset: 4
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index f244874e4..2bc0a8652 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -88,8 +88,10 @@ void t21142_timer(unsigned long data)
next_tick = 3*HZ;
}
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
+ /* mod_timer synchronizes us with potential add_timer calls
+ * from interrupts.
+ */
+ mod_timer(&tp->timer, RUN_AT(next_tick));
}
@@ -108,7 +110,10 @@ void t21142_start_nway(struct net_device *dev)
dev->name, csr14);
outl(0x0001, ioaddr + CSR13);
outl(csr14, ioaddr + CSR14);
- tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ if (tp->chip_id == PNIC2)
+ tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ else
+ tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
tulip_outl_CSR6(tp, tp->csr6);
if (tp->mtable && tp->mtable->csr15dir) {
outl(tp->mtable->csr15dir, ioaddr + CSR15);
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index 0a40abb48..16e048b82 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -171,8 +171,10 @@ void tulip_timer(unsigned long data)
}
break;
}
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
+ /* mod_timer synchronizes us with potential add_timer calls
+ * from interrupts.
+ */
+ mod_timer(&tp->timer, RUN_AT(next_tick));
}
@@ -188,8 +190,7 @@ void mxic_timer(unsigned long data)
inl(ioaddr + CSR12));
}
if (next_tick) {
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
+ mod_timer(&tp->timer, RUN_AT(next_tick));
}
}
@@ -205,7 +206,9 @@ void comet_timer(unsigned long data)
printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
"%4.4x.\n",
dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
+ /* mod_timer synchronizes us with potential add_timer calls
+ * from interrupts.
+ */
+ mod_timer(&tp->timer, RUN_AT(next_tick));
}
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 22260591f..a09437582 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -19,6 +19,22 @@
#include <linux/timer.h>
#include <asm/io.h>
+
+
+/* undefine, or define to various debugging levels (>4 == obscene levels) */
+#undef TULIP_DEBUG
+
+
+#ifdef TULIP_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+
+
+
struct tulip_chip_table {
char *chip_name;
int io_size;
@@ -148,6 +164,38 @@ enum t21041_csr13_bits {
csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl),
};
+enum t21143_csr6_bits {
+ csr6_sc = (1<<31),
+ csr6_ra = (1<<30),
+ csr6_ign_dest_msb = (1<<26),
+ csr6_mbo = (1<<25),
+ csr6_scr = (1<<24),
+ csr6_pcs = (1<<23),
+ csr6_ttm = (1<<22),
+ csr6_sf = (1<<21),
+ csr6_hbd = (1<<19),
+ csr6_ps = (1<<18),
+ csr6_ca = (1<<17),
+ csr6_st = (1<<13),
+ csr6_fc = (1<<12),
+ csr6_om_int_loop = (1<<10),
+ csr6_om_ext_loop = (1<<11),
+ csr6_fd = (1<<9),
+ csr6_pm = (1<<7),
+ csr6_pr = (1<<6),
+ csr6_sb = (1<<5),
+ csr6_if = (1<<4),
+ csr6_pb = (1<<3),
+ csr6_ho = (1<<2),
+ csr6_sr = (1<<1),
+ csr6_hp = (1<<0),
+
+ csr6_mask_capture = (csr6_sc | csr6_ca),
+ csr6_mask_defstate = (csr6_mask_capture | csr6_mbo),
+ csr6_mask_fullcap = (csr6_mask_defstate | csr6_hbd |
+ csr6_ps | (3<<14) | csr6_fd),
+};
+
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
@@ -248,6 +296,7 @@ struct ring_info {
dma_addr_t mapping;
};
+
struct tulip_private {
const char *product_name;
struct net_device *next_module;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 196dcf7f6..ca9988328 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -19,7 +19,7 @@
*/
-static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n";
+static const char version[] = "Linux Tulip driver version 0.9.4.3 (Apr 14, 2000)\n";
#include <linux/module.h>
#include "tulip.h"
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index a9988e77b..ae451a43e 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -32,10 +32,15 @@
- Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
LK1.1.3:
- - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code)
- update "Theory of Operation" with softnet/locking changes
+ - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
+ code) update "Theory of Operation" with
+ softnet/locking changes
- Dave Miller: PCI DMA and endian fixups
- Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
+
+ LK1.1.4:
+ - Urban Widmark: fix gcc 2.95.2 problem and
+ remove writel's to fixed address 0x7c
*/
/* A few user-configurable values. These may be modified when a driver
@@ -105,7 +110,7 @@ static const int multicast_filter_limit = 32;
#include <asm/io.h>
static const char *versionA __devinitdata =
-"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n";
+"via-rhine.c:v1.03a-LK1.1.4 3/28/2000 Written by Donald Becker\n";
static const char *versionB __devinitdata =
" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
@@ -774,6 +779,7 @@ static void via_rhine_init_ring(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
int i;
+ dma_addr_t next = np->rx_ring_dma;
np->cur_rx = np->cur_tx = 0;
np->dirty_rx = np->dirty_tx = 0;
@@ -784,8 +790,8 @@ static void via_rhine_init_ring(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].rx_status = 0;
np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
- np->rx_ring[i].next_desc =
- cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1));
+ next += sizeof(struct rx_desc);
+ np->rx_ring[i].next_desc = cpu_to_le32(next);
np->rx_skbuff[i] = 0;
}
/* Mark the last entry as wrapping the ring. */
@@ -806,13 +812,15 @@ static void via_rhine_init_ring(struct net_device *dev)
np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
}
+ np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+ next = np->tx_ring_dma;
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0;
np->tx_ring[i].tx_status = 0;
np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
- np->tx_ring[i].next_desc =
- cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1));
+ next += sizeof(struct tx_desc);
+ np->tx_ring[i].next_desc = cpu_to_le32(next);
np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
}
np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
@@ -1097,7 +1105,6 @@ static void via_rhine_error(struct net_device *dev, int intr_status)
if (intr_status & IntrStatsMax) {
np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
- writel(0, RxMissed);
}
if (intr_status & IntrTxAbort) {
/* Stats counted in Tx-done handler, just restart Tx. */
@@ -1129,7 +1136,6 @@ static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
non-critical. */
np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
- writel(0, RxMissed);
return &np->stats;
}
@@ -1313,7 +1319,6 @@ module_exit(via_rhine_cleanup);
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
index 4ffe0730f..d53e7f964 100644
--- a/drivers/net/wan/Config.in
+++ b/drivers/net/wan/Config.in
@@ -21,6 +21,12 @@ if [ "$CONFIG_WAN" = "y" ]; then
#
tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX
+
+ #
+ # Lan Media's board. Currently 1000, 1200, 5200, 5245
+ #
+ tristate 'LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards' CONFIG_LANMEDIA
+
if [ "$CONFIG_COMX" != "n" ]; then
dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX
dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index dbb12c2bf..3904c76a6 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -12,7 +12,7 @@
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) lmc
L_TARGET := wan.a
L_OBJS :=
@@ -119,6 +119,19 @@ else
endif
endif
+ifeq ($(CONFIG_LANMEDIA),y)
+ SUB_DIRS += lmc
+ MOD_IN_SUB_DIRS += lmc
+ L_OBJS += lmc/lmc.o
+ CONFIG_SYNCPPP_BUILTIN = y
+else
+ ifeq ($(CONFIG_LANMEDIA),m)
+ CONFIG_SYNCPPP_MODULE = y
+ MOD_IN_SUB_DIRS += lmc
+ endif
+endif
+
+
# If anything built-in uses syncppp, then build it into the kernel also.
# If not, but a module uses it, build as a module.
diff --git a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c
index 1c59075be..65a810889 100644
--- a/drivers/net/wan/comx.c
+++ b/drivers/net/wan/comx.c
@@ -91,8 +91,6 @@ static void comx_delete_dentry(struct dentry *dentry);
static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
int size, struct proc_dir_entry *dir);
-static void comx_fill_inode(struct inode *inode, int fill);
-
static struct dentry_operations comx_dentry_operations = {
NULL, /* revalidate */
NULL, /* d_hash */
@@ -101,13 +99,7 @@ static struct dentry_operations comx_dentry_operations = {
};
-struct proc_dir_entry comx_root_dir = {
- 0, 4, "comx",
- S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &comx_root_inode_ops,
- NULL, comx_fill_inode,
- NULL, &proc_root, NULL
-};
+static struct proc_dir_entry * comx_root_dir;
struct comx_debugflags_struct comx_debugflags[] = {
{ "comx_rx", DEBUG_COMX_RX },
@@ -121,14 +113,6 @@ struct comx_debugflags_struct comx_debugflags[] = {
{ NULL, 0 }
};
-static void comx_fill_inode(struct inode *inode, int fill)
-{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-}
-
int comx_debug(struct net_device *dev, char *fmt, ...)
{
@@ -853,14 +837,13 @@ static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct net_device *dev;
struct comx_channel *ch;
- if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+ if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR;
if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR,
- &comx_root_dir)) == NULL) {
+ comx_root_dir)) == NULL) {
return -EIO;
}
- new_dir->proc_iops = &proc_dir_inode_operations; // ez egy normalis /proc konyvtar
new_dir->nlink = 2;
new_dir->data = NULL; // ide jon majd a struct dev
@@ -930,7 +913,7 @@ static int comx_rmdir(struct inode *dir, struct dentry *dentry)
int ret;
/* Egyelore miert ne ? */
- if (dir->i_ino != comx_root_dir.low_ino) return -ENOTDIR;
+ if (dir->i_ino != comx_root_dir->low_ino) return -ENOTDIR;
if (dev->flags & IFF_UP) {
printk(KERN_ERR "%s: down interface before removing it\n", dev->name);
@@ -968,8 +951,7 @@ static int comx_rmdir(struct inode *dir, struct dentry *dentry)
remove_proc_entry(FILENAME_STATUS, entry);
remove_proc_entry(FILENAME_HARDWARE, entry);
remove_proc_entry(FILENAME_PROTOCOL, entry);
- remove_proc_entry(dentry->d_name.name, &comx_root_dir);
-// proc_unregister(&comx_root_dir, dentry->d_inode->i_ino);
+ remove_proc_entry(dentry->d_name.name, comx_root_dir);
MOD_DEC_USE_COUNT;
return 0;
@@ -1133,23 +1115,15 @@ int __init comx_init(void)
{
struct proc_dir_entry *new_file;
- memcpy(&comx_root_inode_ops, &proc_dir_inode_operations,
- sizeof(struct inode_operations));
comx_root_inode_ops.lookup = &comx_lookup;
comx_root_inode_ops.mkdir = &comx_mkdir;
comx_root_inode_ops.rmdir = &comx_rmdir;
- memcpy(&comx_normal_inode_ops, &proc_net_inode_operations,
- sizeof(struct inode_operations));
- comx_normal_inode_ops.default_file_ops = &comx_normal_file_ops;
comx_normal_inode_ops.lookup = &comx_lookup;
memcpy(&comx_debug_inode_ops, &comx_normal_inode_ops,
sizeof(struct inode_operations));
- comx_debug_inode_ops.default_file_ops = &comx_debug_file_ops;
- memcpy(&comx_normal_file_ops, proc_net_inode_operations.default_file_ops,
- sizeof(struct file_operations));
comx_normal_file_ops.open = &comx_file_open;
comx_normal_file_ops.release = &comx_file_release;
@@ -1158,22 +1132,25 @@ int __init comx_init(void)
comx_debug_file_ops.llseek = &comx_debug_lseek;
comx_debug_file_ops.read = &comx_debug_read;
- if (proc_register(&proc_root, &comx_root_dir) < 0) return -ENOMEM;
-
+ comx_root_dir = create_proc_entry("comx",
+ S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
+ if (!comx_root_dir)
+ return -ENOMEM;
+ comx_root_dir->proc_iops = &comx_root_inode_ops;
if ((new_file = create_proc_entry(FILENAME_HARDWARELIST,
- S_IFREG | 0444, &comx_root_dir)) == NULL) {
+ S_IFREG | 0444, comx_root_dir)) == NULL) {
return -ENOMEM;
}
- new_file->ops = &comx_normal_inode_ops;
+ new_file->proc_iops = &comx_normal_inode_ops;
new_file->data = new_file;
new_file->read_proc = &comx_root_read_proc;
new_file->write_proc = NULL;
new_file->nlink = 1;
if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST,
- S_IFREG | 0444, &comx_root_dir)) == NULL) {
+ S_IFREG | 0444, comx_root_dir)) == NULL) {
return -ENOMEM;
}
@@ -1217,9 +1194,9 @@ int __init comx_init(void)
#ifdef MODULE
void cleanup_module(void)
{
- remove_proc_entry(FILENAME_HARDWARELIST, &comx_root_dir);
- remove_proc_entry(FILENAME_PROTOCOLLIST, &comx_root_dir);
- proc_unregister(&proc_root, comx_root_dir.low_ino);
+ remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
+ remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
+ remove_proc_entry(comx_root_dir->name, &proc_root);
}
#endif
diff --git a/drivers/net/wan/comx.h b/drivers/net/wan/comx.h
index e02849b90..b343eb4ca 100644
--- a/drivers/net/wan/comx.h
+++ b/drivers/net/wan/comx.h
@@ -220,7 +220,7 @@ typedef u16 word;
#define SEEK_END 2
#endif
-extern struct proc_dir_entry comx_root_dir;
+extern struct proc_dir_entry * comx_root_dir;
extern int comx_register_hardware(struct comx_hardware *comx_hw);
extern int comx_unregister_hardware(char *name);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 544fcb8dd..8e0c5d37d 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -79,6 +79,7 @@
/* ---------- Headers, macros, data structures ---------- */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
@@ -374,7 +375,7 @@ static int __init cosa_init(void)
int i;
printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
-#ifdef __SMP__
+#ifdef CONFIG_SMP
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
if (cosa_major > 0) {
diff --git a/drivers/net/wan/lmc/.cvsignore b/drivers/net/wan/lmc/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/net/wan/lmc/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile
new file mode 100644
index 000000000..1fe61a348
--- /dev/null
+++ b/drivers/net/wan/lmc/Makefile
@@ -0,0 +1,39 @@
+# File: drivers/lmc/Makefile
+#
+# Makefile for the Lan Media 21140 based WAN cards
+# Specifically the 1000,1200,5200,5245
+#
+
+ifeq ($(CONFIG_LANMEDIA),y)
+ O_TARGET := lmc.o
+ O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
+else
+ ifeq ($(CONFIG_LANMEDIA),m)
+ MOD_LIST_NAME := NET_MODULES
+ M_OBJS := lmc.o
+ O_TARGET := lmc.o
+ O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
+ endif
+endif
+
+#
+# Base debugging and event log (doubles lmc.o size)
+#
+# DBGDEF = \
+# -DDEBUG
+
+#
+# Like above except every packet gets echoed to KERN_DEBUG
+# in hex
+#
+# DBDEF = \
+# -DDEBUG \
+# -DLMC_PACKET_LOG
+
+EXTRA_CFLAGS += -I. $(DBGDEF)
+
+include $(TOPDIR)/Rules.make
+
+clean:
+ rm -f core *.o *.a *.s
+
diff --git a/drivers/net/wan/lmc/lmc.h b/drivers/net/wan/lmc/lmc.h
new file mode 100644
index 000000000..91b9e8f00
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc.h
@@ -0,0 +1,32 @@
+#ifndef _LMC_H_
+#define _LMC_H_
+
+#include "lmc_var.h"
+
+/*
+ * prototypes for everyone
+ */
+int lmc_probe(struct net_device * dev);
+unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned
+ devaddr, unsigned regno);
+void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr,
+ unsigned regno, unsigned data);
+void lmc_led_on(lmc_softc_t * const, u_int32_t);
+void lmc_led_off(lmc_softc_t * const, u_int32_t);
+unsigned lmc_mii_readreg(lmc_softc_t * const, unsigned, unsigned);
+void lmc_mii_writereg(lmc_softc_t * const, unsigned, unsigned, unsigned);
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits);
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits);
+
+int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+extern lmc_media_t lmc_ds3_media;
+extern lmc_media_t lmc_ssi_media;
+extern lmc_media_t lmc_t1_media;
+extern lmc_media_t lmc_hssi_media;
+
+#ifdef _DBG_EVENTLOG
+static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 );
+#endif
+
+#endif \ No newline at end of file
diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c
new file mode 100644
index 000000000..3db65b0c1
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_debug.c
@@ -0,0 +1,87 @@
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include "lmc_ver.h"
+#include "lmc_debug.h"
+
+/*
+ * Prints out len, max to 80 octets using printk, 20 per line
+ */
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
+{
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+ int iNewLine = 1;
+ char str[80], *pstr;
+
+ sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+ pstr = str+strlen(str);
+
+ if(iLen > 240){
+ printk(KERN_DEBUG "lmc: Printing 240 chars... out of: %d\n", iLen);
+ iLen = 240;
+ }
+ else{
+ printk(KERN_DEBUG "lmc: Printing %d chars\n", iLen);
+ }
+
+ while(iLen > 0)
+ {
+ sprintf(pstr, "%02x ", *ucData);
+ pstr+=3;
+ ucData++;
+ if( !(iNewLine % 20))
+ {
+ sprintf(pstr, "\n");
+ printk(str);
+ sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+ pstr=str+strlen(str);
+ }
+ iNewLine++;
+ iLen--;
+ }
+ sprintf(pstr, "\n");
+ printk(str);
+#endif
+#endif
+}
+
+#ifdef DEBUG
+u_int32_t lmcEventLogIndex = 0;
+u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#endif
+
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3)
+{
+#ifdef DEBUG
+ lmcEventLogBuf[lmcEventLogIndex++] = EventNum;
+ lmcEventLogBuf[lmcEventLogIndex++] = arg2;
+ lmcEventLogBuf[lmcEventLogIndex++] = arg3;
+ lmcEventLogBuf[lmcEventLogIndex++] = jiffies;
+
+ lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1;
+#endif
+}
+
+inline void lmc_trace(struct net_device *dev, char *msg){
+#ifdef LMC_TRACE
+ unsigned long j = jiffies + 3; /* Wait for 50 ms */
+
+ if(in_interrupt()){
+ printk("%s: * %s\n", dev->name, msg);
+// while(jiffies < j+10)
+// ;
+ }
+ else {
+ printk("%s: %s\n", dev->name, msg);
+ while(jiffies < j)
+ schedule();
+ }
+#endif
+}
+
+
+/* --------------------------- end if_lmc_linux.c ------------------------ */
diff --git a/drivers/net/wan/lmc/lmc_debug.h b/drivers/net/wan/lmc/lmc_debug.h
new file mode 100644
index 000000000..f42d59bff
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_debug.h
@@ -0,0 +1,52 @@
+#ifndef _LMC_DEBUG_H_
+#define _LMC_DEBUG_H_
+
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+#define LMC_CONSOLE_LOG(x,y,z) lmcConsoleLog((x), (y), (z))
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+
+
+
+/* Debug --- Event log definitions --- */
+/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */
+#define LMC_EVENTLOGSIZE 1024 /* number of events in eventlog */
+#define LMC_EVENTLOGARGS 4 /* number of args for each event */
+
+/* event indicators */
+#define LMC_EVENT_XMT 1
+#define LMC_EVENT_XMTEND 2
+#define LMC_EVENT_XMTINT 3
+#define LMC_EVENT_RCVINT 4
+#define LMC_EVENT_RCVEND 5
+#define LMC_EVENT_INT 6
+#define LMC_EVENT_XMTINTTMO 7
+#define LMC_EVENT_XMTPRCTMO 8
+#define LMC_EVENT_INTEND 9
+#define LMC_EVENT_RESET1 10
+#define LMC_EVENT_RESET2 11
+#define LMC_EVENT_FORCEDRESET 12
+#define LMC_EVENT_WATCHDOG 13
+#define LMC_EVENT_BADPKTSURGE 14
+#define LMC_EVENT_TBUSY0 15
+#define LMC_EVENT_TBUSY1 16
+
+
+#ifdef DEBUG
+extern u_int32_t lmcEventLogIndex;
+extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z))
+#else
+#define LMC_EVENT_LOG(x,y,z)
+#endif /* end ifdef _DBG_EVENTLOG */
+
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen);
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3);
+inline void lmc_trace(struct net_device *dev, char *msg);
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_ioctl.h b/drivers/net/wan/lmc/lmc_ioctl.h
new file mode 100644
index 000000000..31eaaa673
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_ioctl.h
@@ -0,0 +1,257 @@
+#ifndef _LMC_IOCTL_H_
+#define _LMC_IOCTL_H_
+/* $Id: lmc_ioctl.h,v 1.15 2000/04/06 12:16:43 asj Exp $ */
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ */
+
+#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */
+#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */
+#define LMCIOCGETLMCSTATS SIOCDEVPRIVATE+5
+#define LMCIOCCLEARLMCSTATS SIOCDEVPRIVATE+6
+#define LMCIOCDUMPEVENTLOG SIOCDEVPRIVATE+7
+#define LMCIOCGETXINFO SIOCDEVPRIVATE+8
+#define LMCIOCSETCIRCUIT SIOCDEVPRIVATE+9
+#define LMCIOCUNUSEDATM SIOCDEVPRIVATE+10
+#define LMCIOCRESET SIOCDEVPRIVATE+11
+#define LMCIOCT1CONTROL SIOCDEVPRIVATE+12
+#define LMCIOCIFTYPE SIOCDEVPRIVATE+13
+#define LMCIOCXILINX SIOCDEVPRIVATE+14
+
+#define LMC_CARDTYPE_UNKNOWN -1
+#define LMC_CARDTYPE_HSSI 1 /* probed card is a HSSI card */
+#define LMC_CARDTYPE_DS3 2 /* probed card is a DS3 card */
+#define LMC_CARDTYPE_SSI 3 /* probed card is a SSI card */
+#define LMC_CARDTYPE_T1 4 /* probed card is a T1 card */
+
+#define LMC_CTL_CARDTYPE_LMC5200 0 /* HSSI */
+#define LMC_CTL_CARDTYPE_LMC5245 1 /* DS3 */
+#define LMC_CTL_CARDTYPE_LMC1000 2 /* SSI, V.35 */
+#define LMC_CTL_CARDTYPE_LMC1200 3 /* DS1 */
+
+#define LMC_CTL_OFF 0 /* generic OFF value */
+#define LMC_CTL_ON 1 /* generic ON value */
+
+#define LMC_CTL_CLOCK_SOURCE_EXT 0 /* clock off line */
+#define LMC_CTL_CLOCK_SOURCE_INT 1 /* internal clock */
+
+#define LMC_CTL_CRC_LENGTH_16 16
+#define LMC_CTL_CRC_LENGTH_32 32
+#define LMC_CTL_CRC_BYTESIZE_2 2
+#define LMC_CTL_CRC_BYTESIZE_4 4
+
+
+#define LMC_CTL_CABLE_LENGTH_LT_100FT 0 /* DS3 cable < 100 feet */
+#define LMC_CTL_CABLE_LENGTH_GT_100FT 1 /* DS3 cable >= 100 feet */
+
+#define LMC_CTL_CIRCUIT_TYPE_E1 0
+#define LMC_CTL_CIRCUIT_TYPE_T1 1
+
+/*
+ * IFTYPE defines
+ */
+#define LMC_PPP 1 /* use sppp interface */
+#define LMC_NET 2 /* use direct net interface */
+#define LMC_RAW 3 /* use direct net interface */
+
+/*
+ * These are not in the least IOCTL related, but I want them common.
+ */
+/*
+ * assignments for the GPIO register on the DEC chip (common)
+ */
+#define LMC_GEP_INIT 0x01 /* 0: */
+#define LMC_GEP_RESET 0x02 /* 1: */
+#define LMC_GEP_MODE 0x10 /* 4: */
+#define LMC_GEP_DP 0x20 /* 5: */
+#define LMC_GEP_DATA 0x40 /* 6: serial out */
+#define LMC_GEP_CLK 0x80 /* 7: serial clock */
+
+/*
+ * HSSI GPIO assignments
+ */
+#define LMC_GEP_HSSI_ST 0x04 /* 2: receive timing sense (deprecated) */
+#define LMC_GEP_HSSI_CLOCK 0x08 /* 3: clock source */
+
+/*
+ * T1 GPIO assignments
+ */
+#define LMC_GEP_SSI_GENERATOR 0x04 /* 2: enable prog freq gen serial i/f */
+#define LMC_GEP_SSI_TXCLOCK 0x08 /* 3: provide clock on TXCLOCK output */
+
+/*
+ * Common MII16 bits
+ */
+#define LMC_MII16_LED0 0x0080
+#define LMC_MII16_LED1 0x0100
+#define LMC_MII16_LED2 0x0200
+#define LMC_MII16_LED3 0x0400 /* Error, and the red one */
+#define LMC_MII16_LED_ALL 0x0780 /* LED bit mask */
+#define LMC_MII16_FIFO_RESET 0x0800
+
+/*
+ * definitions for HSSI
+ */
+#define LMC_MII16_HSSI_TA 0x0001
+#define LMC_MII16_HSSI_CA 0x0002
+#define LMC_MII16_HSSI_LA 0x0004
+#define LMC_MII16_HSSI_LB 0x0008
+#define LMC_MII16_HSSI_LC 0x0010
+#define LMC_MII16_HSSI_TM 0x0020
+#define LMC_MII16_HSSI_CRC 0x0040
+
+/*
+ * assignments for the MII register 16 (DS3)
+ */
+#define LMC_MII16_DS3_ZERO 0x0001
+#define LMC_MII16_DS3_TRLBK 0x0002
+#define LMC_MII16_DS3_LNLBK 0x0004
+#define LMC_MII16_DS3_RAIS 0x0008
+#define LMC_MII16_DS3_TAIS 0x0010
+#define LMC_MII16_DS3_BIST 0x0020
+#define LMC_MII16_DS3_DLOS 0x0040
+#define LMC_MII16_DS3_CRC 0x1000
+#define LMC_MII16_DS3_SCRAM 0x2000
+#define LMC_MII16_DS3_SCRAM_LARS 0x4000
+
+/* Note: 2 pairs of LEDs where swapped by mistake
+ * in Xilinx code for DS3 & DS1 adapters */
+#define LMC_DS3_LED0 0x0100 /* bit 08 yellow */
+#define LMC_DS3_LED1 0x0080 /* bit 07 blue */
+#define LMC_DS3_LED2 0x0400 /* bit 10 green */
+#define LMC_DS3_LED3 0x0200 /* bit 09 red */
+
+/*
+ * framer register 0 and 7 (7 is latched and reset on read)
+ */
+#define LMC_FRAMER_REG0_DLOS 0x80 /* digital loss of service */
+#define LMC_FRAMER_REG0_OOFS 0x40 /* out of frame sync */
+#define LMC_FRAMER_REG0_AIS 0x20 /* alarm indication signal */
+#define LMC_FRAMER_REG0_CIS 0x10 /* channel idle */
+#define LMC_FRAMER_REG0_LOC 0x08 /* loss of clock */
+
+/*
+ * Framer register 9 contains the blue alarm signal
+ */
+#define LMC_FRAMER_REG9_RBLUE 0x02 /* Blue alarm failure */
+
+/*
+ * Framer register 0x10 contains xbit error
+ */
+#define LMC_FRAMER_REG10_XBIT 0x01 /* X bit error alarm failure */
+
+/*
+ * And SSI, LMC1000
+ */
+#define LMC_MII16_SSI_DTR 0x0001 /* DTR output RW */
+#define LMC_MII16_SSI_DSR 0x0002 /* DSR input RO */
+#define LMC_MII16_SSI_RTS 0x0004 /* RTS output RW */
+#define LMC_MII16_SSI_CTS 0x0008 /* CTS input RO */
+#define LMC_MII16_SSI_DCD 0x0010 /* DCD input RO */
+#define LMC_MII16_SSI_RI 0x0020 /* RI input RO */
+#define LMC_MII16_SSI_CRC 0x1000 /* CRC select - RW */
+
+/*
+ * bits 0x0080 through 0x0800 are generic, and described
+ * above with LMC_MII16_LED[0123] _LED_ALL, and _FIFO_RESET
+ */
+#define LMC_MII16_SSI_LL 0x1000 /* LL output RW */
+#define LMC_MII16_SSI_RL 0x2000 /* RL output RW */
+#define LMC_MII16_SSI_TM 0x4000 /* TM input RO */
+#define LMC_MII16_SSI_LOOP 0x8000 /* loopback enable RW */
+
+/*
+ * Some of the MII16 bits are mirrored in the MII17 register as well,
+ * but let's keep thing seperate for now, and get only the cable from
+ * the MII17.
+ */
+#define LMC_MII17_SSI_CABLE_MASK 0x0038 /* mask to extract the cable type */
+#define LMC_MII17_SSI_CABLE_SHIFT 3 /* shift to extract the cable type */
+
+/*
+ * And T1, LMC1200
+ */
+#define LMC_MII16_T1_UNUSED1 0x0003
+#define LMC_MII16_T1_XOE 0x0004
+#define LMC_MII16_T1_RST 0x0008 /* T1 chip reset - RW */
+#define LMC_MII16_T1_Z 0x0010 /* output impedance T1=1, E1=0 output - RW */
+#define LMC_MII16_T1_INTR 0x0020 /* interrupt from 8370 - RO */
+#define LMC_MII16_T1_ONESEC 0x0040 /* one second square wave - ro */
+
+#define LMC_MII16_T1_LED0 0x0100
+#define LMC_MII16_T1_LED1 0x0080
+#define LMC_MII16_T1_LED2 0x0400
+#define LMC_MII16_T1_LED3 0x0200
+#define LMC_MII16_T1_FIFO_RESET 0x0800
+
+#define LMC_MII16_T1_CRC 0x1000 /* CRC select - RW */
+#define LMC_MII16_T1_UNUSED2 0xe000
+
+
+/* 8370 framer registers */
+
+#define T1FRAMER_ALARM1_STATUS 0x47
+#define T1FRAMER_ALARM2_STATUS 0x48
+#define T1FRAMER_FERR_LSB 0x50
+#define T1FRAMER_FERR_MSB 0x51 /* framing bit error counter */
+#define T1FRAMER_LCV_LSB 0x54
+#define T1FRAMER_LCV_MSB 0x55 /* line code violation counter */
+#define T1FRAMER_AERR 0x5A
+
+/* mask for the above AERR register */
+#define T1FRAMER_LOF_MASK (0x0f0) /* receive loss of frame */
+#define T1FRAMER_COFA_MASK (0x0c0) /* change of frame alignment */
+#define T1FRAMER_SEF_MASK (0x03) /* severely errored frame */
+
+/* 8370 framer register ALM1 (0x47) values
+ * used to determine link status
+ */
+
+#define T1F_SIGFRZ 0x01 /* signaling freeze */
+#define T1F_RLOF 0x02 /* receive loss of frame alignment */
+#define T1F_RLOS 0x04 /* receive loss of signal */
+#define T1F_RALOS 0x08 /* receive analog loss of signal or RCKI loss of clock */
+#define T1F_RAIS 0x10 /* receive alarm indication signal */
+#define T1F_UNUSED 0x20
+#define T1F_RYEL 0x40 /* receive yellow alarm */
+#define T1F_RMYEL 0x80 /* receive multiframe yellow alarm */
+
+#define LMC_T1F_WRITE 0
+#define LMC_T1F_READ 1
+
+typedef struct lmc_st1f_control {
+ int command;
+ int address;
+ int value;
+ char *data;
+} lmc_t1f_control;
+
+enum lmc_xilinx_c {
+ lmc_xilinx_reset = 1,
+ lmc_xilinx_load_prom = 2,
+ lmc_xilinx_load = 3
+};
+
+struct lmc_xilinx_control {
+ enum lmc_xilinx_c command;
+ int len;
+ char *data;
+};
+
+/* ------------------ end T1 defs ------------------- */
+
+#define LMC_MII_LedMask 0x0780
+#define LMC_MII_LedBitPos 7
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
new file mode 100644
index 000000000..931fca21c
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -0,0 +1,2486 @@
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * With Help By:
+ * David Boggs
+ * Ron Crane
+ * Allan Cox
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ *
+ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+ *
+ * To control link specific options lmcctl is required.
+ * It can be obtained from ftp.lanmedia.com.
+ *
+ * Linux driver notes:
+ * Linux uses the device struct lmc_private to pass private information
+ * arround.
+ *
+ * The initialization portion of this driver (the lmc_reset() and the
+ * lmc_dec_reset() functions, as well as the led controls and the
+ * lmc_initcsrs() functions.
+ *
+ * The watchdog function runs every second and checks to see if
+ * we still have link, and that the timing source is what we expected
+ * it to be. If link is lost, the interface is marked down, and
+ * we no longer can transmit.
+ *
+ */
+
+/* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/segment.h>
+#include <linux/init.h>
+
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>
+#endif
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+
+#if LINUX_VERSION_CODE >= 0x20200
+#include <asm/uaccess.h>
+//#include <asm/spinlock.h>
+#else /* 2.0 kernel */
+#define ARPHRD_HDLC 513
+#endif
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define DRIVER_MAJOR_VERSION 1
+#define DRIVER_MINOR_VERSION 34
+#define DRIVER_SUB_VERSION 0
+
+#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+#include "lmc_proto.h"
+
+
+static int Lmc_Count = 0;
+static struct net_device *Lmc_root_dev = NULL;
+static u8 cards_found = 0;
+
+static int lmc_first_load = 0;
+
+int LMC_PKT_BUF_SZ = 1542;
+
+#ifdef MODULE
+static struct pci_device_id lmc_pci_tbl[] __devinitdata = {
+ { 0x1011, 0x009, 0x1379, PCI_ANY_ID, 0, 0, 0},
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+#endif
+
+
+int lmc_probe_fake(struct net_device *dev);
+static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq,
+ int chip_id, int subdevice, int board_idx);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_rx (struct net_device *dev);
+static int lmc_open(struct net_device *dev);
+static int lmc_close(struct net_device *dev);
+static struct enet_statistics *lmc_get_stats(struct net_device *dev);
+static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int lmc_set_config(struct net_device *dev, struct ifmap *map);
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
+static void lmc_softreset(lmc_softc_t * const);
+static void lmc_running_reset(struct net_device *dev);
+static int lmc_ifdown(struct net_device * const);
+static void lmc_watchdog(unsigned long data);
+static int lmc_init(struct net_device * const);
+static void lmc_reset(lmc_softc_t * const sc);
+static void lmc_dec_reset(lmc_softc_t * const sc);
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev);
+int lmc_setup(void);
+#endif
+
+
+/*
+ * linux reserves 16 device specific IOCTLs. We call them
+ * LMCIOC* to control various bits of our world.
+ */
+int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
+{
+ lmc_softc_t *sc;
+ lmc_ctl_t ctl;
+ int ret;
+ u_int16_t regVal;
+ unsigned long flags;
+
+ struct sppp *sp;
+
+ ret = -EOPNOTSUPP;
+
+ sc = dev->priv;
+
+ lmc_trace(dev, "lmc_ioctl in");
+
+ /*
+ * Most functions mess with the structure
+ * Disable interupts while we do the polling
+ */
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ switch (cmd) {
+ /*
+ * Return current driver state. Since we keep this up
+ * To date internally, just copy this out to the user.
+ */
+ case LMCIOCGINFO: /*fold01*/
+ LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t));
+ ret = 0;
+ break;
+
+ case LMCIOCSINFO: /*fold01*/
+ sp = &((struct ppp_device *) dev)->sppp;
+ if (!suser ()) {
+ ret = -EPERM;
+ break;
+ }
+
+ if(dev->flags & IFF_UP){
+ ret = -EBUSY;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+
+ sc->lmc_media->set_status (sc, &ctl);
+
+ if(ctl.crc_length != sc->ictl.crc_length) {
+ sc->lmc_media->set_crc_length(sc, ctl.crc_length);
+ if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16)
+ sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+ else
+ sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE;
+ }
+
+ if (ctl.keepalive_onoff == LMC_CTL_OFF)
+ sp->pp_flags &= ~PP_KEEPALIVE; /* Turn off */
+ else
+ sp->pp_flags |= PP_KEEPALIVE; /* Turn on */
+
+ ret = 0;
+ break;
+
+ case LMCIOCIFTYPE: /*fold01*/
+ {
+ u_int16_t old_type = sc->if_type;
+ u_int16_t new_type;
+
+ if (!suser ()) {
+ ret = -EPERM;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t));
+
+
+ if (new_type == old_type)
+ {
+ ret = 0 ;
+ break; /* no change */
+ }
+
+ lmc_proto_close(sc);
+ lmc_proto_detach(sc);
+
+ sc->if_type = new_type;
+// lmc_proto_init(sc);
+ lmc_proto_attach(sc);
+ lmc_proto_open(sc);
+
+ ret = 0 ;
+ break ;
+ }
+
+ case LMCIOCGETXINFO: /*fold01*/
+ sc->lmc_xinfo.Magic0 = 0xBEEFCAFE;
+
+ sc->lmc_xinfo.PciCardType = sc->lmc_cardtype;
+ sc->lmc_xinfo.PciSlotNumber = 0;
+ sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION;
+ sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION;
+ sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
+ sc->lmc_xinfo.XilinxRevisionNumber =
+ lmc_mii_readreg (sc, 0, 3) & 0xf;
+ sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ;
+ sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc);
+ sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16);
+
+ sc->lmc_xinfo.Magic1 = 0xDEADBEEF;
+
+ LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo,
+ sizeof (struct lmc_xinfo));
+ ret = 0;
+
+ break;
+
+ case LMCIOCGETLMCSTATS: /*fold01*/
+ if (sc->lmc_cardtype == LMC_CARDTYPE_T1){
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB);
+ sc->stats.framingBitErrorCount +=
+ lmc_mii_readreg (sc, 0, 18) & 0xff;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB);
+ sc->stats.framingBitErrorCount +=
+ (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB);
+ sc->stats.lineCodeViolationCount +=
+ lmc_mii_readreg (sc, 0, 18) & 0xff;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB);
+ sc->stats.lineCodeViolationCount +=
+ (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR);
+ regVal = lmc_mii_readreg (sc, 0, 18) & 0xff;
+
+ sc->stats.lossOfFrameCount +=
+ (regVal & T1FRAMER_LOF_MASK) >> 4;
+ sc->stats.changeOfFrameAlignmentCount +=
+ (regVal & T1FRAMER_COFA_MASK) >> 2;
+ sc->stats.severelyErroredFrameCount +=
+ regVal & T1FRAMER_SEF_MASK;
+ }
+
+ LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats,
+ sizeof (struct lmc_statistics));
+
+ ret = 0;
+ break;
+
+ case LMCIOCCLEARLMCSTATS: /*fold01*/
+ if (!suser ()){
+ ret = -EPERM;
+ break;
+ }
+
+ memset (&sc->stats, 0, sizeof (struct lmc_statistics));
+ sc->stats.check = STATCHECK;
+ sc->stats.version_size = (DRIVER_VERSION << 16) +
+ sizeof (struct lmc_statistics);
+ sc->stats.lmc_cardtype = sc->lmc_cardtype;
+ ret = 0;
+ break;
+
+ case LMCIOCSETCIRCUIT: /*fold01*/
+ if (!suser ()){
+ ret = -EPERM;
+ break;
+ }
+
+ if(dev->flags & IFF_UP){
+ ret = -EBUSY;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+ sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
+ sc->ictl.circuit_type = ctl.circuit_type;
+ ret = 0;
+
+ break;
+
+ case LMCIOCRESET: /*fold01*/
+ if (!suser ()){
+ ret = -EPERM;
+ break;
+ }
+
+ /* Reset driver and bring back to current state */
+ printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+ lmc_running_reset (dev);
+ printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+
+ LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+ ret = 0;
+ break;
+
+#ifdef DEBUG
+ case LMCIOCDUMPEVENTLOG:
+ LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32));
+ LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf));
+
+ ret = 0;
+ break;
+#endif /* end ifdef _DBG_EVENTLOG */
+ case LMCIOCT1CONTROL: /*fold01*/
+ if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case LMCIOCXILINX: /*fold01*/
+ {
+ struct lmc_xilinx_control xc; /*fold02*/
+
+ if (!suser ()){
+ ret = -EPERM;
+ break;
+ }
+
+ /*
+ * Stop the xwitter whlie we restart the hardware
+ */
+ LMC_XMITTER_BUSY(dev);
+
+ LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control));
+ switch(xc.command){
+ case lmc_xilinx_reset: /*fold02*/
+ {
+ u16 mii;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /* Reset the frammer hardware */
+ sc->lmc_media->set_link_status (sc, 1);
+ sc->lmc_media->set_status (sc, NULL);
+// lmc_softreset(sc);
+
+ {
+ int i;
+ for(i = 0; i < 5; i++){
+ lmc_led_on(sc, LMC_DS3_LED0);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED0);
+ lmc_led_on(sc, LMC_DS3_LED1);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED1);
+ lmc_led_on(sc, LMC_DS3_LED3);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED3);
+ lmc_led_on(sc, LMC_DS3_LED2);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED2);
+ }
+ }
+
+
+
+ ret = 0x0;
+
+ }
+
+ break;
+ case lmc_xilinx_load_prom: /*fold02*/
+ {
+ u16 mii;
+ int timeout = 500000;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP);
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ ret = 0x0;
+
+
+ break;
+
+ }
+
+ case lmc_xilinx_load: /*fold02*/
+ {
+ char *data;
+ int pos;
+ int timeout = 500000;
+
+ if(xc.data == 0x0){
+ ret = -EINVAL;
+ break;
+ }
+
+ data = kmalloc(xc.len, GFP_KERNEL);
+ if(data == 0x0){
+ printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name);
+ ret = -ENOMEM;
+ break;
+ }
+
+ LMC_COPY_FROM_USER(data, xc.data, xc.len);
+
+ printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * Clear the Xilinx and start prgramming from the DEC
+ */
+
+ /*
+ * Set ouput as:
+ * Reset: 0 (active)
+ * DP: 0 (active)
+ * Mode: 1
+ *
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio &= ~LMC_GEP_DP;
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Wait at least 10 us 20 to be safe
+ */
+ udelay(50);
+
+ /*
+ * Clear reset and activate programing lines
+ * Reset: Input
+ * DP: Input
+ * Clock: Output
+ * Data: Output
+ * Mode: Output
+ */
+ lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Set LOAD, DATA, Clock to 1
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ sc->lmc_gpio |= LMC_GEP_DATA;
+ sc->lmc_gpio |= LMC_GEP_CLK;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+ printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout);
+
+ for(pos = 0; pos < xc.len; pos++){
+ switch(data[pos]){
+ case 0:
+ sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */
+ break;
+ case 1:
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */
+ break;
+ default:
+ printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */
+ }
+ sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+ udelay(1);
+
+ sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+ udelay(1);
+ }
+ if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){
+ printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name);
+ }
+ else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){
+ printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name);
+ }
+ else {
+ printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos);
+ }
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ kfree(data);
+
+ ret = 0;
+
+ break;
+ }
+ default: /*fold02*/
+ ret = -EBADE;
+ break;
+ }
+
+ LMC_XMITTER_FREE(dev);
+ sc->lmc_txfull = 0;
+
+ }
+ break;
+ default: /*fold01*/
+ /* If we don't know what to do, give the protocol a shot. */
+ ret = lmc_proto_ioctl (sc, ifr, cmd);
+ break;
+ }
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/
+
+ lmc_trace(dev, "lmc_ioctl out");
+
+ return ret;
+}
+
+
+/* the watchdog process that cruises around */
+static void lmc_watchdog (unsigned long data) /*fold00*/
+{
+ struct net_device *dev = (struct net_device *) data;
+ lmc_softc_t *sc;
+ int link_status;
+ u_int32_t ticks;
+ LMC_SPIN_FLAGS;
+
+ sc = dev->priv;
+
+ lmc_trace(dev, "lmc_watchdog in");
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ if(sc->check != 0xBEAFCAFE){
+ printk("LMC: Corrupt net_device stuct, breaking out\n");
+ return;
+ }
+
+
+ /* Make sure the tx jabber and rx watchdog are off,
+ * and the transmit and recieve processes are running.
+ */
+
+ LMC_CSR_WRITE (sc, csr_15, 0x00000011);
+ sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ if (sc->lmc_ok == 0)
+ goto kick_timer;
+
+ LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+ /* --- begin time out check -----------------------------------
+ * check for a transmit interrupt timeout
+ * Has the packet xmt vs xmt serviced threshold been exceeded */
+ if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+ sc->stats.tx_packets > sc->lasttx_packets &&
+ sc->tx_TimeoutInd == 0)
+ {
+
+ /* wait for the watchdog to come around again */
+ sc->tx_TimeoutInd = 1;
+ }
+ else if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+ sc->stats.tx_packets > sc->lasttx_packets &&
+ sc->tx_TimeoutInd)
+ {
+
+ LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0);
+
+ sc->tx_TimeoutDisplay = 1;
+ sc->stats.tx_TimeoutCnt++;
+
+ /* DEC chip is stuck, hit it with a RESET!!!! */
+ lmc_running_reset (dev);
+
+
+ /* look at receive & transmit process state to make sure they are running */
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+
+ /* look at: DSR - 02 for Reg 16
+ * CTS - 08
+ * DCD - 10
+ * RI - 20
+ * for Reg 17
+ */
+ LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17));
+
+ /* reset the transmit timeout detection flag */
+ sc->tx_TimeoutInd = 0;
+ sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+ sc->lasttx_packets = sc->stats.tx_packets;
+ }
+ else
+ {
+ sc->tx_TimeoutInd = 0;
+ sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+ sc->lasttx_packets = sc->stats.tx_packets;
+ }
+
+ /* --- end time out check ----------------------------------- */
+
+
+ link_status = sc->lmc_media->get_link_status (sc);
+
+ /*
+ * hardware level link lost, but the interface is marked as up.
+ * Mark it as down.
+ */
+ if ((link_status == 0) && (sc->last_link_status != 0)) {
+ printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name);
+ sc->last_link_status = 0;
+ /* lmc_reset (sc); Why reset??? The link can go down ok */
+
+ /* Inform the world that link has been lost */
+ dev->flags &= ~IFF_RUNNING;
+ }
+
+ /*
+ * hardware link is up, but the interface is marked as down.
+ * Bring it back up again.
+ */
+ if (link_status != 0 && sc->last_link_status == 0) {
+ printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name);
+ sc->last_link_status = 1;
+ /* lmc_reset (sc); Again why reset??? */
+
+ /* Inform the world that link protocol is back up. */
+ dev->flags |= IFF_RUNNING;
+
+ /* Now we have to tell the syncppp that we had an outage
+ * and that it should deal. Calling sppp_reopen here
+ * should do the trick, but we may have to call sppp_close
+ * when the link goes down, and call sppp_open here.
+ * Subject to more testing.
+ * --bbraun
+ */
+
+ lmc_proto_reopen(sc);
+
+ }
+
+ /* Call media specific watchdog functions */
+ sc->lmc_media->watchdog(sc);
+
+ /*
+ * Poke the transmitter to make sure it
+ * never stops, even if we run out of mem
+ */
+ LMC_CSR_WRITE(sc, csr_rxpoll, 0);
+
+ /*
+ * Check for code that failed
+ * and try and fix it as appropriate
+ */
+ if(sc->failed_ring == 1){
+ /*
+ * Failed to setup the recv/xmit rin
+ * Try again
+ */
+ sc->failed_ring = 0;
+ lmc_softreset(sc);
+ }
+ if(sc->failed_recv_alloc == 1){
+ /*
+ * We failed to alloc mem in the
+ * interupt halder, go through the rings
+ * and rebuild them
+ */
+ sc->failed_recv_alloc = 0;
+ lmc_softreset(sc);
+ }
+
+
+ /*
+ * remember the timer value
+ */
+kick_timer:
+
+ ticks = LMC_CSR_READ (sc, csr_gp_timer);
+ LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL);
+ sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+ /*
+ * restart this timer.
+ */
+ sc->timer.expires = jiffies + (HZ);
+ add_timer (&sc->timer);
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_watchdog out");
+
+}
+
+static int lmc_init(struct net_device * const dev) /*fold00*/
+{
+ lmc_trace(dev, "lmc_init in");
+ lmc_trace(dev, "lmc_init out");
+
+ return 0;
+}
+
+/* This initializes each card from lmc_probe() */
+static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*fold00*/
+ int chip_id, int subdevice, int board_idx)
+{
+ lmc_softc_t *sc = NULL;
+ u_int16_t AdapModelNum;
+
+ /*
+ * Allocate our own device structure
+ */
+
+#if LINUX_VERSION_CODE < 0x20363
+ dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL);
+#else
+ dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL);
+#endif
+ if (dev == NULL){
+ printk (KERN_ERR "lmc: kmalloc for device failed\n");
+ return NULL;
+ }
+ memset (dev, 0, sizeof (struct net_device));
+
+#ifndef GCOM
+ /*
+ * Switch to common hdlc%d naming. We name by type not by vendor
+ */
+#if LINUX_VERSION_CODE < 0x20363
+ dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+#else
+ dev->name = ((char *) (dev)) + sizeof (struct net_device);
+#endif
+
+ dev_alloc_name(dev, "hdlc%d");
+#else
+ /*
+ * GCOM uses LMC vendor name so that clients can know which card
+ * to attach to.
+ */
+ dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+ dev_alloc_name(dev, "lmc%d");
+#endif
+
+ lmc_trace(dev, "lmc_probe1 in");
+
+ Lmc_Count++;
+
+ if(lmc_first_load == 0){
+ printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION);
+ lmc_first_load = 1;
+ }
+
+ /*
+ * Allocate space for the private data structure
+ */
+
+ sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL);
+ if (sc == NULL) {
+ printk (KERN_WARNING "%s: Cannot allocate memory for device state\n",
+ dev->name);
+ return (NULL);
+ }
+ memset (sc, 0, sizeof (lmc_softc_t));
+ dev->priv = sc;
+ sc->lmc_device = dev;
+ sc->name = dev->name;
+
+ /* Initialize the sppp layer */
+ /* An ioctl can cause a subsequent detach for raw frame interface */
+ sc->if_type = LMC_PPP;
+ sc->check = 0xBEAFCAFE;
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ /*
+ * This will get the protocol layer ready and do any 1 time init's
+ * Must have a valid sc and dev structure
+ */
+ lmc_proto_init(sc);
+
+ lmc_proto_attach(sc);
+
+ /* Just fill in the entries for the device */
+
+ dev->init = lmc_init;
+ dev->type = ARPHRD_HDLC;
+ dev->hard_start_xmit = lmc_start_xmit;
+ dev->open = lmc_open;
+ dev->stop = lmc_close;
+ dev->get_stats = lmc_get_stats;
+ dev->do_ioctl = lmc_ioctl;
+ dev->set_config = lmc_set_config;
+#if LINUX_VERSION_CODE >= 0x20363
+ dev->tx_timeout = lmc_driver_timeout;
+ dev->watchdog_timeo = (HZ); /* 1 second */
+#endif
+
+ /*
+ * Why were we changing this???
+ dev->tx_queue_len = 100;
+ */
+
+ /* Init the spin lock so can call it latter */
+
+ spin_lock_init(&sc->lmc_lock);
+
+ LMC_SETUP_20_DEV;
+
+ printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq);
+
+ if (register_netdev (dev) != 0) {
+ printk (KERN_ERR "%s: register_netdev failed.\n", dev->name);
+ lmc_proto_detach(sc);
+ kfree (dev->priv);
+ kfree (dev);
+ return NULL;
+ }
+
+ /*
+ * Request the region of registers we need, so that
+ * later on, no one else will take our card away from
+ * us.
+ */
+ request_region (ioaddr, LMC_REG_RANGE, dev->name);
+
+ sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN;
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+
+ switch (subdevice) {
+ case PCI_PRODUCT_LMC_HSSI:
+ printk ("%s: LMC HSSI\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_HSSI;
+ sc->lmc_media = &lmc_hssi_media;
+ break;
+ case PCI_PRODUCT_LMC_DS3:
+ printk ("%s: LMC DS3\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_DS3;
+ sc->lmc_media = &lmc_ds3_media;
+ break;
+ case PCI_PRODUCT_LMC_SSI:
+ printk ("%s: LMC SSI\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_SSI;
+ sc->lmc_media = &lmc_ssi_media;
+ break;
+ case PCI_PRODUCT_LMC_T1:
+ printk ("%s: LMC T1\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_T1;
+ sc->lmc_media = &lmc_t1_media;
+ break;
+ default:
+ printk (KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name);
+ break;
+ }
+
+ lmc_initcsrs (sc, dev->base_addr, 8);
+
+ lmc_gpio_mkinput (sc, 0xff);
+ sc->lmc_gpio = 0; /* drive no signals yet */
+
+ sc->lmc_media->defaults (sc);
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+ /* verify that the PCI Sub System ID matches the Adapter Model number
+ * from the MII register
+ */
+ AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4;
+
+ if ((AdapModelNum == LMC_ADAP_T1
+ && subdevice == PCI_PRODUCT_LMC_T1) || /* detect LMC1200 */
+ (AdapModelNum == LMC_ADAP_SSI
+ && subdevice == PCI_PRODUCT_LMC_SSI) || /* detect LMC1000 */
+ (AdapModelNum == LMC_ADAP_DS3
+ && subdevice == PCI_PRODUCT_LMC_DS3) || /* detect LMC5245 */
+ (AdapModelNum == LMC_ADAP_HSSI
+ && subdevice == PCI_PRODUCT_LMC_HSSI))
+ { /* detect LMC5200 */
+
+ }
+ else {
+ printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
+ dev->name, AdapModelNum, subdevice);
+// return (NULL);
+ }
+ /*
+ * reset clock
+ */
+ LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL);
+
+ sc->board_idx = board_idx;
+
+ memset (&sc->stats, 0, sizeof (struct lmc_statistics));
+
+ sc->stats.check = STATCHECK;
+ sc->stats.version_size = (DRIVER_VERSION << 16) +
+ sizeof (struct lmc_statistics);
+ sc->stats.lmc_cardtype = sc->lmc_cardtype;
+
+ sc->lmc_ok = 0;
+ sc->last_link_status = 0;
+
+ lmc_trace(dev, "lmc_probe1 out");
+
+ return dev;
+}
+
+
+/* This is the entry point. This is what is called immediatly. */
+/* This goes out and finds the card */
+
+int lmc_probe_fake(struct net_device *dev) /*fold00*/
+{
+ lmc_probe(NULL);
+ /* Return 1 to unloaded bogus device */
+ return 1;
+}
+
+int lmc_probe (struct net_device *dev) /*fold00*/
+{
+ int pci_index = 0;
+#if LINUX_VERSION_CODE >= 0x20155
+ unsigned long pci_ioaddr;
+ unsigned short pci_command;
+ unsigned int pci_irq_line;
+#else
+ unsigned char pci_irq_line;
+ u32 pci_ioaddr;
+#endif
+ u16 vendor, subvendor, device, subdevice;
+ u32 foundaddr = 0;
+ unsigned char pci_bus, pci_device_fn;
+ u8 intcf = 0;
+
+ /* The card is only available on PCI, so if we don't have a
+ * PCI bus, we are in trouble.
+ */
+
+ if (!LMC_PCI_PRESENT()) {
+/* printk ("%s: We really want a pci bios!\n", dev->name);*/
+ return -1;
+ }
+ /* Loop basically until we don't find anymore. */
+ while (pci_index < 0xff){
+ /* The tulip is considered an ethernet class of card... */
+ if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+ pci_index, &pci_bus,
+ &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
+ /* No card found on this pass */
+ break;
+ }
+ /* Read the info we need to determine if this is
+ * our card or not
+ */
+#if LINUX_VERSION_CODE >= 0x20155
+ vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor;
+ device = pci_find_slot (pci_bus, pci_device_fn)->device;
+ pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq;
+#if LINUX_VERSION_CODE < 0x20363
+ pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0];
+#else
+ pci_ioaddr = pci_resource_start (pci_find_slot (pci_bus, pci_device_fn), 0);
+#endif
+ pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
+ PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+ pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
+ PCI_SUBSYSTEM_ID, &subdevice);
+ /*
+ * SPARC PCI Bios doesn't set the BUS Master bit, unlike intel
+ * Without it we won't do much packet work
+ * Do this to everyone
+ */
+ pci_read_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND,
+ &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pci_find_slot (pci_bus, pci_device_fn), PCI_COMMAND,
+ pci_command);
+#else
+ pcibios_read_config_word (pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word (pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+ pcibios_read_config_byte (pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ pcibios_read_config_word (pci_bus, pci_device_fn,
+ PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+ pcibios_read_config_word (pci_bus, pci_device_fn,
+ PCI_SUBSYSTEM_ID, &subdevice);
+#endif
+
+ /* Align the io address on the 32 bit boundry just in case */
+ pci_ioaddr &= ~3;
+
+ /*
+ * Make sure it's the correct card. CHECK SUBVENDOR ID!
+ * There are lots of tulip's out there.
+ * Also check the region of registers we will soon be
+ * poking, to make sure no one else has reserved them.
+ * This prevents taking someone else's device.
+ *
+ * Check either the subvendor or the subdevice, some systems reverse
+ * the setting in the bois, seems to be version and arch dependant?
+ * Fix the two variables
+ *
+ */
+ if (!(check_region (pci_ioaddr, LMC_REG_RANGE)) &&
+ (vendor == CORRECT_VENDOR_ID) &&
+ (device == CORRECT_DEV_ID) &&
+ ((subvendor == PCI_VENDOR_LMC) || (subdevice == PCI_VENDOR_LMC))){
+ struct net_device *cur, *prev = NULL;
+
+ /* Fix the error, exchange the two values */
+ if(subdevice == PCI_VENDOR_LMC){
+ subdevice = subvendor;
+ subvendor = PCI_VENDOR_LMC ;
+ }
+
+ /* Make the call to actually setup this card */
+ dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
+ device, subdevice, cards_found);
+ if (dev == NULL) {
+ printk ("lmc_probe: lmc_probe1 failed\n");
+ goto lmc_probe_next_card;
+ }
+ /* insert the device into the chain of lmc devices */
+ for (cur = Lmc_root_dev;
+ cur != NULL;
+ cur = ((lmc_softc_t *) cur->priv)->next_module) {
+ prev = cur;
+ }
+
+ if (prev == NULL)
+ Lmc_root_dev = dev;
+ else
+ ((lmc_softc_t *) prev->priv)->next_module = dev;
+
+ ((lmc_softc_t *) dev->priv)->next_module = NULL;
+ /* end insert */
+
+ foundaddr = dev->base_addr;
+
+ cards_found++;
+ intcf++;
+ }
+ lmc_probe_next_card:
+ pci_index++;
+ }
+
+ if (cards_found < 1)
+ return -1;
+
+#if LINUX_VERSION_CODE >= 0x20200
+ return foundaddr;
+#else
+ return 0;
+#endif
+}
+
+/* After this is called, packets can be sent.
+ * Does not initialize the addresses
+ */
+static int lmc_open (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc = dev->priv;
+
+ lmc_trace(dev, "lmc_open in");
+
+ lmc_led_on(sc, LMC_DS3_LED0);
+
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+
+ if (sc->lmc_ok){
+ lmc_trace(dev, "lmc_open lmc_ok out");
+ return (0);
+ }
+
+ lmc_softreset (sc);
+
+ /* Since we have to use PCI bus, this should work on x86,alpha,ppc */
+ if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){
+ printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
+ lmc_trace(dev, "lmc_open irq failed out");
+ return -EAGAIN;
+ }
+ sc->got_irq = 1;
+
+ /* Assert Terminal Active */
+ sc->lmc_miireg16 |= LMC_MII16_LED_ALL;
+ sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+ /*
+ * reset to last state.
+ */
+ sc->lmc_media->set_status (sc, NULL);
+
+ /* setup default bits to be used in tulip_desc_t transmit descriptor
+ * -baz */
+ sc->TxDescriptControlInit = (
+ LMC_TDES_INTERRUPT_ON_COMPLETION
+ | LMC_TDES_FIRST_SEGMENT
+ | LMC_TDES_LAST_SEGMENT
+ | LMC_TDES_SECOND_ADDR_CHAINED
+ | LMC_TDES_DISABLE_PADDING
+ );
+
+ if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) {
+ /* disable 32 bit CRC generated by ASIC */
+ sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+ }
+ sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length);
+ /* Acknoledge the Terminal Active and light LEDs */
+
+ /* dev->flags |= IFF_UP; */
+
+ lmc_proto_open(sc);
+
+ dev->do_ioctl = lmc_ioctl;
+
+
+ LMC_XMITTER_INIT(dev);
+
+#if LINUX_VERSION_CODE < 0x20363
+ dev->start = 1;
+#endif
+
+ sc->stats.tx_tbusy0++ ;
+
+ MOD_INC_USE_COUNT;
+
+ /*
+ * select what interrupts we want to get
+ */
+ sc->lmc_intrmask = 0;
+ /* Should be using the default interrupt mask defined in the .h file. */
+ sc->lmc_intrmask |= (TULIP_STS_NORMALINTR
+ | TULIP_STS_RXINTR
+ | TULIP_STS_TXINTR
+ | TULIP_STS_ABNRMLINTR
+ | TULIP_STS_SYSERROR
+ | TULIP_STS_TXSTOPPED
+ | TULIP_STS_TXUNDERFLOW
+ | TULIP_STS_RXSTOPPED
+ | TULIP_STS_RXNOBUF
+ );
+ LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+ sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
+ sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ sc->lmc_ok = 1; /* Run watchdog */
+
+ /*
+ * Set the if up now - pfb
+ */
+
+ sc->last_link_status = 1;
+
+ /*
+ * Setup a timer for the watchdog on probe, and start it running.
+ * Since lmc_ok == 0, it will be a NOP for now.
+ */
+ init_timer (&sc->timer);
+ sc->timer.expires = jiffies + HZ;
+ sc->timer.data = (unsigned long) dev;
+ sc->timer.function = &lmc_watchdog;
+ add_timer (&sc->timer);
+
+ lmc_trace(dev, "lmc_open out");
+
+ return (0);
+}
+
+/* Total reset to compensate for the AdTran DSU doing bad things
+ * under heavy load
+ */
+
+static void lmc_running_reset (struct net_device *dev) /*fold00*/
+{
+
+ lmc_softc_t *sc = (lmc_softc_t *) dev->priv;
+
+ lmc_trace(dev, "lmc_runnig_reset in");
+
+ /* stop interrupts */
+ /* Clear the interrupt mask */
+ LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+ lmc_softreset (sc);
+ /* sc->lmc_miireg16 |= LMC_MII16_LED_ALL; */
+ sc->lmc_media->set_link_status (sc, 1);
+ sc->lmc_media->set_status (sc, NULL);
+
+ //dev->flags |= IFF_RUNNING;
+
+ LMC_XMITTER_FREE(dev);
+
+ sc->lmc_txfull = 0;
+ sc->stats.tx_tbusy0++ ;
+
+ sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK;
+ LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+ sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ lmc_trace(dev, "lmc_runnin_reset_out");
+}
+
+
+/* This is what is called when you ifconfig down a device.
+ * This disables the timer for the watchdog and keepalives,
+ * and disables the irq for dev.
+ */
+static int lmc_close (struct net_device *dev) /*fold00*/
+{
+ /* not calling release_region() as we should */
+ lmc_softc_t *sc;
+
+ lmc_trace(dev, "lmc_close in");
+
+ sc = dev->priv;
+ sc->lmc_ok = 0;
+ sc->lmc_media->set_link_status (sc, 0);
+ del_timer (&sc->timer);
+ lmc_proto_close(sc);
+ lmc_ifdown (dev);
+
+ lmc_trace(dev, "lmc_close out");
+
+ return 0;
+}
+
+/* Ends the transfer of packets */
+/* When the interface goes down, this is called */
+static int lmc_ifdown (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc = dev->priv;
+ u32 csr6;
+ int i;
+
+ lmc_trace(dev, "lmc_ifdown in");
+
+ /* Don't let anything else go on right now */
+ // dev->start = 0;
+ LMC_XMITTER_BUSY(dev);
+ sc->stats.tx_tbusy1++ ;
+
+ /* stop interrupts */
+ /* Clear the interrupt mask */
+ LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+ /* Stop Tx and Rx on the chip */
+ csr6 = LMC_CSR_READ (sc, csr_command);
+ csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */
+ csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */
+ LMC_CSR_WRITE (sc, csr_command, csr6);
+
+ dev->flags &= ~IFF_RUNNING;
+
+ sc->stats.rx_missed_errors +=
+ LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+ /* release the interrupt */
+ if(sc->got_irq == 1){
+ free_irq (dev->irq, dev);
+ sc->got_irq = 0;
+ }
+
+ /* free skbuffs in the Rx queue */
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ struct sk_buff *skb = sc->lmc_rxq[i];
+ sc->lmc_rxq[i] = 0;
+ sc->lmc_rxring[i].status = 0;
+ sc->lmc_rxring[i].length = 0;
+ sc->lmc_rxring[i].buffer1 = 0xDEADBEEF;
+ if (skb != NULL)
+ {
+ LMC_SKB_FREE(skb, 1);
+ LMC_DEV_KFREE_SKB (skb);
+ }
+ sc->lmc_rxq[i] = NULL;
+ }
+
+ for (i = 0; i < LMC_TXDESCS; i++)
+ {
+ if (sc->lmc_txq[i] != NULL)
+ LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+ sc->lmc_txq[i] = NULL;
+ }
+
+ lmc_led_off (sc, LMC_MII16_LED_ALL);
+
+ LMC_XMITTER_FREE(dev);
+ sc->stats.tx_tbusy0++ ;
+
+ lmc_trace(dev, "lmc_ifdown out");
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* Interrupt handling routine. This will take an incoming packet, or clean
+ * up after a trasmit.
+ */
+static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ lmc_softc_t *sc;
+ u32 csr;
+ int i;
+ s32 stat;
+ unsigned int badtx;
+ u32 firstcsr;
+ int max_work = LMC_RXDESCS;
+
+ lmc_trace(dev, "lmc_interrupt in");
+
+ sc = dev->priv;
+
+ spin_lock(&sc->lmc_lock);
+
+ /*
+ * Read the csr to find what interupts we have (if any)
+ */
+ csr = LMC_CSR_READ (sc, csr_status);
+
+ /*
+ * Make sure this is our interrupt
+ */
+ if ( ! (csr & sc->lmc_intrmask)) {
+ goto lmc_int_fail_out;
+ }
+
+ firstcsr = csr;
+
+ /* always go through this loop at least once */
+ while (csr & sc->lmc_intrmask) {
+ /*
+ * Clear interupt bits, we handle all case below
+ */
+ LMC_CSR_WRITE (sc, csr_status, csr);
+
+ /*
+ * One of
+ * - Transmit process timed out CSR5<1>
+ * - Transmit jabber timeout CSR5<3>
+ * - Transmit underflow CSR5<5>
+ * - Transmit Receiver buffer unavailable CSR5<7>
+ * - Receive process stopped CSR5<8>
+ * - Receive watchdog timeout CSR5<9>
+ * - Early transmit interrupt CSR5<10>
+ *
+ * Is this really right? Should we do a running reset for jabber?
+ * (being a WAN card and all)
+ */
+ if (csr & TULIP_STS_ABNRMLINTR){
+ lmc_running_reset (dev);
+ break;
+ }
+
+ if (csr & TULIP_STS_RXINTR){
+ lmc_trace(dev, "rx interupt");
+ lmc_rx (dev);
+
+ }
+ if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) {
+
+ int n_compl = 0 ;
+ /* reset the transmit timeout detection flag -baz */
+ sc->stats.tx_NoCompleteCnt = 0;
+
+ badtx = sc->lmc_taint_tx;
+ i = badtx % LMC_TXDESCS;
+
+ while ((badtx < sc->lmc_next_tx)) {
+ stat = sc->lmc_txring[i].status;
+
+ LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat,
+ sc->lmc_txring[i].length);
+ /*
+ * If bit 31 is 1 the tulip owns it break out of the loop
+ */
+ if (stat & 0x80000000)
+ break;
+
+ n_compl++ ; /* i.e., have an empty slot in ring */
+ /*
+ * If we have no skbuff or have cleared it
+ * Already continue to the next buffer
+ */
+ if (sc->lmc_txq[i] == NULL)
+ continue;
+
+ /*
+ * Check the total error summary to look for any errors
+ */
+ if (stat & 0x8000) {
+ sc->stats.tx_errors++;
+ if (stat & 0x4104)
+ sc->stats.tx_aborted_errors++;
+ if (stat & 0x0C00)
+ sc->stats.tx_carrier_errors++;
+ if (stat & 0x0200)
+ sc->stats.tx_window_errors++;
+ if (stat & 0x0002)
+ sc->stats.tx_fifo_errors++;
+ }
+ else {
+
+#if LINUX_VERSION_CODE >= 0x20200
+ sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
+#endif
+
+ sc->stats.tx_packets++;
+ }
+
+ // LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+ dev_kfree_skb_irq(sc->lmc_txq[i]);
+ sc->lmc_txq[i] = 0;
+
+ badtx++;
+ i = badtx % LMC_TXDESCS;
+ }
+
+ if (sc->lmc_next_tx - badtx > LMC_TXDESCS)
+ {
+ printk ("%s: out of sync pointer\n", dev->name);
+ badtx += LMC_TXDESCS;
+ }
+ LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0);
+ sc->lmc_txfull = 0;
+ LMC_XMITTER_FREE(dev);
+ sc->stats.tx_tbusy0++ ;
+#if LINUX_VERSION_CODE < 0x20363
+ mark_bh (NET_BH); /* Tell Linux to give me more packets */
+#endif
+
+
+#ifdef DEBUG
+ sc->stats.dirtyTx = badtx;
+ sc->stats.lmc_next_tx = sc->lmc_next_tx;
+ sc->stats.lmc_txfull = sc->lmc_txfull;
+#if LINUX_VERSION_CODE < 0x20363
+ sc->stats.tbusy = dev->tbusy;
+#endif
+#endif
+ sc->lmc_taint_tx = badtx;
+
+ /*
+ * Why was there a break here???
+ */
+ } /* end handle transmit interrupt */
+
+ if (csr & TULIP_STS_SYSERROR) {
+ u32 error;
+ printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr);
+ error = csr>>23 & 0x7;
+ switch(error){
+ case 0x000:
+ printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name);
+ break;
+ case 0x001:
+ printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name);
+ break;
+ case 0x010:
+ printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name);
+ break;
+ default:
+ printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name);
+ }
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+ }
+
+
+ if(max_work-- <= 0)
+ break;
+
+ /*
+ * Get current csr status to make sure
+ * we've cleared all interupts
+ */
+ csr = LMC_CSR_READ (sc, csr_status);
+ } /* end interrupt loop */
+ LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);
+
+lmc_int_fail_out:
+
+ spin_unlock(&sc->lmc_lock);
+
+ lmc_trace(dev, "lmc_interrupt out");
+
+ return;
+}
+
+static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc;
+ u32 flag;
+ int entry;
+ int ret = 0;
+ LMC_SPIN_FLAGS;
+
+ lmc_trace(dev, "lmc_start_xmit in");
+
+ sc = dev->priv;
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ /*
+ * If the transmitter is busy
+ * this must be the 5 second polling
+ * from the kernel which called us.
+ * Poke the chip and try to get it running
+ *
+ */
+#if LINUX_VERSION_CODE < 0x20363
+ if(dev->tbusy != 0){
+ u32 csr6;
+
+ printk("%s: Xmitter busy|\n", dev->name);
+
+ sc->stats.tx_tbusy_calls++ ;
+ if (jiffies - dev->trans_start < TX_TIMEOUT) {
+ ret = 1;
+ goto lmc_start_xmit_bug_out;
+ }
+
+ /*
+ * Chip seems to have locked up
+ * Reset it
+ * This whips out all our decriptor
+ * table and starts from scartch
+ */
+
+ LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
+ LMC_CSR_READ (sc, csr_status),
+ sc->stats.tx_ProcTimeout);
+
+ lmc_running_reset (dev);
+
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+ /* restart the tx processes */
+ csr6 = LMC_CSR_READ (sc, csr_command);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+
+ /* immediate transmit */
+ LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+ sc->stats.tx_errors++;
+ sc->stats.tx_ProcTimeout++; /* -baz */
+
+ dev->trans_start = jiffies;
+
+ ret = 1;
+ goto lmc_start_xmit_bug_out;
+ }
+#endif
+ /* normal path, tbusy known to be zero */
+
+ entry = sc->lmc_next_tx % LMC_TXDESCS;
+
+ sc->lmc_txq[entry] = skb;
+ sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data);
+
+ LMC_CONSOLE_LOG("xmit", skb->data, skb->len);
+
+#ifndef GCOM
+ /* If the queue is less than half full, don't interrupt */
+ if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2)
+ {
+ /* Do not interrupt on completion of this packet */
+ flag = 0x60000000;
+ LMC_XMITTER_FREE(dev);
+ }
+ else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2)
+ {
+ /* This generates an interrupt on completion of this packet */
+ flag = 0xe0000000;
+ LMC_XMITTER_FREE(dev);
+ }
+ else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
+ {
+ /* Do not interrupt on completion of this packet */
+ flag = 0x60000000;
+ LMC_XMITTER_FREE(dev);
+ }
+ else
+ {
+ /* This generates an interrupt on completion of this packet */
+ flag = 0xe0000000;
+ sc->lmc_txfull = 1;
+ LMC_XMITTER_BUSY(dev);
+ }
+#else
+ flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
+
+ if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
+ { /* ring full, go busy */
+ sc->lmc_txfull = 1;
+ LMC_XMITTER_BUSY(dev);
+ sc->stats.tx_tbusy1++ ;
+ LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
+ }
+#endif
+
+
+ if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */
+ flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */
+
+ /* don't pad small packets either */
+ flag = sc->lmc_txring[entry].length = (skb->len) | flag |
+ sc->TxDescriptControlInit;
+
+ /* set the transmit timeout flag to be checked in
+ * the watchdog timer handler. -baz
+ */
+
+ sc->stats.tx_NoCompleteCnt++;
+ sc->lmc_next_tx++;
+
+ /* give ownership to the chip */
+ LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry);
+ sc->lmc_txring[entry].status = 0x80000000;
+
+ /* send now! */
+ LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+ dev->trans_start = jiffies;
+
+#if LINUX_VERSION_CODE < 0x20363
+lmc_start_xmit_bug_out:
+#endif
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_start_xmit_out");
+ return ret;
+}
+
+
+static int lmc_rx (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc;
+ int i;
+ int rx_work_limit = LMC_RXDESCS;
+ unsigned int next_rx;
+ int rxIntLoopCnt; /* debug -baz */
+ int localLengthErrCnt = 0;
+ long stat;
+ struct sk_buff *skb, *nsb;
+ u16 len;
+
+ lmc_trace(dev, "lmc_rx in");
+
+ sc = dev->priv;
+
+ lmc_led_on(sc, LMC_DS3_LED3);
+
+ rxIntLoopCnt = 0; /* debug -baz */
+
+ i = sc->lmc_next_rx % LMC_RXDESCS;
+ next_rx = sc->lmc_next_rx;
+
+ while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
+ {
+ rxIntLoopCnt++; /* debug -baz */
+ len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
+ if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */
+ if ((stat & 0x0000ffff) != 0x7fff) {
+ /* Oversized frame */
+ sc->stats.rx_length_errors++;
+ goto skip_packet;
+ }
+ }
+
+ if(stat & 0x00000008){ /* Catch a dribbling bit error */
+ sc->stats.rx_errors++;
+ sc->stats.rx_frame_errors++;
+ goto skip_packet;
+ }
+
+
+ if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */
+ sc->stats.rx_errors++;
+ sc->stats.rx_crc_errors++;
+ goto skip_packet;
+ }
+
+
+ if (len > LMC_PKT_BUF_SZ){
+ sc->stats.rx_length_errors++;
+ localLengthErrCnt++;
+ goto skip_packet;
+ }
+
+ if (len < sc->lmc_crcSize + 2) {
+ sc->stats.rx_length_errors++;
+ sc->stats.rx_SmallPktCnt++;
+ localLengthErrCnt++;
+ goto skip_packet;
+ }
+
+ if(stat & 0x00004000){
+ printk(KERN_WARNING "%s: Receiver descriptor error, receiver out of sync?\n", dev->name);
+ }
+
+ len -= sc->lmc_crcSize;
+
+ skb = sc->lmc_rxq[i];
+
+ /*
+ * We ran out of memory at some point
+ * just allocate an skb buff and continue.
+ */
+
+ if(skb == 0x0){
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if (nsb) {
+ LMC_SKB_FREE(nsb, 1);
+ sc->lmc_rxq[i] = nsb;
+ nsb->dev = dev;
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+ }
+ sc->failed_recv_alloc = 1;
+ goto skip_packet;
+ }
+
+ dev->last_rx = jiffies;
+ sc->stats.rx_packets++;
+
+ LMC_CONSOLE_LOG("recv", skb->data, len);
+
+ /*
+ * I'm not sure of the sanity of this
+ * Packets could be arriving at a constant
+ * 44.210mbits/sec and we're going to copy
+ * them into a new buffer??
+ */
+
+ if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */
+ /*
+ * If it's a large packet don't copy it just hand it up
+ */
+ give_it_anyways:
+
+ sc->lmc_rxq[i] = 0x0;
+ sc->lmc_rxring[i].buffer1 = 0x0;
+
+ skb_put (skb, len);
+ skb->protocol = lmc_proto_type(sc, skb);
+ skb->protocol = htons(ETH_P_WAN_PPP);
+ skb->mac.raw = skb->data;
+// skb->nh.raw = skb->data;
+ skb->dev = dev;
+ lmc_proto_netif(sc, skb);
+
+ /*
+ * This skb will be destroyed by the upper layers, make a new one
+ */
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if (nsb) {
+ LMC_SKB_FREE(nsb, 1);
+ sc->lmc_rxq[i] = nsb;
+ nsb->dev = dev;
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+ /* Transfered to 21140 below */
+ }
+ else {
+ /*
+ * We've run out of memory, stop trying to allocate
+ * memory and exit the interupt handler
+ *
+ * The chip may run out of receivers and stop
+ * in which care we'll try to allocate the buffer
+ * again. (once a second)
+ */
+ sc->stats.rx_BuffAllocErr++;
+ LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+ sc->failed_recv_alloc = 1;
+ goto skip_out_of_mem;
+ }
+ }
+ else {
+ nsb = dev_alloc_skb(len);
+ if(!nsb) {
+ goto give_it_anyways;
+ }
+ memcpy(skb_put(nsb, len), skb->data, len);
+
+ nsb->protocol = lmc_proto_type(sc, skb);
+ nsb->mac.raw = nsb->data;
+// nsb->nh.raw = nsb->data;
+ nsb->dev = dev;
+ lmc_proto_netif(sc, nsb);
+ }
+
+ skip_packet:
+ LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+ sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4;
+
+ sc->lmc_next_rx++;
+ i = sc->lmc_next_rx % LMC_RXDESCS;
+ rx_work_limit--;
+ if (rx_work_limit < 0)
+ break;
+ }
+
+ /* detect condition for LMC1000 where DSU cable attaches and fills
+ * descriptors with bogus packets
+ *
+ if (localLengthErrCnt > LMC_RXDESCS - 3) {
+ sc->stats.rx_BadPktSurgeCnt++;
+ LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE,
+ localLengthErrCnt,
+ sc->stats.rx_BadPktSurgeCnt);
+ } */
+
+ /* save max count of receive descriptors serviced */
+ if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) {
+ sc->stats.rxIntLoopCnt = rxIntLoopCnt; /* debug -baz */
+ }
+
+#ifdef DEBUG
+ if (rxIntLoopCnt == 0)
+ {
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT)
+ != DESC_OWNED_BY_DC21X4)
+ {
+ rxIntLoopCnt++;
+ }
+ }
+ LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0);
+ }
+#endif
+
+
+ lmc_led_off(sc, LMC_DS3_LED3);
+
+skip_out_of_mem:
+
+ lmc_trace(dev, "lmc_rx out");
+
+ return 0;
+}
+
+static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc;
+ LMC_SPIN_FLAGS;
+
+ lmc_trace(dev, "lmc_get_stats in");
+
+ sc = dev->priv;
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_get_stats out");
+
+ return (struct enet_statistics *) &sc->stats;
+}
+
+#ifdef MODULE
+
+int init_module (void) /*fold00*/
+{
+ printk ("lmc: module loaded\n");
+
+ /* Have lmc_probe search for all the cards, and allocate devices */
+ if (lmc_probe (NULL) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+void cleanup_module (void) /*fold00*/
+{
+ struct net_device *dev, *next;
+ lmc_softc_t *sc;
+
+ /* we have no pointer to our devices, since they are all dynamically
+ * allocated. So, here we loop through all the network devices
+ * looking for ours. When found, dispose of them properly.
+ */
+
+ for (dev = Lmc_root_dev;
+ dev != NULL;
+ dev = next )
+ {
+
+ next = ((lmc_softc_t *) dev->priv)->next_module; /* get it now before we deallocate it */
+ printk ("%s: removing...\n", dev->name);
+
+ /* close the syncppp stuff, and release irq. Close is run on unreg net */
+ lmc_close (dev);
+ sc = dev->priv;
+ if (sc != NULL)
+ lmc_proto_detach(sc);
+
+ /* Remove the device from the linked list */
+ unregister_netdev (dev);
+
+ /* Let go of the io region */;
+ release_region (dev->base_addr, LMC_REG_RANGE);
+
+ /* free our allocated structures. */
+ kfree (dev->priv);
+ dev->priv = NULL;
+
+ kfree ((struct ppp_device *) dev);
+ dev = NULL;
+ }
+
+
+ Lmc_root_dev = NULL;
+ printk ("lmc module unloaded\n");
+}
+#endif
+
+unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/
+{
+ int i;
+ int command = (0xf6 << 10) | (devaddr << 5) | regno;
+ int retval = 0;
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg in");
+
+ LMC_MII_SYNC (sc);
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync");
+
+ for (i = 15; i >= 0; i--)
+ {
+ int dataval = (command & (1 << i)) ? 0x20000 : 0;
+
+ LMC_CSR_WRITE (sc, csr_9, dataval);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1");
+
+ for (i = 19; i > 0; i--)
+ {
+ LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0);
+ LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg out");
+
+ return (retval >> 1) & 0xffff;
+}
+
+void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/
+{
+ int i = 32;
+ int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data;
+
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg in");
+
+ LMC_MII_SYNC (sc);
+
+ i = 31;
+ while (i >= 0)
+ {
+ int datav;
+
+ if (command & (1 << i))
+ datav = 0x20000;
+ else
+ datav = 0x00000;
+
+ LMC_CSR_WRITE (sc, csr_9, datav);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000));
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ i--;
+ }
+
+ i = 2;
+ while (i > 0)
+ {
+ LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, 0x50000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ i--;
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg out");
+}
+
+static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
+{
+ int i;
+
+ lmc_trace(sc->lmc_device, "lmc_softreset in");
+
+ /* Initialize the recieve rings and buffers. */
+ sc->lmc_txfull = 0;
+ sc->lmc_next_rx = 0;
+ sc->lmc_next_tx = 0;
+ sc->lmc_taint_rx = 0;
+ sc->lmc_taint_tx = 0;
+
+ /*
+ * Setup each one of the receiver buffers
+ * allocate an skbuff for each one, setup the the descriptor table
+ * and point each buffer at the next one
+ */
+
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ struct sk_buff *skb;
+
+ if (sc->lmc_rxq[i] == NULL)
+ {
+ skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if(skb == NULL){
+ printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name);
+ sc->failed_ring = 1;
+ break;
+ }
+ else{
+ sc->lmc_rxq[i] = skb;
+ }
+ }
+ else
+ {
+ skb = sc->lmc_rxq[i];
+ }
+
+ skb->dev = sc->lmc_device;
+ LMC_SKB_FREE(skb, 1);
+
+ /* owned by 21140 */
+ sc->lmc_rxring[i].status = 0x80000000;
+
+ /* used to be PKT_BUF_SZ now uses skb since we loose some to head room */
+ sc->lmc_rxring[i].length = skb->end - skb->data;
+
+ /* use to be tail which is dumb since you're thinking why write
+ * to the end of the packj,et but since there's nothing there tail == data
+ */
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data);
+
+ /* This is fair since the structure is static and we have the next address */
+ sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]);
+
+ }
+
+ /*
+ * Sets end of ring
+ */
+ sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */
+ sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */
+ LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */
+
+
+ /* Initialize the transmit rings and buffers */
+ for (i = 0; i < LMC_TXDESCS; i++)
+ {
+ if (sc->lmc_txq[i] != NULL){ /* have buffer */
+ dev_kfree_skb(sc->lmc_txq[i]); /* free it */
+ sc->stats.tx_dropped++; /* We just dropped a packet */
+ }
+ sc->lmc_txq[i] = 0;
+ sc->lmc_txring[i].status = 0x00000000;
+ sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]);
+ }
+ sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]);
+ LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring));
+
+ lmc_trace(sc->lmc_device, "lmc_softreset out");
+}
+
+static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/
+{
+ lmc_trace(dev, "lmc_set_config in");
+ lmc_trace(dev, "lmc_set_config out");
+ return -EOPNOTSUPP;
+}
+
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in");
+ sc->lmc_gpio_io &= ~bits;
+ LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out");
+}
+
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in");
+ sc->lmc_gpio_io |= bits;
+ LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out");
+}
+
+void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_led_on in");
+ if((~sc->lmc_miireg16) & led){ /* Already on! */
+ lmc_trace(sc->lmc_device, "lmc_led_on aon out");
+ return;
+ }
+
+ sc->lmc_miireg16 &= ~led;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_on out");
+}
+
+void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_led_off in");
+ if(sc->lmc_miireg16 & led){ /* Already set don't do anything */
+ lmc_trace(sc->lmc_device, "lmc_led_off aoff out");
+ return;
+ }
+
+ sc->lmc_miireg16 |= led;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_off out");
+}
+
+static void lmc_reset(lmc_softc_t * const sc) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_reset in");
+ sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ /*
+ * make some of the GPIO pins be outputs
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+ /*
+ * RESET low to force state reset. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_RESET);
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, LMC_GEP_RESET);
+
+ /*
+ * Call media specific init routine
+ */
+ sc->lmc_media->init(sc);
+
+ sc->stats.resetCount++;
+ lmc_trace(sc->lmc_device, "lmc_reset out");
+}
+
+static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/
+{
+ u_int32_t val;
+ lmc_trace(sc->lmc_device, "lmc_dec_reset in");
+
+ /*
+ * disable all interrupts
+ */
+ sc->lmc_intrmask = 0;
+ LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask);
+
+ /*
+ * Reset the chip with a software reset command.
+ * Wait 10 microseconds (actually 50 PCI cycles but at
+ * 33MHz that comes to two microseconds but wait a
+ * bit longer anyways)
+ */
+ LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ udelay(25);
+#ifdef __sparc__
+ sc->lmc_busmode = LMC_CSR_READ(sc, csr_busmode);
+ sc->lmc_busmode = 0x00100000;
+ sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET;
+ LMC_CSR_WRITE(sc, csr_busmode, sc->lmc_busmode);
+#endif
+ sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command);
+
+ /*
+ * We want:
+ * no ethernet address in frames we write
+ * disable padding (txdesc, padding disable)
+ * ignore runt frames (rdes0 bit 15)
+ * no receiver watchdog or transmitter jabber timer
+ * (csr15 bit 0,14 == 1)
+ * if using 16-bit CRC, turn off CRC (trans desc, crc disable)
+ */
+
+ sc->lmc_cmdmode |= ( TULIP_CMD_PROMISCUOUS
+ | TULIP_CMD_FULLDUPLEX
+ | TULIP_CMD_PASSBADPKT
+ | TULIP_CMD_NOHEARTBEAT
+ | TULIP_CMD_PORTSELECT
+ | TULIP_CMD_RECEIVEALL
+ | TULIP_CMD_MUSTBEONE
+ );
+ sc->lmc_cmdmode &= ~( TULIP_CMD_OPERMODE
+ | TULIP_CMD_THRESHOLDCTL
+ | TULIP_CMD_STOREFWD
+ | TULIP_CMD_TXTHRSHLDCTL
+ );
+
+ LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
+
+ /*
+ * disable receiver watchdog and transmit jabber
+ */
+ val = LMC_CSR_READ(sc, csr_sia_general);
+ val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE);
+ LMC_CSR_WRITE(sc, csr_sia_general, val);
+
+ lmc_trace(sc->lmc_device, "lmc_dec_reset out");
+}
+
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/
+ size_t csr_size)
+{
+ lmc_trace(sc->lmc_device, "lmc_initcsrs in");
+ sc->lmc_csrs.csr_busmode = csr_base + 0 * csr_size;
+ sc->lmc_csrs.csr_txpoll = csr_base + 1 * csr_size;
+ sc->lmc_csrs.csr_rxpoll = csr_base + 2 * csr_size;
+ sc->lmc_csrs.csr_rxlist = csr_base + 3 * csr_size;
+ sc->lmc_csrs.csr_txlist = csr_base + 4 * csr_size;
+ sc->lmc_csrs.csr_status = csr_base + 5 * csr_size;
+ sc->lmc_csrs.csr_command = csr_base + 6 * csr_size;
+ sc->lmc_csrs.csr_intr = csr_base + 7 * csr_size;
+ sc->lmc_csrs.csr_missed_frames = csr_base + 8 * csr_size;
+ sc->lmc_csrs.csr_9 = csr_base + 9 * csr_size;
+ sc->lmc_csrs.csr_10 = csr_base + 10 * csr_size;
+ sc->lmc_csrs.csr_11 = csr_base + 11 * csr_size;
+ sc->lmc_csrs.csr_12 = csr_base + 12 * csr_size;
+ sc->lmc_csrs.csr_13 = csr_base + 13 * csr_size;
+ sc->lmc_csrs.csr_14 = csr_base + 14 * csr_size;
+ sc->lmc_csrs.csr_15 = csr_base + 15 * csr_size;
+ lmc_trace(sc->lmc_device, "lmc_initcsrs out");
+}
+
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
+ lmc_softc_t *sc;
+ u32 csr6;
+ LMC_SPIN_FLAGS;
+
+ lmc_trace(dev, "lmc_driver_timeout in");
+
+ sc = dev->priv;
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ printk("%s: Xmitter busy|\n", dev->name);
+
+ sc->stats.tx_tbusy_calls++ ;
+ if (jiffies - dev->trans_start < TX_TIMEOUT) {
+ goto bug_out;
+ }
+
+ /*
+ * Chip seems to have locked up
+ * Reset it
+ * This whips out all our decriptor
+ * table and starts from scartch
+ */
+
+ LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
+ LMC_CSR_READ (sc, csr_status),
+ sc->stats.tx_ProcTimeout);
+
+ lmc_running_reset (dev);
+
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+ /* restart the tx processes */
+ csr6 = LMC_CSR_READ (sc, csr_command);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+
+ /* immediate transmit */
+ LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+ sc->stats.tx_errors++;
+ sc->stats.tx_ProcTimeout++; /* -baz */
+
+ dev->trans_start = jiffies;
+
+bug_out:
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_driver_timout out");
+
+
+}
+
+int lmc_setup(void) { /*FOLD00*/
+ return lmc_probe(NULL);
+}
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
new file mode 100644
index 000000000..8df3cb36c
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -0,0 +1,1258 @@
+/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+//#include <asm/smp.h>
+
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>
+#endif
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+
+#if LINUX_VERSION_CODE >= 0x20200
+#include <asm/uaccess.h>
+//#include <asm/spinlock.h>
+#endif
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+
+#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ */
+
+/*
+ * For lack of a better place, put the SSI cable stuff here.
+ */
+char *lmc_t1_cables[] = {
+ "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35",
+ "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL
+};
+
+/*
+ * protocol independent method.
+ */
+static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *);
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+static void lmc_ds3_init (lmc_softc_t * const);
+static void lmc_ds3_default (lmc_softc_t * const);
+static void lmc_ds3_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ds3_set_100ft (lmc_softc_t * const, int);
+static int lmc_ds3_get_link_status (lmc_softc_t * const);
+static void lmc_ds3_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ds3_set_scram (lmc_softc_t * const, int);
+static void lmc_ds3_watchdog (lmc_softc_t * const);
+
+static void lmc_hssi_init (lmc_softc_t * const);
+static void lmc_hssi_default (lmc_softc_t * const);
+static void lmc_hssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_hssi_set_clock (lmc_softc_t * const, int);
+static int lmc_hssi_get_link_status (lmc_softc_t * const);
+static void lmc_hssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_hssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_hssi_watchdog (lmc_softc_t * const);
+
+static void lmc_ssi_init (lmc_softc_t * const);
+static void lmc_ssi_default (lmc_softc_t * const);
+static void lmc_ssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ssi_set_clock (lmc_softc_t * const, int);
+static void lmc_ssi_set_speed (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_ssi_get_link_status (lmc_softc_t * const);
+static void lmc_ssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_ssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ssi_watchdog (lmc_softc_t * const);
+
+static void lmc_t1_init (lmc_softc_t * const);
+static void lmc_t1_default (lmc_softc_t * const);
+static void lmc_t1_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_t1_get_link_status (lmc_softc_t * const);
+static void lmc_t1_set_circuit_type (lmc_softc_t * const, int);
+static void lmc_t1_set_crc_length (lmc_softc_t * const, int);
+static void lmc_t1_set_clock (lmc_softc_t * const, int);
+static void lmc_t1_watchdog (lmc_softc_t * const);
+
+static void lmc_dummy_set_1 (lmc_softc_t * const, int);
+static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *);
+
+static inline void write_av9110_bit (lmc_softc_t *, int);
+static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t);
+
+lmc_media_t lmc_ds3_media = {
+ lmc_ds3_init, /* special media init stuff */
+ lmc_ds3_default, /* reset to default state */
+ lmc_ds3_set_status, /* reset status to state provided */
+ lmc_dummy_set_1, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_ds3_set_100ft, /* set cable length */
+ lmc_ds3_set_scram, /* set scrambler */
+ lmc_ds3_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_ds3_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+ lmc_hssi_init, /* special media init stuff */
+ lmc_hssi_default, /* reset to default state */
+ lmc_hssi_set_status, /* reset status to state provided */
+ lmc_hssi_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_hssi_get_link_status, /* get link status */
+ lmc_hssi_set_link_status, /* set link status */
+ lmc_hssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
+ lmc_ssi_default, /* reset to default state */
+ lmc_ssi_set_status, /* reset status to state provided */
+ lmc_ssi_set_clock, /* set clock source */
+ lmc_ssi_set_speed, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_ssi_get_link_status, /* get link status */
+ lmc_ssi_set_link_status, /* set link status */
+ lmc_ssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+ lmc_t1_init, /* special media init stuff */
+ lmc_t1_default, /* reset to default state */
+ lmc_t1_set_status, /* reset status to state provided */
+ lmc_t1_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_t1_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_t1_set_crc_length, /* set CRC length */
+ lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+ lmc_t1_watchdog
+};
+
+static void
+lmc_dummy_set_1 (lmc_softc_t * const sc, int a)
+{
+}
+
+static void
+lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a)
+{
+}
+
+/*
+ * HSSI methods
+ */
+
+static void
+lmc_hssi_init (lmc_softc_t * const sc)
+{
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200;
+
+ lmc_gpio_mkoutput (sc, LMC_GEP_HSSI_CLOCK);
+}
+
+static void
+lmc_hssi_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in clock source
+ */
+ if (ctl->clock_source && !sc->ictl.clock_source)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+ }
+ else if (!ctl->clock_source && sc->ictl.clock_source)
+ {
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ }
+
+ lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = sc->ictl.clock_source;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_hssi_get_link_status (lmc_softc_t * const sc)
+{
+ /*
+ * We're using the same code as SSI since
+ * they're practically the same
+ */
+ return lmc_ssi_get_link_status(sc);
+}
+
+static void
+lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_LINK_UP)
+ sc->lmc_miireg16 |= LMC_MII16_HSSI_TA;
+ else
+ sc->lmc_miireg16 &= ~LMC_MII16_HSSI_TA;
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_hssi_watchdog (lmc_softc_t * const sc)
+{
+ /* HSSI is blank */
+}
+
+/*
+ * DS3 methods
+ */
+
+/*
+ * Set cable length
+ */
+static void
+lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT)
+ {
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_ZERO;
+ sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_GT_100FT;
+ }
+ else if (ie == LMC_CTL_CABLE_LENGTH_LT_100FT)
+ {
+ sc->lmc_miireg16 |= LMC_MII16_DS3_ZERO;
+ sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_LT_100FT;
+ }
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_cable_length (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+ sc->lmc_media->set_scrambler (sc, LMC_CTL_OFF);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_cable_length (sc, sc->ictl.cable_length);
+ sc->lmc_media->set_scrambler (sc, sc->ictl.scrambler_onoff);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in cable length setting
+ */
+ if (ctl->cable_length && !sc->ictl.cable_length)
+ lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_GT_100FT);
+ else if (!ctl->cable_length && sc->ictl.cable_length)
+ lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+
+ /*
+ * Check for change in scrambler setting (requires reset)
+ */
+ if (ctl->scrambler_onoff && !sc->ictl.scrambler_onoff)
+ lmc_ds3_set_scram (sc, LMC_CTL_ON);
+ else if (!ctl->scrambler_onoff && sc->ictl.scrambler_onoff)
+ lmc_ds3_set_scram (sc, LMC_CTL_OFF);
+
+ lmc_set_protocol (sc, ctl);
+}
+
+static void
+lmc_ds3_init (lmc_softc_t * const sc)
+{
+ int i;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5245;
+
+ /* writes zeros everywhere */
+ for (i = 0; i < 21; i++)
+ {
+ lmc_mii_writereg (sc, 0, 17, i);
+ lmc_mii_writereg (sc, 0, 18, 0);
+ }
+
+ /* set some essential bits */
+ lmc_mii_writereg (sc, 0, 17, 1);
+ lmc_mii_writereg (sc, 0, 18, 0x25); /* ser, xtx */
+
+ lmc_mii_writereg (sc, 0, 17, 5);
+ lmc_mii_writereg (sc, 0, 18, 0x80); /* emode */
+
+ lmc_mii_writereg (sc, 0, 17, 14);
+ lmc_mii_writereg (sc, 0, 18, 0x30); /* rcgen, tcgen */
+
+ /* clear counters and latched bits */
+ for (i = 0; i < 21; i++)
+ {
+ lmc_mii_writereg (sc, 0, 17, i);
+ lmc_mii_readreg (sc, 0, 18);
+ }
+}
+
+/*
+ * 1 == DS3 payload scrambled, 0 == not scrambled
+ */
+static void
+lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_ON)
+ {
+ sc->lmc_miireg16 |= LMC_MII16_DS3_SCRAM;
+ sc->ictl.scrambler_onoff = LMC_CTL_ON;
+ }
+ else
+ {
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_SCRAM;
+ sc->ictl.scrambler_onoff = LMC_CTL_OFF;
+ }
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ds3_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status, link_status_11;
+ int ret = 1;
+
+ lmc_mii_writereg (sc, 0, 17, 7);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+ /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+ * led0 yellow = far-end adapter is in Red alarm condition
+ * led1 blue = received an Alarm Indication signal
+ * (upstream failure)
+ * led2 Green = power to adapter, Gate Array loaded & driver
+ * attached
+ * led3 red = Loss of Signal (LOS) or out of frame (OOF)
+ * conditions detected on T3 receive signal
+ */
+
+ lmc_led_on(sc, LMC_DS3_LED2);
+
+ if ((link_status & LMC_FRAMER_REG0_DLOS) ||
+ (link_status & LMC_FRAMER_REG0_OOFS)){
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ u16 r1;
+ lmc_mii_writereg (sc, 0, 17, 01); /* Turn on Xbit error as our cisco does */
+ r1 = lmc_mii_readreg (sc, 0, 18);
+ r1 &= 0xfe;
+ lmc_mii_writereg(sc, 0, 18, r1);
+ printk(KERN_WARNING "%s: Red Alarm - Loss of Signal or Loss of Framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3); /* turn on red LED */
+ sc->last_led_err[3] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED3); /* turn on red LED */
+ if(sc->last_led_err[3] == 1){
+ u16 r1;
+ lmc_mii_writereg (sc, 0, 17, 01); /* Turn off Xbit error */
+ r1 = lmc_mii_readreg (sc, 0, 18);
+ r1 |= 0x01;
+ lmc_mii_writereg(sc, 0, 18, r1);
+ }
+ sc->last_led_err[3] = 0;
+ }
+
+ lmc_mii_writereg(sc, 0, 17, 0x10);
+ link_status_11 = lmc_mii_readreg(sc, 0, 18);
+ if((link_status & LMC_FRAMER_REG0_AIS) ||
+ (link_status_11 & LMC_FRAMER_REG10_XBIT)) {
+ ret = 0;
+ if(sc->last_led_err[0] != 1){
+ printk(KERN_WARNING "%s: AIS Alarm or XBit Error\n", sc->name);
+ printk(KERN_WARNING "%s: Remote end has loss of signal or framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 0;
+ }
+
+ lmc_mii_writereg (sc, 0, 17, 9);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+ if(link_status & LMC_FRAMER_REG9_RBLUE){
+ ret = 0;
+ if(sc->last_led_err[1] != 1){
+ printk(KERN_WARNING "%s: Blue Alarm - Receiving all 1's\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_DS3_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_watchdog (lmc_softc_t * const sc)
+{
+
+}
+
+
+/*
+ * SSI methods
+ */
+
+static void
+lmc_ssi_init (lmc_softc_t * const sc)
+{
+ u_int16_t mii17;
+ int cable;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1000;
+
+ mii17 = lmc_mii_readreg (sc, 0, 17);
+
+ cable = (mii17 & LMC_MII17_SSI_CABLE_MASK) >> LMC_MII17_SSI_CABLE_SHIFT;
+ sc->ictl.cable_type = cable;
+
+ lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+}
+
+static void
+lmc_ssi_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ /*
+ * make TXCLOCK always be an output
+ */
+ lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_media->set_speed (sc, NULL);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+ sc->lmc_media->set_speed (sc, &sc->ictl);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in clock source
+ */
+ if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_INT
+ && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+ }
+ else if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_EXT
+ && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_INT)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+ }
+
+ if (ctl->clock_rate != sc->ictl.clock_rate)
+ sc->lmc_media->set_speed (sc, ctl);
+
+ lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_ssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = ie;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(ie != old)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(ie != old)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+static void
+lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ lmc_ctl_t *ictl = &sc->ictl;
+ lmc_av9110_t *av;
+
+ /* original settings for clock rate of:
+ * 100 Khz (8,25,0,0,2) were incorrect
+ * they should have been 80,125,1,3,3
+ * There are 17 param combinations to produce this freq.
+ * For 1.5 Mhz use 120,100,1,1,2 (226 param. combinations)
+ */
+ if (ctl == NULL)
+ {
+ av = &ictl->cardspec.ssi;
+ ictl->clock_rate = 1500000;
+ av->f = ictl->clock_rate;
+ av->n = 120;
+ av->m = 100;
+ av->v = 1;
+ av->x = 1;
+ av->r = 2;
+
+ write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+ return;
+ }
+
+ av = &ctl->cardspec.ssi;
+
+ if (av->f == 0)
+ return;
+
+ ictl->clock_rate = av->f; /* really, this is the rate we are */
+ ictl->cardspec.ssi = *av;
+
+ write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ssi_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status;
+ u_int32_t ticks;
+ int ret = 1;
+ int hw_hdsk = 1;
+
+ /*
+ * missing CTS? Hmm. If we require CTS on, we may never get the
+ * link to come up, so omit it in this test.
+ *
+ * Also, it seems that with a loopback cable, DCD isn't asserted,
+ * so just check for things like this:
+ * DSR _must_ be asserted.
+ * One of DCD or CTS must be asserted.
+ */
+
+ /* LMC 1000 (SSI) LED definitions
+ * led0 Green = power to adapter, Gate Array loaded &
+ * driver attached
+ * led1 Green = DSR and DTR and RTS and CTS are set
+ * led2 Green = Cable detected
+ * led3 red = No timing is available from the
+ * cable or the on-board frequency
+ * generator.
+ */
+
+ link_status = lmc_mii_readreg (sc, 0, 16);
+
+ /* Is the transmit clock still available */
+ ticks = LMC_CSR_READ (sc, csr_gp_timer);
+ ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+ lmc_led_on (sc, LMC_MII16_LED0);
+
+ /* ====== transmit clock determination ===== */
+ if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_INT) {
+ lmc_led_off(sc, LMC_MII16_LED3);
+ }
+ else if (ticks == 0 ) { /* no clock found ? */
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ sc->stats.tx_lossOfClockCnt++;
+ printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name);
+ }
+ sc->last_led_err[3] = 1;
+ lmc_led_on (sc, LMC_MII16_LED3); /* turn ON red LED */
+ }
+ else {
+ if(sc->last_led_err[3] == 1)
+ printk(KERN_WARNING "%s: Clock Returned\n", sc->name);
+ sc->last_led_err[3] = 0;
+ lmc_led_off (sc, LMC_MII16_LED3); /* turn OFF red LED */
+ }
+
+ if ((link_status & LMC_MII16_SSI_DSR) == 0) { /* Also HSSI CA */
+ ret = 0;
+ hw_hdsk = 0;
+ }
+
+#ifdef CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE
+ if ((link_status & (LMC_MII16_SSI_CTS | LMC_MII16_SSI_DCD)) == 0){
+ ret = 0;
+ hw_hdsk = 0;
+ }
+#endif
+
+ if(hw_hdsk == 0){
+ if(sc->last_led_err[1] != 1)
+ printk(KERN_WARNING "%s: DSR not asserted\n", sc->name);
+ sc->last_led_err[1] = 1;
+ lmc_led_off(sc, LMC_MII16_LED1);
+ }
+ else {
+ if(sc->last_led_err[1] != 0)
+ printk(KERN_WARNING "%s: DSR now asserted\n", sc->name);
+ sc->last_led_err[1] = 0;
+ lmc_led_on(sc, LMC_MII16_LED1);
+ }
+
+ if(ret == 1) {
+ lmc_led_on(sc, LMC_MII16_LED2); /* Over all good status? */
+ }
+
+ return ret;
+}
+
+static void
+lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_LINK_UP)
+ {
+ sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+ printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+ printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_SSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_SSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * These are bits to program the ssi frequency generator
+ */
+static inline void
+write_av9110_bit (lmc_softc_t * sc, int c)
+{
+ /*
+ * set the data bit as we need it.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
+ if (c & 0x01)
+ sc->lmc_gpio |= LMC_GEP_DATA;
+ else
+ sc->lmc_gpio &= ~(LMC_GEP_DATA);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * set the clock to high
+ */
+ sc->lmc_gpio |= LMC_GEP_CLK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * set the clock to low again.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+}
+
+static void
+write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
+ u_int32_t x, u_int32_t r)
+{
+ int i;
+
+#if 0
+ printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n",
+ LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r);
+#endif
+
+ sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR;
+ sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK
+ * as outputs.
+ */
+ lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK
+ | LMC_GEP_SSI_GENERATOR));
+
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * a shifting we will go...
+ */
+ for (i = 0; i < 7; i++)
+ write_av9110_bit (sc, n >> i);
+ for (i = 0; i < 7; i++)
+ write_av9110_bit (sc, m >> i);
+ for (i = 0; i < 1; i++)
+ write_av9110_bit (sc, v >> i);
+ for (i = 0; i < 2; i++)
+ write_av9110_bit (sc, x >> i);
+ for (i = 0; i < 2; i++)
+ write_av9110_bit (sc, r >> i);
+ for (i = 0; i < 5; i++)
+ write_av9110_bit (sc, 0x17 >> i);
+
+ /*
+ * stop driving serial-related signals
+ */
+ lmc_gpio_mkinput (sc,
+ (LMC_GEP_DATA | LMC_GEP_CLK
+ | LMC_GEP_SSI_GENERATOR));
+}
+
+static void
+lmc_ssi_watchdog (lmc_softc_t * const sc)
+{
+ u_int16_t mii17;
+ struct ssicsr2
+ {
+ unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1,
+ led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1;
+ };
+ struct ssicsr2 *ssicsr;
+ mii17 = lmc_mii_readreg (sc, 0, 17);
+ ssicsr = (struct ssicsr2 *) &mii17;
+ if (ssicsr->cable == 7)
+ {
+ lmc_led_off (sc, LMC_MII16_LED2);
+ }
+ else
+ {
+ lmc_led_on (sc, LMC_MII16_LED2);
+ }
+
+}
+
+/*
+ * T1 methods
+ */
+
+/*
+ * The framer regs are multiplexed through MII regs 17 & 18
+ * write the register address to MII reg 17 and the * data to MII reg 18. */
+static void
+lmc_t1_write (lmc_softc_t * const sc, int a, int d)
+{
+ lmc_mii_writereg (sc, 0, 17, a);
+ lmc_mii_writereg (sc, 0, 18, d);
+}
+
+/* Save a warning
+static int
+lmc_t1_read (lmc_softc_t * const sc, int a)
+{
+ lmc_mii_writereg (sc, 0, 17, a);
+ return lmc_mii_readreg (sc, 0, 18);
+}
+*/
+
+
+static void
+lmc_t1_init (lmc_softc_t * const sc)
+{
+ u_int16_t mii16;
+ int i;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200;
+ mii16 = lmc_mii_readreg (sc, 0, 16);
+
+ /* reset 8370 */
+ mii16 &= ~LMC_MII16_T1_RST;
+ lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST);
+ lmc_mii_writereg (sc, 0, 16, mii16);
+
+ /* set T1 or E1 line. Uses sc->lmcmii16 reg in function so update it */
+ sc->lmc_miireg16 = mii16;
+ lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ mii16 = sc->lmc_miireg16;
+
+ lmc_t1_write (sc, 0x01, 0x1B); /* CR0 - primary control */
+ lmc_t1_write (sc, 0x02, 0x42); /* JAT_CR - jitter atten config */
+ lmc_t1_write (sc, 0x14, 0x00); /* LOOP - loopback config */
+ lmc_t1_write (sc, 0x15, 0x00); /* DL3_TS - external data link timeslot */
+ lmc_t1_write (sc, 0x18, 0xFF); /* PIO - programmable I/O */
+ lmc_t1_write (sc, 0x19, 0x30); /* POE - programmable OE */
+ lmc_t1_write (sc, 0x1A, 0x0F); /* CMUX - clock input mux */
+ lmc_t1_write (sc, 0x20, 0x41); /* LIU_CR - RX LIU config */
+ lmc_t1_write (sc, 0x22, 0x76); /* RLIU_CR - RX LIU config */
+ lmc_t1_write (sc, 0x40, 0x03); /* RCR0 - RX config */
+ lmc_t1_write (sc, 0x45, 0x00); /* RALM - RX alarm config */
+ lmc_t1_write (sc, 0x46, 0x05); /* LATCH - RX alarm/err/cntr latch */
+ lmc_t1_write (sc, 0x68, 0x40); /* TLIU_CR - TX LIU config */
+ lmc_t1_write (sc, 0x70, 0x0D); /* TCR0 - TX framer config */
+ lmc_t1_write (sc, 0x71, 0x05); /* TCR1 - TX config */
+ lmc_t1_write (sc, 0x72, 0x0B); /* TFRM - TX frame format */
+ lmc_t1_write (sc, 0x73, 0x00); /* TERROR - TX error insert */
+ lmc_t1_write (sc, 0x74, 0x00); /* TMAN - TX manual Sa/FEBE config */
+ lmc_t1_write (sc, 0x75, 0x00); /* TALM - TX alarm signal config */
+ lmc_t1_write (sc, 0x76, 0x00); /* TPATT - TX test pattern config */
+ lmc_t1_write (sc, 0x77, 0x00); /* TLB - TX inband loopback config */
+ lmc_t1_write (sc, 0x90, 0x05); /* CLAD_CR - clock rate adapter config */
+ lmc_t1_write (sc, 0x91, 0x05); /* CSEL - clad freq sel */
+ lmc_t1_write (sc, 0xA6, 0x00); /* DL1_CTL - DL1 control */
+ lmc_t1_write (sc, 0xB1, 0x00); /* DL2_CTL - DL2 control */
+ lmc_t1_write (sc, 0xD0, 0x47); /* SBI_CR - sys bus iface config */
+ lmc_t1_write (sc, 0xD1, 0x70); /* RSB_CR - RX sys bus config */
+ lmc_t1_write (sc, 0xD4, 0x30); /* TSB_CR - TX sys bus config */
+ for (i = 0; i < 32; i++)
+ {
+ lmc_t1_write (sc, 0x0E0 + i, 0x00); /* SBCn - sys bus per-channel ctl */
+ lmc_t1_write (sc, 0x100 + i, 0x00); /* TPCn - TX per-channel ctl */
+ lmc_t1_write (sc, 0x180 + i, 0x00); /* RPCn - RX per-channel ctl */
+ }
+ for (i = 1; i < 25; i++)
+ {
+ lmc_t1_write (sc, 0x0E0 + i, 0x0D); /* SBCn - sys bus per-channel ctl */
+ }
+
+ mii16 |= LMC_MII16_T1_XOE;
+ lmc_mii_writereg (sc, 0, 16, mii16);
+ sc->lmc_miireg16 = mii16;
+}
+
+static void
+lmc_t1_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+ /* Right now we can only clock from out internal source */
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+}
+/* * Given a user provided state, set ourselves up to match it. This will * always reset the card if needed.
+ */
+static void
+lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_circuit_type (sc, sc->ictl.circuit_type);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+ /*
+ * check for change in circuit type */
+ if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_T1
+ && sc->ictl.circuit_type ==
+ LMC_CTL_CIRCUIT_TYPE_E1) sc->lmc_media->set_circuit_type (sc,
+ LMC_CTL_CIRCUIT_TYPE_E1);
+ else if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_E1
+ && sc->ictl.circuit_type == LMC_CTL_CIRCUIT_TYPE_T1)
+ sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ lmc_set_protocol (sc, ctl);
+}
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */ static int
+lmc_t1_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status;
+ int ret = 1;
+
+ /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+ * led0 yellow = far-end adapter is in Red alarm condition
+ * led1 blue = received an Alarm Indication signal
+ * (upstream failure)
+ * led2 Green = power to adapter, Gate Array loaded & driver
+ * attached
+ * led3 red = Loss of Signal (LOS) or out of frame (OOF)
+ * conditions detected on T3 receive signal
+ */
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in");
+ lmc_led_on(sc, LMC_DS3_LED2);
+
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+
+ if (link_status & T1F_RAIS) { /* turn on blue LED */
+ ret = 0;
+ if(sc->last_led_err[1] != 1){
+ printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 1;
+ }
+ else {
+ if(sc->last_led_err[1] != 0){
+ printk(KERN_WARNING "%s: End AIS/Blue Alarm\n", sc->name);
+ }
+ lmc_led_off (sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 0;
+ }
+
+ /*
+ * Yellow Alarm is nasty evil stuff, looks at data patterns
+ * inside the channel and confuses it with HDLC framing
+ * ignore all yellow alarms.
+ *
+ * Do listen to MultiFrame Yellow alarm which while implemented
+ * different ways isn't in the channel and hence somewhat
+ * more reliable
+ */
+
+ if (link_status & T1F_RMYEL) {
+ ret = 0;
+ if(sc->last_led_err[0] != 1){
+ printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 1;
+ }
+ else {
+ if(sc->last_led_err[0] != 0){
+ printk(KERN_WARNING "%s: End of Yellow AIS Alarm\n", sc->name);
+ }
+ lmc_led_off(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 0;
+ }
+
+ /*
+ * Loss of signal and los of frame
+ * Use the green bit to identify which one lit the led
+ */
+ if(link_status & T1F_RLOF){
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3);
+ sc->last_led_err[3] = 1;
+
+ }
+ else {
+ if(sc->last_led_err[3] != 0){
+ printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name);
+ }
+ if( ! (link_status & T1F_RLOS))
+ lmc_led_off(sc, LMC_DS3_LED3);
+ sc->last_led_err[3] = 0;
+ }
+
+ if(link_status & T1F_RLOS){
+ ret = 0;
+ if(sc->last_led_err[2] != 1){
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3);
+ sc->last_led_err[2] = 1;
+
+ }
+ else {
+ if(sc->last_led_err[2] != 0){
+ printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name);
+ }
+ if( ! (link_status & T1F_RLOF))
+ lmc_led_off(sc, LMC_DS3_LED3);
+ sc->last_led_err[2] = 0;
+ }
+
+ sc->lmc_xinfo.t1_alarm1_status = link_status;
+
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS);
+ sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18);
+
+
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out");
+
+ return ret;
+}
+
+/*
+ * 1 == T1 Circuit Type , 0 == E1 Circuit Type
+ */
+static void
+lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_CIRCUIT_TYPE_T1) {
+ sc->lmc_miireg16 |= LMC_MII16_T1_Z;
+ sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1;
+ printk(KERN_INFO "%s: In T1 Mode\n", sc->name);
+ }
+ else {
+ sc->lmc_miireg16 &= ~LMC_MII16_T1_Z;
+ sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1;
+ printk(KERN_INFO "%s: In E1 Mode\n", sc->name);
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit */
+static void
+lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_T1_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+ }
+ else
+ {
+ /* 16 bit */ sc->lmc_miireg16 &= ~LMC_MII16_T1_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_t1_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = ie;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+static void
+lmc_t1_watchdog (lmc_softc_t * const sc)
+{
+}
+
+static void
+lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == 0)
+ {
+ sc->ictl.keepalive_onoff = LMC_CTL_ON;
+
+ return;
+ }
+}
diff --git a/drivers/net/wan/lmc/lmc_media.h b/drivers/net/wan/lmc/lmc_media.h
new file mode 100644
index 000000000..7cc6c1650
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_media.h
@@ -0,0 +1,64 @@
+#ifndef _LMC_MEDIA_H_
+#define _LMC_MEDIA_H_
+
+lmc_media_t lmc_ds3_media = {
+ lmc_ds3_init, /* special media init stuff */
+ lmc_ds3_default, /* reset to default state */
+ lmc_ds3_set_status, /* reset status to state provided */
+ lmc_dummy_set_1, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_ds3_set_100ft, /* set cable length */
+ lmc_ds3_set_scram, /* set scrambler */
+ lmc_ds3_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_ds3_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+ lmc_hssi_init, /* special media init stuff */
+ lmc_hssi_default, /* reset to default state */
+ lmc_hssi_set_status, /* reset status to state provided */
+ lmc_hssi_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_hssi_get_link_status, /* get link status */
+ lmc_hssi_set_link_status, /* set link status */
+ lmc_hssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
+ lmc_ssi_default, /* reset to default state */
+ lmc_ssi_set_status, /* reset status to state provided */
+ lmc_ssi_set_clock, /* set clock source */
+ lmc_ssi_set_speed, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_ssi_get_link_status, /* get link status */
+ lmc_ssi_set_link_status, /* set link status */
+ lmc_ssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+ lmc_t1_init, /* special media init stuff */
+ lmc_t1_default, /* reset to default state */
+ lmc_t1_set_status, /* reset status to state provided */
+ lmc_t1_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_t1_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_t1_set_crc_length, /* set CRC length */
+ lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+ lmc_t1_watchdog
+};
+
+
+#endif \ No newline at end of file
diff --git a/drivers/net/wan/lmc/lmc_prot.h b/drivers/net/wan/lmc/lmc_prot.h
new file mode 100644
index 000000000..859ef0f00
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_prot.h
@@ -0,0 +1,14 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t * const)
+void lmc_proto_attach(lmc_softc_t *sc const)
+void lmc_proto_detach(lmc_softc *sc const)
+void lmc_proto_reopen(lmc_softc_t *sc const)
+int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd)
+void lmc_proto_open(lmc_softc_t *sc const)
+void lmc_proto_close(lmc_softc_t *sc const)
+unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb)
+
+
+#endif \ No newline at end of file
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
new file mode 100644
index 000000000..c15104f6a
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -0,0 +1,270 @@
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * With Help By:
+ * David Boggs
+ * Ron Crane
+ * Allan Cox
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ *
+ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_debug.h"
+#include "lmc_ioctl.h"
+#include "lmc_proto.h"
+//#include "lmc_proto_raw.h"
+
+/*
+ * The compile-time variable SPPPSTUP causes the module to be
+ * compiled without referencing any of the sync ppp routines.
+ */
+#ifdef SPPPSTUB
+#define SYNC_PPP_init() (void)0
+#define SPPP_detach(d) (void)0
+#define SPPP_open(d) 0
+#define SPPP_reopen(d) (void)0
+#define SPPP_close(d) (void)0
+#define SPPP_attach(d) (void)0
+#define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP
+#else
+#if LINUX_VERSION_CODE < 0x20363
+#define SYNC_PPP_init sync_ppp_init
+#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device)
+#define SPPP_detach(x) sppp_detach((x)->lmc_device)
+#define SPPP_open(x) sppp_open((x)->lmc_device)
+#define SPPP_reopen(x) sppp_reopen((x)->lmc_device)
+#define SPPP_close(x) sppp_close((x)->lmc_device)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z))
+#else
+#define SYNC_PPP_init sync_ppp_init
+#define SPPP_attach(x) sppp_attach((x)->pd)
+#define SPPP_detach(x) sppp_detach((x)->pd->dev)
+#define SPPP_open(x) sppp_open((x)->pd->dev)
+#define SPPP_reopen(x) sppp_reopen((x)->pd->dev)
+#define SPPP_close(x) sppp_close((x)->pd->dev)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z))
+#endif
+#endif
+
+static int lmc_first_ppp_load = 0;
+
+// init
+void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_init in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ if(lmc_first_ppp_load == 0)
+#ifndef MODULE
+ SYNC_PPP_init();
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20363
+ sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+ sc->pd->dev = sc->lmc_device;
+#endif
+ sc->if_ptr = sc->pd;
+ break;
+ case LMC_RAW:
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_init out");
+}
+
+// attach
+void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_attach in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ {
+ struct net_device *dev = sc->lmc_device;
+ SPPP_attach(sc);
+ dev->do_ioctl = lmc_ioctl;
+ }
+ break;
+ case LMC_NET:
+ {
+ struct net_device *dev = sc->lmc_device;
+ /*
+ * They set a few basics because they don't use sync_ppp
+ */
+ dev->flags |= IFF_POINTOPOINT;
+ dev->hard_header = 0;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ }
+ case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */
+ {
+ }
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_attach out");
+}
+
+// detach
+void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/
+{
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_detach(sc);
+ break;
+ case LMC_RAW: /* Tell someone we're detaching? */
+ break;
+ default:
+ break;
+ }
+
+}
+
+// reopen
+void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_reopen(sc);
+ break;
+ case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen out");
+}
+
+
+// ioctl
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return SPPP_do_ioctl (sc, ifr, cmd);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+}
+
+// open
+void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/
+{
+ int ret;
+
+ lmc_trace(sc->lmc_device, "lmc_proto_open in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ ret = SPPP_open(sc);
+ if(ret < 0)
+ printk("%s: syncPPP open failed: %d\n", sc->name, ret);
+ break;
+ case LMC_RAW: /* We're about to start getting packets! */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_open out");
+}
+
+// close
+
+void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_close in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_close(sc);
+ break;
+ case LMC_RAW: /* Interface going down */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_close out");
+}
+
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_type in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return htons(ETH_P_WAN_PPP);
+ break;
+ case LMC_NET:
+ return htons(ETH_P_802_2);
+ break;
+ case LMC_RAW: /* Packet type for skbuff kind of useless */
+ return htons(ETH_P_802_2);
+ break;
+ default:
+ printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name);
+ return htons(ETH_P_802_2);
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_tye out");
+
+}
+
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_netif in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ case LMC_NET:
+ default:
+ netif_rx(skb);
+ break;
+ case LMC_RAW:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_netif out");
+}
+
diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h
new file mode 100644
index 000000000..6136dfad7
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_proto.h
@@ -0,0 +1,15 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t *sc);
+void lmc_proto_attach(lmc_softc_t *sc);
+void lmc_proto_detach(lmc_softc_t *sc);
+void lmc_proto_reopen(lmc_softc_t *sc);
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd);
+void lmc_proto_open(lmc_softc_t *sc);
+void lmc_proto_close(lmc_softc_t *sc);
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb);
+int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused);
+
+#endif \ No newline at end of file
diff --git a/drivers/net/wan/lmc/lmc_proto_raw.h b/drivers/net/wan/lmc/lmc_proto_raw.h
new file mode 100644
index 000000000..c07c0b330
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_proto_raw.h
@@ -0,0 +1,4 @@
+#ifndef _LMC_PROTO_RAW_H_
+#define _LMC_PROTO_RAW_H_
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h
new file mode 100644
index 000000000..67215b93b
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_var.h
@@ -0,0 +1,590 @@
+#ifndef _LMC_VAR_H_
+#define _LMC_VAR_H_
+
+/* $Id: lmc_var.h,v 1.17 2000/04/06 12:16:47 asj Exp $ */
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ */
+
+#include <linux/timer.h>
+
+#ifndef __KERNEL__
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+#endif
+
+/*
+ * basic definitions used in lmc include files
+ */
+
+typedef struct lmc___softc lmc_softc_t;
+typedef struct lmc___media lmc_media_t;
+typedef struct lmc___ctl lmc_ctl_t;
+
+#define lmc_csrptr_t unsigned long
+#define u_int16_t u16
+#define u_int8_t u8
+#define tulip_uint32_t u32
+#if LINUX_VERSION_CODE < 0x20155
+#define u_int32_t u32
+#endif
+
+#define LMC_REG_RANGE 0x80
+
+#define LMC_PRINTF_FMT "%s"
+#define LMC_PRINTF_ARGS (sc->lmc_device->name)
+
+#define TX_TIMEOUT (2*HZ)
+
+#define LMC_TXDESCS 32
+#define LMC_RXDESCS 32
+
+#define LMC_LINK_UP 1
+#define LMC_LINK_DOWN 0
+
+/* These macros for generic read and write to and from the dec chip */
+#define LMC_CSR_READ(sc, csr) \
+ inl((sc)->lmc_csrs.csr)
+#define LMC_CSR_WRITE(sc, reg, val) \
+ outl((val), (sc)->lmc_csrs.reg)
+
+//#ifdef _LINUX_DELAY_H
+// #define SLOW_DOWN_IO udelay(2);
+// #undef __SLOW_DOWN_IO
+// #define __SLOW_DOWN_IO udelay(2);
+//#endif
+
+#define DELAY(n) SLOW_DOWN_IO
+
+#define lmc_delay() inl(sc->lmc_csrs.csr_9)
+
+/* This macro sync's up with the mii so that reads and writes can take place */
+#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \
+ LMC_CSR_WRITE((sc), csr_9, 0x20000); \
+ lmc_delay(); \
+ LMC_CSR_WRITE((sc), csr_9, 0x30000); \
+ lmc_delay(); \
+ n--; }} while(0);
+
+struct lmc_regfile_t {
+ lmc_csrptr_t csr_busmode; /* CSR0 */
+ lmc_csrptr_t csr_txpoll; /* CSR1 */
+ lmc_csrptr_t csr_rxpoll; /* CSR2 */
+ lmc_csrptr_t csr_rxlist; /* CSR3 */
+ lmc_csrptr_t csr_txlist; /* CSR4 */
+ lmc_csrptr_t csr_status; /* CSR5 */
+ lmc_csrptr_t csr_command; /* CSR6 */
+ lmc_csrptr_t csr_intr; /* CSR7 */
+ lmc_csrptr_t csr_missed_frames; /* CSR8 */
+ lmc_csrptr_t csr_9; /* CSR9 */
+ lmc_csrptr_t csr_10; /* CSR10 */
+ lmc_csrptr_t csr_11; /* CSR11 */
+ lmc_csrptr_t csr_12; /* CSR12 */
+ lmc_csrptr_t csr_13; /* CSR13 */
+ lmc_csrptr_t csr_14; /* CSR14 */
+ lmc_csrptr_t csr_15; /* CSR15 */
+};
+
+#define csr_enetrom csr_9 /* 21040 */
+#define csr_reserved csr_10 /* 21040 */
+#define csr_full_duplex csr_11 /* 21040 */
+#define csr_bootrom csr_10 /* 21041/21140A/?? */
+#define csr_gp csr_12 /* 21140* */
+#define csr_watchdog csr_15 /* 21140* */
+#define csr_gp_timer csr_11 /* 21041/21140* */
+#define csr_srom_mii csr_9 /* 21041/21140* */
+#define csr_sia_status csr_12 /* 2104x */
+#define csr_sia_connectivity csr_13 /* 2104x */
+#define csr_sia_tx_rx csr_14 /* 2104x */
+#define csr_sia_general csr_15 /* 2104x */
+
+/* tulip length/control transmit descriptor definitions
+ * used to define bits in the second tulip_desc_t field (length)
+ * for the transmit descriptor -baz */
+
+#define LMC_TDES_FIRST_BUFFER_SIZE ((u_int32_t)(0x000007FF))
+#define LMC_TDES_SECOND_BUFFER_SIZE ((u_int32_t)(0x003FF800))
+#define LMC_TDES_HASH_FILTERING ((u_int32_t)(0x00400000))
+#define LMC_TDES_DISABLE_PADDING ((u_int32_t)(0x00800000))
+#define LMC_TDES_SECOND_ADDR_CHAINED ((u_int32_t)(0x01000000))
+#define LMC_TDES_END_OF_RING ((u_int32_t)(0x02000000))
+#define LMC_TDES_ADD_CRC_DISABLE ((u_int32_t)(0x04000000))
+#define LMC_TDES_SETUP_PACKET ((u_int32_t)(0x08000000))
+#define LMC_TDES_INVERSE_FILTERING ((u_int32_t)(0x10000000))
+#define LMC_TDES_FIRST_SEGMENT ((u_int32_t)(0x20000000))
+#define LMC_TDES_LAST_SEGMENT ((u_int32_t)(0x40000000))
+#define LMC_TDES_INTERRUPT_ON_COMPLETION ((u_int32_t)(0x80000000))
+
+#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER 11
+#define TDES_COLLISION_COUNT_BIT_NUMBER 3
+
+/* Constants for the RCV descriptor RDES */
+
+#define LMC_RDES_OVERFLOW ((u_int32_t)(0x00000001))
+#define LMC_RDES_CRC_ERROR ((u_int32_t)(0x00000002))
+#define LMC_RDES_DRIBBLING_BIT ((u_int32_t)(0x00000004))
+#define LMC_RDES_REPORT_ON_MII_ERR ((u_int32_t)(0x00000008))
+#define LMC_RDES_RCV_WATCHDOG_TIMEOUT ((u_int32_t)(0x00000010))
+#define LMC_RDES_FRAME_TYPE ((u_int32_t)(0x00000020))
+#define LMC_RDES_COLLISION_SEEN ((u_int32_t)(0x00000040))
+#define LMC_RDES_FRAME_TOO_LONG ((u_int32_t)(0x00000080))
+#define LMC_RDES_LAST_DESCRIPTOR ((u_int32_t)(0x00000100))
+#define LMC_RDES_FIRST_DESCRIPTOR ((u_int32_t)(0x00000200))
+#define LMC_RDES_MULTICAST_FRAME ((u_int32_t)(0x00000400))
+#define LMC_RDES_RUNT_FRAME ((u_int32_t)(0x00000800))
+#define LMC_RDES_DATA_TYPE ((u_int32_t)(0x00003000))
+#define LMC_RDES_LENGTH_ERROR ((u_int32_t)(0x00004000))
+#define LMC_RDES_ERROR_SUMMARY ((u_int32_t)(0x00008000))
+#define LMC_RDES_FRAME_LENGTH ((u_int32_t)(0x3FFF0000))
+#define LMC_RDES_OWN_BIT ((u_int32_t)(0x80000000))
+
+#define RDES_FRAME_LENGTH_BIT_NUMBER 16
+
+#define LMC_RDES_ERROR_MASK ( (u_int32_t)( \
+ LMC_RDES_OVERFLOW \
+ | LMC_RDES_DRIBBLING_BIT \
+ | LMC_RDES_REPORT_ON_MII_ERR \
+ | LMC_RDES_COLLISION_SEEN ) )
+
+
+/*
+ * Ioctl info
+ */
+
+typedef struct {
+ u_int32_t n;
+ u_int32_t m;
+ u_int32_t v;
+ u_int32_t x;
+ u_int32_t r;
+ u_int32_t f;
+ u_int32_t exact;
+} lmc_av9110_t;
+
+/*
+ * Common structure passed to the ioctl code.
+ */
+struct lmc___ctl {
+ u_int32_t cardtype;
+ u_int32_t clock_source; /* HSSI, T1 */
+ u_int32_t clock_rate; /* T1 */
+ u_int32_t crc_length;
+ u_int32_t cable_length; /* DS3 */
+ u_int32_t scrambler_onoff; /* DS3 */
+ u_int32_t cable_type; /* T1 */
+ u_int32_t keepalive_onoff; /* protocol */
+ u_int32_t ticks; /* ticks/sec */
+ union {
+ lmc_av9110_t ssi;
+ } cardspec;
+ u_int32_t circuit_type; /* T1 or E1 */
+};
+
+
+/*
+ * Carefull, look at the data sheet, there's more to this
+ * structure than meets the eye. It should probably be:
+ *
+ * struct tulip_desc_t {
+ * u8 own:1;
+ * u32 status:31;
+ * u32 control:10;
+ * u32 buffer1;
+ * u32 buffer2;
+ * };
+ * You could also expand status control to provide more bit information
+ */
+
+struct tulip_desc_t {
+ s32 status;
+ s32 length;
+ u32 buffer1;
+ u32 buffer2;
+};
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+struct lmc___media {
+ void (* init)(lmc_softc_t * const);
+ void (* defaults)(lmc_softc_t * const);
+ void (* set_status)(lmc_softc_t * const, lmc_ctl_t *);
+ void (* set_clock_source)(lmc_softc_t * const, int);
+ void (* set_speed)(lmc_softc_t * const, lmc_ctl_t *);
+ void (* set_cable_length)(lmc_softc_t * const, int);
+ void (* set_scrambler)(lmc_softc_t * const, int);
+ int (* get_link_status)(lmc_softc_t * const);
+ void (* set_link_status)(lmc_softc_t * const, int);
+ void (* set_crc_length)(lmc_softc_t * const, int);
+ void (* set_circuit_type)(lmc_softc_t * const, int);
+ void (* watchdog)(lmc_softc_t * const);
+};
+
+
+#define STATCHECK 0xBEEFCAFE
+
+/* Included in this structure are first
+ * - standard enet_statistics
+ * - some other counters used for debug and driver performance
+ * evaluation -baz
+ */
+struct lmc_statistics
+{
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long multicast; /* multicast packets received */
+ unsigned long collisions;
+
+ /* detailed rx_errors: */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
+
+ /* for cslip etc */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
+
+ /* -------------------------------------
+ * Custom stats & counters follow -baz */
+ u_int32_t version_size;
+ u_int32_t lmc_cardtype;
+
+ u_int32_t tx_ProcTimeout;
+ u_int32_t tx_IntTimeout;
+ u_int32_t tx_NoCompleteCnt;
+ u_int32_t tx_MaxXmtsB4Int;
+ u_int32_t tx_TimeoutCnt;
+ u_int32_t tx_OutOfSyncPtr;
+ u_int32_t tx_tbusy0;
+ u_int32_t tx_tbusy1;
+ u_int32_t tx_tbusy_calls;
+ u_int32_t resetCount;
+ u_int32_t lmc_txfull;
+ u_int32_t tbusy;
+ u_int32_t dirtyTx;
+ u_int32_t lmc_next_tx;
+ u_int32_t otherTypeCnt;
+ u_int32_t lastType;
+ u_int32_t lastTypeOK;
+ u_int32_t txLoopCnt;
+ u_int32_t usedXmtDescripCnt;
+ u_int32_t txIndexCnt;
+ u_int32_t rxIntLoopCnt;
+
+ u_int32_t rx_SmallPktCnt;
+ u_int32_t rx_BadPktSurgeCnt;
+ u_int32_t rx_BuffAllocErr;
+ u_int32_t tx_lossOfClockCnt;
+
+ /* T1 error counters */
+ u_int32_t framingBitErrorCount;
+ u_int32_t lineCodeViolationCount;
+
+ u_int32_t lossOfFrameCount;
+ u_int32_t changeOfFrameAlignmentCount;
+ u_int32_t severelyErroredFrameCount;
+
+ u_int32_t check;
+};
+
+
+typedef struct lmc_xinfo {
+ u_int32_t Magic0; /* BEEFCAFE */
+
+ u_int32_t PciCardType;
+ u_int32_t PciSlotNumber; /* PCI slot number */
+
+ u_int16_t DriverMajorVersion;
+ u_int16_t DriverMinorVersion;
+ u_int16_t DriverSubVersion;
+
+ u_int16_t XilinxRevisionNumber;
+ u_int16_t MaxFrameSize;
+
+ u_int16_t t1_alarm1_status;
+ u_int16_t t1_alarm2_status;
+
+ int link_status;
+ u_int32_t mii_reg16;
+
+ u_int32_t Magic1; /* DEADBEEF */
+} LMC_XINFO;
+
+
+/*
+ * forward decl
+ */
+struct lmc___softc {
+ void *if_ptr; /* General purpose pointer (used by SPPP) */
+ char *name;
+ u8 board_idx;
+ struct lmc_statistics stats;
+ struct net_device *lmc_device;
+
+ int hang, rxdesc, bad_packet, some_counter;
+ u_int32_t txgo;
+ struct lmc_regfile_t lmc_csrs;
+ volatile u_int32_t lmc_txtick;
+ volatile u_int32_t lmc_rxtick;
+ u_int32_t lmc_flags;
+ u_int32_t lmc_intrmask; /* our copy of csr_intr */
+ u_int32_t lmc_cmdmode; /* our copy of csr_cmdmode */
+ u_int32_t lmc_busmode; /* our copy of csr_busmode */
+ u_int32_t lmc_gpio_io; /* state of in/out settings */
+ u_int32_t lmc_gpio; /* state of outputs */
+ struct sk_buff* lmc_txq[LMC_TXDESCS];
+ struct sk_buff* lmc_rxq[LMC_RXDESCS];
+ volatile
+ struct tulip_desc_t lmc_rxring[LMC_RXDESCS];
+ volatile
+ struct tulip_desc_t lmc_txring[LMC_TXDESCS];
+ unsigned int lmc_next_rx, lmc_next_tx;
+ volatile
+ unsigned int lmc_taint_tx, lmc_taint_rx;
+ int lmc_tx_start, lmc_txfull;
+ int lmc_txbusy;
+ u_int16_t lmc_miireg16;
+ int lmc_ok;
+ int last_link_status;
+ int lmc_cardtype;
+ u_int32_t last_frameerr;
+ lmc_media_t *lmc_media;
+ struct timer_list timer;
+ lmc_ctl_t ictl;
+ u_int32_t TxDescriptControlInit;
+ struct net_device *next_module; /* Link to the next module */
+ int tx_TimeoutInd; /* additional driver state */
+ int tx_TimeoutDisplay;
+ unsigned int lastlmc_taint_tx;
+ int lasttx_packets;
+ u_int32_t tx_clockState;
+ u_int32_t lmc_crcSize;
+ LMC_XINFO lmc_xinfo;
+ char lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */
+ char lmc_timing; /* for HSSI and SSI */
+ int got_irq;
+
+ char last_led_err[4];
+
+ u32 last_int;
+ u32 num_int;
+
+#if LINUX_VERSION_CODE >= 0x20200
+ spinlock_t lmc_lock;
+#endif
+ u_int16_t if_type; /* PPP or NET */
+ struct ppp_device *pd;
+
+ /* Failure cases */
+ u8 failed_ring;
+ u8 failed_recv_alloc;
+
+ /* Structure check */
+ u32 check;
+};
+
+#define LMC_PCI_TIME 1
+#define LMC_EXT_TIME 0
+
+#define PKT_BUF_SZ 1542 /* was 1536 */
+
+/* CSR5 settings */
+#define TIMER_INT 0x00000800
+#define TP_LINK_FAIL 0x00001000
+#define TP_LINK_PASS 0x00000010
+#define NORMAL_INT 0x00010000
+#define ABNORMAL_INT 0x00008000
+#define RX_JABBER_INT 0x00000200
+#define RX_DIED 0x00000100
+#define RX_NOBUFF 0x00000080
+#define RX_INT 0x00000040
+#define TX_FIFO_UNDER 0x00000020
+#define TX_JABBER 0x00000008
+#define TX_NOBUFF 0x00000004
+#define TX_DIED 0x00000002
+#define TX_INT 0x00000001
+
+/* CSR6 settings */
+#define OPERATION_MODE 0x00000200 /* Full Duplex */
+#define PROMISC_MODE 0x00000040 /* Promiscuous Mode */
+#define RECIEVE_ALL 0x40000000 /* Recieve All */
+#define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames */
+
+/* Dec control registers CSR6 as well */
+#define LMC_DEC_ST 0x00002000
+#define LMC_DEC_SR 0x00000002
+
+/* CSR15 settings */
+#define RECV_WATCHDOG_DISABLE 0x00000010
+#define JABBER_DISABLE 0x00000001
+
+/* More settings */
+/*
+ * aSR6 -- Command (Operation Mode) Register
+ */
+#define TULIP_CMD_RECEIVEALL 0x40000000L /* (RW) Receivel all frames? */
+#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */
+#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */
+#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */
+#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */
+#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */
+#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */
+#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */
+#define TULIP_CMD_PROMISCUOUS 0x00000041L /* (RW) Promiscuous Mode */
+#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */
+#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */
+
+#define TULIP_GP_PINSET 0x00000100L
+#define TULIP_BUSMODE_SWRESET 0x00000001L
+#define TULIP_WATCHDOG_TXDISABLE 0x00000001L
+#define TULIP_WATCHDOG_RXDISABLE 0x00000010L
+
+#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */
+#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */
+#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interupt */
+#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */
+#define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */
+#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interupt */
+#define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */
+#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */
+#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */
+#define TULIP_STS_TXJABER 0x00000008L /* (RW) Jabber timeout */
+#define TULIP_STS_TXNOBUF 0x00000004L
+#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */
+#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */
+
+#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */
+
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L
+
+#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */
+#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */
+#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */
+#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = 21040) */
+#define TULIP_DSTS_RxMIIERR 0x00000008
+#define LMC_DSTS_ERRSUM (TULIP_DSTS_RxMIIERR)
+
+#define TULIP_DEFAULT_INTR_MASK (TULIP_STS_NORMALINTR \
+ | TULIP_STS_RXINTR \
+ | TULIP_STS_TXINTR \
+ | TULIP_STS_ABNRMLINTR \
+ | TULIP_STS_SYSERROR \
+ | TULIP_STS_TXSTOPPED \
+ | TULIP_STS_TXUNDERFLOW\
+ | TULIP_STS_RXSTOPPED )
+
+#define DESC_OWNED_BY_SYSTEM ((u_int32_t)(0x00000000))
+#define DESC_OWNED_BY_DC21X4 ((u_int32_t)(0x80000000))
+
+#ifndef TULIP_CMD_RECEIVEALL
+#define TULIP_CMD_RECEIVEALL 0x40000000L
+#endif
+
+
+/* PCI register values */
+#define CORRECT_VENDOR_ID 0x1011
+#define CORRECT_DEV_ID 9
+
+#define PCI_VENDOR_LMC 0x1376
+#define PCI_PRODUCT_LMC_HSSI 0x0003
+#define PCI_PRODUCT_LMC_DS3 0x0004
+#define PCI_PRODUCT_LMC_SSI 0x0005
+#define PCI_PRODUCT_LMC_T1 0x0006
+
+/* Adapcter module number */
+#define LMC_ADAP_HSSI 2
+#define LMC_ADAP_DS3 3
+#define LMC_ADAP_SSI 4
+#define LMC_ADAP_T1 5
+
+#define HDLC_HDR_LEN 4
+#define HDLC_ADDR_LEN 1
+#define HDLC_SLARP 0x8035
+#define LMC_MTU 1500
+#define SLARP_LINECHECK 2
+
+#define LMC_CRC_LEN_16 2 /* 16-bit CRC */
+#define LMC_CRC_LEN_32 4
+
+#if LINUX_VERSION_CODE < 0x20100
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+#ifdef LMC_HDLC
+/* definition of an hdlc header. */
+struct hdlc_hdr
+{
+ u8 address;
+ u8 control;
+ u16 type;
+};
+
+/* definition of a slarp header. */
+struct slarp
+{
+ long code;
+ union sl
+ {
+ struct
+ {
+ ulong address;
+ ulong mask;
+ ushort unused;
+ } add;
+ struct
+ {
+ ulong mysequence;
+ ulong yoursequence;
+ ushort reliability;
+ ulong time;
+ } chk;
+ } t;
+};
+#endif /* LMC_HDLC */
+
+
+#endif /* _LMC_VAR_H_ */
diff --git a/drivers/net/wan/lmc/lmc_ver.h b/drivers/net/wan/lmc/lmc_ver.h
new file mode 100644
index 000000000..1f3826617
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_ver.h
@@ -0,0 +1,123 @@
+#ifndef _IF_LMC_LINUXVER_
+#define _IF_LMC_LINUXVER_
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License version 2, incorporated herein by reference.
+ */
+
+ /*
+ * This file defines and controls all linux version
+ * differences.
+ *
+ * This is being done to keep 1 central location where all linux
+ * version differences can be kept and maintained. as this code was
+ * found version issues where pepered throughout the source code and
+ * made the souce code not only hard to read but version problems hard
+ * to track down. If I'm overiding a function/etc with something in
+ * this file it will be prefixed by "LMC_" which will mean look
+ * here for the the version dependant change that's been done.
+ *
+ */
+
+#if LINUX_VERSION_CODE < 0x20363
+#define net_device device
+#endif
+
+#if LINUX_VERSION_CODE < 0x20363
+#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1
+#define LMC_XMITTER_FREE(x) (x)->tbusy = 0
+#define LMC_XMITTER_INIT(x) (x)->tbusy = 0
+#else
+#define LMC_XMITTER_BUSY(x) netif_stop_queue(x)
+#define LMC_XMITTER_FREE(x) netif_wake_queue(x)
+#define LMC_XMITTER_INIT(x) netif_start_queue(x)
+
+#endif
+
+
+#if LINUX_VERSION_CODE < 0x20100
+//typedef unsigned int u_int32_t;
+
+#define LMC_SETUP_20_DEV {\
+ int indx; \
+ for (indx = 0; indx < DEV_NUMBUFFS; indx++) \
+ skb_queue_head_init (&dev->buffs[indx]); \
+ } \
+ dev->family = AF_INET; \
+ dev->pa_addr = 0; \
+ dev->pa_brdaddr = 0; \
+ dev->pa_mask = 0xFCFFFFFF; \
+ dev->pa_alen = 4; /* IP addr. sizeof(u32) */
+
+#else
+
+#define LMC_SETUP_20_DEV
+
+#endif
+
+
+#if LINUX_VERSION_CODE < 0x20155 /* basically 2.2 plus */
+
+#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb((skb), FREE_WRITE)
+#define LMC_PCI_PRESENT() pcibios_present()
+
+#else /* Mostly 2.0 kernels */
+
+#define LMC_DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define LMC_PCI_PRESENT() pci_present()
+
+#endif
+
+#if LINUX_VERSION_CODE < 0x20200
+#else
+
+#endif
+
+#if LINUX_VERSION_CODE < 0x20100
+#define LMC_SKB_FREE(skb, val) (skb->free = val)
+#else
+#define LMC_SKB_FREE(skb, val)
+#endif
+
+
+#if (LINUX_VERSION_CODE >= 0x20200)
+
+#define LMC_SPIN_FLAGS unsigned long flags;
+#define LMC_SPIN_LOCK_INIT(x) spin_lock_init(&(x)->lmc_lock);
+#define LMC_SPIN_UNLOCK(x) ((x)->lmc_lock = SPIN_LOCK_UNLOCKED)
+#define LMC_SPIN_LOCK_IRQSAVE(x) spin_lock_irqsave (&(x)->lmc_lock, flags);
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags);
+#else
+#define LMC_SPIN_FLAGS
+#define LMC_SPIN_LOCK_INIT(x)
+#define LMC_SPIN_UNLOCK(x)
+#define LMC_SPIN_LOCK_IRQSAVE(x)
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x)
+#endif
+
+
+#if LINUX_VERSION_CODE >= 0x20100
+#define LMC_COPY_FROM_USER(x, y, z) if(copy_from_user ((x), (y), (z))) return -EFAULT
+#define LMC_COPY_TO_USER(x, y, z) if(copy_to_user ((x), (y), (z))) return -EFAULT
+#else
+#define LMC_COPY_FROM_USER(x, y, z) if(verify_area(VERIFY_READ, (y), (z))) \
+ return -EFAULT; \
+ memcpy_fromfs ((x), (y), (z))
+
+#define LMC_COPY_TO_USER(x, y, z) if(verify_area(VERIFY_WRITE, (x), (z))) \
+ return -EFAULT; \
+ memcpy_tofs ((x), (y), (z))
+#endif
+
+
+#endif
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
index 4bc7762cb..62881254e 100644
--- a/drivers/net/wan/sdla_chdlc.c
+++ b/drivers/net/wan/sdla_chdlc.c
@@ -22,6 +22,7 @@
* Aug 07, 1998 David Fong Initial version.
*****************************************************************************/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
@@ -2762,7 +2763,7 @@ static void port_set_state (sdla_t *card, int state)
void s508_lock (sdla_t *card, unsigned long *smp_flags)
{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_lock_irqsave(&card->lock, *smp_flags);
if (card->next){
spin_lock(&card->next->lock);
@@ -2774,7 +2775,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags)
void s508_unlock (sdla_t *card, unsigned long *smp_flags)
{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
if (card->next){
spin_unlock(&card->next->lock);
}
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
index 14257cc85..d7a246dd9 100644
--- a/drivers/net/wan/sdla_fr.c
+++ b/drivers/net/wan/sdla_fr.c
@@ -109,6 +109,7 @@
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
+#include <linux/config.h>
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
@@ -3677,13 +3678,13 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
{
if (card->hw.type != SDLA_S514){
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_lock_irqsave(&card->lock, *smp_flags);
#else
disable_irq(card->hw.irq);
#endif
}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
else{
spin_lock(&card->lock);
}
@@ -3693,13 +3694,13 @@ void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
{
if (card->hw.type != SDLA_S514){
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_unlock_irqrestore(&card->lock, *smp_flags);
#else
enable_irq(card->hw.irq);
#endif
}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
else{
spin_unlock(&card->lock);
}
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
index 40134ff72..f8c8fcae2 100644
--- a/drivers/net/wan/sdla_ppp.c
+++ b/drivers/net/wan/sdla_ppp.c
@@ -74,6 +74,7 @@
* Jan 06, 1997 Gene Kozin Initial version.
*****************************************************************************/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
@@ -2896,7 +2897,7 @@ static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
void s508_lock (sdla_t *card, unsigned long *smp_flags)
{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_lock_irqsave(&card->lock, *smp_flags);
#else
disable_irq(card->hw.irq);
@@ -2905,7 +2906,7 @@ void s508_lock (sdla_t *card, unsigned long *smp_flags)
void s508_unlock (sdla_t *card, unsigned long *smp_flags)
{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_unlock_irqrestore(&card->lock, *smp_flags);
#else
enable_irq(card->hw.irq);
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c
index 06e86de82..c2396ead3 100644
--- a/drivers/net/wan/sdladrv.c
+++ b/drivers/net/wan/sdladrv.c
@@ -308,7 +308,7 @@ static unsigned char s507_irqmask[] =
#ifdef MODULE
int init_module (void)
#else
-__initfunc(int wanpipe_init(void))
+int __init wanpipe_init(void)
#endif
{
printk(KERN_INFO "%s v%u.%u %s\n",
diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
index 3565954e1..6d46b2e46 100644
--- a/drivers/net/wan/sdlamain.c
+++ b/drivers/net/wan/sdlamain.c
@@ -391,7 +391,7 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf)
if (!card->configured){
- #ifdef __SMP__
+ #ifdef CONFIG_SMP
/* Initialize the Spin lock */
printk(KERN_INFO "%s: Initializing SMP\n",wandev->name);
spin_lock_init(&card->lock);
@@ -825,13 +825,13 @@ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
/* Use spin lock only for S508 */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_lock(&card->lock);
#endif
sdla_intack(&card->hw);
if (card->isr)
card->isr(card);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
spin_unlock(&card->lock);
#endif
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 5b8504616..1ee37e20e 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -33,7 +33,7 @@
*
* Version 1.9, Wed Oct 4 18:58:15 MSK 1995
*
- * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $
+ * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $
*/
#undef DEBUG
@@ -193,7 +193,7 @@ static void sppp_clear_timeout(struct sppp *p)
*
* This can be called directly by cards that do not have
* timing constraints but is normally called from the network layer
- * after interrupt servicing to process frames queued via netif_rx.
+ * after interrupt servicing to process frames queued via netif_rx().
*
* We process the options in the card. If the frame is destined for
* the protocol stacks then it requeues the frame for the upper level
@@ -395,7 +395,7 @@ static void sppp_keepalive (unsigned long dummy)
if (sp->pp_alivecnt == MAXALIVECNT) {
/* No keepalive packets got. Stop the interface. */
- printk (KERN_WARNING "%s: down\n", dev->name);
+ printk (KERN_WARNING "%s: protocol down\n", dev->name);
if_down (dev);
if (! (sp->pp_flags & PP_CISCO)) {
/* Shut down the PPP link. */
@@ -529,7 +529,6 @@ badreq:
sppp_ipcp_open (sp);
break;
case LCP_STATE_OPENED:
-#if 0
/* Remote magic changed -- close session. */
sp->lcp.state = LCP_STATE_CLOSED;
sp->ipcp.state = IPCP_STATE_CLOSED;
@@ -537,7 +536,6 @@ badreq:
sppp_lcp_open (sp);
/* An ACK has already been sent. */
sp->lcp.state = LCP_STATE_ACK_SENT;
-#endif
break;
}
break;
@@ -549,7 +547,7 @@ badreq:
(dev->flags & IFF_UP)) {
/* Coming out of loopback mode. */
sp->pp_link_state=SPPP_LINK_UP;
- printk (KERN_INFO "%s: up\n", dev->name);
+ printk (KERN_INFO "%s: protocol up\n", dev->name);
}
switch (sp->lcp.state) {
case LCP_STATE_CLOSED:
@@ -716,7 +714,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
if (sp->pp_link_state==SPPP_LINK_DOWN &&
(dev->flags & IFF_UP)) {
sp->pp_link_state=SPPP_LINK_UP;
- printk (KERN_INFO "%s: up\n", dev->name);
+ printk (KERN_INFO "%s: protocol up\n", dev->name);
}
break;
case CISCO_ADDR_REQ:
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 7b369c004..c45e6f7ae 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -1313,12 +1313,12 @@ EXPORT_SYMBOL(z8530_shutdown);
/**
* z8530_channel_load - Load channel data
* @c: Z8530 channel to configure
- * @rtable: Table of register, value pairs
+ * @rtable: table of register, value pairs
* FIXME: ioctl to allow user uploaded tables
*
* Load a Z8530 channel up from the system data. We use +16 to
- * indicate the 'prime' registers. The value 255 terminates the
- * table
+ * indicate the "prime" registers. The value 255 terminates the
+ * table.
*/
int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index a86c83b7d..17207612d 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1418,7 +1418,6 @@ module_exit(yellowfin_cleanup);
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4