patch-2.1.126 linux/drivers/net/eth16i.c
Next file: linux/drivers/net/ethertap.c
Previous file: linux/drivers/net/eepro100.c
Back to the patch index
Back to the overall index
- Lines: 1885
- Date:
Fri Oct 9 11:56:59 1998
- Orig file:
v2.1.125/linux/drivers/net/eth16i.c
- Orig date:
Thu Feb 12 20:56:08 1998
diff -u --recursive --new-file v2.1.125/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
@@ -1,122 +1,207 @@
/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
- Written 1994-95 by Mika Kuoppala
-
- Copyright (C) 1994, 1995 by Mika Kuoppala
- Based on skeleton.c and at1700.c by Donald Becker
+
+ Written 1994-1998 by Mika Kuoppala
+
+ Copyright (C) 1994-1998 by Mika Kuoppala
+ Based on skeleton.c and heavily on at1700.c by Donald Becker
This software may be used and distributed according to the terms
of the GNU Public Licence, incorporated herein by reference.
- The author may be reached as miku@elt.icl.fi
+ The author may be reached as miku@iki.fi
This driver supports following cards :
- ICL EtherTeam 16i
- - ICL EtherTeam 32 EISA
+ - ICL EtherTeam 32 EISA
+ (Uses true 32 bit transfers rather than 16i compability mode)
+
+ Example Module usage:
+ insmod eth16i.o ioaddr=0x2a0 mediatype=bnc
+
+ mediatype can be one of the following: bnc,tp,dix,auto,eprom
+ 'auto' will try to autoprobe mediatype.
+ 'eprom' will use whatever type defined in eprom.
+
+ I have benchmarked driver with PII/300Mhz as a ftp client
+ and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
+
Sources:
- skeleton.c a sample network driver core for linux,
written by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
- - at1700.c a driver for Allied Telesis AT1700, written
+ - at1700.c a driver for Allied Telesis AT1700, written
by Donald Becker.
- e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
written by Markku Viima
- The Fujitsu MB86965 databook.
-
- Valuable assistance from:
- Markku Viima (ICL)
- Ari Valve (ICL)
+
+ Author thanks following persons due to their valueble assistance:
+ Markku Viima (ICL)
+ Ari Valve (ICL)
+ Donald Becker
+ Kurt Huwig <kurt@huwig.de>
Revision history:
Version Date Description
-
- 0.01 15.12-94 Initial version (card detection)
+
+ 0.01 15.12-94 Initial version (card detection)
0.02 23.01-95 Interrupt is now hooked correctly
0.03 01.02-95 Rewrote initialization part
0.04 07.02-95 Base skeleton done...
- Made a few changes to signature checking
- to make it a bit reliable.
- - fixed bug in tx_buf mapping
- - fixed bug in initialization (DLC_EN
- wasn't enabled when initialization
- was done.)
- 0.05 08.02-95 If there were more than one packet to send,
- transmit was jammed due to invalid
- register write...now fixed
- 0.06 19.02-95 Rewrote interrupt handling
+ Made a few changes to signature checking
+ to make it a bit reliable.
+ - fixed bug in tx_buf mapping
+ - fixed bug in initialization (DLC_EN
+ wasn't enabled when initialization
+ was done.)
+ 0.05 08.02-95 If there were more than one packet to send,
+ transmit was jammed due to invalid
+ register write...now fixed
+ 0.06 19.02-95 Rewrote interrupt handling
0.07 13.04-95 Wrote EEPROM read routines
Card configuration now set according to
- data read from EEPROM
+ data read from EEPROM
0.08 23.06-95 Wrote part that tries to probe used interface
port if AUTO is selected
- 0.09 01.09-95 Added module support
-
- 0.10 04.09-95 Fixed receive packet allocation to work
- with kernels > 1.3.x
+ 0.09 01.09-95 Added module support
+
+ 0.10 04.09-95 Fixed receive packet allocation to work
+ with kernels > 1.3.x
+
+ 0.20 20.09-95 Added support for EtherTeam32 EISA
- 0.20 20.09-95 Added support for EtherTeam32 EISA
-
- 0.21 17.10-95 Removed the unnecessary extern
+ 0.21 17.10-95 Removed the unnecessary extern
init_etherdev() declaration. Some
other cleanups.
+
+ 0.22 22.02-96 Receive buffer was not flushed
+ correctly when faulty packet was
+ received. Now fixed.
+
+ 0.23 26.02-96 Made resetting the adapter
+ more reliable.
+
+ 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx
+
+ 0.25 22.05-96 kfree() was missing from cleanup_module.
+
+ 0.26 11.06-96 Sometimes card was not found by
+ check_signature(). Now made more reliable.
+
+ 0.27 23.06-96 Oops. 16 consecutive collisions halted
+ adapter. Now will try to retransmit
+ MAX_COL_16 times before finally giving up.
+
+ 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq
+
+ 0.29 29.10-97 Multiple card support for module users
+
+ 0.30 30.10-97 Fixed irq allocation bug.
+ (request_irq moved from probe to open)
+
+ 0.30a 21.08-98 Card detection made more relaxed. Driver
+ had problems with some TCP/IP-PROM boots
+ to find the card. Suggested by
+ Kurt Huwig <kurt@huwig.de>
+
+ 0.31 28.08-98 Media interface port can now be selected
+ with module parameters or kernel
+ boot parameters.
+
+ 0.32 31.08-98 IRQ was never freed if open/close
+ pair wasn't called. Now fixed.
+
+ 0.33 10.09-98 When eth16i_open() was called after
+ eth16i_close() chip never recovered.
+ Now more shallow reset is made on
+ close.
+
Bugs:
- In some cases the interface autoprobing code doesn't find
- the correct interface type. In this case you can
- manually choose the interface type in DOS with E16IC.EXE which is
+ In some cases the media interface autoprobing code doesn't find
+ the correct interface type. In this case you can
+ manually choose the interface type in DOS with E16IC.EXE which is
configuration software for EtherTeam16i and EtherTeam32 cards.
+ This is also true for IRQ setting. You cannot use module
+ parameter to configure IRQ of the card (yet).
To do:
- Real multicast support
+ - Rewrite the media interface autoprobing code. Its _horrible_ !
+ - Possibly merge all the MB86965 specific code to external
+ module for use by eth16.c and Donald's at1700.c
+ - IRQ configuration with module parameter. I will do
+ this when i will get enough info about setting
+ irq without configuration utility.
*/
-static char *version =
- "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@elt.icl.fi)\n";
+static char *version =
+ "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n";
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/delay.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+#if LINUX_VERSION_CODE < 0x20138
+#define test_and_set_bit(val,addr) set_bit(val,addr)
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+typedef struct enet_statistics eth16i_stats_type;
+#else
+typedef struct net_device_stats eth16i_stats_type;
+#endif
/* Few macros */
-#define BIT(a) ( (1 << (a)) )
-#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
+#define BIT(a) ( (1 << (a)) )
+#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
#define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
/* This is the I/O address space for Etherteam 16i adapter. */
-#define ETH16I_IO_EXTENT 32
+#define ETH16I_IO_EXTENT 32
/* Ticks before deciding that transmit has timed out */
-#define TIMEOUT_TICKS 30
+#define TX_TIMEOUT (400*HZ/1000)
/* Maximum loop count when receiving packets */
-#define MAX_RX_LOOP 40
+#define MAX_RX_LOOP 20
/* Some interrupt masks */
-#define ETH16I_INTR_ON 0x8f82
+#define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
#define ETH16I_INTR_OFF 0x0000
-
+
/* Buffers header status byte meanings */
#define PKT_GOOD BIT(5)
#define PKT_GOOD_RMT BIT(4)
@@ -131,6 +216,7 @@
#define NET_BUSY BIT(6)
#define TX_PKT_RCD BIT(5)
#define CR_LOST BIT(4)
+#define TX_JABBER_ERR BIT(3)
#define COLLISION BIT(2)
#define COLLISIONS_16 BIT(1)
@@ -142,7 +228,7 @@
#define ALIGN_ERR BIT(2)
#define CRC_ERR BIT(1)
#define RX_BUF_OVERFLOW BIT(0)
-
+
/* Transmit Interrupt Enable Register (DLCR2) */
#define TX_INTR_REG 2
#define TX_INTR_DONE BIT(7)
@@ -181,18 +267,18 @@
#define SRAM_CYCLE_TIME_100NS BIT(6)
#define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
#define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
-#define TBS1 BIT(3)
+#define TBS1 BIT(3)
#define TBS0 BIT(2)
-#define MBS1 BIT(1) /* 00=8kb, 01=16kb */
-#define MBS0 BIT(0) /* 10=32kb, 11=64kb */
+#define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
+#define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
-#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
-#define ETH16I_TX_BUF_SIZE 2 /* 2 = 8kb, 3 = 16kb */
-#endif
-#define TX_BUF_1x2048 0
-#define TX_BUF_2x2048 1
-#define TX_BUF_2x4098 2
-#define TX_BUF_2x8192 3
+#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
+#define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
+#endif
+#define TX_BUF_1x2048 0
+#define TX_BUF_2x2048 1
+#define TX_BUF_2x4098 2
+#define TX_BUF_2x8192 3
/* Configuration Register 1 (DLCR7) */
#define CONFIG_REG_1 7
@@ -212,18 +298,21 @@
#define HASH_TABLE_RB 1
/* Buffer memory ports */
-#define BUFFER_MEM_PORT_LB 8
-#define DATAPORT BUFFER_MEM_PORT_LB
-#define BUFFER_MEM_PORT_HB 9
+#define BUFFER_MEM_PORT_LB 8
+#define DATAPORT BUFFER_MEM_PORT_LB
+#define BUFFER_MEM_PORT_HB 9
/* 16 Collision control register (BMPR11) */
#define COL_16_REG 11
#define HALT_ON_16 0x00
#define RETRANS_AND_HALT_ON_16 0x02
+/* Maximum number of attempts to send after 16 concecutive collisions */
+#define MAX_COL_16 10
+
/* DMA Burst and Transceiver Mode Register (BMPR13) */
#define TRANSCEIVER_MODE_REG 13
-#define TRANSCEIVER_MODE_RB 2
+#define TRANSCEIVER_MODE_RB 2
#define IO_BASE_UNLOCK BIT(7)
#define LOWER_SQUELCH_TRESH BIT(6)
#define LINK_TEST_DISABLE BIT(5)
@@ -232,9 +321,8 @@
/* Filter Self Receive Register (BMPR14) */
#define FILTER_SELF_RX_REG 14
-#define SKIP_RECEIVE_PACKET BIT(2)
+#define SKIP_RX_PACKET BIT(2)
#define FILTER_SELF_RECEIVE BIT(0)
-#define RX_BUF_SKIP_PACKET SKIP_RECEIVE_PACKET | FILTER_SELF_RECEIVE
/* EEPROM Control Register (BMPR 16) */
#define EEPROM_CTRL_REG 16
@@ -254,19 +342,20 @@
#define EEPROM_READ 0x80
/* NMC93CSx6 EEPROM Addresses */
-#define E_NODEID_0 0x02
-#define E_NODEID_1 0x03
-#define E_NODEID_2 0x04
-#define E_PORT_SELECT 0x14
- #define E_PORT_BNC 0
- #define E_PORT_DIX 1
- #define E_PORT_TP 2
- #define E_PORT_AUTO 3
-#define E_PRODUCT_CFG 0x30
-
+#define E_NODEID_0 0x02
+#define E_NODEID_1 0x03
+#define E_NODEID_2 0x04
+#define E_PORT_SELECT 0x14
+ #define E_PORT_BNC 0x00
+ #define E_PORT_DIX 0x01
+ #define E_PORT_TP 0x02
+ #define E_PORT_AUTO 0x03
+ #define E_PORT_FROM_EPROM 0x04
+#define E_PRODUCT_CFG 0x30
+
/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() udelay(100) /* FIXME: smaller but right value here */
+#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
/* Jumperless Configuration Register (BMPR19) */
#define JUMPERLESS_CONFIG 19
@@ -277,31 +366,24 @@
#define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] __initdata = {
- 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
+static unsigned int eth16i_portlist[] =
+ { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
-static unsigned int eth32i_portlist[] __initdata = {
- 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
-};
+static unsigned int eth32i_portlist[] =
+ { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
/* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] __initdata = {
- 9, 10, 5, 15
-};
+static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
+#define NUM_OF_ISA_IRQS 4
/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = {
- 3, 5, 7, 9, 10, 11, 12, 15
-};
-
+static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
#define EISA_IRQ_REG 0xc89
+#define NUM_OF_EISA_IRQS 8
-static unsigned int eth16i_tx_buf_map[] = {
- 2048, 2048, 4096, 8192
-};
-unsigned int boot = 1;
+static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
+static unsigned int boot = 1;
/* Use 0 for production, 1 for verification, >2 for debug */
#ifndef ETH16I_DEBUG
@@ -310,60 +392,76 @@
static unsigned int eth16i_debug = ETH16I_DEBUG;
/* Information for each board */
-struct eth16i_local
-{
- struct net_device_stats stats;
- unsigned int tx_started:1;
- unsigned char tx_queue; /* Number of packets in transmit buffer */
- unsigned short tx_queue_len;
- unsigned int tx_buf_size;
- unsigned long open_time;
+
+struct eth16i_local {
+ eth16i_stats_type stats;
+ unsigned char tx_started;
+ unsigned char tx_buf_busy;
+ unsigned short tx_queue; /* Number of packets in transmit buffer */
+ unsigned short tx_queue_len;
+ unsigned int tx_buf_size;
+ unsigned long open_time;
+ unsigned long tx_buffered_packets;
+ unsigned long col_16;
};
/* Function prototypes */
-extern int eth16i_probe(struct device *dev);
+extern int eth16i_probe(struct device *dev);
+
+static int eth16i_probe1(struct device *dev, int ioaddr);
+static int eth16i_check_signature(int ioaddr);
+static int eth16i_probe_port(int ioaddr);
+static void eth16i_set_port(int ioaddr, int porttype);
+static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
+static int eth16i_receive_probe_packet(int ioaddr);
+static int eth16i_get_irq(int ioaddr);
+static int eth16i_read_eeprom(int ioaddr, int offset);
+static int eth16i_read_eeprom_word(int ioaddr);
+static void eth16i_eeprom_cmd(int ioaddr, unsigned char command);
+static int eth16i_open(struct device *dev);
+static int eth16i_close(struct device *dev);
+static int eth16i_tx(struct sk_buff *skb, struct device *dev);
+static void eth16i_rx(struct device *dev);
+static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void eth16i_reset(struct device *dev);
+static void eth16i_skip_packet(struct device *dev);
+static void eth16i_multicast(struct device *dev);
+static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
+static void eth16i_initialize(struct device *dev);
+
+#if 0
+static int eth16i_set_irq(struct device *dev);
+#endif
+
+#ifdef MODULE
+static ushort eth16i_parse_mediatype(const char* s);
+#endif
-static int eth16i_probe1(struct device *dev, short ioaddr);
-static int eth16i_check_signature(short ioaddr);
-static int eth16i_probe_port(short ioaddr);
-static void eth16i_set_port(short ioaddr, int porttype);
-static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l);
-static int eth16i_receive_probe_packet(short ioaddr);
-static int eth16i_get_irq(short ioaddr);
-static int eth16i_read_eeprom(int ioaddr, int offset);
-static int eth16i_read_eeprom_word(int ioaddr);
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command);
-static int eth16i_open(struct device *dev);
-static int eth16i_close(struct device *dev);
-static int eth16i_tx(struct sk_buff *skb, struct device *dev);
-static void eth16i_rx(struct device *dev);
-static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eth16i_multicast(struct device *dev);
-static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
-static void eth16i_initialize(struct device *dev);
-static struct net_device_stats *eth16i_get_stats(struct device *dev);
+static struct enet_statistics *eth16i_get_stats(struct device *dev);
static char *cardname = "ICL EtherTeam 16i/32";
-#ifdef HAVE_DEVLIST
+#ifdef HAVE_DEVLIST
+
/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv =
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
+/struct netdev_entry eth16i_drv =
+ {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
#else /* Not HAVE_DEVLIST */
+
__initfunc(int eth16i_probe(struct device *dev))
{
int i;
int ioaddr;
int base_addr = dev ? dev->base_addr : 0;
+
+ if(eth16i_debug > 4)
+ printk(KERN_DEBUG "Probing started for %s\n", cardname);
- if(eth16i_debug > 4)
- printk("Probing started for %s\n", cardname);
-
- if(base_addr > 0x1ff) /* Check only single location */
+ if(base_addr > 0x1ff) /* Check only single location */
return eth16i_probe1(dev, base_addr);
- else if(base_addr != 0) /* Don't probe at all */
+ else if(base_addr != 0) /* Don't probe at all */
return ENXIO;
/* Seek card from the ISA io address space */
@@ -377,88 +475,107 @@
/* Seek card from the EISA io address space */
for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
if(check_region(ioaddr, ETH16I_IO_EXTENT))
- continue;
+ continue;
if(eth16i_probe1(dev, ioaddr) == 0)
- return 0;
- }
+ return 0;
+ }
return ENODEV;
}
-#endif /* Not HAVE_DEVLIST */
+#endif /* Not HAVE_DEVLIST */
-__initfunc(static int eth16i_probe1(struct device *dev, short ioaddr))
+__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr))
{
static unsigned version_printed = 0;
- unsigned int irq = 0;
- boot = 1; /* To inform initialization that we are in boot probe */
+ boot = 1; /* To inform initilization that we are in boot probe */
/*
- The MB86985 chip has on register which holds information in which
- io address the chip lies. First read this register and compare
- it to our current io address and if match then this could
- be our chip.
- */
+ The MB86985 chip has on register which holds information in which
+ io address the chip lies. First read this register and compare
+ it to our current io address and if match then this could
+ be our chip.
+ */
if(ioaddr < 0x1000) {
- if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr)
+
+ if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
+ != ioaddr)
return -ENODEV;
}
/* Now we will go a bit deeper and try to find the chip's signature */
- if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */
+ if(eth16i_check_signature(ioaddr) != 0)
return -ENODEV;
- /*
- Now it seems that we have found an ethernet chip in this particular
- ioaddr. The MB86985 chip has this feature, that when you read a
- certain register it will increase its io base address to next
- configurable slot. Now when we have found the chip, first thing is
- to make sure that the chip's ioaddr will hold still here.
- */
+ /*
+ Now it seems that we have found a ethernet chip in this particular
+ ioaddr. The MB86985 chip has this feature, that when you read a
+ certain register it will increase it's io base address to next
+ configurable slot. Now when we have found the chip, first thing is
+ to make sure that the chip's ioaddr will hold still here.
+ */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
- outb(0x00, ioaddr + RESET); /* Will reset some parts of chip */
- BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* This will disable the data link */
+ outb(0x00, ioaddr + RESET); /* Reset some parts of chip */
+ BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* Disable the data link */
if(dev == NULL)
- dev = init_etherdev(0, sizeof(struct eth16i_local));
+ dev = init_etherdev(0, 0);
if( (eth16i_debug & version_printed++) == 0)
- printk(version);
+ printk(KERN_INFO "%s", version);
dev->base_addr = ioaddr;
+
+#if 0
+ if(dev->irq) {
+ if(eth16i_set_irq(dev)) {
+ dev->irq = eth16i_get_irq(ioaddr);
+ }
+
+ }
+ else {
+#endif
- irq = eth16i_get_irq(ioaddr);
- dev->irq = irq;
+ dev->irq = eth16i_get_irq(ioaddr);
/* Try to obtain interrupt vector */
- if(request_irq(dev->irq, ð16i_interrupt, 0, "eth16i", dev)) {
- printk("%s: %s at %#3x, but is unusable due
- conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq);
- return EAGAIN;
+
+ if (request_irq(dev->irq, (void *)ð16i_interrupt, 0, "eth16i", dev)) {
+ printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n",
+ dev->name, cardname, ioaddr, dev->irq);
+ return -EAGAIN;
}
- printk("%s: %s at %#3x, IRQ %d, ",
- dev->name, cardname, ioaddr, dev->irq);
+#if 0
+ irq2dev_map[dev->irq] = dev;
+#endif
+
+ printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
+ dev->name, cardname, ioaddr, dev->irq);
/* Let's grab the region */
request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
/* Now we will have to lock the chip's io address */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+ outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
- eth16i_initialize(dev); /* Initialize rest of the chip's registers */
+ eth16i_initialize(dev); /* Initialize rest of the chip's registers */
/* Now let's same some energy by shutting down the chip ;) */
BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
/* Initialize the device structure */
- if(dev->priv == NULL)
+ if(dev->priv == NULL) {
dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
+ if(dev->priv == NULL)
+ return -ENOMEM;
+ }
+
memset(dev->priv, 0, sizeof(struct eth16i_local));
dev->open = eth16i_open;
@@ -478,7 +595,7 @@
static void eth16i_initialize(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
int i, node_w = 0;
unsigned char node_byte = 0;
@@ -489,11 +606,9 @@
((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
}
- for(i = 0; i < 6; i++)
- {
+ for(i = 0; i < 6; i++) {
outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
- if(boot)
- {
+ if(boot) {
printk("%02x", inb(ioaddr + NODE_ID_0 + i));
if(i != 5)
printk(":");
@@ -502,14 +617,14 @@
/* Now we will set multicast addresses to accept none */
eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
- for(i = 0; i < 8; i++)
+ for(i = 0; i < 8; i++)
outb(0x00, ioaddr + HASH_TABLE_0 + i);
/*
- Now let's disable the transmitter and receiver, set the buffer ram
- cycle time, bus width and buffer data path width. Also we shall
- set transmit buffer size and total buffer size.
- */
+ Now let's disable the transmitter and receiver, set the buffer ram
+ cycle time, bus width and buffer data path width. Also we shall
+ set transmit buffer size and total buffer size.
+ */
eth16i_select_regbank(2, ioaddr);
@@ -519,38 +634,56 @@
if( (node_w & 0xFF00) == 0x0800)
node_byte |= BUFFER_WIDTH_8;
- node_byte |= MBS1;
+ node_byte |= SRAM_BS1;
if( (node_w & 0x00FF) == 64)
- node_byte |= MBS0;
+ node_byte |= SRAM_BS0;
node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
outb(node_byte, ioaddr + CONFIG_REG_0);
/* We shall halt the transmitting, if 16 collisions are detected */
- outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG);
+ outb(HALT_ON_16, ioaddr + COL_16_REG);
- if(boot) /* Now set port type */
- {
- char *porttype[] = {"BNC", "DIX", "TP", "AUTO"};
+#ifdef MODULE
+ /* if_port already set by init_module() */
+#else
+ dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
+ dev->mem_start : E_PORT_FROM_EPROM;
+#endif
- ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
- dev->if_port = (ptype & 0x00FF);
+ /* Set interface port type */
+ if(boot) {
+ char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" };
- printk(" %s interface.\n", porttype[dev->if_port]);
+ switch(dev->if_port)
+ {
+
+ case E_PORT_FROM_EPROM:
+ dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
+ break;
+
+ case E_PORT_AUTO:
+ dev->if_port = eth16i_probe_port(ioaddr);
+ break;
+
+ case E_PORT_BNC:
+ case E_PORT_TP:
+ case E_PORT_DIX:
+ break;
+ }
- if(ptype == E_PORT_AUTO)
- ptype = eth16i_probe_port(ioaddr);
+ printk(" %s interface.\n", porttype[dev->if_port]);
- eth16i_set_port(ioaddr, ptype);
+ eth16i_set_port(ioaddr, dev->if_port);
}
/* Set Receive Mode to normal operation */
outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
}
-static int eth16i_probe_port(short ioaddr)
+static int eth16i_probe_port(int ioaddr)
{
int i;
int retcode;
@@ -579,136 +712,163 @@
eth16i_set_port(ioaddr, i);
if(eth16i_debug > 1)
- printk("Set port number %d\n", i);
+ printk(KERN_DEBUG "Set port number %d\n", i);
retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
- if(retcode == 0)
- {
+ if(retcode == 0) {
retcode = eth16i_receive_probe_packet(ioaddr);
- if(retcode != -1)
- {
+ if(retcode != -1) {
if(eth16i_debug > 1)
- printk("Eth16i interface port found at %d\n", i);
+ printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
return i;
}
}
else {
if(eth16i_debug > 1)
- printk("TRANSMIT_DONE timeout\n");
+ printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
}
}
if( eth16i_debug > 1)
- printk("Using default port\n");
+ printk(KERN_DEBUG "Using default port\n");
return E_PORT_BNC;
}
-static void eth16i_set_port(short ioaddr, int porttype)
-{
+static void eth16i_set_port(int ioaddr, int porttype)
+{
unsigned short temp = 0;
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
temp |= DIS_AUTO_PORT_SEL;
- switch(porttype)
- {
- case E_PORT_BNC :
- temp |= AUI_SELECT;
- break;
+ switch(porttype) {
- case E_PORT_TP :
- break;
+ case E_PORT_BNC :
+ temp |= AUI_SELECT;
+ break;
+
+ case E_PORT_TP :
+ break;
+
+ case E_PORT_DIX :
+ temp |= AUI_SELECT;
+ BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
+ break;
+ }
- case E_PORT_DIX :
- temp |= AUI_SELECT;
- BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
- break;
- }
outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
if(eth16i_debug > 1) {
- printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
- printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG));
+ printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
+ printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
+ inb(ioaddr+TRANSCEIVER_MODE_REG));
}
}
-static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l)
+static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
{
int starttime;
outb(0xff, ioaddr + TX_STATUS_REG);
outw(l, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+ outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
starttime = jiffies;
- outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+ outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
- while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0)
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- break;
- return(0);
+ while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
+ return -1;
+ }
+ }
+
+ return 0;
}
-static int eth16i_receive_probe_packet(short ioaddr)
+static int eth16i_receive_probe_packet(int ioaddr)
{
int starttime;
starttime = jiffies;
- while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0)
- {
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- {
+ while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
+
if(eth16i_debug > 1)
- printk("Timeout occurred waiting transmit packet received\n");
+ printk(KERN_DEBUG "Timeout occured waiting transmit packet received\n");
starttime = jiffies;
- while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0)
- {
- if( (jiffies - starttime) > TIMEOUT_TICKS)
- {
+ while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
+ if( (jiffies - starttime) > TX_TIMEOUT) {
if(eth16i_debug > 1)
- printk("Timeout occurred waiting receive packet\n");
+ printk(KERN_DEBUG "Timeout occured waiting receive packet\n");
return -1;
}
}
if(eth16i_debug > 1)
- printk("RECEIVE_PACKET\n");
+ printk(KERN_DEBUG "RECEIVE_PACKET\n");
return(0); /* Found receive packet */
}
}
if(eth16i_debug > 1) {
- printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
- printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
+ printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
+ printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
}
return(0); /* Return success */
}
-static int eth16i_get_irq(short ioaddr)
+#if 0
+static int eth16i_set_irq(struct device* dev)
+{
+ const int ioaddr = dev->base_addr;
+ const int irq = dev->irq;
+ int i = 0;
+
+ if(ioaddr < 0x1000) {
+ while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
+ i++;
+
+ if(i < NUM_OF_ISA_IRQS) {
+ u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
+ cbyte = (cbyte & 0x3F) | (i << 6);
+ outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
+ return 0;
+ }
+ }
+ else {
+ printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
+ }
+
+ return -1;
+
+}
+#endif
+
+static int eth16i_get_irq(int ioaddr)
{
unsigned char cbyte;
if( ioaddr < 0x1000) {
cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
- return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
- } else { /* Oh..the card is EISA so method getting IRQ different */
- unsigned short index = 0;
- cbyte = inb(ioaddr + EISA_IRQ_REG);
- while( (cbyte & 0x01) == 0) {
- cbyte = cbyte >> 1;
- index++;
- }
- return( eth32i_irqmap[ index ] );
+ return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] );
+ } else { /* Oh..the card is EISA so method getting IRQ different */
+ unsigned short index = 0;
+ cbyte = inb(ioaddr + EISA_IRQ_REG);
+ while( (cbyte & 0x01) == 0) {
+ cbyte = cbyte >> 1;
+ index++;
+ }
+ return( eth32i_irqmap[ index ] );
}
}
-static int eth16i_check_signature(short ioaddr)
+static int eth16i_check_signature(int ioaddr)
{
int i;
unsigned char creg[4] = { 0 };
@@ -718,36 +878,37 @@
creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
if(eth16i_debug > 1)
- printk("eth16i: read signature byte %x at %x\n", creg[i],
- ioaddr + TRANSMIT_MODE_REG + i);
+ printk("eth16i: read signature byte %x at %x\n",
+ creg[i],
+ ioaddr + TRANSMIT_MODE_REG + i);
}
creg[0] &= 0x0F; /* Mask collision cnr */
creg[2] &= 0x7F; /* Mask DCLEN bit */
-#if 0
-/*
- This was removed because the card was sometimes left to state
- from which it couldn't be find anymore. If there is need
- to have a more strict check still this have to be fixed.
-*/
- if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) {
+#ifdef 0
+ /*
+ This was removed because the card was sometimes left to state
+ from which it couldn't be find anymore. If there is need
+ to more strict check still this have to be fixed.
+ */
+ if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
if(creg[1] != 0x42)
return -1;
}
#endif
- if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) )
- {
- creg[2] &= 0x42;
+ if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
+ creg[2] &= 0x40;
creg[3] &= 0x03;
-
- if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) )
+
+ if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
return -1;
}
-
+
if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
return -1;
+
if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
return -1;
@@ -763,20 +924,22 @@
data = eth16i_read_eeprom_word(ioaddr);
outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
- return(data);
+ return(data);
}
static int eth16i_read_eeprom_word(int ioaddr)
{
int i;
int data = 0;
-
+
for(i = 16; i > 0; i--) {
outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+ data = (data << 1) |
+ ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
+
eeprom_slow_io();
}
@@ -800,25 +963,26 @@
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- }
+ }
}
static int eth16i_open(struct device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
-
+
/* Powerup the chip */
outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
/* Initialize the chip */
- eth16i_initialize(dev);
+ eth16i_initialize(dev);
/* Set the transmit buffer size */
lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
- if(eth16i_debug > 3)
- printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size);
+ if(eth16i_debug > 0)
+ printk(KERN_DEBUG "%s: transmit buffer size %d\n",
+ dev->name, lp->tx_buf_size);
/* Now enable Transmitter and Receiver sections */
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
@@ -832,15 +996,13 @@
lp->tx_queue_len = 0;
/* Turn on interrupts*/
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
-#ifdef MODULE
MOD_INC_USE_COUNT;
-#endif
return 0;
}
@@ -850,23 +1012,26 @@
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
- lp->open_time = 0;
+ eth16i_reset(dev);
+
+ /* Turn off interrupts*/
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- dev->tbusy = 1;
dev->start = 0;
+ dev->tbusy = 1;
+
+ lp->open_time = 0;
/* Disable transmit and receive */
BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
/* Reset the chip */
- outb(0xff, ioaddr + RESET);
+ /* outb(0xff, ioaddr + RESET); */
+ /* outw(0xffff, ioaddr + TX_STATUS_REG); */
+
+ outb(0x00, ioaddr + CONFIG_REG_1);
- /* Save some energy by switching off power */
- BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
-
-#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -875,88 +1040,120 @@
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
+ int status = 0;
if(dev->tbusy) {
- /*
- If we get here, some higher level has decided that we are broken.
- There should really be a "kick me" function call instead.
- */
+
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
+ */
int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < TIMEOUT_TICKS) /* Let's not rush with our timeout, */
- return 1; /* wait a couple of ticks first */
+ if(tickssofar < TX_TIMEOUT)
+ return 1;
- printk("%s: transmit timed out with status %04x, %s ?\n", dev->name,
- inw(ioaddr + TX_STATUS_REG),
- (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
- "IRQ conflict" : "network cable problem");
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+ inw(ioaddr + TX_STATUS_REG),
+ (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ "IRQ conflict" : "network cable problem");
+ dev->trans_start = jiffies;
- printk("lp->tx_queue = %d\n", lp->tx_queue);
- printk("lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk("lp->tx_started = %d\n", lp->tx_started);
+ /* Let's dump all registers */
+ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+
+ printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+ dev->name, inb(ioaddr + TRANSMIT_START_REG),
+ inb(ioaddr + COL_16_REG));
+
+ printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
+ printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+ printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
lp->stats.tx_errors++;
- /* Now let's try to restart the adaptor */
-
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
- outw(0xffff, ioaddr + RESET);
- eth16i_initialize(dev);
- outw(0xffff, ioaddr + TX_STATUS_REG);
- BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+ eth16i_reset(dev);
- lp->tx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- dev->tbusy = 0;
- dev->trans_start = jiffies;
}
- /* Block a timer based transmitter from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ /*
+ If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself
+ */
+
+ if(skb == NULL) {
+#if LINUX_VERSION_CODE < 0x020100
+ dev_tint(dev);
+#endif
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
+ return 0;
+ }
+
+ /* Block a timer based transmitter from overlapping.
+ This could better be done with atomic_swap(1, dev->tbusy),
+ but set_bit() works as well. */
+ set_bit(0, (void *)&lp->tx_buf_busy);
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
+ if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+ status = -1;
+ }
else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
- outw(length, ioaddr + DATAPORT);
-
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else
- {
- unsigned char frag = length % 4;
-
- outsl(ioaddr + DATAPORT, buf, length >> 2);
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
+ else {
+ outw(length, ioaddr + DATAPORT);
- if( frag != 0 )
- {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1);
+ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+ else {
+ unsigned char frag = length % 4;
+
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
+
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
+ }
}
- }
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
+ lp->tx_buffered_packets++;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+
+ }
+
+ lp->tx_buf_busy = 0;
if(lp->tx_started == 0) {
/* If the transmitter is idle..always trigger a transmit */
@@ -971,15 +1168,21 @@
/* There is still more room for one more packet in tx buffer */
dev->tbusy = 0;
}
-
+
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+
/* Turn TX interrupts back on */
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- }
+ status = 0;
+ }
+
+#if LINUX_VERSION_CODE >= 0x020100
dev_kfree_skb(skb);
+#else
+ dev_kfree_skb(skb, FREE_WRITE);
+#endif
- return 0;
+ return status;
}
static void eth16i_rx(struct device *dev)
@@ -989,71 +1192,63 @@
int boguscount = MAX_RX_LOOP;
/* Loop until all packets have been read */
- while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0)
- {
- /* Read status byte from receive buffer */
+ while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
+
+ /* Read status byte from receive buffer */
ushort status = inw(ioaddr + DATAPORT);
- if(eth16i_debug > 4)
- printk("%s: Receiving packet mode %02x status %04x.\n",
- dev->name, inb(ioaddr + RECEIVE_MODE_REG), status);
+ /* Get the size of the packet from receive buffer */
+ ushort pkt_len = inw(ioaddr + DATAPORT);
- if( !(status & PKT_GOOD) )
- {
- /* Hmm..something went wrong. Let's check what error occurred */
+ if(eth16i_debug > 4)
+ printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
+ dev->name,
+ inb(ioaddr + RECEIVE_MODE_REG), status);
+
+ if( !(status & PKT_GOOD) ) {
lp->stats.rx_errors++;
- if( status & PKT_SHORT)
+
+ if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
lp->stats.rx_length_errors++;
- if( status & PKT_ALIGN_ERR )
- lp->stats.rx_frame_errors++;
- if( status & PKT_CRC_ERR )
- lp->stats.rx_crc_errors++;
- if( status & PKT_RX_BUF_OVERFLOW)
- lp->stats.rx_over_errors++;
+ eth16i_reset(dev);
+ return;
+ }
+ else {
+ eth16i_skip_packet(dev);
+ lp->stats.rx_dropped++;
+ }
}
- else
- { /* Ok so now we should have a good packet */
+ else { /* Ok so now we should have a good packet */
struct sk_buff *skb;
- /* Get the size of the packet from receive buffer */
- ushort pkt_len = inw(ioaddr + DATAPORT);
-
- if(pkt_len > ETH_FRAME_LEN)
- {
- printk("%s: %s claimed a very large packet, size of %d bytes.\n",
- dev->name, cardname, pkt_len);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
- lp->stats.rx_dropped++;
- break;
- }
skb = dev_alloc_skb(pkt_len + 3);
- if( skb == NULL )
- {
- printk("%s: Couldn't allocate memory for packet (len %d)\n",
- dev->name, pkt_len);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ if( skb == NULL ) {
+ printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
+ dev->name, pkt_len);
+ eth16i_skip_packet(dev);
lp->stats.rx_dropped++;
break;
}
+
skb->dev = dev;
skb_reserve(skb,2);
- /*
- Now let's get the packet out of buffer.
- size is (pkt_len + 1) >> 1, cause we are now reading words
- and it has to be even aligned.
- */
-
- if( ioaddr < 0x1000)
- insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1);
- else
- {
+
+ /*
+ Now let's get the packet out of buffer.
+ size is (pkt_len + 1) >> 1, cause we are now reading words
+ and it have to be even aligned.
+ */
+
+ if(ioaddr < 0x1000)
+ insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+ (pkt_len + 1) >> 1);
+ else {
unsigned char *buf = skb_put(skb, pkt_len);
unsigned char frag = pkt_len % 4;
insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
- if(frag != 0)
- {
+ if(frag != 0) {
unsigned short rest[2];
rest[0] = inw( ioaddr + DATAPORT );
if(frag == 3)
@@ -1067,13 +1262,13 @@
netif_rx(skb);
lp->stats.rx_packets++;
- if( eth16i_debug > 5 )
- {
+ if( eth16i_debug > 5 ) {
int i;
- printk("%s: Received packet of length %d.\n", dev->name, pkt_len);
- for(i = 0; i < 14; i++)
- printk(" %02x", skb->data[i]);
- printk(".\n");
+ printk(KERN_DEBUG "%s: Received packet of length %d.\n",
+ dev->name, pkt_len);
+ for(i = 0; i < 14; i++)
+ printk(KERN_DEBUG " %02x", skb->data[i]);
+ printk(KERN_DEBUG ".\n");
}
} /* else */
@@ -1087,16 +1282,16 @@
{
int i;
- for(i = 0; i < 20; i++)
- {
- if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY)
+ for(i = 0; i < 20; i++) {
+ if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) ==
+ RX_BUFFER_EMPTY)
break;
inw(ioaddr + DATAPORT);
- outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
}
if(eth16i_debug > 1)
- printk("%s: Flushed receive buffer.\n", dev->name);
+ printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
}
#endif
@@ -1108,126 +1303,302 @@
struct device *dev = dev_id;
struct eth16i_local *lp;
int ioaddr = 0,
- status;
+ status;
if(dev == NULL) {
- printk("eth16i_interrupt(): irq %d for unknown device. \n", irq);
+ printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
return;
}
/* Turn off all interrupts from adapter */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */
+ /* eth16i_tx wont be called */
+
+ if(dev->interrupt)
+ printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
ioaddr = dev->base_addr;
lp = (struct eth16i_local *)dev->priv;
- status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
- outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
+ status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
+ outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
if(eth16i_debug > 3)
- printk("%s: Interrupt with status %04x.\n", dev->name, status);
+ printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
+
+ if( status & 0x7f00 ) {
+
+ lp->stats.rx_errors++;
+
+ if(status & (BUS_RD_ERR << 8) )
+ printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
+ if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
+ if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
+ if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++;
+ if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+ }
+ if( status & 0x001a) {
+
+ lp->stats.tx_errors++;
+
+ if(status & CR_LOST) lp->stats.tx_carrier_errors++;
+ if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
- if( status & 0x00ff ) { /* Let's check the transmit status reg */
- if(status & TX_DONE)
- { /* The transmit has been done */
- lp->stats.tx_packets++;
- if(lp->tx_queue)
- { /* Are there still packets ? */
+#if 0
+ if(status & COLLISION) {
+ lp->stats.collisions +=
+ ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
+ }
+#endif
+ if(status & COLLISIONS_16) {
+ if(lp->col_16 < MAX_COL_16) {
+ lp->col_16++;
+ lp->stats.collisions++;
+ /* Resume transmitting, skip failed packet */
+ outb(0x02, ioaddr + COL_16_REG);
+ }
+ else {
+ printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
+ }
+ }
+ }
+
+ if( status & 0x00ff ) { /* Let's check the transmit status reg */
+
+ if(status & TX_DONE) { /* The transmit has been done */
+ lp->stats.tx_packets = lp->tx_buffered_packets;
+ lp->col_16 = 0;
+
+ if(lp->tx_queue) { /* Is there still packets ? */
/* There was packet(s) so start transmitting and write also
- how many packets there is to be sent */
+ how many packets there is to be sended */
outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
+ lp->tx_started = 1;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ mark_bh(NET_BH);
}
- else
- {
+ else {
lp->tx_started = 0;
- dev->tbusy = 0;
mark_bh(NET_BH);
}
}
}
- if( ( status & 0xff00 ) ||
- ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
- eth16i_rx(dev); /* We have packet in receive buffer */
- }
-
+ if( ( status & 0x8000 ) ||
+ ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
+ eth16i_rx(dev); /* We have packet in receive buffer */
+ }
+
dev->interrupt = 0;
-
+
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+
+ if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ dev->tbusy = 0;
+ }
+
return;
}
-static void eth16i_multicast(struct device *dev)
+static void eth16i_skip_packet(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ inw(ioaddr + DATAPORT);
+ inw(ioaddr + DATAPORT);
+ inw(ioaddr + DATAPORT);
+
+ outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
+ while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
+}
+
+static void eth16i_reset(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if(eth16i_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
+
+ BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
+ outw(0xffff, ioaddr + TX_STATUS_REG);
+ eth16i_select_regbank(2, ioaddr);
+
+ lp->tx_started = 0;
+ lp->tx_buf_busy = 0;
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
+}
- if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+static void eth16i_multicast(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
{
dev->flags|=IFF_PROMISC; /* Must do this */
- outb(3, ioaddr + RECEIVE_MODE_REG);
+ outb(3, ioaddr + RECEIVE_MODE_REG);
} else {
outb(2, ioaddr + RECEIVE_MODE_REG);
}
}
-static struct net_device_stats *eth16i_get_stats(struct device *dev)
+static struct enet_statistics *eth16i_get_stats(struct device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
return &lp->stats;
}
-static void eth16i_select_regbank(unsigned char banknbr, short ioaddr)
+static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
{
unsigned char data;
data = inb(ioaddr + CONFIG_REG_1);
- outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+ outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
}
#ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_eth16i = {
- devicename,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, eth16i_probe
+
+static ushort eth16i_parse_mediatype(const char* s)
+{
+ if(!s)
+ return E_PORT_FROM_EPROM;
+
+ if (!strncmp(s, "bnc", 3))
+ return E_PORT_BNC;
+ else if (!strncmp(s, "tp", 2))
+ return E_PORT_TP;
+ else if (!strncmp(s, "dix", 3))
+ return E_PORT_DIX;
+ else if (!strncmp(s, "auto", 4))
+ return E_PORT_AUTO;
+ else
+ return E_PORT_FROM_EPROM;
+}
+
+#define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */
+#define NAMELEN 8 /* number of chars for storing dev->name */
+
+static char namelist[NAMELEN * MAX_ETH16I_CARDS] = { 0, };
+static struct device dev_eth16i[MAX_ETH16I_CARDS] = {
+ {
+ NULL,
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, NULL
+ },
};
-int io = 0x2a0;
-int irq = 0;
+static int ioaddr[MAX_ETH16I_CARDS] = { 0, };
+#if 0
+static int irq[MAX_ETH16I_CARDS] = { 0, };
+#endif
+static char* mediatype[MAX_ETH16I_CARDS] = { 0, };
+static int debug = -1;
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
+#if (LINUX_VERSION_CODE >= 0x20115)
+MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
+MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
+
+MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(ioaddr, "eth16i io base address");
+
+#if 0
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(irq, "eth16i interrupt request number");
+#endif
+
+MODULE_PARM(mediatype, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "s");
+MODULE_PARM_DESC(mediatype, "eth16i interfaceport mediatype");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "eth16i debug level (0-4)");
+#endif
int init_module(void)
{
- if(io == 0)
- printk("eth16i: You should not use auto-probing with insmod!\n");
+ int this_dev, found = 0;
- dev_eth16i.base_addr = io;
- dev_eth16i.irq = irq;
- if( register_netdev( &dev_eth16i ) != 0 ) {
- printk("eth16i: register_netdev() returned non-zero.\n");
- return -EIO;
- }
+ for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)
+ {
+ struct device *dev = &dev_eth16i[this_dev];
+
+ dev->name = namelist + (NAMELEN*this_dev);
+ dev->irq = 0; /* irq[this_dev]; */
+ dev->base_addr = ioaddr[this_dev];
+ dev->init = eth16i_probe;
+
+ if(debug != -1)
+ eth16i_debug = debug;
+
+ if(eth16i_debug > 1)
+ printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
+ dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
+
+ if(ioaddr[this_dev] == 0)
+ {
+ if(this_dev != 0) break; /* Only autoprobe 1st one */
+
+ printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
+ }
+
+ if(register_netdev(dev) != 0)
+ {
+ printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
+ ioaddr[this_dev]);
+
+ if(found != 0) return 0;
+ return -ENXIO;
+ }
+
+ found++;
+ }
return 0;
}
-
+
void cleanup_module(void)
{
- unregister_netdev( &dev_eth16i );
- free_irq( dev_eth16i.irq, &dev_eth16i );
- release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT );
-}
+ int this_dev;
+ for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++)
+ {
+ struct device* dev = &dev_eth16i[this_dev];
+
+ if(dev->priv != NULL)
+ {
+ unregister_netdev(dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, ETH16I_IO_EXTENT);
+
+ }
+ }
+}
#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c"
+ * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * End:
+ */
+
+/* End of file eth16i.c */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov