diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-06-01 03:16:17 +0000 |
commit | d8d9b8f76f22b7a16a83e261e64f89ee611f49df (patch) | |
tree | 3067bc130b80d52808e6390c9fc7fc087ec1e33c /drivers/net | |
parent | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (diff) |
Initial revision
Diffstat (limited to 'drivers/net')
61 files changed, 3300 insertions, 1127 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index d17ea2c93..77a5e302d 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -413,7 +413,7 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev) * Avoid timer-based retransmission conflicts. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { restore_flags(flags); printk("%s: Transmitter access conflict.\n", dev->name); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 31a64990a..d8a7b33ce 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -412,7 +412,7 @@ static int send_pcb(struct device *dev, pcb_struct * pcb) return FALSE; /* Avoid contention */ - if (set_bit(1, &adapter->send_pcb_semaphore)) { + if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { printk("%s: send_pcb entered while threaded\n", dev->name); } @@ -545,7 +545,7 @@ static int receive_pcb(struct device *dev, pcb_struct * pcb) } if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) { - if (set_bit(0, (void *) &adapter->busy)) { + if (test_and_set_bit(0, (void *) &adapter->busy)) { if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) { set_hsf(dev, HSF_PCB_NAK); printk("%s: PCB rejected, transfer in progress and backlog full\n", dev->name); @@ -621,7 +621,7 @@ static void receive_packet(struct device *dev, int len) } /* if this happens, we die */ - if (set_bit(0, (void *) &adapter->dmaing)) + if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk("%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction); skb->dev = dev; @@ -1031,7 +1031,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb) */ unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1); - if (set_bit(0, (void *) &adapter->busy)) { + if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) printk("%s: transmit blocked\n", dev->name); return FALSE; @@ -1054,7 +1054,7 @@ static int send_packet(struct device *dev, struct sk_buff *skb) return FALSE; } /* if this happens, we die */ - if (set_bit(0, (void *) &adapter->dmaing)) + if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; @@ -1119,7 +1119,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct device *dev) if (elp_debug >= 3) printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len); - if (set_bit(0, (void *) &dev->tbusy)) { + if (test_and_set_bit(0, (void *) &dev->tbusy)) { printk("%s: transmitter access conflict\n", dev->name); return 1; } diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 00038f96d..c12d6ee98 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -479,7 +479,7 @@ static int el16_send_packet(struct sk_buff *skb, struct device *dev) } /* Block a timer-based transmit from overlapping. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index d3d941d20..af1be0848 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -468,7 +468,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev) #endif #endif /* Avoid timer-based retransmission conflicts. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { lp->stats.tx_bytes+=skb->len; diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 63c6240d3..39750860e 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -1137,7 +1137,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev) return 0; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); } else { memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 69464b4e9..56541f0c2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -799,7 +799,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index b62102e7a..8de7f28b9 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -599,7 +599,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev) #ifdef OLD_METHOD dev->tbusy = 1; #else - if (set_bit (0, (void *) &dev->tbusy) != 0) { + if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { printk ("Transmitter access conflict.\n"); return -1; } diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c index 2a00c4481..cc118f7e3 100644 --- a/drivers/net/apricot.c +++ b/drivers/net/apricot.c @@ -616,7 +616,7 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index b25dd02c2..7a8069fd6 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -1588,7 +1588,7 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", ARCSTATUS,lp->intx,jiffies-dev->trans_start); diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 290b9761e..884398c53 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -593,12 +593,12 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return(1); } - if (set_bit(0, (void*)&priv->lock) != 0) { + if (test_and_set_bit(0, (void*)&priv->lock) != 0) { if (ariadne_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index bd1f93846..c75274c01 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -395,7 +395,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index bb08b8927..764416d79 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -776,12 +776,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit( 0, (void*)&dev->tbusy ) != 0) { + if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) { DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name )); return 1; } - if (set_bit( 0, (void*)&lp->lock ) != 0) { + if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name )); /* don't clear dev->tbusy flag. */ return 1; diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 411374119..997368ef4 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -437,7 +437,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 6a38177b6..66852e388 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -752,7 +752,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { struct net_local *lp = (struct net_local *)dev->priv; diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index aae249ed0..a199c7f8a 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -3,8 +3,30 @@ Copyright 1994, 1995 Digital Equipment Corporation. - This software may be used and distributed according to the terms of - the GNU Public License, incorporated herein by reference. + Testing resources for this driver have been made available + in part by NASA Ames Research Center (mjacob@nas.nasa.gov). + + The author may be reached at davies@maniac.ultranet.com. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. Originally, this driver was written for the Digital Equipment Corporation series of EtherWORKS ethernet cards: @@ -15,8 +37,8 @@ DE450 TP/COAX/AUI PCI DE500 10/100 PCI Fasternet - but it will now attempt to support all cards which conform to the - Digital Semiconductor SROM Specification. The driver currently + but it will now attempt to support all cards which conform to the + Digital Semiconductor SROM Specification. The driver currently recognises the following chips: DC21040 (no SROM) @@ -32,6 +54,7 @@ SMC8432 SMC9332 (w/new SROM) ZNYX31[45] + ZNYX346 10/100 4 port (can act as a 10/100 bridge!) The driver has been tested on a relatively busy network using the DE425, DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred @@ -48,13 +71,11 @@ measurement. Their error is +/-20k on a quiet (private) network and also depend on what load the CPU has. - The author may be reached at davies@maniac.ultranet.com. - ========================================================================= - This driver has been written substantially from scratch, although its + This driver has been written substantially from scratch, although its inheritance of style and stack interface from 'ewrk3.c' and in turn from Donald Becker's 'lance.c' should be obvious. With the module autoload of - every usable DECchip board, I pinched Donald's 'next_module' field to + every usable DECchip board, I pinched Donald's 'next_module' field to link my modules together. Upto 15 EISA cards can be supported under this driver, limited primarily @@ -80,7 +101,7 @@ 1) copy de4x5.c from the /linux/drivers/net directory to your favourite temporary directory. 2) for fixed autoprobes (not recommended), edit the source code near - line 4927 to reflect the I/O address you're using, or assign these when + line 5005 to reflect the I/O address you're using, or assign these when loading by: insmod de4x5 io=0xghh where g = bus number @@ -113,7 +134,7 @@ By default, the driver will now autodetect any DECchip based card. Should you have a need to restrict the driver to DIGITAL only cards, you can compile with a DEC_ONLY define, or if loading as a module, use the - 'dec_only=1' parameter. + 'dec_only=1' parameter. I've changed the timing routines to use the kernel timer and scheduling functions so that the hangs and other assorted problems that occurred @@ -145,6 +166,19 @@ (quad 21041 MAC) cards also appear to work despite their incorrectly wired IRQs. + I have added a temporary fix for interrupt problems when some SCSI cards + share the same interrupt as the DECchip based cards. The problem occurs + because the SCSI card wants to grab the interrupt as a fast interrupt + (runs the service routine with interrupts turned off) vs. this card + which really needs to run the service routine with interrupts turned on. + This driver will now add the interrupt service routine as a fast + interrupt if it is bounced from the slow interrupt. THIS IS NOT A + RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time + until people sort out their compatibility issues and the kernel + interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST + INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not + run on the same interrupt. PCMCIA/CardBus is another can of worms... + TO DO: ------ @@ -234,7 +268,7 @@ 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported by <bhat@mundook.cs.mu.OZ.AU> 0.45 8-Dec-96 Include endian functions for PPC use, from work - by <cort@cs.nmt.edu>. + by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>. 0.451 28-Dec-96 Added fix to allow autoprobe for modules after suggestion from <mjacob@feral.com>. 0.5 30-Jan-97 Added SROM decoding functions. @@ -247,11 +281,30 @@ Added attempt to use an SMC9332 with broken SROM. Added fix for ZYNX multi-mac cards that didn't get their IRQs wired correctly. + 0.51 13-Feb-97 Added endian fixes for the SROM accesses from + <paubert@iram.es> + Fix init_connection() to remove extra device reset. + Fix MAC/PHY reset ordering in dc21140m_autoconf(). + Fix initialisation problem with lp->timeout in + typeX_infoblock() from <paubert@iram.es>. + Fix MII PHY reset problem from work done by + <paubert@iram.es>. + 0.52 26-Apr-97 Some changes may not credit the right people - + a disk crash meant I lost some mail. + Change RX interrupt routine to drop rather than + defer packets to avoid hang reported by + <g.thomas@opengroup.org>. + Fix srom_exec() to return for COMPACT and type 1 + infoblocks. + Added DC21142 and DC21143 functions. + Added byte counters from <phil@tazenda.demon.co.uk> + Added SA_INTERRUPT temporary fix from + <mjacob@feral.com>. ========================================================================= */ -static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n"; #include <linux/module.h> @@ -270,8 +323,8 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n" #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> -#include <asm/uaccess.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -286,14 +339,37 @@ static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n" #define c_char const char +#include <linux/version.h> +#if LINUX_VERSION_CODE < ((2 << 16) | (1 << 8)) +#define net_device_stats enet_statistics +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) +#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c) +#define le16_to_cpu(a) cpu_to_le16(a) +#define le32_to_cpu(a) cpu_to_le32(a) +#ifdef __powerpc__ +#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8)) +#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\ + (((a) & 0x0000ff00U) << 8) |\ + (((a) & 0x00ff0000U) >> 8) |\ + (((a) & 0xff000000U) >> 24)) +#else +#define cpu_to_le16(a) (a) +#define cpu_to_le32(a) (a) +#endif /* __powerpc__ */ +#include <asm/segment.h> +#else +#include <asm/uaccess.h> +#endif /* LINUX_VERSION_CODE */ +#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) + /* ** MII Information */ struct phy_table { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ int ta; /* One cycle TA time - 802.3u is confusing here */ - struct { /* Non autonegotiation (parallel) speed det. */ + struct { /* Non autonegotiation (parallel) speed det. */ int reg; int mask; int value; @@ -301,25 +377,35 @@ struct phy_table { }; struct mii_phy { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ - int ta; /* One cycle TA time */ + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ + int ta; /* One cycle TA time */ struct { /* Non autonegotiation (parallel) speed det. */ int reg; int mask; int value; } spd; - int addr; /* MII address for the PHY */ - u_char *gep; /* Start of GEP sequence block in SROM */ - u_char *rst; /* Start of reset sequence in SROM */ - u_int mc; /* Media Capabilities */ - u_int ana; /* NWay Advertisement */ - u_int fdx; /* Full DupleX capabilites for each media */ - u_int ttm; /* Transmit Threshold Mode for each media */ + int addr; /* MII address for the PHY */ + u_char *gep; /* Start of GEP sequence block in SROM */ + u_char *rst; /* Start of reset sequence in SROM */ + u_int mc; /* Media Capabilities */ + u_int ana; /* NWay Advertisement */ + u_int fdx; /* Full DupleX capabilites for each media */ + u_int ttm; /* Transmit Threshold Mode for each media */ }; #define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ +struct sia_phy { + u_char mc; /* Media Code */ + u_char ext; /* csr13-15 valid when set */ + int csr13; /* SIA Connectivity Register */ + int csr14; /* SIA TX/RX Register */ + int csr15; /* SIA General Register */ + int gepc; /* SIA GEP Control Information */ + int gep; /* SIA GEP Data */ +}; + /* ** Define the know universe of PHY devices that can be ** recognised by this driver @@ -327,8 +413,8 @@ struct mii_phy { static struct phy_table phy_info[] = { {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */ {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */ - {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */ - {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */ + {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */ + {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */ }; /* @@ -354,7 +440,6 @@ static c_char srom_repair_info[][100] = { 0x00,0x18,} }; -#undef DE4X5_VERBOSE /* define to get more verbose startup messages */ #ifdef DE4X5_DEBUG static int de4x5_debug = DE4X5_DEBUG; @@ -581,6 +666,7 @@ struct de4x5_private { int setup_f; /* Setup frame filtering type */ int local_state; /* State within a 'media' state */ struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */ + struct sia_phy sia; /* SIA PHY Information */ int active; /* Index to active PHY device */ int mii_cnt; /* Number of attached PHY's */ int timeout; /* Scheduling counter */ @@ -770,9 +856,6 @@ static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, static void yawn(struct device *dev, int state); static int de4x5_dev_index(char *s); static void link_modules(struct device *dev, struct device *tmp); -#ifdef MODULE -static struct device *unlink_modules(struct device *p); -#endif static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); @@ -794,6 +877,7 @@ static int compact_infoblock(struct device *dev, u_char count, u_char *p); #ifdef MODULE int init_module(void); void cleanup_module(void); +static struct device *unlink_modules(struct device *p); static int autoprobed = 0, loading_module = 1; # else static int autoprobed = 0, loading_module = 0; @@ -898,7 +982,7 @@ de4x5_hw_init(struct device *dev, u_long iobase)) PCI_CFDA_PSM, WAKEUP); } de4x5_ms_delay(10); - + RESET_DE4X5; if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { @@ -964,6 +1048,9 @@ de4x5_hw_init(struct device *dev, u_long iobase)) lp->chipset = bus.chipset; lp->cache.priv = tmp; lp->cache.gepc = GEP_INIT; + lp->asBit = GEP_SLNK; + lp->asPolarity = GEP_SLNK; + lp->asBitValid = TRUE; lp->timeout = -1; lp->useSROM = useSROM; memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom)); @@ -1071,11 +1158,6 @@ de4x5_hw_init(struct device *dev, u_long iobase)) printk(" and requires IRQ%d (provided by %s).\n", dev->irq, ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); - -#ifdef DE4X5_VERBOSE - printk("%s: INFOLEAF_SIZE: %ld, COMPACT: %ld\n", dev->name, - INFOLEAF_SIZE, COMPACT); -#endif } if (de4x5_debug & DEBUG_VERSION) { @@ -1133,18 +1215,29 @@ de4x5_open(struct device *dev) if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, lp->adapter_name, dev)) { - printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq); - status = -EAGAIN; - } else { - dev->tbusy = 0; - dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; - dev->trans_start = jiffies; - - START_DE4X5; - - de4x5_setup_intr(dev); + printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); + if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, + lp->adapter_name, dev)) { + printk("\n Cannot get IRQ- reconfigure your hardware.\n"); + disable_ast(dev); + de4x5_free_rx_buffs(dev); + de4x5_free_tx_buffs(dev); + yawn(dev, SLEEP); + lp->state = CLOSED; + return -EAGAIN; + } else { + printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n"); + printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n"); + } } + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = UNMASK_INTERRUPTS; + dev->trans_start = jiffies; + + START_DE4X5; + + de4x5_setup_intr(dev); if (de4x5_debug & DEBUG_OPEN) { printk("\tsts: 0x%08x\n", inl(DE4X5_STS)); @@ -1287,7 +1380,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) sti(); /* Test if cache is already locked - requeue skb if so */ - if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; + if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; /* Transmit descriptor ring full or stale skb */ if (dev->tbusy || lp->tx_skb[lp->tx_new]) { @@ -1300,9 +1393,6 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); } } else if (skb->len > 0) { - /* Update the byte counter */ - lp->stats.tx_bytes += skb->len; - /* If we already have stuff queued locally, use that first */ if (lp->cache.skb && !dev->interrupt) { de4x5_put_cache(dev, skb); @@ -1313,6 +1403,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) cli(); set_bit(0, (void*)&dev->tbusy); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) + lp->stats.tx_bytes += skb->len; +#endif outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -1326,7 +1419,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) } if (skb) de4x5_putb_cache(dev, skb); } - + lp->cache.lock = 0; return status; @@ -1360,9 +1453,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); - + DISABLE_IRQs; /* Ensure non re-entrancy */ +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) synchronize_irq(); +#endif dev->interrupt = MASK_INTERRUPTS; for (limit=0; limit<8; limit++) { @@ -1394,8 +1489,8 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) } /* Load the TX ring with any locally stored packets */ - if (!set_bit(0, (void *)&lp->cache.lock)) { - if (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { + while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { de4x5_queue_pkt(de4x5_get_cache(dev), dev); } lp->cache.lock = 0; @@ -1450,19 +1545,21 @@ de4x5_rx(struct device *dev) if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { printk("%s: Insufficient memory; nuking packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ - break; - } - de4x5_dbg_rx(skb, pkt_len); + lp->stats.rx_dropped++; + } else { + de4x5_dbg_rx(skb, pkt_len); - /* Push up the protocol stack */ - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); + /* Push up the protocol stack */ + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); - /* Update stats */ - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; - de4x5_local_stats(dev, skb->data, pkt_len); + /* Update stats */ + lp->stats.rx_packets++; +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) + lp->stats.rx_bytes += pkt_len; +#endif + de4x5_local_stats(dev, skb->data, pkt_len); + } } /* Change buffer ownership for this frame, back to the adapter */ @@ -1575,10 +1672,7 @@ de4x5_txur(struct device *dev) if ((omr & OMR_TR) < OMR_TR) { omr += 0x4000; } else { - if (omr & OMR_TTM) - omr &= ~OMR_TTM; - else - omr |= OMR_SF; + omr |= OMR_SF; } outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); } @@ -1645,7 +1739,8 @@ de4x5_close(struct device *dev) return 0; } -static struct net_device_stats *de4x5_get_stats(struct device *dev) +static struct net_device_stats * +de4x5_get_stats(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -1880,7 +1975,7 @@ pci_probe(struct device *dev, u_long ioaddr)) { u_char irq; u_char pb, pbus, dev_num, dnum, dev_fn; - u_short vendor, index, status; + u_short dev_id, vendor, index, status; u_int class = DE4X5_CLASS_CODE; u_int device, iobase; struct bus_type *lp = &bus; @@ -1908,7 +2003,8 @@ pci_probe(struct device *dev, u_long ioaddr)) if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { device = 0; pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; device <<= 8; if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { continue; @@ -2091,31 +2187,6 @@ link_modules(struct device *dev, struct device *tmp)) return; } -#ifdef MODULE -static struct device * -unlink_modules(struct device *p) -{ - struct device *next = NULL; - - if (p->priv) { /* Private areas allocated? */ - struct de4x5_private *lp = (struct de4x5_private *)p->priv; - - next = lp->next_module; - if (lp->cache.buf) { /* MAC buffers allocated? */ - kfree(lp->cache.buf); /* Free the MAC buffers */ - } - kfree(lp->cache.priv); /* Free the private area */ - release_region(p->base_addr, (lp->bus == PCI ? - DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE)); - } - unregister_netdev(p); - kfree(p); /* Free the device structure */ - - return next; -} -#endif - /* ** Auto configure the media here rather than setting the port at compile ** time. This routine is called by de4x5_init() and when a loss of media is @@ -2300,6 +2371,7 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state, lp->media = prev_state; } else { lp->media = INIT; + lp->tcount++; } } @@ -2527,16 +2599,22 @@ dc21140m_autoconf(struct device *dev) switch(lp->media) { case INIT: - DISABLE_IRQs; - lp->tx_enable = FALSE; - lp->linkOK = 0; -/* lp->timeout = -1;*/ + if (lp->timeout < 0) { + DISABLE_IRQs; + lp->tx_enable = FALSE; + lp->linkOK = 0; + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + } if ((next_tick = de4x5_reset_phy(dev)) < 0) { next_tick &= ~TIMER_CB; } else { - de4x5_save_skbs(dev); /* Save non transmitted skb's */ if (lp->useSROM) { srom_map_media(dev); + srom_exec(dev, lp->phy[lp->active].gep); + if (lp->infoblock_media == ANS) { + ana = lp->phy[lp->active].ana | MII_ANA_CSMA; + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + } } else { lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ SET_10Mb; @@ -2752,9 +2830,9 @@ de4x5_init_connection(struct device *dev) de4x5_dbg_media(dev); lp->c_media = lp->media; /* Stop scrolling media messages */ } - de4x5_restore_skbs(dev); + cli(); - de4x5_rx(dev); + de4x5_restore_skbs(dev); de4x5_setup_intr(dev); lp->tx_enable = YES; dev->tbusy = 0; @@ -2766,7 +2844,9 @@ de4x5_init_connection(struct device *dev) } /* -** General PHY reset function. +** General PHY reset function. Some MII devices don't reset correctly +** since their MII address pins can float at voltages that are dependent +** on the signal pin use. Do a double reset to ensure a reset. */ static int de4x5_reset_phy(struct device *dev) @@ -2780,8 +2860,10 @@ de4x5_reset_phy(struct device *dev) if (lp->useSROM) { if (lp->phy[lp->active].rst) { /* MII device specific reset */ srom_exec(dev, lp->phy[lp->active].rst); + srom_exec(dev, lp->phy[lp->active].rst); } else if (lp->rst) { /* Type 5 infoblock reset */ srom_exec(dev, lp->rst); + srom_exec(dev, lp->rst); } } else { PHY_HARD_RESET; @@ -3151,13 +3233,26 @@ de4x5_restore_skbs(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; + int i; s32 omr; if (lp->cache.save_cnt) { STOP_DE4X5; - de4x5_cache_state(dev, DE4X5_SAVE_STATE); - de4x5_sw_reset(dev); - de4x5_cache_state(dev, DE4X5_RESTORE_STATE); + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + + lp->rx_new = lp->rx_old = 0; + lp->tx_new = lp->tx_old = 0; + + for (i = 0; i < lp->rxRingSize; i++) { + lp->rx_ring[i].status = cpu_to_le32(R_OWN); + } + + for (i = 0; i < lp->txRingSize; i++) { + lp->tx_ring[i].status = cpu_to_le32(0); + } + + barrier(); lp->cache.save_cnt--; START_DE4X5; } @@ -3446,9 +3541,10 @@ DevicePresent(u_long aprom_addr) if (lp->chipset == DC21040) { outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ } else { /* Read new srom */ - short *p = (short *)&lp->srom; + u_short tmp, *p = (short *)&lp->srom; for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) { - *p++ = srom_rd(aprom_addr, i); + tmp = srom_rd(aprom_addr, i); + *p++ = le16_to_cpu(tmp); } de4x5_dbg_srom((struct de4x5_srom *)&lp->srom); } @@ -3756,7 +3852,7 @@ srom_infoleaf_info(struct device *dev) } } - lp->infoleaf_offset = (u_short)*((u_short *)(p+1)); + lp->infoleaf_offset = TWIDDLE(p+1); return 0; } @@ -3776,14 +3872,10 @@ srom_init(struct device *dev) u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; u_char count; + p+=2; if (lp->chipset == DC21140) { - p+=2; lp->cache.gepc = (*p++ | GEP_CTRL); outl(lp->cache.gepc, DE4X5_GEP); - } else if (lp->chipset == DC21142) { - p+=2; - } else if (lp->chipset == DC21143) { - p+=2; } /* Block count */ @@ -3815,7 +3907,7 @@ srom_exec(struct device *dev, u_char *p) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - u_char count = *p++; + u_char count = (p ? *p++ : 0); while (count--) { if (lp->chipset == DC21140) { @@ -3910,7 +4002,7 @@ compact_infoblock(struct device *dev, u_char count, u_char *p) } } - if (lp->media == INIT) { + if ((lp->media == INIT) && (lp->timeout < 0)) { outl(lp->cache.gepc, DE4X5_GEP); lp->infoblock_media = (*p++) & COMPACT_MC; lp->cache.gep = *p++; @@ -3949,7 +4041,7 @@ type0_infoblock(struct device *dev, u_char count, u_char *p) } } - if (lp->media == INIT) { + if ((lp->media == INIT) && (lp->timeout < 0)) { outl(lp->cache.gepc, DE4X5_GEP); p+=2; lp->infoblock_media = (*p++) & BLOCK0_MC; @@ -3976,9 +4068,7 @@ static int type1_infoblock(struct device *dev, u_char count, u_char *p) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; u_char len = (*p & BLOCK_LEN)+1; - int ana; /* Recursively figure out the info blocks */ if (--count > lp->tcount) { @@ -3989,22 +4079,20 @@ type1_infoblock(struct device *dev, u_char count, u_char *p) } } + p += 2; if (lp->state == INITIALISED) { - lp->ibn = 1; p += 2; + lp->ibn = 1; lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].mc = *(u_short *)p; p += 2; - lp->phy[lp->active].ana = *(u_short *)p; p += 2; - lp->phy[lp->active].fdx = *(u_short *)p; p += 2; - lp->phy[lp->active].ttm = *(u_short *)p; + lp->phy[lp->active].mc = TWIDDLE(p); p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); return 0; - } else if (lp->media == INIT) { - if (lp->phy[lp->active].gep) { - srom_exec(dev, lp->phy[lp->active].gep); - } - ana = lp->phy[lp->active].ana | MII_ANA_CSMA; - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + } else if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 1; + lp->active = *p; lp->infoblock_csr6 = OMR_PS | OMR_HBD; lp->useMII = TRUE; lp->infoblock_media = ANS; @@ -4040,10 +4128,10 @@ type3_infoblock(struct device *dev, u_char count, u_char *p) lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].mc = *(u_short *)p; p += 2; - lp->phy[lp->active].ana = *(u_short *)p; p += 2; - lp->phy[lp->active].fdx = *(u_short *)p; p += 2; - lp->phy[lp->active].ttm = *(u_short *)p; + lp->phy[lp->active].mc = TWIDDLE(p); p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); return 0; } else if (lp->media == INIT) { p+=2; @@ -4672,18 +4760,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) u_long iobase = dev->base_addr; int i, j, status = 0; s32 omr; - struct { - u8 *addr; - u16 *sval; - u32 *lval; + union { + u8 addr[144]; + u16 sval[72]; + u32 lval[36]; } tmp; - - tmp.addr = tmp.sval = tmp.lval = kmalloc(HASH_TABLE_LEN * ETH_ALEN, GFP_KERNEL); - if (!tmp.addr){ - printk("%s ioctl: memory squeeze.\n", dev->name); - return -ENOMEM; - } - + switch(ioc->cmd) { case DE4X5_GET_HWADDR: /* Get the hardware address */ ioc->len = ETH_ALEN; @@ -4710,7 +4792,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) } build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ - while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ + while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -4743,39 +4825,12 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case DE4X5_GET_MCA: /* Get the multicast address table */ - ioc->len = (HASH_TABLE_LEN >> 3); - status = verify_area(VERIFY_WRITE, ioc->data, ioc->len); - if (!status) { - copy_to_user(ioc->data, lp->setup_frame, ioc->len); - } - break; case DE4X5_SET_MCA: /* Set a multicast address */ - if (suser()) { - /******* FIX ME! ********/ - if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */ - if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); - } - } else { - set_multicast_list(dev); - } - } else { - status = -EPERM; - } - break; case DE4X5_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { - /******* FIX ME! ********/ - set_multicast_list(dev); - } else { - status = -EPERM; - } - break; - case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ + case DE4X5_MCA_EN: /* Enable pass all multicast addresses*/ if (suser()) { omr = inl(DE4X5_OMR); omr |= OMR_PM; @@ -4840,7 +4895,8 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; -#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ +/* +#define DE4X5_DUMP 0x0f / * Dump the DE4X5 Status * / case DE4X5_DUMP: j = 0; @@ -4931,12 +4987,11 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) } break; +*/ default: status = -EOPNOTSUPP; } - - kfree(tmp.addr); - + return status; } @@ -4975,6 +5030,30 @@ cleanup_module(void) return; } + +static struct device * +unlink_modules(struct device *p) +{ + struct device *next = NULL; + + if (p->priv) { /* Private areas allocated? */ + struct de4x5_private *lp = (struct de4x5_private *)p->priv; + + next = lp->next_module; + if (lp->cache.buf) { /* MAC buffers allocated? */ + kfree(lp->cache.buf); /* Free the MAC buffers */ + } + kfree(lp->cache.priv); /* Free the private area */ + release_region(p->base_addr, (lp->bus == PCI ? + DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE)); + } + unregister_netdev(p); + kfree(p); /* Free the device structure */ + + return next; +} + #endif /* MODULE */ diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h index bda97578c..525e0122d 100644 --- a/drivers/net/de4x5.h +++ b/drivers/net/de4x5.h @@ -139,7 +139,7 @@ #define CFCS_DST 0x06000000 /* DEVSEL Timing (S) */ #define CFCS_DPR 0x01000000 /* Data Parity Report (S) */ #define CFCS_FBB 0x00800000 /* Fast Back-To-Back (S) */ -#define CFCS_SLE 0x00000100 /* System Error Enable (C) */ +#define CFCS_SEE 0x00000100 /* System Error Enable (C) */ #define CFCS_PER 0x00000040 /* Parity Error Response (C) */ #define CFCS_MO 0x00000004 /* Master Operation (C) */ #define CFCS_MSA 0x00000002 /* Memory Space Access (C) */ @@ -150,8 +150,8 @@ */ #define CFRV_BC 0xff000000 /* Base Class */ #define CFRV_SC 0x00ff0000 /* Subclass */ -#define CFRV_SN 0x000000f0 /* Step Number */ -#define CFRV_RN 0x0000000f /* Revision Number */ +#define CFRV_RN 0x000000f0 /* Revision Number */ +#define CFRV_SN 0x0000000f /* Step Number */ #define BASE_CLASS 0x02000000 /* Indicates Network Controller */ #define SUB_CLASS 0x00000000 /* Indicates Ethernet Controller */ #define STEP_NUMBER 0x00000020 /* Increments for future chips */ @@ -170,12 +170,33 @@ #define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */ /* +** PCI Configuration Card Information Structure Register (PCI_CCIS) +*/ +#define CCIS_ROMI 0xf0000000 /* ROM Image */ +#define CCIS_ASO 0x0ffffff8 /* Address Space Offset */ +#define CCIS_ASI 0x00000007 /* Address Space Indicator */ + +/* +** PCI Configuration Subsystem ID Register (PCI_SSID) +*/ +#define SSID_SSID 0xffff0000 /* Subsystem ID */ +#define SSID_SVID 0x0000ffff /* Subsystem Vendor ID */ + +/* ** PCI Configuration Expansion ROM Base Address Register (PCI_CBER) */ #define CBER_MASK 0xfffffc00 /* Expansion ROM Base Address Mask */ #define CBER_ROME 0x00000001 /* ROM Enable */ /* +** PCI Configuration Interrupt Register (PCI_CFIT) +*/ +#define CFIT_MXLT 0xff000000 /* MAX_LAT Value (0.25us periods) */ +#define CFIT_MNGT 0x00ff0000 /* MIN_GNT Value (0.25us periods) */ +#define CFIT_IRQP 0x0000ff00 /* Interrupt Pin */ +#define CFIT_IRQL 0x000000ff /* Interrupt Line */ + +/* ** PCI Configuration Power Management Area Register (PCI_CFPM) */ #define SLEEP 0x80 /* Power Saving Sleep Mode */ @@ -188,6 +209,7 @@ /* ** DC21040 Bus Mode Register (DE4X5_BMR) */ +#define BMR_RML 0x00200000 /* [Memory] Read Multiple */ #define BMR_DBO 0x00100000 /* Descriptor Byte Ordering (Endian) */ #define BMR_TAP 0x000e0000 /* Transmit Automatic Polling */ #define BMR_DAS 0x00010000 /* Diagnostic Address Space */ @@ -198,6 +220,7 @@ #define BMR_BAR 0x00000002 /* Bus ARbitration */ #define BMR_SWR 0x00000001 /* Software Reset */ + /* Timings here are for 10BASE-T/AUI only*/ #define TAP_NOPOLL 0x00000000 /* No automatic polling */ #define TAP_200US 0x00020000 /* TX automatic polling every 200us */ #define TAP_800US 0x00040000 /* TX automatic polling every 800us */ @@ -249,18 +272,21 @@ #define TRBA 0xfffffffc /* TX Descriptor List Start Address */ /* -** DC21040 Status Register (DE4X5_STS) +** Status Register (DE4X5_STS) */ +#define STS_GPI 0x04000000 /* General Purpose Port Interrupt */ #define STS_BE 0x03800000 /* Bus Error Bits */ #define STS_TS 0x00700000 /* Transmit Process State */ #define STS_RS 0x000e0000 /* Receive Process State */ #define STS_NIS 0x00010000 /* Normal Interrupt Summary */ #define STS_AIS 0x00008000 /* Abnormal Interrupt Summary */ #define STS_ER 0x00004000 /* Early Receive */ +#define STS_FBE 0x00002000 /* Fatal Bus Error */ #define STS_SE 0x00002000 /* System Error */ #define STS_LNF 0x00001000 /* Link Fail */ #define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */ #define STS_TM 0x00000800 /* Timer Expired (DC21041) */ +#define STS_ETI 0x00000400 /* Early Transmit Interupt */ #define STS_AT 0x00000400 /* AUI/TP Pin */ #define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */ #define STS_RPS 0x00000100 /* Receive Process Stopped */ @@ -268,6 +294,7 @@ #define STS_RI 0x00000040 /* Receive Interrupt */ #define STS_UNF 0x00000020 /* Transmit Underflow */ #define STS_LNP 0x00000010 /* Link Pass */ +#define STS_ANC 0x00000010 /* Autonegotiation Complete */ #define STS_TJT 0x00000008 /* Transmit Jabber Time-Out */ #define STS_TU 0x00000004 /* Transmit Buffer Unavailable */ #define STS_TPS 0x00000002 /* Transmit Process Stopped */ @@ -300,8 +327,10 @@ #define INT_CANCEL 0x0001ffff /* For zeroing all interrupt sources */ /* -** DC21040 Operation Mode Register (DE4X5_OMR) +** Operation Mode Register (DE4X5_OMR) */ +#define OMR_SC 0x80000000 /* Special Capture Effect Enable */ +#define OMR_RA 0x40000000 /* Receive All */ #define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */ #define OMR_SCR 0x01000000 /* Scrambler Mode */ #define OMR_PCS 0x00800000 /* PCS Function */ @@ -326,27 +355,31 @@ #define OMR_SR 0x00000002 /* Start/Stop Receive */ #define OMR_HP 0x00000001 /* Hash/Perfect Receive Filtering Mode */ -#define TR_72 0x00000000 /* Threshold set to 72 bytes */ -#define TR_96 0x00004000 /* Threshold set to 96 bytes */ -#define TR_128 0x00008000 /* Threshold set to 128 bytes */ -#define TR_160 0x0000c000 /* Threshold set to 160 bytes */ +#define TR_72 0x00000000 /* Threshold set to 72 (128) bytes */ +#define TR_96 0x00004000 /* Threshold set to 96 (256) bytes */ +#define TR_128 0x00008000 /* Threshold set to 128 (512) bytes */ +#define TR_160 0x0000c000 /* Threshold set to 160 (1024) bytes */ /* ** DC21040 Interrupt Mask Register (DE4X5_IMR) */ +#define IMR_GPM 0x04000000 /* General Purpose Port Mask */ #define IMR_NIM 0x00010000 /* Normal Interrupt Summary Mask */ #define IMR_AIM 0x00008000 /* Abnormal Interrupt Summary Mask */ #define IMR_ERM 0x00004000 /* Early Receive Mask */ +#define IMR_FBM 0x00002000 /* Fatal Bus Error Mask */ #define IMR_SEM 0x00002000 /* System Error Mask */ #define IMR_LFM 0x00001000 /* Link Fail Mask */ #define IMR_FDM 0x00000800 /* Full-Duplex (Short Frame) Mask */ #define IMR_TMM 0x00000800 /* Timer Expired Mask (DC21041) */ +#define IMR_ETM 0x00000400 /* Early Transmit Interrupt Mask */ #define IMR_ATM 0x00000400 /* AUI/TP Switch Mask */ #define IMR_RWM 0x00000200 /* Receive Watchdog Time-Out Mask */ #define IMR_RSM 0x00000100 /* Receive Stopped Mask */ #define IMR_RUM 0x00000080 /* Receive Buffer Unavailable Mask */ #define IMR_RIM 0x00000040 /* Receive Interrupt Mask */ #define IMR_UNM 0x00000020 /* Underflow Interrupt Mask */ +#define IMR_ANM 0x00000010 /* Autonegotiation Complete Mask */ #define IMR_LPM 0x00000010 /* Link Pass */ #define IMR_TJM 0x00000008 /* Transmit Time-Out Jabber Mask */ #define IMR_TUM 0x00000004 /* Transmit Buffer Unavailable Mask */ @@ -354,13 +387,7 @@ #define IMR_TIM 0x00000001 /* Transmit Interrupt Mask */ /* -** DC21040 Missed Frames Counter (DE4X5_MFC) -*/ -#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */ -#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */ - -/* -** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC) +** Missed Frames and FIFO Overflow Counters (DE4X5_MFC) */ #define MFC_FOCO 0x10000000 /* FIFO Overflow Counter Overflow Bit */ #define MFC_FOC 0x0ffe0000 /* FIFO Overflow Counter Bits */ @@ -461,7 +488,7 @@ ** MII Management Auto Negotiation Advertisement Register */ #define MII_ANA_TAF 0x03e0 /* Technology Ability Field */ -#define MII_ANA_T4AM 0x0400 /* T4 Technology Ability Mask */ +#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */ #define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */ #define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ #define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ @@ -476,7 +503,7 @@ #define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */ #define MII_ANLPA_RF 0x2000 /* Remote Fault */ #define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */ -#define MII_ANLPA_T4AM 0x0400 /* T4 Technology Ability Mask */ +#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */ #define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */ #define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ #define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ @@ -547,6 +574,8 @@ #define SROM_100BASEFF 0x0008 /* 100BASE-FX full duplex */ #define BLOCK_LEN 0x7f /* Extended blocks length mask */ +#define EXT_FIELD 0x40 /* Extended blocks extension field bit */ +#define MEDIA_CODE 0x3f /* Extended blocks media code mask */ /* ** SROM Compact Format Block Masks @@ -589,14 +618,18 @@ #define GEP_CTRL 0x00000100 /* GEP control bit */ /* -** DC21040 SIA Status Register (DE4X5_SISR) +** SIA Status Register (DE4X5_SISR) */ #define SISR_LPC 0xffff0000 /* Link Partner's Code Word */ #define SISR_LPN 0x00008000 /* Link Partner Negotiable */ #define SISR_ANS 0x00007000 /* Auto Negotiation Arbitration State */ -#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected */ +#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected (DC21041) */ +#define SISR_TRF 0x00000800 /* Transmit Remote Fault */ +#define SISR_NSND 0x00000400 /* Non Stable NLPs Detected (DC21142) */ #define SISR_ANR_FDS 0x00000400 /* Auto Negotiate Restart/Full Duplex Sel.*/ +#define SISR_TRA 0x00000200 /* 10BASE-T Receive Port Activity */ #define SISR_NRA 0x00000200 /* Non Selected Port Receive Activity */ +#define SISR_ARA 0x00000100 /* AUI Receive Port Activity */ #define SISR_SRA 0x00000100 /* Selected Port Receive Activity */ #define SISR_DAO 0x00000080 /* PLL All One */ #define SISR_DAZ 0x00000040 /* PLL All Zero */ @@ -606,7 +639,7 @@ #define SISR_LKF 0x00000004 /* Link Fail Status */ #define SISR_NCR 0x00000002 /* Network Connection Error */ #define SISR_PAUI 0x00000001 /* AUI_TP Indication */ -#define SIA_RESET 0x00000000 /* SIA Reset */ +#define SISR_MRA 0x00000001 /* MII Receive Port Activity */ #define ANS_NDIS 0x00000000 /* Nway disable */ #define ANS_TDIS 0x00001000 /* Transmit Disable */ @@ -617,7 +650,7 @@ #define ANS_LCHK 0x00006000 /* Link Check */ /* -** DC21040 SIA Connectivity Register (DE4X5_SICR) +** SIA Connectivity Register (DE4X5_SICR) */ #define SICR_SDM 0xffff0000 /* SIA Diagnostics Mode */ #define SICR_OE57 0x00008000 /* Output Enable 5 6 7 */ @@ -636,14 +669,14 @@ #define SICR_SIM 0x00000040 /* Serial Interface Input Multiplexer */ #define SICR_ENI 0x00000020 /* Encoder Input Multiplexer */ #define SICR_EDP 0x00000010 /* SIA PLL External Input Enable */ -#define SICR_AUI 0x00000008 /* 10Base-T or AUI */ +#define SICR_AUI 0x00000008 /* 10Base-T (0) or AUI (1) */ #define SICR_CAC 0x00000004 /* CSR Auto Configuration */ #define SICR_PS 0x00000002 /* Pin AUI/TP Selection */ #define SICR_SRL 0x00000001 /* SIA Reset */ -#define SICR_RESET 0xffff0000 /* Reset value for SICR */ +#define SIA_RESET 0x00000000 /* SIA Reset Value */ /* -** DC21040 SIA Transmit and Receive Register (DE4X5_STRR) +** SIA Transmit and Receive Register (DE4X5_STRR) */ #define STRR_TAS 0x00008000 /* 10Base-T/AUI Autosensing Enable */ #define STRR_SPP 0x00004000 /* Set Polarity Plus */ @@ -663,8 +696,20 @@ #define STRR_RESET 0xffffffff /* Reset value for STRR */ /* -** DC21040 SIA General Register (DE4X5_SIGR) -*/ +** SIA General Register (DE4X5_SIGR) +*/ +#define SIGR_RMI 0x40000000 /* Receive Match Interrupt */ +#define SIGR_GI1 0x20000000 /* General Port Interrupt 1 */ +#define SIGR_GI0 0x10000000 /* General Port Interrupt 0 */ +#define SIGR_CWE 0x08000000 /* Control Write Enable */ +#define SIGR_RME 0x04000000 /* Receive Match Enable */ +#define SIGR_GEI1 0x02000000 /* GEP Interrupt Enable on Port 1 */ +#define SIGR_GEI0 0x01000000 /* GEP Interrupt Enable on Port 0 */ +#define SIGR_LGS3 0x00800000 /* LED/GEP3 Select */ +#define SIGR_LGS2 0x00400000 /* LED/GEP2 Select */ +#define SIGR_LGS1 0x00200000 /* LED/GEP1 Select */ +#define SIGR_LGS0 0x00100000 /* LED/GEP0 Select */ +#define SIGR_MD 0x000f0000 /* General Purpose Mode and Data */ #define SIGR_LV2 0x00008000 /* General Purpose LED2 value */ #define SIGR_LE2 0x00004000 /* General Purpose LED2 enable */ #define SIGR_FRL 0x00002000 /* Force Receiver Low */ @@ -687,7 +732,8 @@ ** Receive Descriptor Bit Summary */ #define R_OWN 0x80000000 /* Own Bit */ -#define RD_FL 0x7fff0000 /* Frame Length */ +#define RD_FF 0x40000000 /* Filtering Fail */ +#define RD_FL 0x3fff0000 /* Frame Length */ #define RD_ES 0x00008000 /* Error Summary */ #define RD_LE 0x00004000 /* Length Error */ #define RD_DT 0x00003000 /* Data Type */ @@ -699,6 +745,7 @@ #define RD_CS 0x00000040 /* Collision Seen */ #define RD_FT 0x00000020 /* Frame Type */ #define RD_RJ 0x00000010 /* Receive Watchdog */ +#define RD_RE 0x00000008 /* Report on MII Error */ #define RD_DB 0x00000004 /* Dribbling Bit */ #define RD_CE 0x00000002 /* CRC Error */ #define RD_OF 0x00000001 /* Overflow */ @@ -734,40 +781,39 @@ #define TD_TCH 0x01000000 /* Second Address Chained */ #define TD_DPD 0x00800000 /* Disabled Padding */ #define TD_FT0 0x00400000 /* Filtering Type */ -#define TD_RBS2 0x003ff800 /* Buffer 2 Size */ -#define TD_RBS1 0x000007ff /* Buffer 1 Size */ +#define TD_TBS2 0x003ff800 /* Buffer 2 Size */ +#define TD_TBS1 0x000007ff /* Buffer 1 Size */ #define PERFECT_F 0x00000000 #define HASH_F TD_FT0 #define INVERSE_F TD_FT1 -#define HASH_O_F TD_FT1| TD_F0 +#define HASH_O_F (TD_FT1 | TD_F0) /* ** Media / mode state machine definitions */ -#define NC 0x0000 /* No Connection */ -#define TP 0x0001 /* 10Base-T */ -#define TP_NW 0x0002 /* 10Base-T with Nway */ -#define BNC 0x0004 /* Thinwire */ -#define AUI 0x0008 /* Thickwire */ +#define NC 0x0000 /* No Connection */ +#define TP 0x0001 /* 10Base-T */ +#define TP_NW 0x0002 /* 10Base-T with Nway */ +#define BNC 0x0004 /* Thinwire */ +#define AUI 0x0008 /* Thickwire */ #define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */ -#define ANS 0x0020 /* Intermediate AutoNegotiation State */ -#define ANS_1 0x0021 /* Intermediate AutoNegotiation State */ - -#define _10Mb 0x0040 /* 10Mb/s Ethernet */ -#define _100Mb 0x0080 /* 100Mb/s Ethernet */ -#define SPD_DET 0x0100 /* Parallel speed detection */ -#define INIT 0x0200 /* Initial state */ -#define EXT_SIA 0x0400 /* External SIA for motherboard chip */ -#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */ -#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */ -#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */ -#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ -#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ -#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ - -#define AUTO 0x4000 /* Auto sense the media or speed */ -#define TIMER_CB 0x80000000 /* Timer callback detection */ +#define ANS 0x0020 /* Intermediate AutoNegotiation State */ +#define _10Mb 0x0040 /* 10Mb/s Ethernet */ +#define _100Mb 0x0080 /* 100Mb/s Ethernet */ +#define SPD_DET 0x0100 /* Parallel speed detection */ +#define INIT 0x0200 /* Initial state */ +#define EXT_SIA 0x0400 /* External SIA for motherboard chip */ +#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */ +#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */ +#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */ +#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ +#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ +#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ +#define MII 0x1000 /* MII on the 21143 */ + +#define AUTO 0x4000 /* Auto sense the media or speed */ +#define TIMER_CB 0x80000000 /* Timer callback detection */ /* ** DE4X5 DEBUG Options @@ -798,7 +844,6 @@ #define POLL_DEMAND 1 #define LOST_MEDIA_THRESHOLD 3 -#define LOST_MEDIA (lp->lostMedia > LOST_MEDIA_THRESHOLD) #define MASK_INTERRUPTS 1 #define UNMASK_INTERRUPTS 0 @@ -859,7 +904,7 @@ }\ omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ + if (!lp->useSROM) lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -887,7 +932,7 @@ }\ if (fdx) omr |= OMR_FDX;\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ + if (!lp->useSROM) lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -906,7 +951,6 @@ mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ outl(omr, DE4X5_OMR);\ @@ -934,7 +978,7 @@ struct de4x5_ioctl { ** Recognised commands for the driver */ #define DE4X5_GET_HWADDR 0x01 /* Get the hardware address */ -#define DE4X5_SET_HWADDR 0x02 /* Get the hardware address */ +#define DE4X5_SET_HWADDR 0x02 /* Set the hardware address */ #define DE4X5_SET_PROM 0x03 /* Set Promiscuous Mode */ #define DE4X5_CLR_PROM 0x04 /* Clear Promiscuous Mode */ #define DE4X5_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */ diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 5e50cbfa5..659e71f32 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -226,6 +226,11 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa #include "defxx.h" +#define DYNAMIC_BUFFERS 1 + +#define SKBUFF_RX_COPYBREAK 200 +#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX) + /* Define global routines */ int dfx_probe(struct device *dev); @@ -1083,7 +1088,9 @@ __initfunc(int dfx_driver_init( alloc_size = sizeof(PI_DESCR_BLOCK) + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + +#ifndef DYNAMIC_BUFFERS (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + +#endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); top_v = (char *) kmalloc(alloc_size, GFP_KERNEL); @@ -1135,8 +1142,11 @@ __initfunc(int dfx_driver_init( bp->rcv_block_virt = curr_v; bp->rcv_block_phys = curr_p; + +#ifndef DYNAMIC_BUFFERS curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); +#endif /* Reserve space for the consumer block */ @@ -2926,6 +2936,22 @@ void dfx_rcv_init( * driver initialization when we allocated memory for the receive buffers. */ +#ifdef DYNAMIC_BUFFERS + for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + struct sk_buff *newskb; + bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + newskb = dev_alloc_skb(NEW_SKB_SIZE); + bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data); + /* + * p_rcv_buff_va is only used inside the + * kernel so we put the skb pointer here. + */ + bp->p_rcv_buff_va[i+j] = (char *) newskb; + } +#else for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { @@ -2934,6 +2960,7 @@ void dfx_rcv_init( bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); } +#endif /* Update receive producer and Type 2 register */ @@ -2985,6 +3012,8 @@ void dfx_rcv_queue_process( u32 descr, pkt_len; /* FMC descriptor field and packet length */ struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ + static int testing_dyn; + /* Service all consumed LLC receive frames */ p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); @@ -2992,7 +3021,14 @@ void dfx_rcv_queue_process( { /* Process any errors */ - p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp]; + int entry; + + entry = bp->rcv_xmt_reg.index.rcv_comp; +#ifdef DYNAMIC_BUFFERS + p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data); +#else + p_buff = (char *) bp->p_rcv_buff_va[entry]; +#endif memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); if (descr & PI_FMC_DESCR_M_RCC_FLUSH) @@ -3003,29 +3039,60 @@ void dfx_rcv_queue_process( bp->rcv_frame_status_errors++; } else - { + { + int rx_in_place = 0; + /* The frame was received without errors - verify packet length */ pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); pkt_len -= 4; /* subtract 4 byte CRC */ if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) bp->rcv_length_errors++; - else - { - skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ + else{ +#ifdef DYNAMIC_BUFFERS + if (pkt_len > SKBUFF_RX_COPYBREAK) { + struct sk_buff *newskb; + + newskb = dev_alloc_skb(NEW_SKB_SIZE); + if (newskb){ + rx_in_place = 1; +#define JES_TESTING +#ifdef JES_TESTING + if(testing_dyn++ < 5) + printk("Skipping a memcpy\n"); + skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; + skb->data += RCV_BUFF_K_PADDING; + bp->p_rcv_buff_va[entry] = (char *)newskb; + bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data); +#else + memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); + skb = newskb; +#endif + } else + skb = 0; + } else +#endif + skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ if (skb == NULL) { printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); bp->rcv_discards++; + break; } - else + else { +#ifndef DYNAMIC_BUFFERS + if (! rx_in_place) +#endif { - /* Receive buffer allocated, pass receive packet up */ + /* Receive buffer allocated, pass receive packet up */ + + memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); + } - memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); skb->data += 3; /* adjust data field so that it points to FC byte */ skb->len = pkt_len; /* pass up packet length, NOT including CRC */ skb->dev = bp->dev; /* pass up device pointer */ + skb->protocol = fddi_type_trans(skb, bp->dev); netif_rx(skb); @@ -3034,9 +3101,9 @@ void dfx_rcv_queue_process( bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; - } } } + } /* * Advance the producer (for recycling) and advance the completion @@ -3140,6 +3207,7 @@ int dfx_xmt_queue_pkt( dev->name, skb->len); bp->xmt_length_errors++; /* bump error counter */ dev_tint(dev); /* dequeue packets from xmt queue and send them */ + dev_kfree_skb(skb, FREE_WRITE); return(0); /* return "success" */ } /* diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 85cf704c5..74246fa7a 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -804,7 +804,7 @@ depca_start_xmit(struct sk_buff *skb, struct device *dev) dev_tint(dev); } else if (skb->len > 0) { /* Enforce 1 process per h/w access */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); status = -1; } else { diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c index e42b0dcf4..08d9901ba 100644 --- a/drivers/net/dlci.c +++ b/drivers/net/dlci.c @@ -248,7 +248,7 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev) dlp = dev->priv; - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name); else { diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 814d798c5..877e2256e 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -134,7 +134,7 @@ int init_module(void) { /* Find a name for this unit */ int err=dev_alloc_name(&dev_dummy,"dummy%d"); - if(err) + if(err<0) return err; if (register_netdev(&dev_dummy) != 0) return -EIO; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 72060c53b..25167fa0b 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -714,7 +714,7 @@ eepro_send_packet(struct sk_buff *skb, struct device *dev) } /* Block a timer-based transmit from overlapping. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index cf67f942b..af117e223 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1033,7 +1033,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < TX_TIMEOUT - 2) return 1; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index f5b75bb9f..8e8852bc0 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -94,6 +94,7 @@ #include <asm/io.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -301,7 +302,7 @@ static inline short int SHADOW(short int addr) * checks for presence of EtherExpress card */ -int express_probe(struct device *dev) +__initfunc(int express_probe(struct device *dev)) { unsigned short *port; static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 }; @@ -525,7 +526,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev) } } - if (set_bit(0,(void *)&dev->tbusy)) + if (test_and_set_bit(0,(void *)&dev->tbusy)) { lp->stats.tx_dropped++; } @@ -913,7 +914,7 @@ static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf, * than one card in a machine. */ -static int eexp_hw_probe(struct device *dev, unsigned short ioaddr) +__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)) { unsigned short hw_addr[3]; unsigned char buswidth; @@ -1034,8 +1035,8 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr) * Read a word from the EtherExpress on-board serial EEPROM. * The EEPROM contains 64 words of 16 bits. */ -static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, - unsigned char location) +__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, + unsigned char location)) { unsigned short cmd = 0x180|(location&0x7f); unsigned short rval = 0,wval = EC_CS|i586_RST; diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 24e449390..74cf38d50 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -932,7 +932,7 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev) /* Turn off TX interrupts */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - if(set_bit(0, (void *)&dev->tbusy) != 0) + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 3c3752251..75492e1c1 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -767,7 +767,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev) ** Block a timer-based transmit from overlapping. This could better be ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); DISABLE_IRQs; /* So that the page # remains correct */ @@ -783,7 +783,7 @@ ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev) /* ** Set up shared memory window and pointer into the window */ - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(page, EWRK3_IOPR); } else if (lp->shmem_length == SHMEM_2K) { @@ -953,7 +953,7 @@ ewrk3_rx(struct device *dev) ** Preempt any process using the current page register. Check for ** an existing lock to reduce time taken in I/O transactions. */ - if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */ + if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */ if (lp->shmem_length == IO_ONLY) { /* Get existing page */ tmpPage = inb(EWRK3_IOPR); } else { @@ -1217,7 +1217,7 @@ static void SetMulticastFilter(struct device *dev) u16 hashcode; s32 crc, poly = CRC_POLYNOMIAL_LE; - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); @@ -1723,7 +1723,7 @@ static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd) break; case EWRK3_GET_MCA: /* Get the multicast address table */ if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); outw(PAGE0_HTE, EWRK3_PIR1); diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c index 7536a7e04..59362c8fe 100644 --- a/drivers/net/fmv18x.c +++ b/drivers/net/fmv18x.c @@ -348,7 +348,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/hdlcdrv.c b/drivers/net/hdlcdrv.c index 9098fdf2e..467980406 100644 --- a/drivers/net/hdlcdrv.c +++ b/drivers/net/hdlcdrv.c @@ -288,7 +288,7 @@ void hdlcdrv_receiver(struct device *dev, struct hdlcdrv_state *s) if (!s || s->magic != HDLCDRV_MAGIC) return; - if (set_bit(0, &s->hdlcrx.in_hdlc_rx)) + if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) return; while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { @@ -387,7 +387,7 @@ void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s) if (!s || s->magic != HDLCDRV_MAGIC) return; - if (set_bit(0, &s->hdlctx.in_hdlc_tx)) + if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) return; for (;;) { if (s->hdlctx.numbits >= 16) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 6a599dd60..0780e038f 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1,89 +1,54 @@ /* - * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. - * - * Author: Jaroslav Kysela, <perex@pf.jcu.cz> - * - * Supports only the following Hewlett Packard cards: - * - * HP J2577 10/100 EISA card with REVA Cascade chip - * HP J2573 10/100 ISA card with REVA Cascade chip - * HP 27248B 10 only EISA card with Cascade chip - * HP J2577 10/100 EISA card with Cascade chip - * HP J2573 10/100 ISA card with Cascade chip - * HP J2585 10/100 PCI card - * - * Other ATT2MD01 Chip based boards might be supported in the future - * (there are some minor changes needed). - * - * This driver is based on the 'hpfepkt' crynwr packet driver. - * - * This source/code is public free; you can distribute it and/or modify - * it under terms of the GNU General Public License (published by the - * Free Software Foundation) either version two of this License, or any - * later version. - * ---------------------------------------------------------------------------- - * - * Note: Some routines (interrupt handling, transmit) assumes that - * there is the PERFORMANCE page selected... - * - * ---------------------------------------------------------------------------- - * - * If you are going to use the module version of this driver, you may - * change this values at the "insert time" : - * - * Variable Description - * - * hp100_rx_ratio Range 1-99 - onboard memory used for RX - * packets in %. - * hp100_priority_tx If this variable is nonzero - all outgoing - * packets will be transmitted as priority. - * hp100_port Adapter port (for example 0x380). - * - * ---------------------------------------------------------------------------- - * MY BEST REGARDS GOING TO: - * - * IPEX s.r.o which lend me two HP J2573 cards and - * the HP AdvanceStack 100VG Hub-15 for debugging. - * - * Russel Nellson <nelson@crynwr.com> for help with obtaining sources - * of the 'hpfepkt' packet driver. - * - * Also thanks to Abacus Electric s.r.o which let me to use their - * motherboard for my second computer. - * - * ---------------------------------------------------------------------------- - * - * TO DO: - * ====== - * - ioctl handling - some runtime setup things - * - 100Mb/s Voice Grade AnyLAN network adapter/hub services support - * - 802.5 frames - * - promiscuous mode - * - bridge mode - * - cascaded repeater mode - * - 100Mbit MAC - * - * Revision history: - * ================= - * - * Version Date Description - * - * 0.1 14-May-95 Initial writing. ALPHA code was released. - * Only HP J2573 on 10Mb/s (two machines) tested. - * 0.11 14-Jun-95 Reset interface bug fixed? - * Little bug in hp100_close function fixed. - * 100Mb/s connection debugged. - * 0.12 14-Jul-95 Link down is now handled better. - * 0.20 01-Aug-95 Added PCI support for HP J2585A card. - * Statistics bug fixed. - * 0.21 04-Aug-95 Memory mapped access support for PCI card. - * Added priority transmit support for 100Mb/s - * Voice Grade AnyLAN network. - * - */ - +** hp100.c +** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters +** +** $Id: hp100.c,v 1.52 1997/04/21 14:20:20 perex Exp perex $ +** +** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz> +** Extended for new busmaster capable chipsets by +** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de> +** +** Maintained by: Jaroslav Kysela <perex@jcu.cz> +** +** This driver has only been tested with +** -- HP J2585B 10/100 Mbit/s PCI Busmaster +** -- HP J2585A 10/100 Mbit/s PCI +** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC +** -- HP J2973 10 Mbit/s PCI 10base-T +** -- HP J2573 10/100 ISA +** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA +** +** but it should also work with the other CASCADE based adapters. +** +** TODO: +** - J2573 seems to hang sometimes when in shared memory mode. +** - Mode for Priority TX +** - Check PCI registers, performance might be improved? +** - To reduce interrupt load in busmaster, one could switch off +** the interrupts that are used to refill the queues whenever the +** queues are filled up to more than a certain threshold. +** +** +** This source/code is public free; you can distribute it and/or modify +** it under terms of the GNU General Public License (published by the +** Free Software Foundation) either version two of this License, or any +** later version. +** +*/ + +#define HP100_DEFAULT_PRIORITY_TX 0 + +#undef HP100_DEBUG +#undef HP100_DEBUG_B /* Trace */ +#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ + +#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ +#undef HP100_DEBUG_TX +#undef HP100_DEBUG_IRQ +#undef HP100_DEBUG_RX + +#include <linux/version.h> #include <linux/module.h> - #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> @@ -102,7 +67,17 @@ #include <linux/skbuff.h> #include <linux/types.h> -#include <linux/config.h> /* for CONFIG_PCI */ +#include <linux/config.h> /* for CONFIG_PCI */ +#include <linux/delay.h> + +#if LINUX_VERSION_CODE < 0x020100 +#define ioremap vremap +#define iounmap vfree +typedef struct enet_statistics hp100_stats_t; +#else +#define LINUX_2_1 +typedef struct net_device_stats hp100_stats_t; +#endif #include "hp100.h" @@ -110,18 +85,28 @@ * defines */ -#define HP100_BUS_ISA 0 -#define HP100_BUS_EISA 1 -#define HP100_BUS_PCI 2 +#define HP100_BUS_ISA 0 +#define HP100_BUS_EISA 1 +#define HP100_BUS_PCI 2 -#define HP100_REGION_SIZE 0x20 +#ifndef PCI_DEVICE_ID_HP_J2585B +#define PCI_DEVICE_ID_HP_J2585B 0x1031 +#endif +#ifndef PCI_VENDOR_ID_COMPEX +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#endif +#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 +#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 +#endif + +#define HP100_REGION_SIZE 0x20 /* for ioports */ -#define HP100_MAX_PACKET_SIZE (1536+4) -#define HP100_MIN_PACKET_SIZE 60 +#define HP100_MAX_PACKET_SIZE (1536+4) +#define HP100_MIN_PACKET_SIZE 60 #ifndef HP100_DEFAULT_RX_RATIO -/* default - 65% onboard memory on the card are used for RX packets */ -#define HP100_DEFAULT_RX_RATIO 65 +/* default - 75% onboard memory on the card are used for RX packets */ +#define HP100_DEFAULT_RX_RATIO 75 #endif #ifndef HP100_DEFAULT_PRIORITY_TX @@ -141,18 +126,37 @@ struct hp100_eisa_id { struct hp100_private { struct hp100_eisa_id *id; + u_short chip; u_short soft_model; - u_int memory_size; - u_short rx_ratio; /* 1 - 99 */ - u_short priority_tx; /* != 0 - priority tx */ - short mem_mapped; /* memory mapped access */ - u_char *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - u_char *mem_ptr_phys; /* physical memory mapped area */ - short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ - int hub_status; /* login to hub was successful? */ + u_int memory_size; + u_short rx_ratio; /* 1 - 99 */ + u_short priority_tx; /* != 0 - priority tx */ + u_short mode; /* PIO, Shared Mem or Busmaster */ + u_char bus; + u_char pci_bus; + u_char pci_device_fn; + short mem_mapped; /* memory mapped access */ + u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + u_int *mem_ptr_phys; /* physical memory mapped area */ + short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ + int hub_status; /* was login to hub successful? */ u_char mac1_mode; u_char mac2_mode; - struct net_device_stats stats; + hp100_stats_t stats; + + /* Rings for busmaster mode: */ + hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ + hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ + hp100_ring_t *txrhead; /* Head (oldest) index into txring */ + hp100_ring_t *txrtail; /* Tail (newest) index into txring */ + + hp100_ring_t rxring[ MAX_RX_PDL ]; + hp100_ring_t txring[ MAX_TX_PDL ]; + + u_int *page_vaddr; /* Virtual address of allocated page */ + u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + int rxrcommit; /* # Rx PDLs commited to adapter */ + int txrcommit; /* # Tx PDLs commited to adapter */ }; /* @@ -161,78 +165,124 @@ struct hp100_private { static struct hp100_eisa_id hp100_eisa_ids[] = { - /* 10/100 EISA card with REVA Cascade chip */ - { 0x080F1F022, "HP J2577 rev A", HP100_BUS_EISA }, + /* 10/100 EISA card with revision A Cascade chip */ + { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA }, - /* 10/100 ISA card with REVA Cascade chip */ - { 0x050F1F022, "HP J2573 rev A", HP100_BUS_ISA }, + /* 10/100 ISA card with revision A Cascade chip */ + { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA }, /* 10 only EISA card with Cascade chip */ - { 0x02019F022, "HP 27248B", HP100_BUS_EISA }, + { 0x2019F022, "HP 27248B", HP100_BUS_EISA }, /* 10/100 EISA card with Cascade chip */ - { 0x04019F022, "HP J2577", HP100_BUS_EISA }, + { 0x4019F022, "HP J2577", HP100_BUS_EISA }, /* 10/100 ISA card with Cascade chip */ - { 0x05019F022, "HP J2573", HP100_BUS_ISA }, + { 0x5019F022, "HP J2573", HP100_BUS_ISA }, - /* 10/100 PCI card */ - /* Note: ID for this card is same as PCI vendor/device numbers. */ - { 0x01030103c, "HP J2585", HP100_BUS_PCI }, + /* 10/100 PCI card - old J2585A */ + { 0x1030103c, "HP J2585A", HP100_BUS_PCI }, + + /* 10/100 PCI card - new J2585B - master capable */ + { 0x1041103c, "HP J2585B", HP100_BUS_PCI }, + + /* 10 Mbit Combo Adapter */ + { 0x1042103c, "HP J2970", HP100_BUS_PCI }, + + /* 10 Mbit 10baseT Adapter */ + { 0x1040103c, "HP J2973", HP100_BUS_PCI }, + + /* 10/100 EISA card from Compex */ + { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA }, + + /* 10/100 PCI card from Compex (J2585A compatible) */ + { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI } }; static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; +static int hp100_mode = 1; + +#ifdef LINUX_2_1 +MODULE_PARM( hp100_rx_ratio, "1i" ); +MODULE_PARM( hp100_priority_tx, "1i" ); +MODULE_PARM( hp100_mode, "1i" ); +#endif /* * prototypes */ -static int hp100_probe1( struct device *dev, int ioaddr, int bus ); -static int hp100_open( struct device *dev ); -static int hp100_close( struct device *dev ); -static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); +static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); +static int hp100_open( struct device *dev ); +static int hp100_close( struct device *dev ); +static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); +static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev ); static void hp100_rx( struct device *dev ); -static struct net_device_stats *hp100_get_stats( struct device *dev ); +static hp100_stats_t *hp100_get_stats( struct device *dev ); static void hp100_update_stats( struct device *dev ); static void hp100_clear_stats( int ioaddr ); static void hp100_set_multicast_list( struct device *dev); static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ); - static void hp100_start_interface( struct device *dev ); static void hp100_stop_interface( struct device *dev ); static void hp100_load_eeprom( struct device *dev ); -static int hp100_sense_lan( struct device *dev ); -static int hp100_login_to_vg_hub( struct device *dev ); -static int hp100_down_vg_link( struct device *dev ); +static int hp100_sense_lan( struct device *dev ); +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ); +static int hp100_down_vg_link( struct device *dev ); +static void hp100_cascade_reset( struct device *dev, u_short enable ); +static void hp100_BM_shutdown( struct device *dev ); +static void hp100_mmuinit( struct device *dev ); +static void hp100_init_pdls( struct device *dev ); +static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u_int *pdlptr); +static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u_int *pdlptr); +static void hp100_rxfill( struct device *dev ); +static void hp100_hwinit( struct device *dev ); +static void hp100_clean_txring( struct device *dev ); +#ifdef HP100_DEBUG +static void hp100_RegisterDump( struct device *dev ); +#endif + +/* TODO: This function should not really be needed in a good design... */ +static void wait( void ) +{ + udelay( 1000 ); +} /* * probe functions + * These functions should - if possible - avoid doing write operations + * since this could cause problems when the card is not installed. */ __initfunc(int hp100_probe( struct device *dev )) { int base_addr = dev ? dev -> base_addr : 0; - int ioaddr; + int ioaddr = 0; #ifdef CONFIG_PCI int pci_start_index = 0; #endif +#ifdef HP100_DEBUG_B + hp100_outw( 0x4200, TRACE ); + printk( "hp100: probe\n" ); +#endif + if ( base_addr > 0xff ) /* Check a single specified location. */ { if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; if ( base_addr < 0x400 ) - return hp100_probe1( dev, base_addr, HP100_BUS_ISA ); - else - return hp100_probe1( dev, base_addr, HP100_BUS_EISA ); + return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); + else + return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); } - else + else #ifdef CONFIG_PCI - if ( base_addr > 0 && base_addr < 8 + 1 ) - pci_start_index = 0x100 | ( base_addr - 1 ); - else + if ( base_addr > 0 && base_addr < 8 + 1 ) + pci_start_index = 0x100 | ( base_addr - 1 ); + else #endif - if ( base_addr != 0 ) return -ENXIO; + if ( base_addr != 0 ) return -ENXIO; /* at first - scan PCI bus(es) */ @@ -249,65 +299,80 @@ __initfunc(int hp100_probe( struct device *dev )) u_char pci_bus, pci_device_fn; u_short pci_command; - if ( pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, - pci_index, &pci_bus, - &pci_device_fn ) != 0 ) break; + if ((pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, + pci_index, &pci_bus, + &pci_device_fn ) != 0 ) && + (pcibios_find_device( PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, + pci_index, &pci_bus, + &pci_device_fn ) != 0 ) && + (pcibios_find_device( PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, + pci_index, &pci_bus, + &pci_device_fn ) != 0 ) ) break; + pcibios_read_config_dword( pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr ); + PCI_BASE_ADDRESS_0, &ioaddr ); - ioaddr &= ~3; /* remove I/O space marker in bit 0. */ + ioaddr &= ~3; /* remove I/O space marker in bit 0. */ if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; pcibios_read_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command ); + PCI_COMMAND, &pci_command ); if ( !( pci_command & PCI_COMMAND_MASTER ) ) { -#ifdef HP100_DEBUG_PCI +#ifdef HP100_DEBUG printk( "hp100: PCI Master Bit has not been set. Setting...\n" ); #endif pci_command |= PCI_COMMAND_MASTER; pcibios_write_config_word( pci_bus, pci_device_fn, - PCI_COMMAND, pci_command ); + PCI_COMMAND, pci_command ); } -#ifdef HP100_DEBUG_PCI +#ifdef HP100_DEBUG printk( "hp100: PCI adapter found at 0x%x\n", ioaddr ); #endif - if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI ) == 0 ) return 0; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) + return 0; } } if ( pci_start_index > 0 ) return -ENODEV; #endif /* CONFIG_PCI */ - /* at second - probe all EISA possible port regions (if EISA bus present) */ - + /* Second: Probe all EISA possible port regions (if EISA bus present) */ for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA ) == 0 ) return 0; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; } - /* at third - probe all ISA possible port regions */ - + /* Third Probe all ISA possible port regions */ for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; - if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA ) == 0 ) return 0; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; } return -ENODEV; } -__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus )) + +__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) { int i; + u_char uc, uc_1; u_int eisa_id; + u_int chip; + u_int memory_size = 0; short mem_mapped; - u_char *mem_ptr_phys, *mem_ptr_virt; + u_int *mem_ptr_phys, *mem_ptr_virt; struct hp100_private *lp; struct hp100_eisa_id *eid; +#ifdef HP100_DEBUG_B + hp100_outw( 0x4201, TRACE ); + printk("hp100: probe1\n"); +#endif + if ( dev == NULL ) { #ifdef HP100_DEBUG @@ -315,19 +380,27 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus )) #endif return EIO; } + + if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) + { + return -ENODEV; + } + else + { + chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK; +#ifdef HP100_DEBUG + if ( chip == HP100_CHIPID_SHASTA ) + printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n"); + else if ( chip == HP100_CHIPID_RAINIER ) + printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n"); + else if ( chip == HP100_CHIPID_LASSEN ) + printk("hp100: Lassen Chip detected.\n"); + else + printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n",chip); +#endif + } - if ( bus != HP100_BUS_PCI ) /* don't check PCI cards again */ - if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 || - inb( ioaddr + 1 ) != HP100_HW_ID_1 || - ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA || - inb( ioaddr + 3 ) != HP100_HW_ID_3 ) - return -ENODEV; - - dev -> base_addr = ioaddr; - -#ifdef HP100_DEBUG_PROBE1 - printk( "hp100_probe1: card found at port 0x%x\n", ioaddr ); -#endif + dev->base_addr = ioaddr; hp100_page( ID_MAC_ADDR ); for ( i = uc = eisa_id = 0; i < 4; i++ ) @@ -339,17 +412,13 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus )) } uc += hp100_inb( BOARD_ID + 4 ); -#ifdef HP100_DEBUG_PROBE1 - printk( "hp100_probe1: EISA ID = 0x%08x checksum = 0x%02x\n", eisa_id, uc ); -#endif - - if ( uc != 0xff ) /* bad checksum? */ + if ( uc != 0xff ) /* bad checksum? */ { - printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr ); + printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr ); return -ENODEV; } - for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ ) + for ( i=0; i<sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id); i++) if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) ) break; if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) ) @@ -358,10 +427,10 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus )) return -ENODEV; } eid = &hp100_eisa_ids[ i ]; - if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) ) + if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) ) { printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", - eid -> name, ioaddr ); + eid->name, ioaddr ); return -ENODEV; } @@ -369,461 +438,1592 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, int bus )) uc += hp100_inb( LAN_ADDR + i ); if ( uc != 0xff ) { - printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", - eid -> name, ioaddr ); + printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", + eid->name, ioaddr ); return -EIO; } -#ifndef HP100_IO_MAPPED + /* Determine driver operation mode + * + * Use the variable "hp100_mode" upon insmod or as kernel parameter to + * force driver modes: + * hp100_mode=1 -> default, use busmaster mode if configured. + * hp100_mode=2 -> enable shared memory mode + * hp100_mode=3 -> force use of i/o mapped mode. + * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. + */ + + if(hp100_mode==3) + { + hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: IO mapped mode forced.\n"); + } + else if(hp100_mode==2) + { + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: Shared memory mode requested.\n"); + } + else if(hp100_mode==4) + { + if(chip==HP100_CHIPID_LASSEN) + { + hp100_outw(HP100_BM_WRITE| + HP100_BM_READ | HP100_SET_HB, OPTION_LSW); + hp100_outw(HP100_IO_EN | + HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + printk("hp100: Busmaster mode requested.\n"); + } + hp100_mode=1; + } + + if(hp100_mode==1) /* default behaviour */ + { + if( (hp100_inw(OPTION_LSW)&HP100_IO_EN) && + (~hp100_inw(OPTION_LSW)&HP100_MEM_EN) && + (~hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ)) + ) + { +#ifdef HP100_DEBUG + printk("hp100: IO_EN bit is set on card.\n"); +#endif + hp100_mode=3; + } + else if( ( chip==HP100_CHIPID_LASSEN ) && + ( (hp100_inw(OPTION_LSW)&(HP100_BM_WRITE|HP100_BM_READ) ) == + (HP100_BM_WRITE|HP100_BM_READ) ) ) + { + printk("hp100: Busmaster mode enabled.\n"); + hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); + } + else + { +#ifdef HP100_DEBUG + printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n"); +#endif + /* In this case, try shared memory mode */ + hp100_mode=2; + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ + } + } + + /* Check for shared memory on the card, eventually remap it */ hp100_page( HW_MAP ); - mem_mapped = ( hp100_inw( OPTION_LSW ) & - ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) ) != 0; + mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0); mem_ptr_phys = mem_ptr_virt = NULL; - if ( mem_mapped ) + memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07)); + + /* For memory mapped or busmaster mode, we want the memory address */ + if ( mem_mapped || (hp100_mode==1)) { - mem_ptr_phys = (u_char *)( hp100_inw( MEM_MAP_LSW ) | - ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); - (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | + ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); + (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 ) { + printk("hp100: Can only use programmed i/o mode.\n"); mem_ptr_phys = NULL; mem_mapped = 0; + hp100_mode=3; /* Use programmed i/o */ } - if ( mem_mapped && bus == HP100_BUS_PCI ) - { - if ( ( mem_ptr_virt = ioremap( (u_long)mem_ptr_phys, 0x2000 ) ) == NULL ) - { - printk( "hp100: ioremap for high PCI memory at 0x%lx failed\n", (u_long)mem_ptr_phys ); - mem_ptr_phys = NULL; - mem_mapped = 0; - } - } - } -#else - mem_mapped = 0; - mem_ptr_phys = mem_ptr_virt = NULL; + + /* We do not need access to shared memory in busmaster mode */ + /* However in slave mode we need to remap high (>1GB) card memory */ + if(hp100_mode!=1) /* = not busmaster */ + { + if ( bus == HP100_BUS_PCI ) + { + /* We try with smaller memory sizes, if ioremap fails */ + for(; memory_size>16383; memory_size=memory_size/2) + { + if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,memory_size))==NULL) + { +#ifdef HP100_DEBUG + printk( "hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long)mem_ptr_phys ); +#endif + } + else + { +#ifdef HP100_DEBUG + printk( "hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt); #endif + break; + } + } + + if(mem_ptr_virt==NULL) /* all ioremap tries failed */ + { + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); + hp100_mode=3; + memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07) ); + } + } + } + + } - if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL ) - return -ENOMEM; - memset( dev -> priv, 0, sizeof( struct hp100_private ) ); + if(hp100_mode==3) /* io mapped forced */ + { + mem_mapped = 0; + mem_ptr_phys = mem_ptr_virt = NULL; + printk("hp100: Using (slow) programmed i/o mode.\n"); + } - lp = (struct hp100_private *)dev -> priv; - lp -> id = eid; - lp -> mem_mapped = mem_mapped; - lp -> mem_ptr_phys = mem_ptr_phys; - lp -> mem_ptr_virt = mem_ptr_virt; + /* Initialise the "private" data structure for this card. */ + if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset( dev->priv, 0, sizeof(struct hp100_private) ); + + lp = (struct hp100_private *)dev->priv; + lp->id = eid; + lp->chip = chip; + lp->mode = hp100_mode; + lp->pci_bus = pci_bus; + lp->bus = bus; + lp->pci_device_fn = pci_device_fn; + lp->priority_tx = hp100_priority_tx; + lp->rx_ratio = hp100_rx_ratio; + lp->mem_ptr_phys = mem_ptr_phys; + lp->mem_ptr_virt = mem_ptr_virt; hp100_page( ID_MAC_ADDR ); - lp -> soft_model = hp100_inb( SOFT_MODEL ); - lp -> mac1_mode = HP100_MAC1MODE3; - lp -> mac2_mode = HP100_MAC2MODE3; + lp->soft_model = hp100_inb( SOFT_MODEL ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; - dev -> base_addr = ioaddr; - hp100_page( HW_MAP ); - dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK; - if ( dev -> irq == 2 ) dev -> irq = 9; - lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 ); - lp -> rx_ratio = hp100_rx_ratio; + dev->base_addr = ioaddr; + + lp->memory_size = memory_size; + lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ + + /* memory region for programmed i/o */ + request_region( dev->base_addr, HP100_REGION_SIZE, eid->name ); + + dev->open = hp100_open; + dev->stop = hp100_close; - dev -> open = hp100_open; - dev -> stop = hp100_close; - dev -> hard_start_xmit = hp100_start_xmit; - dev -> get_stats = hp100_get_stats; - dev -> set_multicast_list = &hp100_set_multicast_list; + if (lp->mode==1) /* busmaster */ + dev->hard_start_xmit = hp100_start_xmit_bm; + else + dev->hard_start_xmit = hp100_start_xmit; - request_region( dev -> base_addr, HP100_REGION_SIZE, eid -> name ); + dev->get_stats = hp100_get_stats; + dev->set_multicast_list = &hp100_set_multicast_list; + /* Ask the card for which IRQ line it is configured */ + hp100_page( HW_MAP ); + dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; + if ( dev->irq == 2 ) + dev->irq = 9; + + if(lp->mode==1) /* busmaster */ + dev->dma=4; + + /* Ask the card for its MAC address and store it for later use. */ hp100_page( ID_MAC_ADDR ); for ( i = uc = 0; i < 6; i++ ) - dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); + dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); + /* Reset statistics (counters) */ hp100_clear_stats( ioaddr ); ether_setup( dev ); - lp -> lan_type = hp100_sense_lan( dev ); + /* If busmaster mode is wanted, a dma-capable memory area is needed for + * the rx and tx PDLs + * PCI cards can access the whole PC memory. Therefore GFP_DMA is not + * needed for the allocation of the memory area. + */ - printk( "%s: %s at 0x%x, IRQ %d, ", - dev -> name, lp -> id -> name, ioaddr, dev -> irq ); + /* TODO: We do not need this with old cards, where PDLs are stored + * in the cards shared memory area. But currently, busmaster has been + * implemented/tested only with the lassen chip anyway... */ + if(lp->mode==1) /* busmaster */ + { + /* Get physically continous memory for TX & RX PDLs */ + if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL) + return -ENOMEM; + lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f)); + memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f); + +#ifdef HP100_DEBUG_BM + printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n", + (u_int)lp->page_vaddr_algn, + (u_int)lp->page_vaddr_algn+MAX_RINGSIZE); +#endif + lp->rxrcommit = lp->txrcommit = 0; + lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + lp->txrhead = lp->txrtail = &(lp->txring[0]); + } + + /* Initialise the card. */ + /* (I'm not really sure if it's a good idea to do this during probing, but + * like this it's assured that the lan connection type can be sensed + * correctly) + */ + hp100_hwinit( dev ); + + /* Try to find out which kind of LAN the card is connected to. */ + lp->lan_type = hp100_sense_lan( dev ); + + /* Print out a message what about what we think we have probed. */ + printk( "hp100: %s: %s at 0x%x, IRQ %d, ", + dev->name, lp->id->name, ioaddr, dev->irq ); switch ( bus ) { - case HP100_BUS_EISA: printk( "EISA" ); break; - case HP100_BUS_PCI: printk( "PCI" ); break; - default: printk( "ISA" ); break; + case HP100_BUS_EISA: printk( "EISA" ); break; + case HP100_BUS_PCI: printk( "PCI" ); break; + default: printk( "ISA" ); break; } printk( " bus, %dk SRAM (rx/tx %d%%).\n", - lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio ); - if ( mem_mapped ) + lp->memory_size >> 10, lp->rx_ratio ); + + if ( lp->mode==2 ) /* memory mapped */ { printk( "%s: Memory area at 0x%lx-0x%lx", - dev -> name, (u_long)mem_ptr_phys, (u_long)mem_ptr_phys + 0x1fff ); + dev->name,(u_long)mem_ptr_phys,(u_long)mem_ptr_phys+(u_long)lp->memory_size ); if ( mem_ptr_virt ) - printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); + printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); printk( ".\n" ); + + /* Set for info when doing ifconfig */ + dev->mem_start = (u_long)mem_ptr_phys; + dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size; } - printk( "%s: ", dev -> name ); - if ( lp -> lan_type != HP100_LAN_ERR ) + printk( "%s: ", dev->name ); + if ( lp->lan_type != HP100_LAN_ERR ) printk( "Adapter is attached to " ); - switch ( lp -> lan_type ) { - case HP100_LAN_100: - printk( "100Mb/s Voice Grade AnyLAN network.\n" ); - break; - case HP100_LAN_10: - printk( "10Mb/s network.\n" ); - break; - default: - printk( "Warning! Link down.\n" ); + switch ( lp->lan_type ) { + case HP100_LAN_100: + printk( "100Mb/s Voice Grade AnyLAN network.\n" ); + break; + case HP100_LAN_10: + printk( "10Mb/s network.\n" ); + break; + default: + printk( "Warning! Link down.\n" ); } + return 0; +} - hp100_stop_interface( dev ); + +/* This procedure puts the card into a stable init state */ +static void hp100_hwinit( struct device *dev ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; - return 0; +#ifdef HP100_DEBUG_B + hp100_outw( 0x4202, TRACE ); + printk("hp100: hwinit\n"); +#endif + + /* Initialise the card. -------------------------------------------- */ + + /* Clear all pending Ints and disable Ints */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */ + + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */ + wait(); + } + else + { + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_cascade_reset( dev, TRUE ); + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1); + } + + /* Initiate EEPROM reload */ + hp100_load_eeprom( dev ); + + wait(); + + /* Go into reset again. */ + hp100_cascade_reset( dev, TRUE ); + + /* Set Option Registers to a safe state */ + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | + HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB | + HP100_FAKE_INT | + HP100_INT_EN | + HP100_MEM_EN | + HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw( HP100_TRI_INT | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + + hp100_outb( HP100_PRIORITY_TX | + HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* TODO: Configure MMU for Ram Test. */ + /* TODO: Ram Test. */ + + /* Re-check if adapter is still at same i/o location */ + /* (If the base i/o in eeprom has been changed but the */ + /* registers had not been changed, a reload of the eeprom */ + /* would move the adapter to the address stored in eeprom */ + + /* TODO: Code to implement. */ + + /* Until here it was code from HWdiscover procedure. */ + /* Next comes code from mmuinit procedure of SCO BM driver which is + * called from HWconfigure in the SCO driver. */ + + /* Initialise MMU, eventually switch on Busmaster Mode, initialise + * multicast filter... + */ + hp100_mmuinit( dev ); + + /* We don't turn the interrupts on here - this is done by start_interface. */ + wait(); /* TODO: Do we really need this? */ + + /* Enable Hardware (e.g. unreset) */ + hp100_cascade_reset( dev, FALSE ); + + /* ------- initialisation complete ----------- */ + + /* Finally try to log in the Hub if there may be a VG connection. */ + if( lp->lan_type != HP100_LAN_10 ) + hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ } -/* - * open/close functions + +/* + * mmuinit - Reinitialise Cascade MMU and MAC settings. + * Note: Must already be in reset and leaves card in reset. */ - -static int hp100_open( struct device *dev ) +static void hp100_mmuinit( struct device *dev ) { + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; int i; - int ioaddr = dev -> base_addr; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; - if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name, NULL ) ) +#ifdef HP100_DEBUG_B + hp100_outw( 0x4203, TRACE ); + printk("hp100: mmuinit\n"); +#endif + +#ifdef HP100_DEBUG + if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) ) { - printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq ); - return -EAGAIN; + printk("hp100: Not in reset when entering mmuinit. Fix me.\n"); + return; } - irq2dev_map[ dev -> irq ] = dev; - - MOD_INC_USE_COUNT; +#endif - dev -> tbusy = 0; - dev -> trans_start = jiffies; - dev -> interrupt = 0; - dev -> start = 1; + /* Make sure IRQs are masked off and ack'ed. */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* + * Enable Hardware + * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En + * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable + * - Clear Priority, Advance Pkt and Xmit Cmd + */ + + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | HP100_RESET_HB | + HP100_IO_EN | + HP100_FAKE_INT | + HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if(lp->mode==1) /* busmaster */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + } + else if(lp->mode==2) /* memory mapped */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW ); + hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } + else if( lp->mode==3 ) /* i/o mapped mode */ + { + hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | + HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } - lp -> lan_type = hp100_sense_lan( dev ); - lp -> mac1_mode = HP100_MAC1MODE3; - lp -> mac2_mode = HP100_MAC2MODE3; + hp100_page( HW_MAP ); + hp100_outb( 0, EARLYRXCFG ); + hp100_outw( 0, EARLYTXCFG ); + + /* + * Enable Bus Master mode + */ + if(lp->mode==1) /* busmaster */ + { + /* Experimental: Set some PCI configuration bits */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */ + hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */ + + /* PCI Bus failures should result in a Misc. Interrupt */ + hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2); + + hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW ); + hp100_page( HW_MAP ); + /* Use Burst Mode and switch on PAGE_CK */ + hp100_orb( HP100_BM_BURST_RD | + HP100_BM_BURST_WR, BM); + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + hp100_orb( HP100_BM_PAGE_CK, BM ); + hp100_orb( HP100_BM_MASTER, BM ); + } + else /* not busmaster */ + { + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM ); + } - hp100_page( MAC_CTRL ); - hp100_orw( HP100_LINK_BEAT_DIS | HP100_RESET_LB, LAN_CFG_10 ); + /* + * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs + */ + hp100_page( MMU_CFG ); + if(lp->mode==1) /* only needed for Busmaster */ + { + int xmit_stop, recv_stop; - hp100_stop_interface( dev ); - hp100_load_eeprom( dev ); + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + { + int pdl_stop; + + /* + * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and + * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded + * to the next higher 1k boundary) bytes for the rx-pdl's + * Note: For non-etr chips the transmit stop register must be + * programmed on a 1k boundary, i.e. bits 9:0 must be zero. + */ + pdl_stop = lp->memory_size; + xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff); + recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff); + hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP ); +#ifdef HP100_DEBUG_BM + printk("hp100: PDL_STOP = 0x%x\n", pdl_stop); +#endif + } + else /* ETR chip (Lassen) in busmaster mode */ + { + xmit_stop = ( lp->memory_size ) - 1; + recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff); + } - hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | - HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); - hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB | - HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW ); - hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB | - HP100_PRIORITY_TX | ( hp100_priority_tx ? HP100_SET_HB : HP100_RESET_HB ), - OPTION_MSW ); + hp100_outw( xmit_stop>>4 , TX_MEM_STOP ); + hp100_outw( recv_stop>>4 , RX_MEM_STOP ); +#ifdef HP100_DEBUG_BM + printk("hp100: TX_STOP = 0x%x\n",xmit_stop>>4); + printk("hp100: RX_STOP = 0x%x\n",recv_stop>>4); +#endif + } + else /* Slave modes (memory mapped and programmed io) */ + { + hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP ); + hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP ); +#ifdef HP100_DEBUG + printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP)); + printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP)); +#endif + } + /* Write MAC address into page 1 */ hp100_page( MAC_ADDRESS ); for ( i = 0; i < 6; i++ ) - hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i ); - for ( i = 0; i < 8; i++ ) /* setup multicast filter to receive all */ - hp100_outb( 0xff, HASH_BYTE0 + i ); + hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i ); + + /* Zero the multicast hash registers */ + for ( i = 0; i < 8; i++ ) + hp100_outb( 0x0, HASH_BYTE0 + i ); + + /* Set up MAC defaults */ + hp100_page( MAC_CTRL ); + + /* Go to LAN Page and zero all filter bits */ + /* Zero accept error, accept multicast, accept broadcast and accept */ + /* all directed packet bits */ + hp100_andb( ~(HP100_RX_EN| + HP100_TX_EN| + HP100_ACC_ERRORED| + HP100_ACC_MC| + HP100_ACC_BC| + HP100_ACC_PHY), MAC_CFG_1 ); + + hp100_outb( 0x00, MAC_CFG_2 ); + + /* Zero the frame format bit. This works around a training bug in the */ + /* new hubs. */ + hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */ + + if(lp->priority_tx) + hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW ); + else + hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW ); + + hp100_outb( HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* If busmaster, initialize the PDLs */ + if(lp->mode==1) + hp100_init_pdls( dev ); + + /* Go to performance page and initalize isr and imr registers */ hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ - hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ - hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) | - (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK ); - /* and enable few */ - hp100_reset_card(); - hp100_page( MMU_CFG ); - hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP ); - hp100_outw( lp -> memory_size - 1, TX_MEM_STOP ); - hp100_unreset_card(); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ +} + + +/* + * open/close functions + */ + +static int hp100_open( struct device *dev ) +{ + struct hp100_private *lp = (struct hp100_private *)dev->priv; +#ifdef HP100_DEBUG_B + int ioaddr=dev->base_addr; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4204, TRACE ); + printk("hp100: open\n"); +#endif + + /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ + if((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA)) + { + if(request_irq(dev->irq,hp100_interrupt,SA_SHIRQ,lp->id->name,dev)) + { + printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq ); + return -EAGAIN; + } + } + else + if(request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, NULL)) + { + printk( "%s: unable to get IRQ %d\n", dev->name, dev->irq ); + return -EAGAIN; + } + + irq2dev_map[ dev->irq ] = dev; + + MOD_INC_USE_COUNT; - if ( lp -> lan_type == HP100_LAN_100 ) - lp -> hub_status = hp100_login_to_vg_hub( dev ); + dev->tbusy = 0; + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; - hp100_start_interface( dev ); + lp->lan_type = hp100_sense_lan( dev ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + + hp100_stop_interface( dev ); + + hp100_hwinit( dev ); + + hp100_start_interface( dev ); /* sets mac modes, enables interrupts */ return 0; } + +/* The close function is called when the interface is to be brought down */ static int hp100_close( struct device *dev ) { - int ioaddr = dev -> base_addr; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4205, TRACE ); + printk("hp100:close\n"); +#endif hp100_page( PERFORMANCE ); - hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ hp100_stop_interface( dev ); - if ( lp -> lan_type == HP100_LAN_100 ) /* relogin */ - hp100_login_to_vg_hub( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); - dev -> tbusy = 1; - dev -> start = 0; + dev->tbusy = 1; + dev->start = 0; - free_irq( dev -> irq, NULL ); - irq2dev_map[ dev -> irq ] = NULL; + if ((lp->bus==HP100_BUS_PCI)||(lp->bus==HP100_BUS_EISA)) + free_irq( dev->irq, dev ); + else + free_irq( dev->irq, NULL ); + irq2dev_map[ dev->irq ] = NULL; MOD_DEC_USE_COUNT; return 0; } + +/* + * Configure the PDL Rx rings and LAN + */ +static void hp100_init_pdls( struct device *dev ) +{ + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + u_int *pageptr; + int i; + +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4206, TRACE ); + printk("hp100: init pdls\n"); +#endif + + if(0==lp->page_vaddr_algn) + printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n"); + else + { + /* pageptr shall point into the DMA accessible memory region */ + /* we use this pointer to status the upper limit of allocated */ + /* memory in the allocated page. */ + /* note: align the pointers to the pci cache line size */ + memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ + pageptr=lp->page_vaddr_algn; + + lp->rxrcommit =0; + ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]); + + /* Initialise Rx Ring */ + for (i=MAX_RX_PDL-1; i>=0; i--) + { + lp->rxring[i].next = ringptr; + ringptr=&(lp->rxring[i]); + pageptr+=hp100_init_rxpdl(ringptr, pageptr); + } + + /* Initialise Tx Ring */ + lp->txrcommit = 0; + ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); + for (i=MAX_TX_PDL-1; i>=0; i--) + { + lp->txring[i].next = ringptr; + ringptr=&(lp->txring[i]); + pageptr+=hp100_init_txpdl(ringptr, pageptr); + } + } +} + + +/* These functions "format" the entries in the pdl structure */ +/* They return how much memory the fragments need. */ +static int hp100_init_rxpdl( register hp100_ring_t *ringptr, register u32 *pdlptr ) +{ + /* pdlptr is starting adress for this pdl */ + + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n",(unsigned)pdlptr); + + ringptr->pdl = pdlptr+1; + ringptr->pdl_paddr = virt_to_bus(pdlptr+1); + ringptr->skb = (void *) NULL; + + /* + * Write address and length of first PDL Fragment (which is used for + * storing the RX-Header + * We use the 4 bytes _before_ the PDH in the pdl memory area to + * store this information. (PDH is at offset 0x04) + */ + /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ + + *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ + *(pdlptr+3) = 4; /* Length Frag 1 */ + + return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 ); +} + + +static int hp100_init_txpdl( register hp100_ring_t *ringptr, register u32 *pdlptr ) +{ + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n",(unsigned) pdlptr); + + ringptr->pdl = pdlptr; /* +1; */ + ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ + ringptr->skb = (void *) NULL; + + return((((MAX_TX_FRAG*2+2)+3)/4)*4); +} + + +/* + * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes + * for possible odd word alignment rounding up to next dword and set PDL + * address for fragment#2 + * Returns: 0 if unable to allocate skb_buff + * 1 if successful + */ +int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev ) +{ +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif +#ifdef HP100_DEBUG_BM + u_int *p; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4207, TRACE ); + printk("hp100: build rx pdl\n"); +#endif + + /* Allocate skb buffer of maximum size */ + /* Note: This depends on the alloc_skb functions allocating more + * space than requested, i.e. aligning to 16bytes */ + + ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 ); + + if(NULL!=ringptr->skb) + { + /* + * Reserve 2 bytes at the head of the buffer to land the IP header + * on a long word boundary (According to the Network Driver section + * in the Linux KHG, this should help to increase performance.) + */ + skb_reserve(ringptr->skb, 2); + + ringptr->skb->dev=dev; + ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE ); + + /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ + /* Note: 1st Fragment is used for the 4 byte packet status + * (receive header). Its PDL entries are set up by init_rxpdl. So + * here we only have to set up the PDL fragment entries for the data + * part. Those 4 bytes will be stored in the DMA memory region + * directly before the PDL. + */ +#ifdef HP100_DEBUG_BM + printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", + (u_int) ringptr->pdl, + ((MAX_ETHER_SIZE+2+3)/4)*4, + (unsigned int) ringptr->skb->data); +#endif + + ringptr->pdl[0] = 0x00020000; /* Write PDH */ + ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); + ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ + +#ifdef HP100_DEBUG_BM + for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++) + printk("Adr 0x%.8x = 0x%.8x\n",(u_int) p,(u_int) *p ); +#endif + return(1); + } + /* else: */ + /* alloc_skb failed (no memory) -> still can receive the header + * fragment into PDL memory. make PDL safe by clearing msgptr and + * making the PDL only 1 fragment (i.e. the 4 byte packet status) + */ +#ifdef HP100_DEBUG_BM + printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n", + (u_int) ringptr->pdl); +#endif + + ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */ + + return(0); +} + + +/* + * hp100_rxfill - attempt to fill the Rx Ring will empty skb's + * + * Makes assumption that skb's are always contiguous memory areas and + * therefore PDLs contain only 2 physical fragments. + * - While the number of Rx PDLs with buffers is less than maximum + * a. Get a maximum packet size skb + * b. Put the physical address of the buffer into the PDL. + * c. Output physical address of PDL to adapter. + */ +static void hp100_rxfill( struct device *dev ) +{ + int ioaddr=dev->base_addr; + + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4208, TRACE ); + printk("hp100: rxfill\n"); +#endif + + hp100_page( PERFORMANCE ); + + while (lp->rxrcommit < MAX_RX_PDL) + { + /* + ** Attempt to get a buffer and build a Rx PDL. + */ + ringptr = lp->rxrtail; + if (0 == hp100_build_rx_pdl( ringptr, dev )) + { + return; /* None available, return */ + } + + /* Hand this PDL over to the card */ + /* Note: This needs performance page selected! */ +#ifdef HP100_DEBUG_BM + printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", + lp->rxrcommit, + (u_int)ringptr->pdl, + (u_int)ringptr->pdl_paddr, + (u_int)ringptr->pdl[3]); +#endif + + hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); + + lp->rxrcommit += 1; + lp->rxrtail = ringptr->next; + } +} + + /* - * transmit + * BM_shutdown - shutdown bus mastering and leave chip in reset state */ +static void hp100_BM_shutdown( struct device *dev ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + unsigned long time; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4209, TRACE ); + printk("hp100: bm shutdown\n"); +#endif + + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */ + + /* Ensure Interrupts are off */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW ); + + /* Disable all MAC activity */ + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + + /* If cascade MMU is not already in reset */ + if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) ) + { + /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so + * MMU pointers will not be reset out from underneath + */ + hp100_page( MAC_CTRL ); + for(time=0; time<5000; time++) + { + if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))== + (HP100_TX_IDLE|HP100_RX_IDLE) ) break; + } + + /* Shutdown algorithm depends on the generation of Cascade */ + if( lp->chip==HP100_CHIPID_LASSEN ) + { /* ETR shutdown/reset */ + /* Disable Busmaster mode and wait for bit to go to zero. */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + /* 100 ms timeout */ + for(time=0; time<32000; time++) + { + if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break; + } + } + else + { /* Shasta or Rainier Shutdown/Reset */ + /* To ensure all bus master inloading activity has ceased, + * wait for no Rx PDAs or no Rx packets on card. + */ + hp100_page( PERFORMANCE ); + /* 100 ms timeout */ + for(time=0; time<10000; time++) + { + /* RX_PDL: PDLs not executed. */ + /* RX_PKT_CNT: RX'd packets on card. */ + if ( (hp100_inb( RX_PDL ) == 0) && + (hp100_inb( RX_PKT_CNT ) == 0) ) break; + } + + if(time>=10000) + printk("hp100: BM shutdown error.\n"); + + /* To ensure all bus master outloading activity has ceased, + * wait until the Tx PDA count goes to zero or no more Tx space + * available in the Tx region of the card. + */ + /* 100 ms timeout */ + for(time=0; time<10000; time++) { + if ( (0 == hp100_inb( TX_PKT_CNT )) && + (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break; + } + + /* Disable Busmaster mode */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + } /* end of shutdown procedure for non-etr parts */ + + hp100_cascade_reset( dev, TRUE ); + } + hp100_page( PERFORMANCE ); + hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); + /* Busmaster mode should be shut down now. */ +} + + + +/* + * transmit functions + */ + +/* tx function for busmaster mode */ +static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ) +{ + int i, ok_flag; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4210, TRACE ); + printk("hp100: start_xmit_bm\n"); +#endif + + if ( skb==NULL ) + { + dev_tint( dev ); + return 0; + } + + if ( skb->len <= 0 ) return 0; + + /* Get Tx ring tail pointer */ + if( lp->txrtail->next==lp->txrhead ) + { + /* No memory. */ +#ifdef HP100_DEBUG + printk("hp100: start_xmit_bm: No TX PDL available.\n"); +#endif + /* not waited long enough since last tx? */ + if ( jiffies - dev->trans_start < HZ/10 ) return -EAGAIN; + + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ + { + hp100_stop_interface( dev ); + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) + { + printk( "%s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */ + return -EIO; + } + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ + hp100_start_interface( dev ); + } + + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk( "%s: login to 100Mb/s hub retry\n", dev->name ); + hp100_stop_interface( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + hp100_ints_off(); + i = hp100_sense_lan( dev ); + hp100_page( PERFORMANCE ); + hp100_ints_on(); + if ( i == HP100_LAN_ERR ) + printk( "%s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "%s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + hp100_start_interface( dev ); + } + } + + dev->trans_start = jiffies; + return -EAGAIN; + } + + /* + * we have to turn int's off before modifying this, otherwise + * a tx_pdl_cleanup could occur at the same time + */ + cli(); + ringptr=lp->txrtail; + lp->txrtail=ringptr->next; + + /* Check whether packet has minimal packet size */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + ringptr->skb=skb; + ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */ + ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ + if(lp->chip==HP100_CHIPID_SHASTA) + { + /* TODO:Could someone who has the EISA card please check if this works? */ + ringptr->pdl[2]=i; + } + else /* Lassen */ + { + /* In the PDL, don't use the padded size but the real packet size: */ + ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */ + } + + /* Hand this PDL to the card. */ + hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ + + lp->txrcommit++; + sti(); + + /* Update statistics */ + lp->stats.tx_packets++; +#ifdef LINUX_2_1 + lp->stats.tx_bytes += skb->len; +#endif + dev->trans_start = jiffies; + + return 0; +} + + +/* clean_txring checks if packets have been sent by the card by reading + * the TX_PDL register from the performance page and comparing it to the + * number of commited packets. It then frees the skb's of the packets that + * obviously have been sent to the network. + * + * Needs the PERFORMANCE page selected. + */ +static void hp100_clean_txring( struct device *dev ) +{ + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + int donecount; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4211, TRACE ); + printk("hp100: clean txring\n"); +#endif + + /* How many PDLs have been transmitted? */ + donecount=(lp->txrcommit)-hp100_inb(TX_PDL); + +#ifdef HP100_DEBUG + if(donecount>MAX_TX_PDL) + printk("hp100: Warning: More PDLs transmitted than commited to card???\n"); +#endif + + for( ; 0!=donecount; donecount-- ) + { +#ifdef HP100_DEBUG_BM + printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", + (u_int) lp->txrhead->skb->data, + lp->txrcommit, + hp100_inb(TX_PDL), + donecount); +#endif + dev_kfree_skb( lp->txrhead->skb, FREE_WRITE ); + lp->txrhead->skb=(void *)NULL; + lp->txrhead=lp->txrhead->next; + lp->txrcommit--; + } +} + + +/* tx function for slave modes */ static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ) { int i, ok_flag; - int ioaddr = dev -> base_addr; + int ioaddr = dev->base_addr; u_short val; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4212, TRACE ); + printk("hp100: start_xmit\n"); +#endif - if ( lp -> lan_type < 0 ) + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ { hp100_stop_interface( dev ); - if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 ) + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) { - printk( "%s: no connection found - check wire\n", dev -> name ); - hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ + printk( "%s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ return -EIO; } - if ( lp -> lan_type == HP100_LAN_100 ) - lp -> hub_status = hp100_login_to_vg_hub( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ hp100_start_interface( dev ); } - if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 ) + /* If there is not enough free memory on the card... */ + i=hp100_inl(TX_MEM_FREE)&0x7fffffff; + if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) ) { #ifdef HP100_DEBUG - printk( "hp100_start_xmit: rx free mem = 0x%x\n", i ); + printk( "hp100_start_xmit: tx free mem = 0x%x\n", i ); #endif - if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN; - if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 ) - /* 100Mb/s adapter isn't connected to hub */ + /* not waited long enough since last failed tx try? */ + if ( jiffies - dev->trans_start < HZ/2 ) + { +#ifdef HP100_DEBUG + printk("hp100: trans_start timing problem\n"); +#endif + return -EAGAIN; + } + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ { - printk( "%s: login to 100Mb/s hub retry\n", dev -> name ); + printk( "%s: login to 100Mb/s hub retry\n", dev->name ); hp100_stop_interface( dev ); - lp -> hub_status = hp100_login_to_vg_hub( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); hp100_start_interface( dev ); } - else + else { hp100_ints_off(); i = hp100_sense_lan( dev ); hp100_page( PERFORMANCE ); hp100_ints_on(); if ( i == HP100_LAN_ERR ) - printk( "%s: link down detected\n", dev -> name ); - else - if ( lp -> lan_type != i ) - { - /* it's very heavy - all network setting must be changed!!! */ - printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name ); - lp -> lan_type = i; - hp100_stop_interface( dev ); - if ( lp -> lan_type == HP100_LAN_100 ) - lp -> hub_status = hp100_login_to_vg_hub( dev ); - hp100_start_interface( dev ); - } - else - { - printk( "%s: interface reset\n", dev -> name ); - hp100_stop_interface( dev ); - hp100_start_interface( dev ); - } + printk( "%s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "%s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + hp100_start_interface( dev ); + udelay(1000); + } } - dev -> trans_start = jiffies; + dev->trans_start = jiffies; return -EAGAIN; } - for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ ) + for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ ) { #ifdef HP100_DEBUG_TX printk( "hp100_start_xmit: busy\n" ); #endif } - + hp100_ints_off(); val = hp100_inw( IRQ_STATUS ); - hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS ); + /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set + * when the current packet being transmitted on the wire is completed. */ + hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); #ifdef HP100_DEBUG_TX - printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len ); + printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",val,hp100_inw(IRQ_MASK),(int)skb->len ); #endif - ok_flag = skb -> len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb -> len : HP100_MIN_PACKET_SIZE; - hp100_outw( i, DATA32 ); /* length to memory manager */ - hp100_outw( i, FRAGMENT_LEN ); - if ( lp -> mem_mapped ) + + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + hp100_outw( i, DATA32 ); /* tell card the total packet length */ + hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */ + + if ( lp->mode==2 ) /* memory mapped */ { - if ( lp -> mem_ptr_virt ) - { - memcpy( lp -> mem_ptr_virt, skb -> data, skb -> len ); - if ( !ok_flag ) - memset( lp -> mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb -> len ); - } - else - { - memcpy_toio( lp -> mem_ptr_phys, skb -> data, skb -> len ); - if ( !ok_flag ) - memset_io( lp -> mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb -> len ); - } + if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ + { + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy( lp->mem_ptr_virt, skb->data, ( skb->len +3 ) & ~3 ); + if ( !ok_flag ) + memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); + } + else + { + memcpy_toio( lp->mem_ptr_phys, skb->data, skb->len ); + if ( !ok_flag ) + memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); + } } - else + else /* programmed i/o */ { - outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 ); + outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 ); if ( !ok_flag ) - for ( i = ( skb -> len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) - hp100_outl( 0, DATA32 ); + for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) + hp100_outl( 0, DATA32 ); } - hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ - lp -> stats.tx_packets++; - dev -> trans_start = jiffies; + + hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ + + lp->stats.tx_packets++; +#ifdef LINUX_2_1 + lp->stats.tx_bytes += skb->len; +#endif + dev->trans_start=jiffies; hp100_ints_on(); - + dev_kfree_skb( skb, FREE_WRITE ); - + #ifdef HP100_DEBUG_TX printk( "hp100_start_xmit: end\n" ); #endif - + return 0; } + /* - * receive - called from interrupt handler + * Receive Function (Non-Busmaster mode) + * Called when an "Receive Packet" interrupt occurs, i.e. the receive + * packet counter is non-zero. + * For non-busmaster, this function does the whole work of transfering + * the packet to the host memory and then up to higher layers via skb + * and netif_rx. */ static void hp100_rx( struct device *dev ) { int packets, pkt_len; - int ioaddr = dev -> base_addr; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; u_int header; struct sk_buff *skb; -#if 0 - if ( lp -> lan_type < 0 ) - { - if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) == HP100_LAN_100 ) - lp -> hub_status = hp100_login_to_vg_hub( dev ); - hp100_page( PERFORMANCE ); - } +#ifdef DEBUG_B + hp100_outw( 0x4213, TRACE ); + printk("hp100: rx\n"); #endif + /* First get indication of received lan packet */ + /* RX_PKT_CND indicates the number of packets which have been fully */ + /* received onto the card but have not been fully transfered of the card */ packets = hp100_inb( RX_PKT_CNT ); -#ifdef HP100_DEBUG +#ifdef HP100_DEBUG_RX if ( packets > 1 ) printk( "hp100_rx: waiting packets = %d\n", packets ); #endif + while ( packets-- > 0 ) { - for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ ) + /* If ADV_NXT_PKT is still set, we have to wait until the card has */ + /* really advanced to the next packet. */ + for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT); + pkt_len++ ) { -#ifdef HP100_DEBUG_TX +#ifdef HP100_DEBUG_RX printk( "hp100_rx: busy, remaining packets = %d\n", packets ); -#endif +#endif } - if ( lp -> mem_mapped ) + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + if( lp->mode==2 ) /* memory mapped mode */ { - if ( lp -> mem_ptr_virt ) - header = *(__u32 *)lp -> mem_ptr_virt; - else - header = readl( lp -> mem_ptr_phys ); + if ( lp->mem_ptr_virt ) /* if memory was remapped */ + header = *(__u32 *)lp->mem_ptr_virt; + else + header = readl( lp->mem_ptr_phys ); } - else + else /* programmed i/o */ header = hp100_inl( DATA32 ); + pkt_len = header & HP100_PKT_LEN_MASK; + #ifdef HP100_DEBUG_RX - printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n", - header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 ); + printk( "hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", + header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8, + (header>>16)&7); #endif - /* - * NOTE! This (and the skb_put() below) depends on the skb-functions + + /* Now we allocate the skb and transfer the data into it. */ + /* NOTE! This (and the skb_put() below) depends on the skb-functions * allocating more than asked (notably, aligning the request up to * the next 16-byte length). */ skb = dev_alloc_skb( pkt_len ); - if ( skb == NULL ) - { + if ( skb == NULL ) /* Not enough memory->drop packet */ + { #ifdef HP100_DEBUG - printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len ); + printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len ); #endif - lp -> stats.rx_dropped++; - } - else - { - u_char *ptr; - - skb -> dev = dev; - ptr = (u_char *)skb_put( skb, pkt_len ); - if ( lp -> mem_mapped ) + lp->stats.rx_dropped++; + } + else /* skb successfully allocated */ + { + u_char *ptr; + + skb->dev = dev; + + /* ptr to start of the sk_buff data area */ + ptr = (u_char *)skb_put( skb, pkt_len ); + + /* Now transfer the data from the card into that area */ + if ( lp->mode==2 ) { - if ( lp -> mem_ptr_virt ) - memcpy( ptr, lp -> mem_ptr_virt, ( pkt_len + 3 ) & ~3 ); - else - memcpy_fromio( ptr, lp -> mem_ptr_phys, ( pkt_len + 3 ) & ~3 ); + if ( lp->mem_ptr_virt ) + memcpy( ptr, lp->mem_ptr_virt, ( pkt_len + 3 ) & ~3 ); + /* Note alignment to 32bit transfers */ + else + memcpy_fromio( ptr, lp->mem_ptr_phys, ( pkt_len + 3 ) & ~3 ); } - else - insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 ); - skb -> protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - lp -> stats.rx_packets++; + else /* io mapped */ + insl( ioaddr + HP100_REG_DATA32, ptr, ( pkt_len + 3 ) >> 2 ); + + skb->protocol = eth_type_trans( skb, dev ); + + netif_rx( skb ); + lp->stats.rx_packets++; +#ifdef LINUX_2_1 + lp->stats.rx_bytes += skb->len; +#endif + #ifdef HP100_DEBUG_RX - printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], - ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); + printk( "rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], + ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); #endif - } - hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); + } + + /* Indicate the card that we have got the packet */ + hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); + switch ( header & 0x00070000 ) { - case (HP100_MULTI_ADDR_HASH<<16): - case (HP100_MULTI_ADDR_NO_HASH<<16): - lp -> stats.multicast++; break; + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; } - } + } /* end of while(there are packets) loop */ #ifdef HP100_DEBUG_RX - printk( "hp100_rx: end\n" ); + printk( "hp100_rx: end\n" ); +#endif +} + + +/* + * Receive Function for Busmaster Mode + */ +static void hp100_rx_bm( struct device *dev ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ptr; + u_int header; + int pkt_len; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4214, TRACE ); + printk("hp100: rx_bm\n"); +#endif + +#ifdef HP100_DEBUG + if(0==lp->rxrcommit) + { + printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); + return; + } + else + + /* RX_PKT_CNT states how many PDLs are currently formatted and available to + * the cards BM engine */ + if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit) + { + printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit); + return; + } +#endif + + while( (lp->rxrcommit > hp100_inb(RX_PDL)) ) + { + /* + * The packet was received into the pdl pointed to by lp->rxrhead ( + * the oldest pdl in the ring + */ + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + + ptr=lp->rxrhead; + + header = *(ptr->pdl-1); + pkt_len = (header & HP100_PKT_LEN_MASK); + +#ifdef HP100_DEBUG_BM + printk( "hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", + (u_int) (ptr->pdl-1),(u_int) header, + pkt_len, + (header>>16)&0xfff8, + (header>>16)&7); + printk( "hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", + hp100_inb( RX_PDL ), + hp100_inb( TX_PDL ), + hp100_inb( RX_PKT_CNT ), + (u_int) *(ptr->pdl), + (u_int) *(ptr->pdl+3), + (u_int) *(ptr->pdl+4)); +#endif + + if( (pkt_len>=MIN_ETHER_SIZE) && + (pkt_len<=MAX_ETHER_SIZE) ) + { + if(ptr->skb==NULL) + { + printk("hp100: rx_bm: skb null\n"); + /* can happen if we only allocated room for the pdh due to memory shortage. */ + lp->stats.rx_dropped++; + } + else + { + skb_trim( ptr->skb, pkt_len ); /* Shorten it */ + ptr->skb->protocol = eth_type_trans( ptr->skb, dev ); + + netif_rx( ptr->skb ); /* Up and away... */ + + lp->stats.rx_packets++; +#ifdef LINUX_2_1 + lp->stats.rx_bytes += ptr->skb->len; +#endif + } + + switch ( header & 0x00070000 ) { + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; + } + } + else + { +#ifdef HP100_DEBUG + printk("hp100: rx_bm: Received bad packet (length=%d)\n",pkt_len); +#endif + if(ptr->skb!=NULL) + dev_kfree_skb( ptr->skb, FREE_READ ); + lp->stats.rx_errors++; + } + + lp->rxrhead=lp->rxrhead->next; + + /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ + if (0 == hp100_build_rx_pdl( lp->rxrtail, dev )) + { + /* No space for skb, header can still be received. */ +#ifdef HP100_DEBUG + printk("hp100: rx_bm: No space for new PDL.\n"); #endif + return; + } + else + { /* successfully allocated new PDL - put it in ringlist at tail. */ + hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA); + lp->rxrtail=lp->rxrtail->next; + } + + } } + + /* * statistics */ - -static struct net_device_stats *hp100_get_stats( struct device *dev ) +static hp100_stats_t *hp100_get_stats( struct device *dev ) { - int ioaddr = dev -> base_addr; + int ioaddr = dev->base_addr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4215, TRACE ); +#endif hp100_ints_off(); hp100_update_stats( dev ); hp100_ints_on(); - return &((struct hp100_private *)dev -> priv) -> stats; + return &((struct hp100_private *)dev->priv)->stats; } static void hp100_update_stats( struct device *dev ) { - int ioaddr = dev -> base_addr; + int ioaddr = dev->base_addr; u_short val; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4216, TRACE ); + printk("hp100: update-stats\n"); +#endif - hp100_page( MAC_CTRL ); /* get all statistics bytes */ + /* Note: Statistics counters clear when read. */ + hp100_page( MAC_CTRL ); val = hp100_inw( DROPPED ) & 0x0fff; - lp -> stats.rx_errors += val; - lp -> stats.rx_over_errors += val; + lp->stats.rx_errors += val; + lp->stats.rx_over_errors += val; val = hp100_inb( CRC ); - lp -> stats.rx_errors += val; - lp -> stats.rx_crc_errors += val; + lp->stats.rx_errors += val; + lp->stats.rx_crc_errors += val; val = hp100_inb( ABORT ); - lp -> stats.tx_errors += val; - lp -> stats.tx_aborted_errors += val; + lp->stats.tx_errors += val; + lp->stats.tx_aborted_errors += val; hp100_page( PERFORMANCE ); } static void hp100_clear_stats( int ioaddr ) { +#ifdef HP100_DEBUG_B + hp100_outw( 0x4217, TRACE ); + printk("hp100: clear_stats\n"); +#endif + cli(); - hp100_page( MAC_CTRL ); /* get all statistics bytes */ + hp100_page( MAC_CTRL ); /* get all statistics bytes */ hp100_inw( DROPPED ); hp100_inb( CRC ); hp100_inb( ABORT ); @@ -831,54 +2031,73 @@ static void hp100_clear_stats( int ioaddr ) sti(); } + /* * multicast setup */ /* * Set or clear the multicast filter for this adapter. + * TODO: Currently when in multicast mode, card accepts all multicast packets + * for all MC addresses. Should better use the list on the card. */ - + static void hp100_set_multicast_list( struct device *dev) { - int ioaddr = dev -> base_addr; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; -#ifdef HP100_DEBUG_MULTI - printk( "hp100_set_multicast_list: num_addrs = %d\n", dev->mc_count); +#ifdef HP100_DEBUG_B + hp100_outw( 0x4218, TRACE ); + printk("hp100: set_mc_list\n"); #endif + cli(); hp100_ints_off(); hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ - if ( dev->flags&IFF_PROMISC) + if ( dev->flags & IFF_PROMISC ) { - lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */ - lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */ + lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ + lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ } - else - if ( dev->mc_count || dev->flags&IFF_ALLMULTI ) + else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) ) { - lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */ - lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */ + lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ + lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ } - else + else { - lp -> mac2_mode = HP100_MAC2MODE3; /* normal mode, packets for me */ - lp -> mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ + lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ + lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ } - hp100_outb( lp -> mac2_mode, MAC_CFG_2 ); - hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); - hp100_orb( lp -> mac1_mode | - HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */ + if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) || + ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) { + hp100_outb( lp->mac2_mode, MAC_CFG_2 ); + hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */ + hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */ + + if(lp->lan_type==HP100_LAN_100) + { +#ifdef HP100_DEBUG + printk("hp100: 100VG MAC settings have changed - relogin.\n"); +#endif + lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ + } + } + + hp100_page( MAC_CTRL ); + hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ + HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */ + hp100_page( PERFORMANCE ); hp100_ints_on(); sti(); } + /* * hardware interrupt handling */ @@ -886,249 +2105,747 @@ static void hp100_set_multicast_list( struct device *dev) static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ) { struct device *dev = (struct device *)irq2dev_map[ irq ]; - struct hp100_private *lp; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr; - u_short val; + u_int val; if ( dev == NULL ) return; - ioaddr = dev -> base_addr; - if ( dev -> interrupt ) - printk( "%s: re-entering the interrupt handler\n", dev -> name ); + ioaddr = dev->base_addr; + + if ( dev->interrupt ) + printk( "%s: re-entering the interrupt handler\n", dev->name ); hp100_ints_off(); - dev -> interrupt = 1; - hp100_page( PERFORMANCE ); + dev->interrupt = 1; /* mark that we are inside the handler */ + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4219, TRACE ); +#endif + + /* hp100_page( PERFORMANCE ); */ val = hp100_inw( IRQ_STATUS ); #ifdef HP100_DEBUG_IRQ - printk( "hp100_interrupt: irq_status = 0x%x\n", val ); + printk( "hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", + lp->mode, + (u_int)val, + hp100_inb( RX_PKT_CNT ), + hp100_inb( RX_PDL ), + hp100_inb( TX_PKT_CNT ), + hp100_inb( TX_PDL ) + ); #endif - if ( val & HP100_RX_PACKET ) + + if(val==0) /* might be a shared interrupt */ { - hp100_rx( dev ); - hp100_outw( HP100_RX_PACKET, IRQ_STATUS ); + dev->interrupt=0; + hp100_ints_on(); + return; } - if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) ) + /* We're only interested in those interrupts we really enabled. */ + /* val &= hp100_inw( IRQ_MASK ); */ + + /* + * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL + * is considered executed whenever the RX_PDL data structure is no longer + * needed. + */ + if ( val & HP100_RX_PDL_FILL_COMPL ) { - hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS ); + if(lp->mode==1) + hp100_rx_bm( dev ); + else + printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n"); } - if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) ) + + /* + * The RX_PACKET interrupt is set, when the receive packet counter is + * non zero. We use this interrupt for receiving in slave mode. In + * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill + * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then + * we somehow have missed a rx_pdl_fill_compl interrupt. + */ + + if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */ { - lp = (struct hp100_private *)dev -> priv; - hp100_update_stats( dev ); - hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS ); + if(lp->mode!=1) /* non busmaster */ + hp100_rx( dev ); + else if ( !(val & HP100_RX_PDL_FILL_COMPL )) + { + /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ + hp100_rx_bm( dev ); + } } + + /* + * Ack. that we have noticed the interrupt and thereby allow next one. + * Note that this is now done after the slave rx function, since first + * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt + * on the J2573. + */ + hp100_outw( val, IRQ_STATUS ); + + /* + * RX_ERROR is set when a packet is dropped due to no memory resources on + * the card or when a RCV_ERR occurs. + * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists + * only in the 802.3 MAC and happens when 16 collisions occur during a TX + */ + if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) ) + { #ifdef HP100_DEBUG_IRQ - printk( "hp100_interrupt: end\n" ); + printk("hp100: TX/RX Error IRQ\n"); #endif - dev -> interrupt = 0; + hp100_update_stats( dev ); + if(lp->mode==1) + { + hp100_rxfill( dev ); + hp100_clean_txring( dev ); + } + } + + /* + * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. + */ + if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) ) + hp100_rxfill( dev ); + + /* + * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire + * is completed + */ + if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) ) + hp100_clean_txring( dev ); + + /* + * MISC_ERROR is set when either the LAN link goes down or a detected + * bus error occurs. + */ + if ( val & HP100_MISC_ERROR ) /* New for J2585B */ + { + printk("hp100: Misc. Error Interrupt - Check cabling.\n"); + if(lp->mode==1) + { + hp100_clean_txring( dev ); + hp100_rxfill( dev ); + } + } + + dev->interrupt = 0; hp100_ints_on(); } + /* * some misc functions */ static void hp100_start_interface( struct device *dev ) { - int ioaddr = dev -> base_addr; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4220, TRACE ); + printk("hp100: hp100_start_interface %s\n",dev->name); +#endif cli(); - hp100_unreset_card(); - hp100_page( MAC_CTRL ); - hp100_outb( lp -> mac2_mode, MAC_CFG_2 ); - hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); - hp100_orb( lp -> mac1_mode | - HP100_RX_EN | HP100_RX_IDLE | - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); + + /* Ensure the adapter does not want to request an interrupt when */ + /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ hp100_page( PERFORMANCE ); - hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW ); - hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); - if ( lp -> mem_mapped ) + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */ + hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW); + /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ + hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + /* Make sure BM bit is set... */ + hp100_page(HW_MAP); + hp100_orb( HP100_BM_MASTER, BM ); + hp100_rxfill( dev ); + } + else if(lp->mode==2) { - /* enable memory mapping */ + /* Enable memory mapping. Note: Don't do this when busmaster. */ hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); } - sti(); + + hp100_page(PERFORMANCE); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* enable a few interrupts: */ + if(lp->mode==1) /* busmaster mode */ + { + hp100_outw( HP100_RX_PDL_FILL_COMPL | + HP100_RX_PDA_ZERO | + HP100_RX_ERROR | + /* HP100_RX_PACKET | */ + /* HP100_RX_EARLY_INT | */ HP100_SET_HB | + /* HP100_TX_PDA_ZERO | */ + HP100_TX_COMPLETE | + /* HP100_MISC_ERROR | */ + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK ); + } + else + { + hp100_outw( HP100_RX_PACKET | + HP100_RX_ERROR | HP100_SET_HB | + HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK ); + } + + /* Enable MAC Tx and RX, set MAC modes, ... */ + /* Note: This function also turns on the interrupts. */ + hp100_set_multicast_list( dev ); } + static void hp100_stop_interface( struct device *dev ) { - int ioaddr = dev -> base_addr; - u_short val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + u_int val; - hp100_outw( HP100_INT_EN | HP100_RESET_LB | - HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); - val = hp100_inw( OPTION_LSW ); - hp100_page( HW_MAP ); - hp100_andb( HP100_BM_SLAVE, BM ); - hp100_page( MAC_CTRL ); - hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); - if ( !(val & HP100_HW_RST) ) return; - for ( val = 0; val < 6000; val++ ) - if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) == - (HP100_TX_IDLE | HP100_RX_IDLE) ) - return; - printk( "%s: hp100_stop_interface - timeout\n", dev -> name ); +#ifdef HP100_DEBUG_B + printk("hp100: hp100_stop_interface %s\n",dev->name); + hp100_outw( 0x4221, TRACE ); +#endif + + if (lp->mode==1) + hp100_BM_shutdown( dev ); + else + { + /* Note: MMAP_DIS will be reenabled by start_interface */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB | + HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + val = hp100_inw( OPTION_LSW ); + + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); + + if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */ + /* ... else: busy wait until idle */ + for ( val = 0; val < 6000; val++ ) + if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) == + (HP100_TX_IDLE | HP100_RX_IDLE) ) + { + hp100_page(PERFORMANCE); + return; + } + printk( "%s: hp100_stop_interface - timeout\n", dev->name ); + hp100_page(PERFORMANCE); + } } + static void hp100_load_eeprom( struct device *dev ) { int i; - int ioaddr = dev -> base_addr; + int ioaddr = dev->base_addr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4222, TRACE ); +#endif hp100_page( EEPROM_CTRL ); hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL ); hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL ); - for ( i = 0; i < 6000; i++ ) - if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return; - printk( "%s: hp100_load_eeprom - timeout\n", dev -> name ); + for ( i = 0; i < 10000; i++ ) + if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return; + printk( "%s: hp100_load_eeprom - timeout\n", dev->name ); } -/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */ - + +/* Sense connection status. + * return values: LAN_10 - Connected to 10Mbit/s network + * LAN_100 - Connected to 100Mbit/s network + * LAN_ERR - not connected or 100Mbit/s Hub down + */ static int hp100_sense_lan( struct device *dev ) { - int i; - int ioaddr = dev -> base_addr; + int ioaddr = dev->base_addr; u_short val_VG, val_10; - struct hp100_private *lp = (struct hp100_private *)dev -> priv; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4223, TRACE ); +#endif hp100_page( MAC_CTRL ); - hp100_orw( HP100_VG_RESET, LAN_CFG_VG ); - val_10 = hp100_inw( LAN_CFG_10 ); - val_VG = hp100_inw( LAN_CFG_VG ); -#ifdef HP100_DEBUG_SENSE + /* Enable Auto Selection */ + /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */ + /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */ + /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */ + /* Now we have to wait a while... */ + /* for(i=0; i<5000; i++) */ + /* { */ + val_10 = hp100_inb( 10_LAN_CFG_1 ); + val_VG = hp100_inb( VG_LAN_CFG_1 ); + /* } */ +#ifdef HP100_DEBUG printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 ); #endif if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10; - if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */ - return HP100_LAN_ERR; - for ( i = 0; i < 2500; i++ ) - { - val_VG = hp100_inw( LAN_CFG_VG ); - if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100; + if ( (lp->id->id == 0x02019F022) || + (lp->id->id == 0x01042103c) || + (lp->id->id == 0x01040103c) ) + { + hp100_page(PERFORMANCE); + return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ } + /* for ( i = 0; i < 2500; i++ ) */ + /* { */ + val_VG = hp100_inb( VG_LAN_CFG_1 ); + hp100_page(PERFORMANCE); + + if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */ + return HP100_LAN_100; + /* } */ return HP100_LAN_ERR; } + + static int hp100_down_vg_link( struct device *dev ) { - int ioaddr = dev -> base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; unsigned long time; - int i; + long savelan, newlan; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4224, TRACE ); + printk("hp100: down_vg_link\n"); +#endif hp100_page( MAC_CTRL ); - for ( i = 2500; i > 0; i-- ) - if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break; - if ( i <= 0 ) /* not signal - not logout */ + time=jiffies+(HZ/4); + do{ + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while (time>jiffies); + + if ( jiffies >= time ) /* no signal->no logout */ return 0; - hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG ); - time = jiffies + 10*HZ/100; - while ( time > jiffies ) - if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST | - HP100_LINK_CABLE_ST | - HP100_LINK_GOOD_ST ) ) ) - return 0; + + /* Drop the VG Link by clearing the link up cmd and load addr.*/ + + hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1); + hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1); + + /* Conditionally stall for >250ms on Link-Up Status (to go down) */ + time=jiffies+(HZ/2); + do{ + if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break; + } while(time>jiffies); + #ifdef HP100_DEBUG - printk( "hp100_down_vg_link: timeout\n" ); + if (jiffies>=time) + printk("hp100_down_vg_link: Link does not go down?\n"); #endif - return -EIO; -} -static int hp100_login_to_vg_hub( struct device *dev ) -{ - int i; - int ioaddr = dev -> base_addr; - u_short val; - unsigned long time; + /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ + /* logout under traffic (even though all the status bits are cleared), */ + /* do this workaround to get the Rev 1 MAC in its idle state */ + if ( lp->chip==HP100_CHIPID_LASSEN ) + { + /* Reset VG MAC to insure it leaves the logoff state even if */ + /* the Hub is still emitting tones */ + hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); + udelay(1500); /* wait for >1ms */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ + udelay(1500); + } - hp100_page( MAC_CTRL ); - hp100_orw( HP100_VG_RESET, LAN_CFG_VG ); - time = jiffies + ( HZ / 2 ); + /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ + /* to get the VG mac to full reset. This is not req.d with later chips */ + /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ + /* selected again! This will be left to the connect hub function to */ + /* perform if desired. */ + if (lp->chip==HP100_CHIPID_LASSEN) + { + /* Have to write to 10 and 100VG control registers simultaneously */ + savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ + newlan &= ~(HP100_VG_SEL<<16); + newlan |= (HP100_DOT3_MAC)<<8; + hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ + hp100_outl(newlan, 10_LAN_CFG_1); + + /* Conditionally stall for 5sec on VG selected. */ + time=jiffies+(HZ*5); + do{ + if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break; + } while(time>jiffies); + + hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ + hp100_outl(savelan, 10_LAN_CFG_1); + } + + time=jiffies+(3*HZ); /* Timeout 3s */ do { - if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break; - } while ( time > jiffies ); - if ( time <= jiffies ) + if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break; + } while (time>jiffies); + + if(time<=jiffies) { #ifdef HP100_DEBUG - printk( "hp100_login_to_vg_hub: timeout for link\n" ); + printk( "hp100_down_vg_link: timeout\n" ); #endif return -EIO; } + + time=jiffies+(2*HZ); /* This seems to take a while.... */ + do {} while (time>jiffies); + + return 0; +} + + +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + u_short val=0; + unsigned long time; + int startst; - if ( hp100_down_vg_link( dev ) < 0 ) /* if fail, try reset VG link */ +#ifdef HP100_DEBUG_B + hp100_outw( 0x4225, TRACE ); + printk("hp100: login_to_vg_hub\n"); +#endif + + /* Initiate a login sequence iff VG MAC is enabled and either Load Address + * bit is zero or the force relogin flag is set (e.g. due to MAC address or + * promiscuous mode change) + */ + hp100_page( MAC_CTRL ); + startst=hp100_inb( VG_LAN_CFG_1 ); + if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST)) { - hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG ); - hp100_orw( HP100_VG_RESET, LAN_CFG_VG ); +#ifdef HP100_DEBUG_TRAINING + printk("hp100: Start training\n"); +#endif + + /* Ensure VG Reset bit is 1 (i.e., do not reset)*/ + hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 ); + + /* If Lassen AND auto-select-mode AND VG tones were sensed on */ + /* entry then temporarily put them into force 100Mbit mode */ + if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) ) + hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 ); + + /* Drop the VG link by zeroing Link Up Command and Load Address */ + hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1); + +#ifdef HP100_DEBUG_TRAINING + printk("hp100: Bring down the link\n"); +#endif + + /* Wait for link to drop */ + time = jiffies + (HZ/10); + do { + if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break; + } while (time>jiffies); + + /* Start an addressed training and optionally request promiscuous port */ + if ( (dev->flags) & IFF_PROMISC ) + { + hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2); + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + else + { + hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2); + /* For ETR parts we need to reset the prom. bit in the training + * register, otherwise promiscious mode won't be disabled. + */ + if(lp->chip==HP100_CHIPID_LASSEN) + { + hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + } + + /* With ETR parts, frame format request bits can be set. */ + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); + + hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1); + + /* Note: Next wait could be omitted for Hood and earlier chips under */ + /* certain circumstances */ + /* TODO: check if hood/earlier and skip wait. */ + + /* Wait for either short timeout for VG tones or long for login */ + /* Wait for the card hardware to signalise link cable status ok... */ + hp100_page( MAC_CTRL ); + time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */ + do { + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while ( jiffies < time ); + + if ( jiffies >= time ) + { +#ifdef HP100_DEBUG_TRAINING + printk( "hp100: Link cable status not ok? Training aborted.\n" ); +#endif + } + else + { +#ifdef HP100_DEBUG_TRAINING + printk( "hp100: HUB tones detected. Trying to train.\n"); +#endif + + time = jiffies + ( 2*HZ ); /* again a timeout */ + do { + val = hp100_inb( VG_LAN_CFG_1 ); + if ( (val & ( HP100_LINK_UP_ST )) ) + { +#ifdef HP100_DEBUG_TRAINING + printk( "hp100: Passed training.\n"); +#endif + break; + } + } while ( time > jiffies ); + } + + /* If LINK_UP_ST is set, then we are logged into the hub. */ + if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) ) + { +#ifdef HP100_DEBUG_TRAINING + printk( "hp100: Successfully logged into the HUB.\n"); + if(lp->chip==HP100_CHIPID_LASSEN) + { + val = hp100_inw(TRAIN_ALLOW); + printk( "hp100: Card supports 100VG MAC Version \"%s\" ", + (hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre"); + printk( "Driver will use MAC Version \"%s\"\n", + ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" ); + printk( "hp100: Frame format is %s.\n",(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3"); + } +#endif + } + else + { + /* If LINK_UP_ST is not set, login was not successful */ + printk("hp100/%s: Problem logging into the HUB.\n",dev->name); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Check allowed Register to find out why there is a problem. */ + val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */ +#ifdef HP100_DEBUG_TRAINING + printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val); +#endif + if ( val & HP100_MALLOW_ACCDENIED ) + printk("hp100: HUB access denied.\n"); + if ( val & HP100_MALLOW_CONFIGURE ) + printk("hp100: MAC Configuration is incompatible with the Network.\n"); + if ( val & HP100_MALLOW_DUPADDR ) + printk("hp100: Duplicate MAC Address on the Network.\n"); + } + } + + /* If we have put the chip into forced 100 Mbit mode earlier, go back */ + /* to auto-select mode */ + + if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) ) + { + hp100_page( MAC_CTRL ); + hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 ); + } + + val=hp100_inb(VG_LAN_CFG_1); + + /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ + hp100_page(PERFORMANCE); + hp100_outw( HP100_MISC_ERROR, IRQ_STATUS); + + if (val&HP100_LINK_UP_ST) + return(0); /* login was ok */ + else + { + printk("hp100: Training failed.\n"); + hp100_down_vg_link( dev ); + return -EIO; + } } - /* bring up link */ - hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG ); - for ( i = 2500; i > 0; i-- ) - if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break; - if ( i <= 0 ) - { -#ifdef HP100_DEBUG - printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" ); + /* no forced relogin & already link there->no training. */ + return -EIO; +} + + +static void hp100_cascade_reset( struct device *dev, u_short enable ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int i; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4226, TRACE ); + printk("hp100: cascade_reset\n"); #endif - goto down_link; + + if (enable==TRUE) + { + hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW ); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Lassen requires a PCI transmit fifo reset */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_orb( HP100_PCI_RESET, PCICTRL2 ); + /* Wait for min. 300 ns */ + /* we cant use jiffies here, because it may be */ + /* that we have disabled the timer... */ + for (i=0; i<0xffff; i++); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_page( PERFORMANCE ); + } + } + else + { /* bring out of reset */ + hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW); + for (i=0; i<0xffff; i++ ); + hp100_page(PERFORMANCE); } +} - time = jiffies + ( HZ / 2 ); - do { - val = hp100_inw( LAN_CFG_VG ); - if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) == - ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) - return 0; /* success */ - } while ( time > jiffies ); - if ( val & HP100_LINK_GOOD_ST ) - printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name ); - else - printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name ); - -down_link: - hp100_down_vg_link( dev ); - hp100_page( MAC_CTRL ); - hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG ); - hp100_orw( HP100_LINK_CMD, LAN_CFG_VG ); - return -EIO; +#ifdef HP100_DEBUG +void hp100_RegisterDump( struct device *dev ) +{ + int ioaddr=dev->base_addr; + int Page; + int Register; + + /* Dump common registers */ + printk("hp100: Cascade Register Dump\n"); + printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID)); + printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING)); + printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW)); + printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW)); + + /* Dump paged registers */ + for (Page = 0; Page < 8; Page++) + { + /* Dump registers */ + printk("page: 0x%.2x\n",Page); + outw( Page, ioaddr+0x02); + for (Register = 0x8; Register < 0x22; Register += 2) + { + /* Display Register contents except data port */ + if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) + { + printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register)); + } + } + } + hp100_page(PERFORMANCE); } +#endif + + /* * module section */ - + #ifdef MODULE -static int hp100_port = -1; -MODULE_PARM(hp100_port, "i"); +/* Parameters set by insmod */ +int hp100_port[5] = { 0, -1, -1, -1, -1 }; +#ifdef LINUX_2_1 +MODULE_PARM(hp100_port, "1-5i"); +#endif -static char devicename[9] = { 0, }; -static struct device dev_hp100 = { - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, hp100_probe -}; +#ifdef LINUX_2_1 +char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; +MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); +#else +static char devname[5][IFNAMSIZ] = { "", "", "", "", "" }; +static char *hp100_name[5] = { devname[0], devname[1], + devname[2], devname[3], + devname[4] }; +#endif + +/* List of devices */ +static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; + +/* + * Note: if you have more than five 100vg cards in your pc, feel free to + * increase this value + */ + +/* + * Note: to register three eisa or pci devices, use: + * option hp100 hp100_port=0,0,0 + * to register one card at io 0x280 as eth239, use: + * option hp100 hp100_port=0x280 hp100_name=eth239 + */ int init_module( void ) { - if (hp100_port == 0 && !EISA_bus) + int i; + int ret = 0; + + if (hp100_port == 0 && !EISA_bus && !pcibios_present()) printk("HP100: You should not use auto-probing with insmod!\n"); - if ( hp100_port > 0 ) - dev_hp100.base_addr = hp100_port; - if ( register_netdev( &dev_hp100 ) != 0 ) - return -EIO; - return 0; + + /* Loop on all possible base addresses */ + i = -1; + while((hp100_port[++i] != -1) && (i < 5)) + { + /* Create device and set basics args */ + hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); + memset(hp100_devlist[i], 0x00, sizeof(struct device)); + hp100_devlist[i]->name = hp100_name[i]; + hp100_devlist[i]->base_addr = hp100_port[i]; + hp100_devlist[i]->init = &hp100_probe; + + /* Try to create the device */ + if(register_netdev(hp100_devlist[i]) != 0) + { + /* DeAllocate everything */ + /* Note: if dev->priv is mallocated, there is no way to fail */ + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + ret = -EIO; + } + } /* Loop over all devices */ + + return ret; } void cleanup_module( void ) { - unregister_netdev( &dev_hp100 ); - release_region( dev_hp100.base_addr, HP100_REGION_SIZE ); - if ( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt ) - iounmap( ((struct hp100_private *)dev_hp100.priv) -> mem_ptr_virt ); - kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) ); - dev_hp100.priv = NULL; + int i; + + /* TODO: Check if all skb's are released/freed. */ + for(i = 0; i < 5; i++) + if(hp100_devlist[i] != (struct device *) NULL) + { + unregister_netdev( hp100_devlist[i] ); + release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); + if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ + kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f); + if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) + iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); + kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) ); + hp100_devlist[i]->priv = NULL; + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } } -#endif +#endif /* MODULE */ + + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" + * c-indent-level: 2 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h index 1ebca564d..436dd3700 100644 --- a/drivers/net/hp100.h +++ b/drivers/net/hp100.h @@ -1,9 +1,10 @@ /* * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. * - * Author: Jaroslav Kysela, <perex@pf.jcu.cz> + * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ * - * Header file... + * Authors: Jaroslav Kysela, <perex@pf.jcu.cz> + * Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de> * * This driver is based on the 'hpfepkt' crynwr packet driver. * @@ -16,9 +17,10 @@ /**************************************************************************** * Hardware Constants ****************************************************************************/ - -/* - * ATT2MD01 Register Page Constants + +/* + * Page Identifiers + * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02) */ #define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */ @@ -30,11 +32,8 @@ #define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */ #define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */ -/* - * ATT2MD01 Register Addresses - */ -/* Present on all pages */ +/* Registers that are present on all pages */ #define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */ #define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */ @@ -47,14 +46,29 @@ #define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */ #define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */ -#define HP100_REG_FRAGMENT_LEN 0x0c /* RW: (16)12:0 Current fragment len */ +#define HP100_REG_FRAGMENT_LEN 0x0c /* W: (16)12:0 Current fragment len */ +/* Note: For 32 bit systems, fragment len and offset registers are available */ +/* at offset 0x28 and 0x2c, where they can be written as 32bit values. */ #define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */ #define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */ #define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */ #define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */ +#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */ +#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */ #define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */ #define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */ - +#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */ +#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */ +#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */ + /* which point to a PDL */ +#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */ +#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */ +#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */ +#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */ +#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */ +#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */ +#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */ + /* Page 1 - MAC Address/Hash Table */ #define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */ @@ -68,27 +82,46 @@ #define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */ #define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */ #define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */ + +/* New on Page 2 for ETR chips: */ +#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */ +#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */ +#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */ +#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */ +#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */ +#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */ +#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */ +#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */ +#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */ /* Page 3 - EEPROM/Boot ROM */ #define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */ +#define HP100_REG_BOOTROM_CTRL 0x0a -/* Page 4 - LAN Configuration */ +/* Page 4 - LAN Configuration (MAC_CTRL) */ -#define HP100_REG_LAN_CFG_10 0x08 /* RW: (16) Set 10M XCVR functions */ -#define HP100_REG_LAN_CFG_VG 0x0a /* RW: (16) Set 100M XCVR functions */ +#define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */ +#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */ +#define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */ +#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */ #define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */ #define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */ -/* The follow clear when read: */ +#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ +#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ #define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem*/ #define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */ #define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */ - +#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register.*/ +#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */ + /* Page 5 - MMU */ #define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */ #define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */ - +#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */ +#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */ + /* Page 6 - Card ID/Physical LAN Address */ #define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */ @@ -99,32 +132,46 @@ /* Page 7 - MMU Current Pointers */ -#define HP100_REG_RX_MEM_BR 0x08 /* R: (16) Current begin of Rx ring */ -#define HP100_REG_RX_MEM_ER 0x0a /* R: (16) Current end of Rx ring */ -#define HP100_REG_TX_MEM_BR 0x0c /* R: (16) Current begin of Tx ring */ -#define HP100_REG_TX_MEM_ER 0x0e /* R: (16) Current end of Rx ring */ -#define HP100_REG_MEM_DEBUG 0x1a /* RW: (16) Used for memory tests */ - -/* - * HardwareIDReg bits/masks +#define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */ +#define HP100_REG_PTR_RXEND 0x0a /* R: (16) Current end of Rx ring */ +#define HP100_REG_PTR_TXSTART 0x0c /* R: (16) Current begin of Tx ring */ +#define HP100_REG_PTR_TXEND 0x0e /* R: (16) Current end of Rx ring */ +#define HP100_REG_PTR_RPDLSTART 0x10 +#define HP100_REG_PTR_RPDLEND 0x12 +#define HP100_REG_PTR_RINGPTRS 0x14 +#define HP100_REG_PTR_MEMDEBUG 0x1a +/* ------------------------------------------------------------------------ */ + + +/* + * Hardware ID Register I (Always available, HW_ID, Offset 0x00) */ +#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */ -#define HP100_HW_ID_0 0x50 /* Hardware ID bytes. */ -#define HP100_HW_ID_1 0x48 -#define HP100_HW_ID_2_REVA 0x50 /* Rev. A ID. NOTE: lower nibble not used */ -#define HP100_HW_ID_3 0x53 +/* + * Hardware ID Register 2 & Paging Register + * (Always available, PAGING, Offset 0x02) + * Bits 15:4 are for the Chip ID + */ +#define HP100_CHIPID_MASK 0xFFF0 +#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */ + /* EISA BM/SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM,*/ + /* PCI SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */ + /* LRF supported */ /* - * OptionLSWReg bits/masks + * Option Registers I and II + * (Always available, OPTION_LSW, Offset 0x04-0x05) */ - -#define HP100_DEBUG_EN 0x8000 /* 0:Disable, 1:Enable Debug Dump Pointer */ -#define HP100_RX_HDR 0x4000 /* 0:Disable, 1:Enable putting pkt into */ - /* system memory before Rx interrupt */ -#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable memory mapping. */ - /* MMAP_DIS must be 0 and MEM_EN must */ - /* be 1 for memory-mapped mode to be */ - /* enabled */ +#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */ +#define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */ + /* system mem. before Rx interrupt */ +#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */ + /* MMAP_DIS must be 0 and MEM_EN */ + /* must be 1 for memory-mapped */ + /* mode to be enabled */ #define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */ #define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */ #define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */ @@ -132,121 +179,236 @@ #define HP100_MEM_EN 0x0040 /* Config program set this to */ /* 0:Disable, 1:Enable mem map. */ /* See MMAP_DIS. */ -#define HP100_IO_EN 0x0020 /* 0:Disable, 1:Enable I/O transfers */ -#define HP100_BOOT_EN 0x0010 /* 0:Disable, 1:Enable boot ROM access */ -#define HP100_FAKE_INT 0x0008 /* 0:No int, 1:int */ -#define HP100_INT_EN 0x0004 /* 0:Disable, 1:Enable ints from card */ +#define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */ +#define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */ +#define HP100_FAKE_INT 0x0008 /* 1:int */ +#define HP100_INT_EN 0x0004 /* 1:Enable ints from card */ #define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */ + /* NIC reset on 0 to 1 transition */ /* - * OptionMSWReg bits/masks + * Option Register III + * (Always available, OPTION_MSW, Offset 0x06) */ -#define HP100_PRIORITY_TX 0x0080 /* 0:Don't, 1:Do all Tx pkts as priority */ +#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */ #define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */ -#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue, */ +#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */ /* h/w will set to 0 when done */ -#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w will set */ - /* to 0 when done */ +#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */ + /* will set to 0 when done */ /* - * InterruptStatusReg/InterruptMaskReg bits/masks. These bits will 0 when a 1 - * is written to them. + * Interrupt Status Registers I and II + * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09) + * Note: With old chips, these Registers will clear when 1 is written to them + * with new chips this depends on setting of CLR_ISMODE */ +#define HP100_RX_EARLY_INT 0x2000 +#define HP100_RX_PDA_ZERO 0x1000 +#define HP100_RX_PDL_FILL_COMPL 0x0800 #define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */ #define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */ +#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */ #define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */ #define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */ +#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error*/ #define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */ - + /* - * TxMemoryFreeCountReg bits/masks. + * Xmit Memory Free Count + * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit) */ -#define HP100_AUTO_COMPARE 0x8000 /* Says at least 8k is available for Tx. */ - /* NOTE: This mask is for the upper */ - /* word of the register. */ +#define HP100_AUTO_COMPARE 0x80000000 /* Tx Space avail & pkts<255 */ +#define HP100_FREE_SPACE 0x7fffffe0 /* Tx free memory */ /* - * IRQChannelReg bits/masks. + * IRQ Channel + * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d) */ #define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes asserts NOWS signal */ +#define HP100_IRQ_SCRAMBLE 0x40 +#define HP100_BOND_HP 0x20 #define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */ - /* Only valid on EISA cards. */ -#define HP100_IRQ_MASK 0x0F /* Isolate the IRQ bits */ + /* (Only valid on EISA cards) */ +#define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */ /* - * SRAMReg bits/masks. + * SRAM Parameters + * (Page HW_MAP, SRAM, Offset 0x0e) */ #define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */ -#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count to put index in lower bits */ +#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits)*/ + +/* + * Bus Master Register + * (Page HW_MAP, BM, Offset 0x0f) + */ +#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (tx) */ +#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (rx) */ +#define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */ +#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in*/ + /* an EISA system */ +#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */ + + +/* + * Mode Control Register I + * (Page HW_MAP, MODECTRL1, Offset0x10) + */ +#define HP100_TX_DUALQ 0x10 + /* If set and BM -> dual tx pda queues*/ +#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */ + /* interrupts on read (etr only?) */ +#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */ + /* from the eeprom */ +#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */ +#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */ + /* first three data elements of a PDL */ + /* on the first access. */ +#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */ + +/* + * Mode Control Register II + * (Page HW_MAP, MODECTRL2, Offset0x11) + */ +#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */ + /* certain resources */ +#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */ +#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */ + /* written back to system mem */ +#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */ + /* interrupt */ + +/* + * PCI Configuration and Control Register I + * (Page HW_MAP, PCICTRL1, Offset 0x12) + */ +#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */ +#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */ + /* bios */ +#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */ + /* simultaneously with PCI decodes */ +#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */ +#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */ + +/* + * PCI Configuration and Control Register II + * (Page HW_MAP, PCICTRL2, Offset 0x13) + */ +#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */ +#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */ +#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */ +#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */ +#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */ + /* pci stop if cascade not ready */ +#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity*/ +#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */ /* - * BMReg bits/masks. + * Early TX Configuration and Control Register + * (Page HW_MAP, EARLYTXCFG, Offset 0x16) */ -#define HP100_BM_SLAVE 0x04 /* 0:Slave, 1:BM mode */ +#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */ +#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */ +#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */ +#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */ +#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */ /* - * EEPROMControlReg bits/masks. + * Early RX Configuration and Control Register + * (Page HW_MAP, EARLYRXCFG, Offset 0x18) */ -#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads the EEPROM into registers. */ - /* When it goes back to 0, load is */ - /* complete. This should take ~600us. */ +#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */ +#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */ +#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the + * early rx circuit will start the + * dma of received packet into system + * memory for BM */ /* - * LANCntrCfg10Reg bits/masks. - */ -#define HP100_SQU_ST 0x0100 /* 0:No, 1:Yes collision signal sent */ - /* after Tx. Only used for AUI. */ -#define HP100_MAC10_SEL 0x00c0 /* Get bits to indicate MAC */ -#define HP100_AUI_SEL 0x0020 /* Status of AUI selection */ -#define HP100_LOW_TH 0x0010 /* 0:No, 1:Yes allow better cabling */ -#define HP100_LINK_BEAT_DIS 0x0008 /* 0:Enable, 1:Disable link beat */ -#define HP100_LINK_BEAT_ST 0x0004 /* 0:No, 1:Yes link beat being Rx */ -#define HP100_R_ROL_ST 0x0002 /* 0:No, 1:Yes Rx twisted pair has been */ - /* reversed */ -#define HP100_AUI_ST 0x0001 /* 0:No, 1:Yes use AUI on TP card */ - -/* MAC Selection, use with MAC10_SEL bits */ + * Serial Devices Control Register + * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08) + */ +#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */ + /* When it goes back to 0, load is */ + /* complete. This should take ~600us.*/ + +/* + * 10MB LAN Control and Configuration Register I + * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08) + */ +#define HP100_MAC10_SEL 0xc0 /* Get bits to indicate MAC */ +#define HP100_AUI_SEL 0x20 /* Status of AUI selection */ +#define HP100_LOW_TH 0x10 /* 0:No, 1:Yes allow better cabling */ +#define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */ +#define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */ +#define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */ + /* been reversed */ +#define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */ + +/* + * 10 MB LAN Control and Configuration Register II + * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09) + */ +#define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */ + /* after Tx.Only used for AUI. */ +#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */ +#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */ + +/* + * MAC Selection, use with MAC10_SEL bits + */ #define HP100_AUTO_SEL_10 0x0 /* Auto select */ #define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */ #define HP100_XCVR_7213 0x2 /* 7213 transceiver */ #define HP100_XCVR_82503 0x3 /* 82503 transceiver */ +/* + * 100MB LAN Training Register + * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12) + */ +#define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */ +#define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */ +#define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */ + /* promiscuous */ +#define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */ + /* be a cascaded repeater */ /* - * LANCntrCfgVGReg bits/masks. - */ -#define HP100_FRAME_FORMAT 0x0800 /* 0:802.3, 1:802.5 frames */ -#define HP100_BRIDGE 0x0400 /* 0:No, 1:Yes tell hub it's a bridge */ -#define HP100_PROM_MODE 0x0200 /* 0:No, 1:Yes tell hub card is */ - /* promiscuous */ -#define HP100_REPEATER 0x0100 /* 0:No, 1:Yes tell hub MAC wants to be */ - /* a cascaded repeater */ -#define HP100_MAC100_SEL 0x0080 /* 0:No, 1:Yes use 100 Mbit MAC */ -#define HP100_LINK_UP_ST 0x0040 /* 0:No, 1:Yes endnode logged in */ -#define HP100_LINK_CABLE_ST 0x0020 /* 0:No, 1:Yes cable can hear tones from */ - /* hub */ -#define HP100_LOAD_ADDR 0x0010 /* 0->1 card addr will be sent to hub. */ - /* 100ms later the link status bits are */ - /* valid */ -#define HP100_LINK_CMD 0x0008 /* 0->1 link will attempt to log in. */ - /* 100ms later the link status bits are */ - /* valid */ -#define HP100_LINK_GOOD_ST 0x0002 /* 0:No, 1:Yes cable passed training */ -#define HP100_VG_RESET 0x0001 /* 0:Yes, 1:No reset the 100VG MAC */ + * 100MB LAN Control and Configuration Register + * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a) + */ +#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */ +#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */ +#define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */ + /* from hub */ +#define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */ + /* 100ms later the link status */ + /* bits are valid */ +#define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */ + /* 100ms later the link status */ + /* bits are valid */ +#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */ + /* after LinkUp Cmd is given and set */ + /* when training has completed. */ +#define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */ +#define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */ /* - * MACConfiguration1Reg bits/masks. + * MAC Configuration Register I + * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c) */ #define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */ #define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */ -#define HP100_RX_EN 0x20 /* 0:No, 1:Yes allow receiving of pkts */ -#define HP100_TX_EN 0x10 /* 0:No, 1:Yes allow transmitting of pkts */ +#define HP100_RX_EN 0x20 /* 1: allow receiving of pkts */ +#define HP100_TX_EN 0x10 /* 1: allow transmitting of pkts */ #define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */ #define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */ #define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */ -#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL physical pkts */ - +#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL phys. pkts */ #define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */ #define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */ #define HP100_MAC1MODE2 0x00 @@ -254,15 +416,14 @@ #define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC #define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */ #define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */ - /* Note MODE6 will receive all GOOD packets on the LAN. This really needs a mode 7 defined to be LAN Analyzer mode, which will receive errored and runt packets, and keep the CRC bytes. */ - -#define HP100_MAC1MODE7 MAC1MODE6 OR ACC_ERRORED +#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED /* - * MACConfiguration2Reg bits/masks. + * MAC Configuration Register II + * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d) */ #define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */ #define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */ @@ -270,9 +431,12 @@ /* transceiver */ #define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */ #define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */ +#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring + * group addr that maches NA mask */ #define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */ /* The length will reflect this. */ - +#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional + * addrs that match FA mask (page1) */ #define HP100_MAC2MODEMASK 0x02 #define HP100_MAC2MODE1 0x00 #define HP100_MAC2MODE2 0x00 @@ -283,6 +447,65 @@ #define HP100_MAC2MODE7 KEEP_CRC /* + * MAC Configuration Register III + * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e) + */ +#define HP100_PACKET_PACE 0x03 /* Packet Pacing: + * 00: No packet pacing + * 01: 8 to 16 uS delay + * 10: 16 to 32 uS delay + * 11: 32 to 64 uS delay + */ +#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and + * TCP/IP Checksumming enabled. */ +#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */ + +/* + * MAC Configuration Register IV + * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f) + */ +#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL + * Signal, 1=100VG, 0=10Mbit sel. */ +#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion + * of the Misc. Interrupt */ + +/* + * 100 MB LAN Training Request/Allowed Registers + * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only) + */ +#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be + * a cascaded repeater + * 0: ... wants to be a DTE */ +#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */ +#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */ +#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */ +#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */ +#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an + * end node is allowed */ +#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format + * 00: 802.3 format will be used + * 10: 802.5 format will be used */ +#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */ +#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */ +#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */ +#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */ + /* protocol of repeater */ + +/* ****************************************************************************** */ + +/* * Set/Reset bits */ #define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */ @@ -297,20 +520,45 @@ #define HP100_LAN_10 10 /* lan_type value for 10BaseT */ #define HP100_LAN_ERR (-1) /* lan_type value for link down */ -/* - * Receive Header Definition. +#define TRUE 1 +#define FALSE 0 + + +/* + * Bus Master Data Structures ---------------------------------------------- */ -struct hp100_rx_header { - u_short rx_length; /* Pkt length is bits 12:0 */ - u_short rx_status; /* status of the packet */ -}; +#define MAX_RX_PDL 30 /* Card limit = 31 */ +#define MAX_RX_FRAG 2 /* Dont need more... */ +#define MAX_TX_PDL 29 +#define MAX_TX_FRAG 2 /* Limit = 31 */ + +/* Define total PDL area size in bytes (should be 4096) */ +/* This is the size of kernel (dma) memory that will be allocated. */ +#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16 + +/* Ethernet Packet Sizes */ +#define MIN_ETHER_SIZE 60 +#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */ + /* skb buffer when busmastering */ + +/* Tx or Rx Ring Entry */ +typedef struct hp100_ring { + u_int *pdl; /* Address of PDLs PDH, dword before + * this address is used for rx hdr */ + u_int pdl_paddr; /* Physical address of PDL */ + struct sk_buff *skb; + struct hp100_ring *next; +} hp100_ring_t; + + + +/* Mask for Header Descriptor */ +#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */ -#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length bits */ /* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED bit in the MAC Configuration Register 1 is set. */ - #define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */ #define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */ #define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */ @@ -368,7 +616,11 @@ struct hp100_rx_header { outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW ) #define hp100_mem_map_disable() \ outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW ) -#define hp100_reset_card() \ - outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW ) -#define hp100_unreset_card() \ - outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW ) + + +/* + * Local variables: + * c-indent-level: 2 + * tab-width: 8 + * End: +*/ diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index faedd45fa..e0d71b202 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -84,7 +84,7 @@ /* version and credits */ static char *version = "ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" -" v2.1.29 3/15/97 Paul Norton <pnorton@cts.com>\n"; +" v2.1.35 5/ 1/97 Paul Norton <pnorton@cts.com>\n"; static char pcchannelid[] = { 0x05, 0x00, 0x04, 0x09, @@ -1013,14 +1013,15 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs) } /* ARB response */ if (status & SSB_RESP_INT) { /* SSB response */ - + unsigned char retcode; switch (readb(ti->ssb)) { /* SSB command check */ - + case XMIT_DIR_FRAME: case XMIT_UI_FRAME: - if (readb(ti->ssb+2)) /* checks ret_code */ + retcode = readb(ti->ssb+2); + if (retcode && (retcode != 0x22)) /* checks ret_code */ DPRINTK("xmit ret_code: %02X xmit error code: %02X\n", - (int)readb(ti->ssb+2), (int)readb(ti->ssb+6)); + (int)retcode, (int)readb(ti->ssb+6)); else ti->tr_stats.tx_packets++; break; @@ -1321,12 +1322,12 @@ static void tr_rx(struct device *dev) __u32 rbuffer, rbufdata; __u32 llc; unsigned char *data; - unsigned int rbuffer_len, lan_hdr_len, hdr_len; - unsigned int arb_frame_len; + unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; struct sk_buff *skb; unsigned int skb_size = 0; int is8022 = 0; unsigned int chksum = 0; + struct iphdr *iph; rbuffer=(ti->sram +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2; @@ -1400,8 +1401,8 @@ static void tr_rx(struct device *dev) } #endif - arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); - skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr); + length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); + skb_size = length-lan_hdr_len+sizeof(struct trh_hdr); if (is8022) { skb_size += sizeof(struct trllc); } @@ -1429,30 +1430,42 @@ static void tr_rx(struct device *dev) rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))-lan_hdr_len; if (is8022) { - /* create whitewashed LLC header in skb buffer (why not the real one?) */ + /* create whitewashed LLC header in sk buffer */ struct trllc *local_llc = (struct trllc *)data; memset(local_llc, 0, sizeof(*local_llc)); local_llc->ethertype = htons(ETH_P_TR_802_2); hdr_len = sizeof(struct trllc); + /* copy the real LLC header to the sk buffer */ + data += hdr_len; + memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len); } else { /* Copy the LLC header and the IPv4 header */ hdr_len = sizeof(struct trllc) + sizeof(struct iphdr); memcpy_fromio(data, rbuffer+offsetof(struct rec_buf, data)+lan_hdr_len,hdr_len); + + /* Watch for padded packets and bogons */ + iph=(struct iphdr*)(data+sizeof(struct trllc)); + ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr); + length -= lan_hdr_len + hdr_len; + if ((ip_len <= length) && (ip_len > 7)) + length = ip_len; } data += hdr_len; - lan_hdr_len += hdr_len; rbuffer_len -= hdr_len; - rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len; + rbufdata = rbuffer + offsetof(struct rec_buf,data) + lan_hdr_len + hdr_len; /* Copy the payload... */ for (;;) { if (is8022) memcpy_fromio(data, rbufdata, rbuffer_len); else - chksum = csum_partial_copy(bus_to_virt(rbufdata), data, rbuffer_len, chksum); + chksum = csum_partial_copy(bus_to_virt(rbufdata), data, + length < rbuffer_len ? length : rbuffer_len, + chksum); rbuffer = ntohs(readw(rbuffer)); if (!rbuffer) break; + length -= rbuffer_len; data += rbuffer_len; rbuffer += ti->sram; rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); @@ -1495,7 +1508,7 @@ static int tok_send_packet(struct sk_buff *skb, struct device *dev) return 0; } - if (set_bit(0,(void *)&dev->tbusy)!=0) + if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) DPRINTK("Transmitter access conflict\n"); else { /* Save skb; we'll need it when the adapter asks for the data */ diff --git a/drivers/net/lance.c b/drivers/net/lance.c index c1aa556d6..bf4061b05 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -858,12 +858,12 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&lp->lock) != 0) { + if (test_and_set_bit(0, (void*)&lp->lock) != 0) { if (lance_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c index 8a4fae560..1da2ee64f 100644 --- a/drivers/net/ltpc.c +++ b/drivers/net/ltpc.c @@ -1259,7 +1259,7 @@ void cleanup_module(void) if(debug&DEBUG_VERBOSE) printk("waiting\n"); /* if it's in process, wait a bit for it to finish */ timeout = jiffies+HZ; - add_timer(<pc_timer) + add_timer(<pc_timer); while(del_timer(<pc_timer) && (timeout > jiffies)) { add_timer(<pc_timer); diff --git a/drivers/net/mkiss.c b/drivers/net/mkiss.c index 6f772fd68..13ebbd9b4 100644 --- a/drivers/net/mkiss.c +++ b/drivers/net/mkiss.c @@ -109,7 +109,7 @@ static inline struct ax_disp *ax_alloc(void) break; /* Not in use ? */ - if (!set_bit(AXF_INUSE, &axp->ctrl.flags)) + if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) break; } @@ -165,7 +165,7 @@ static inline void ax_free(struct ax_disp *ax) if (ax->xbuff) kfree(ax->xbuff); ax->xbuff = NULL; - if (!clear_bit(AXF_INUSE, &ax->flags)) + if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name); } @@ -244,7 +244,7 @@ static void ax_changedmtu(struct ax_disp *ax) /* Set the "sending" flag. This must be atomic, hence the ASM. */ static inline void ax_lock(struct ax_disp *ax) { - if (set_bit(0, (void *)&ax->dev->tbusy)) + if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name); } @@ -252,7 +252,7 @@ static inline void ax_lock(struct ax_disp *ax) /* Clear the "sending" flag. This must be atomic, hence the ASM. */ static inline void ax_unlock(struct ax_disp *ax) { - if (!clear_bit(0, (void *)&ax->dev->tbusy)) + if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name); } @@ -551,7 +551,7 @@ static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch /* Read the characters out of the buffer */ while (count--) { if (fp != NULL && *fp++) { - if (!set_bit(AXF_ERROR, &ax->flags)) + if (!test_and_set_bit(AXF_ERROR, &ax->flags)) ax->rx_errors++; cp++; continue; @@ -709,7 +709,7 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s) if (test_bit(AXF_KEEPTEST, &ax->flags)) clear_bit(AXF_KEEPTEST, &ax->flags); - if (!clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) + if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) ax_bump(ax); clear_bit(AXF_ESCAPE, &ax->flags); @@ -720,11 +720,11 @@ static void kiss_unesc(struct ax_disp *ax, unsigned char s) set_bit(AXF_ESCAPE, &ax->flags); return; case ESC_ESC: - if (clear_bit(AXF_ESCAPE, &ax->flags)) + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = ESC; break; case ESC_END: - if (clear_bit(AXF_ESCAPE, &ax->flags)) + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = END; break; } diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 3d7a2587a..4ae7aa069 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -584,7 +584,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev) return 0; } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { DTX(("tbusy, maybe a race? returning 1\n")); printk("%s: Transmitter access conflict.\n", dev->name); return 1; diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 746037adf..0935f4f0b 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -1171,12 +1171,12 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev) return 0; } - if (set_bit(0, (void*)&dev->tbusy)) { + if (test_and_set_bit(0, (void*)&dev->tbusy)) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } #if(NUM_XMIT_BUFFS > 1) - else if(set_bit(0,(void *) &p->lock)) { + else if(test_and_set_bit(0,(void *) &p->lock)) { printk("%s: Queue was locked\n",dev->name); return 1; } diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 07a946d3b..a008a3ea7 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -804,7 +804,7 @@ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs) return; } - if(set_bit(0,(int *) &dev->interrupt)) { + if(test_and_set_bit(0,(int *) &dev->interrupt)) { printk("ni65: oops .. interrupt while proceeding interrupt\n"); return; } @@ -1087,11 +1087,11 @@ static int ni65_send_packet(struct sk_buff *skb, struct device *dev) dev->trans_start = jiffies; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&p->lock)) { + if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); return 1; } diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 3f34e690c..d10663ff5 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -613,12 +613,12 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&lp->lock) != 0) { + if (test_and_set_bit(0, (void*)&lp->lock) != 0) { if (pcnet32_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 25c33ab1a..f06a66afc 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -910,7 +910,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev) return 0; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index a1dbb5020..e3615534d 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -1291,7 +1291,7 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto, * The total length includes the protocol data. * Lock the user information buffer. */ - if (set_bit (0, &ppp->ubuf->locked)) { + if (test_and_set_bit (0, &ppp->ubuf->locked)) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_us_queue: can't get lock\n"); @@ -1698,7 +1698,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) return 0; - if (set_bit (0, &ppp->ubuf->locked) != 0) { + if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: sleeping(ubuf)\n"); @@ -2584,7 +2584,7 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait) poll_wait(&ppp->write_wait, wait); /* Must lock the user buffer area while checking. */ - if(set_bit(0, &ppp->ubuf->locked) == 0) { + if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) { if(ppp->ubuf->head != ppp->ubuf->tail) mask |= POLLIN | POLLRDNORM; clear_bit(0, &ppp->ubuf->locked); @@ -3130,7 +3130,7 @@ ppp_find (int pid_value) while (ctl) { ppp = ctl2ppp (ctl); - if (!set_bit(0, &ppp->inuse)) { + if (!test_and_set_bit(0, &ppp->inuse)) { if (ppp->sc_xfer == pid_value) { ppp->sc_xfer = 0; return (ppp); @@ -3160,7 +3160,7 @@ ppp_alloc (void) while (ctl) { ppp = ctl2ppp (ctl); - if (!set_bit(0, &ppp->inuse)) + if (!test_and_set_bit(0, &ppp->inuse)) return (ppp); ctl = ctl->next; if (++if_num == max_dev) diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c index f2762eef1..feaeef4cc 100644 --- a/drivers/net/sdla.c +++ b/drivers/net/sdla.c @@ -657,7 +657,7 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev) if (skb == NULL) return(0); - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name); else { diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c index 79a493c2c..d2dc0eb90 100644 --- a/drivers/net/sdla_fr.c +++ b/drivers/net/sdla_fr.c @@ -440,7 +440,7 @@ static int if_open (struct device* dev) if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; if (!card->open_cnt) @@ -489,7 +489,7 @@ static int if_close (struct device* dev) fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -574,7 +574,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) sdla_t* card = chan->card; int retry = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -584,7 +584,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c index c6b1ce945..c5c5ecc55 100644 --- a/drivers/net/sdla_ppp.c +++ b/drivers/net/sdla_ppp.c @@ -286,7 +286,7 @@ static int if_open (struct device* dev) if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) @@ -365,7 +365,7 @@ static int if_close (struct device* dev) { sdla_t* card = dev->priv; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -441,7 +441,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) sdla_t* card = dev->priv; int retry = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -451,7 +451,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c index f6f540709..3296c2819 100644 --- a/drivers/net/sdla_x25.c +++ b/drivers/net/sdla_x25.c @@ -476,7 +476,7 @@ static int if_open (struct device* dev) if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; @@ -503,7 +503,7 @@ static int if_close (struct device* dev) x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -590,7 +590,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) sdla_t* card = chan->card; int retry = 0, queued = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -600,7 +600,7 @@ static int if_send (struct sk_buff* skb, struct device* dev) return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c index 2ff8a4605..75d7df944 100644 --- a/drivers/net/sdlamain.c +++ b/drivers/net/sdlamain.c @@ -332,7 +332,7 @@ static int shutdown (wan_device_t* wandev) if (wandev->state == WAN_UNCONFIGURED) return 0 ; - if (set_bit(0, (void*)&wandev->critical)) + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN ; card = wandev->private; @@ -364,7 +364,7 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) if (wandev->state == WAN_UNCONFIGURED) return -ENODEV ; - if (set_bit(0, (void*)&wandev->critical)) + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN ; switch (cmd) @@ -514,7 +514,7 @@ STATIC void sdla_poll (void* data) sdla_t* card = &card_array[i]; if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !set_bit(0, (void*)&card->wandev.critical)) + !test_and_set_bit(0, (void*)&card->wandev.critical)) { card->poll(card); card->wandev.critical = 0; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 397228647..1a41960c4 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -392,7 +392,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 3022e8a0b..bf85e014a 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -519,7 +519,7 @@ static inline int verify_tx(struct sgiseeq_private *sp, return -1; } /* Are we getting in someone else's way? */ - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return -1; } diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 1421356e3..51e8fe8ba 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -68,6 +68,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; #include <asm/io.h> #include <asm/bitops.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -532,7 +533,7 @@ void SK_print_ram(struct device *dev); * (detachable devices only). */ -int SK_init(struct device *dev) +__initfunc(int SK_init(struct device *dev)) { int ioaddr = 0; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ @@ -616,7 +617,7 @@ int SK_init(struct device *dev) * 94/06/30 pwe SK_ADDR now checked and at the correct place -*/ -int SK_probe(struct device *dev, short ioaddr) +__initfunc(int SK_probe(struct device *dev, short ioaddr)) { int i,j; /* Counters */ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ @@ -1210,7 +1211,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev) * This means check if we are already in. */ - if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ { printk("%s: Transmitter access conflict.\n", dev->name); } @@ -1740,7 +1741,7 @@ static void set_multicast_list(struct device *dev) * YY/MM/DD uid Description -*/ -unsigned int SK_rom_addr(void) +__initfunc(unsigned int SK_rom_addr(void)) { int i,j; int rom_found = 0; diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c index 115d419c9..0df5feaae 100644 --- a/drivers/net/skeleton.c +++ b/drivers/net/skeleton.c @@ -56,6 +56,7 @@ static const char *version = #include <asm/io.h> #include <asm/dma.h> #include <linux/errno.h> +#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -70,7 +71,7 @@ static const char* cardname = "netcard"; /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int netcard_portlist[] = +static unsigned int netcard_portlist[] __initdata = { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0}; /* use 0 for production, 1 for verification, >2 for debug */ @@ -126,8 +127,8 @@ extern void chipset_init(struct device *dev, int startp); struct netdev_entry netcard_drv = {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else -int -netcard_probe(struct device *dev) +__initfunc(int +netcard_probe(struct device *dev)) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -154,7 +155,7 @@ netcard_probe(struct device *dev) * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -static int netcard_probe1(struct device *dev, int ioaddr) +__initfunc(static int netcard_probe1(struct device *dev, int ioaddr)) { static unsigned version_printed = 0; int i; @@ -365,7 +366,7 @@ static int net_send_packet(struct sk_buff *skb, struct device *dev) * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index f091e38a4..057d3c9d2 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -123,7 +123,7 @@ sl_alloc(void) if (slp == NULL) break; /* Not in use ? */ - if (!set_bit(SLF_INUSE, &slp->ctrl.flags)) + if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) break; } /* SLP is set.. */ @@ -207,7 +207,7 @@ sl_free(struct slip *sl) sl->slcomp = NULL; #endif - if (!clear_bit(SLF_INUSE, &sl->flags)) { + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { printk("%s: sl_free for already free unit.\n", sl->dev->name); } } @@ -317,7 +317,7 @@ static void sl_changedmtu(struct slip *sl) static inline void sl_lock(struct slip *sl) { - if (set_bit(0, (void *) &sl->dev->tbusy)) { + if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) { printk("%s: trying to lock already locked device!\n", sl->dev->name); } } @@ -327,7 +327,7 @@ sl_lock(struct slip *sl) static inline void sl_unlock(struct slip *sl) { - if (!clear_bit(0, (void *)&sl->dev->tbusy)) { + if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) { printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); } } @@ -661,7 +661,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { sl->rx_errors++; } cp++; @@ -843,7 +843,7 @@ static void slip_unesc(struct slip *sl, unsigned char s) if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } clear_bit(SLF_ESCAPE, &sl->flags); @@ -854,12 +854,12 @@ static void slip_unesc(struct slip *sl, unsigned char s) set_bit(SLF_ESCAPE, &sl->flags); return; case ESC_ESC: - if (clear_bit(SLF_ESCAPE, &sl->flags)) { + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = ESC; } break; case ESC_END: - if (clear_bit(SLF_ESCAPE, &sl->flags)) { + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = END; } break; @@ -928,7 +928,7 @@ slip_unesc6(struct slip *sl, unsigned char s) if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } sl->rcount = 0; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 5b3e9b73c..55f04121f 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -1245,7 +1245,7 @@ static int smc_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n"); dev_kfree_skb (skb, FREE_WRITE); } else { diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index dfa5b272c..c42450a44 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -28,6 +28,7 @@ static const char *version = #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/ptrace.h> +#include <linux/init.h> #include <linux/ioport.h> #include <linux/in.h> #include <linux/malloc.h> @@ -127,7 +128,7 @@ static int sonic_init(struct device *dev); * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */ -int sonic_probe(struct device *dev) +__initfunc(int sonic_probe(struct device *dev)) { unsigned int base_addr = dev ? dev->base_addr : 0; int i; @@ -152,8 +153,8 @@ int sonic_probe(struct device *dev) return -ENODEV; } -static int -sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq) +__initfunc(static int sonic_probe1(struct device *dev, + unsigned int base_addr, unsigned int irq)) { static unsigned version_printed = 0; unsigned int silicon_revision; @@ -403,7 +404,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev) * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } @@ -719,8 +720,7 @@ sonic_multicast_list(struct device *dev) /* * Initialize the SONIC ethernet controller. */ -static int -sonic_init(struct device *dev) +static int sonic_init(struct device *dev) { unsigned int base_addr = dev->base_addr; unsigned int cmd; diff --git a/drivers/net/soundmodem/sm.c b/drivers/net/soundmodem/sm.c index 777b5142f..7d57dd692 100644 --- a/drivers/net/soundmodem/sm.c +++ b/drivers/net/soundmodem/sm.c @@ -56,6 +56,7 @@ #include <asm/bitops.h> #include <linux/delay.h> #include <linux/errno.h> +#include <linux/init.h> #include "sm.h" /* --------------------------------------------------------------------- */ @@ -662,10 +663,7 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr, /* --------------------------------------------------------------------- */ -#ifdef MODULE -static -#endif /* MODULE */ -int sm_init(void) +__initfunc(int sm_init(void)) { int i, j, found = 0; char set_hw = 1; @@ -800,7 +798,7 @@ void cleanup_module(void) * modem: afsk1200, fsk9600 */ -void sm_setup(char *str, int *ints) +__initfunc(void sm_setup(char *str, int *ints)) { int i; diff --git a/drivers/net/strip.c b/drivers/net/strip.c index 862a13370..32c02b4f0 100644 --- a/drivers/net/strip.c +++ b/drivers/net/strip.c @@ -891,7 +891,7 @@ static void strip_unlock(struct strip *strip_info) */ strip_info->idle_timer.expires = jiffies + HZ; add_timer(&strip_info->idle_timer); - if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) + if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", strip_info->dev.name); } @@ -1745,7 +1745,7 @@ static int strip_xmit(struct sk_buff *skb, struct device *dev) printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); return(1); } - if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); + if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); del_timer(&strip_info->idle_timer); /* See if someone has been ifconfigging */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 66e3b0b68..7299b0f4b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1673,6 +1673,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev, netif_rx(skb); hp->net_stats.rx_packets++; + hp->net_stats.rx_bytes+=len; next: elem = NEXT_RX(elem); this = &rxbase[elem]; @@ -1729,6 +1730,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); hp->net_stats.rx_packets++; + hp->net_stats.rx_bytes+=len; } } /* Return the buffer to the Happy Meal. */ @@ -1898,7 +1900,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev) } } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; } @@ -1955,7 +1957,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev) return 0; } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; } diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 0485aa2d1..4e7325016 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.62 1997/04/16 10:27:25 jj Exp $ +/* $Id: sunlance.c,v 1.64 1997/05/14 20:46:40 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -673,8 +673,7 @@ static int lance_open (struct device *dev) /* On the 4m, setup the ledma to provide the upper bits for buffers */ if (lp->ledma) - lp->ledma->regs->dma_test = ((unsigned long) lp->init_block) - & 0xff000000; + lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000; lance_init_ring (dev); load_csrs (lp); @@ -758,8 +757,7 @@ static inline int lance_reset (struct device *dev) lp->ledma->regs->cond_reg |= DMA_RST_ENET; udelay (200); lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; - lp->ledma->regs->dma_test = ((unsigned long) lp->init_block) - & 0xff000000; + lp->ledma->regs->dma_test = ((__u32) lp->init_block_dvma) & 0xff000000; } lance_init_ring (dev); load_csrs (lp); @@ -800,7 +798,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev) } /* Block a timer-based transmit from overlapping. */ - if (set_bit (0, (void *) &dev->tbusy) != 0) { + if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { printk ("Transmitter access conflict.\n"); return -1; } diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index c987c5e9f..18e758c80 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -720,7 +720,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct device *dev) if(dev->tbusy) return 1; - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } @@ -762,7 +762,7 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev) if(dev->tbusy) return 1; - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c index fe4cf2662..f87beba00 100644 --- a/drivers/net/tulip.c +++ b/drivers/net/tulip.c @@ -863,7 +863,7 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index 0b18de7d9..336283df0 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -64,8 +64,8 @@ wv_irq_to_psa(int irq) /* * Translate PSA irq parameter to irq number */ -static int -wv_psa_to_irq(u_char irqval) +__initfunc(static int +wv_psa_to_irq(u_char irqval)) { int irq; @@ -895,7 +895,7 @@ wv_82586_reconfig(device * dev) net_local * lp = (net_local *)dev->priv; /* Check if we can do it now ! */ - if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0)) + if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) { lp->reconfig_82586 = 1; #ifdef DEBUG_CONFIG_INFO @@ -2799,7 +2799,7 @@ wavelan_packet_xmit(struct sk_buff * skb, * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. */ - if(set_bit(0, (void *)&dev->tbusy) != 0) + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) #ifdef DEBUG_TX_ERROR printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); #endif @@ -3999,8 +3999,8 @@ wavelan_close(device * dev) * device structure * (called by wavelan_probe() & via init_module()) */ -static int -wavelan_config(device * dev) +__initfunc(static int +wavelan_config(device * dev)) { u_long ioaddr = dev->base_addr; u_char irq_mask; @@ -4112,11 +4112,9 @@ wavelan_config(device * dev) * the initial value of dev->base_addr. * We follow the example in drivers/net/ne.c.) * (called in "Space.c") - * As this function is called outside the wavelan module, it should be - * declared extern, but it seem to cause troubles... */ -/* extern */ int -wavelan_probe(device * dev) +__initfunc(int +wavelan_probe(device * dev)) { short base_addr; mac_addr mac; /* Mac address (check wavelan existence) */ diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index 338ef1f6f..18320dcc4 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -305,6 +305,7 @@ #include <linux/skbuff.h> #include <linux/malloc.h> #include <linux/timer.h> +#include <linux/init.h> #include <linux/wireless.h> /* Wireless extensions */ diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c index 21963477c..f6f953201 100644 --- a/drivers/net/x25_asy.c +++ b/drivers/net/x25_asy.c @@ -59,7 +59,7 @@ static inline struct x25_asy *x25_asy_alloc(void) if (slp == NULL) break; /* Not in use ? */ - if (!set_bit(SLF_INUSE, &slp->ctrl.flags)) + if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) break; } /* SLP is set.. */ @@ -124,7 +124,7 @@ static inline void x25_asy_free(struct x25_asy *sl) } sl->xbuff = NULL; - if (!clear_bit(SLF_INUSE, &sl->flags)) { + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); } } @@ -201,7 +201,7 @@ static void x25_asy_changed_mtu(struct x25_asy *sl) static inline void x25_asy_lock(struct x25_asy *sl) { - if (set_bit(0, (void *) &sl->dev->tbusy)) + if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) printk("%s: trying to lock already locked device!\n", sl->dev->name); } @@ -210,7 +210,7 @@ static inline void x25_asy_lock(struct x25_asy *sl) static inline void x25_asy_unlock(struct x25_asy *sl) { - if (!clear_bit(0, (void *)&sl->dev->tbusy)) + if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); } @@ -587,7 +587,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { sl->rx_errors++; } cp++; @@ -736,7 +736,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) switch(s) { case X25_END: - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { x25_asy_bump(sl); } @@ -750,7 +750,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) case X25_ESCAPE(X25_ESC): case X25_ESCAPE(X25_END): - if (clear_bit(SLF_ESCAPE, &sl->flags)) + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) s = X25_UNESCAPE(s); break; } diff --git a/drivers/net/znet.c b/drivers/net/znet.c index eb198bc78..cb53120a2 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -351,7 +351,7 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev) /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; |