diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/net | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/net')
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 |