diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
commit | 78c388aed2b7184182c08428db1de6c872d815f5 (patch) | |
tree | 4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /drivers/net/eth16i.c | |
parent | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff) |
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'drivers/net/eth16i.c')
-rw-r--r-- | drivers/net/eth16i.c | 1285 |
1 files changed, 828 insertions, 457 deletions
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index e68c0d64d..59921bfc2 100644 --- a/drivers/net/eth16i.c +++ b/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 @@ static char *version = #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 @@ static char *version = #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 @@ static char *version = #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 @@ static char *version = #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 @@ static char *version = /* 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 @@ static char *version = #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 @@ static char *version = #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 @@ unsigned int boot = 1; 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); - -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); +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 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 @@ __initfunc(int eth16i_probe(struct device *dev)) /* 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 @@ __initfunc(static int eth16i_probe1(struct device *dev, short ioaddr)) 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 @@ static void eth16i_initialize(struct device *dev) ((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 @@ static void eth16i_initialize(struct device *dev) /* 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 @@ static void eth16i_initialize(struct device *dev) 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 @@ static int eth16i_probe_port(short ioaddr) 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 @@ static int eth16i_check_signature(short ioaddr) 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 @@ static int eth16i_read_eeprom(int ioaddr, int offset) 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 @@ static void eth16i_eeprom_cmd(int ioaddr, unsigned char command) 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 @@ static int eth16i_open(struct device *dev) 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 @@ static int eth16i_close(struct device *dev) 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); - - /* Save some energy by switching off power */ - BITCLR(ioaddr + CONFIG_REG_1, POWERUP); + /* outb(0xff, ioaddr + RESET); */ + /* outw(0xffff, ioaddr + TX_STATUS_REG); */ + + outb(0x00, ioaddr + CONFIG_REG_1); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif return 0; } @@ -875,88 +1040,120 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev) { 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( (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( ioaddr < 0x1000 ) - outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); - else - { - unsigned char frag = length % 4; + if( ioaddr < 0x1000 ) + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); + else { + unsigned char frag = length % 4; - outsl(ioaddr + DATAPORT, buf, length >> 2); + 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); + 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 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev) /* 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 @@ static void eth16i_rx(struct device *dev) 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 @@ static void eth16i_rx(struct device *dev) 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 @@ static void eth16i_rx(struct device *dev) { 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 @@ static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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); - - 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 ? */ + 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 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"); - - 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; - } + int this_dev, found = 0; + + 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 */ |