2005-04-17 02:20:36 +04:00
/*
* linux / drivers / acorn / net / ether3 . c
*
* Copyright ( C ) 1995 - 2000 Russell King
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* SEEQ nq8005 ethernet driver for Acorn / ANT Ether3 card
* for Acorn machines
*
* By Russell King , with some suggestions from borris @ ant . co . uk
*
* Changelog :
* 1.04 RMK 29 / 02 / 1996 Won ' t pass packets that are from our ethernet
* address up to the higher levels - they ' re
* silently ignored . I / F can now be put into
* multicast mode . Receiver routine optimised .
* 1.05 RMK 30 / 02 / 1996 Now claims interrupt at open when part of
* the kernel rather than when a module .
* 1.06 RMK 02 / 03 / 1996 Various code cleanups
* 1.07 RMK 13 / 10 / 1996 Optimised interrupt routine and transmit
* routines .
* 1.08 RMK 14 / 10 / 1996 Fixed problem with too many packets ,
* prevented the kernel message about dropped
* packets appearing too many times a second .
* Now does not disable all IRQs , only the IRQ
* used by this card .
* 1.09 RMK 10 / 11 / 1996 Only enables TX irq when buffer space is low ,
* but we still service the TX queue if we get a
* RX interrupt .
* 1.10 RMK 15 / 07 / 1997 Fixed autoprobing of NQ8004 .
* 1.11 RMK 16 / 11 / 1997 Fixed autoprobing of NQ8005A .
* 1.12 RMK 31 / 12 / 1997 Removed reference to dev_tint for Linux 2.1 .
* RMK 27 / 06 / 1998 Changed asm / delay . h to linux / delay . h .
* 1.13 RMK 29 / 06 / 1998 Fixed problem with transmission of packets .
* Chip seems to have a bug in , whereby if the
* packet starts two bytes from the end of the
* buffer , it corrupts the receiver chain , and
* never updates the transmit status correctly .
* 1.14 RMK 07 / 01 / 1998 Added initial code for ETHERB addressing .
* 1.15 RMK 30 / 04 / 1999 More fixes to the transmit routine for buggy
* hardware .
* 1.16 RMK 10 / 02 / 2000 Updated for 2.3 .43
* 1.17 RMK 13 / 05 / 2000 Updated for 2.3 .99 - pre8
*/
# 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/slab.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/device.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/bitops.h>
# include <asm/system.h>
# include <asm/ecard.h>
# include <asm/io.h>
static char version [ ] __initdata = " ether3 ethernet driver (c) 1995-2000 R.M.King v1.17 \n " ;
# include "ether3.h"
static unsigned int net_debug = NET_DEBUG ;
static void ether3_setmulticastlist ( struct net_device * dev ) ;
static int ether3_rx ( struct net_device * dev , unsigned int maxcnt ) ;
static void ether3_tx ( struct net_device * dev ) ;
static int ether3_open ( struct net_device * dev ) ;
static int ether3_sendpacket ( struct sk_buff * skb , struct net_device * dev ) ;
static irqreturn_t ether3_interrupt ( int irq , void * dev_id , struct pt_regs * regs ) ;
static int ether3_close ( struct net_device * dev ) ;
static struct net_device_stats * ether3_getstats ( struct net_device * dev ) ;
static void ether3_setmulticastlist ( struct net_device * dev ) ;
static void ether3_timeout ( struct net_device * dev ) ;
# define BUS_16 2
# define BUS_8 1
# define BUS_UNKNOWN 0
/* --------------------------------------------------------------------------- */
typedef enum {
buffer_write ,
buffer_read
} buffer_rw_t ;
/*
* ether3 read / write . Slow things down a bit . . .
* The SEEQ8005 doesn ' t like us writing to its registers
* too quickly .
*/
static inline void ether3_outb ( int v , const void __iomem * r )
{
writeb ( v , r ) ;
udelay ( 1 ) ;
}
static inline void ether3_outw ( int v , const void __iomem * r )
{
writew ( v , r ) ;
udelay ( 1 ) ;
}
# define ether3_inb(r) ({ unsigned int __v = readb((r)); udelay(1); __v; })
# define ether3_inw(r) ({ unsigned int __v = readw((r)); udelay(1); __v; })
static int
ether3_setbuffer ( struct net_device * dev , buffer_rw_t read , int start )
{
int timeout = 1000 ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_LOCBUFMEM , REG_CONFIG1 ) ;
ether3_outw ( priv ( dev ) - > regs . command | CMD_FIFOWRITE , REG_COMMAND ) ;
while ( ( ether3_inw ( REG_STATUS ) & STAT_FIFOEMPTY ) = = 0 ) {
if ( ! timeout - - ) {
printk ( " %s: setbuffer broken \n " , dev - > name ) ;
priv ( dev ) - > broken = 1 ;
return 1 ;
}
udelay ( 1 ) ;
}
if ( read = = buffer_read ) {
ether3_outw ( start , REG_DMAADDR ) ;
ether3_outw ( priv ( dev ) - > regs . command | CMD_FIFOREAD , REG_COMMAND ) ;
} else {
ether3_outw ( priv ( dev ) - > regs . command | CMD_FIFOWRITE , REG_COMMAND ) ;
ether3_outw ( start , REG_DMAADDR ) ;
}
return 0 ;
}
/*
* write data to the buffer memory
*/
# define ether3_writebuffer(dev,data,length) \
writesw ( REG_BUFWIN , ( data ) , ( length ) > > 1 )
# define ether3_writeword(dev,data) \
writew ( ( data ) , REG_BUFWIN )
# define ether3_writelong(dev,data) { \
void __iomem * reg_bufwin = REG_BUFWIN ; \
writew ( ( data ) , reg_bufwin ) ; \
writew ( ( data ) > > 16 , reg_bufwin ) ; \
}
/*
* read data from the buffer memory
*/
# define ether3_readbuffer(dev,data,length) \
readsw ( REG_BUFWIN , ( data ) , ( length ) > > 1 )
# define ether3_readword(dev) \
readw ( REG_BUFWIN )
# define ether3_readlong(dev) \
readw ( REG_BUFWIN ) | ( readw ( REG_BUFWIN ) < < 16 )
/*
* Switch LED off . . .
*/
static void ether3_ledoff ( unsigned long data )
{
struct net_device * dev = ( struct net_device * ) data ;
ether3_outw ( priv ( dev ) - > regs . config2 | = CFG2_CTRLO , REG_CONFIG2 ) ;
}
/*
* switch LED on . . .
*/
static inline void ether3_ledon ( struct net_device * dev )
{
del_timer ( & priv ( dev ) - > timer ) ;
priv ( dev ) - > timer . expires = jiffies + HZ / 50 ; /* leave on for 1/50th second */
priv ( dev ) - > timer . data = ( unsigned long ) dev ;
priv ( dev ) - > timer . function = ether3_ledoff ;
add_timer ( & priv ( dev ) - > timer ) ;
if ( priv ( dev ) - > regs . config2 & CFG2_CTRLO )
ether3_outw ( priv ( dev ) - > regs . config2 & = ~ CFG2_CTRLO , REG_CONFIG2 ) ;
}
/*
* Read the ethernet address string from the on board rom .
* This is an ascii string ! ! !
*/
static int __init
ether3_addr ( char * addr , struct expansion_card * ec )
{
struct in_chunk_dir cd ;
char * s ;
if ( ecard_readchunk ( & cd , ec , 0xf5 , 0 ) & & ( s = strchr ( cd . d . string , ' ( ' ) ) ) {
int i ;
for ( i = 0 ; i < 6 ; i + + ) {
addr [ i ] = simple_strtoul ( s + 1 , & s , 0x10 ) ;
if ( * s ! = ( i = = 5 ? ' ) ' : ' : ' ) )
break ;
}
if ( i = = 6 )
return 0 ;
}
/* I wonder if we should even let the user continue in this case
* - no , it would be better to disable the device
*/
printk ( KERN_ERR " ether3: Couldn't read a valid MAC address from card. \n " ) ;
return - ENODEV ;
}
/* --------------------------------------------------------------------------- */
static int __init
ether3_ramtest ( struct net_device * dev , unsigned char byte )
{
unsigned char * buffer = kmalloc ( RX_END , GFP_KERNEL ) ;
int i , ret = 0 ;
int max_errors = 4 ;
int bad = - 1 ;
if ( ! buffer )
return 1 ;
memset ( buffer , byte , RX_END ) ;
ether3_setbuffer ( dev , buffer_write , 0 ) ;
ether3_writebuffer ( dev , buffer , TX_END ) ;
ether3_setbuffer ( dev , buffer_write , RX_START ) ;
ether3_writebuffer ( dev , buffer + RX_START , RX_LEN ) ;
memset ( buffer , byte ^ 0xff , RX_END ) ;
ether3_setbuffer ( dev , buffer_read , 0 ) ;
ether3_readbuffer ( dev , buffer , TX_END ) ;
ether3_setbuffer ( dev , buffer_read , RX_START ) ;
ether3_readbuffer ( dev , buffer + RX_START , RX_LEN ) ;
for ( i = 0 ; i < RX_END ; i + + ) {
if ( buffer [ i ] ! = byte ) {
if ( max_errors > 0 & & bad ! = buffer [ i ] ) {
printk ( " %s: RAM failed with (%02X instead of %02X) at 0x%04X " ,
dev - > name , buffer [ i ] , byte , i ) ;
ret = 2 ;
max_errors - - ;
bad = i ;
}
} else {
if ( bad ! = - 1 ) {
if ( bad ! = i - 1 )
printk ( " - 0x%04X \n " , i - 1 ) ;
printk ( " \n " ) ;
bad = - 1 ;
}
}
}
if ( bad ! = - 1 )
printk ( " - 0xffff \n " ) ;
kfree ( buffer ) ;
return ret ;
}
/* ------------------------------------------------------------------------------- */
static int __init ether3_init_2 ( struct net_device * dev )
{
int i ;
priv ( dev ) - > regs . config1 = CFG1_RECVCOMPSTAT0 | CFG1_DMABURST8 ;
priv ( dev ) - > regs . config2 = CFG2_CTRLO | CFG2_RECVCRC | CFG2_ERRENCRC ;
priv ( dev ) - > regs . command = 0 ;
/*
* Set up our hardware address
*/
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_BUFSELSTAT0 , REG_CONFIG1 ) ;
for ( i = 0 ; i < 6 ; i + + )
ether3_outb ( dev - > dev_addr [ i ] , REG_BUFWIN ) ;
if ( dev - > flags & IFF_PROMISC )
priv ( dev ) - > regs . config1 | = CFG1_RECVPROMISC ;
else if ( dev - > flags & IFF_MULTICAST )
priv ( dev ) - > regs . config1 | = CFG1_RECVSPECBRMULTI ;
else
priv ( dev ) - > regs . config1 | = CFG1_RECVSPECBROAD ;
/*
* There is a problem with the NQ8005 in that it occasionally loses the
* last two bytes . To get round this problem , we receive the CRC as
* well . That way , if we do lose the last two , then it doesn ' t matter .
*/
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_TRANSEND , REG_CONFIG1 ) ;
ether3_outw ( ( TX_END > > 8 ) - 1 , REG_BUFWIN ) ;
ether3_outw ( priv ( dev ) - > rx_head , REG_RECVPTR ) ;
ether3_outw ( 0 , REG_TRANSMITPTR ) ;
ether3_outw ( priv ( dev ) - > rx_head > > 8 , REG_RECVEND ) ;
ether3_outw ( priv ( dev ) - > regs . config2 , REG_CONFIG2 ) ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_LOCBUFMEM , REG_CONFIG1 ) ;
ether3_outw ( priv ( dev ) - > regs . command , REG_COMMAND ) ;
i = ether3_ramtest ( dev , 0x5A ) ;
if ( i )
return i ;
i = ether3_ramtest ( dev , 0x1E ) ;
if ( i )
return i ;
ether3_setbuffer ( dev , buffer_write , 0 ) ;
ether3_writelong ( dev , 0 ) ;
return 0 ;
}
static void
ether3_init_for_open ( struct net_device * dev )
{
int i ;
memset ( & priv ( dev ) - > stats , 0 , sizeof ( struct net_device_stats ) ) ;
/* Reset the chip */
ether3_outw ( CFG2_RESET , REG_CONFIG2 ) ;
udelay ( 4 ) ;
priv ( dev ) - > regs . command = 0 ;
ether3_outw ( CMD_RXOFF | CMD_TXOFF , REG_COMMAND ) ;
while ( ether3_inw ( REG_STATUS ) & ( STAT_RXON | STAT_TXON ) )
barrier ( ) ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_BUFSELSTAT0 , REG_CONFIG1 ) ;
for ( i = 0 ; i < 6 ; i + + )
ether3_outb ( dev - > dev_addr [ i ] , REG_BUFWIN ) ;
priv ( dev ) - > tx_head = 0 ;
priv ( dev ) - > tx_tail = 0 ;
priv ( dev ) - > regs . config2 | = CFG2_CTRLO ;
priv ( dev ) - > rx_head = RX_START ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_TRANSEND , REG_CONFIG1 ) ;
ether3_outw ( ( TX_END > > 8 ) - 1 , REG_BUFWIN ) ;
ether3_outw ( priv ( dev ) - > rx_head , REG_RECVPTR ) ;
ether3_outw ( priv ( dev ) - > rx_head > > 8 , REG_RECVEND ) ;
ether3_outw ( 0 , REG_TRANSMITPTR ) ;
ether3_outw ( priv ( dev ) - > regs . config2 , REG_CONFIG2 ) ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_LOCBUFMEM , REG_CONFIG1 ) ;
ether3_setbuffer ( dev , buffer_write , 0 ) ;
ether3_writelong ( dev , 0 ) ;
priv ( dev ) - > regs . command = CMD_ENINTRX | CMD_ENINTTX ;
ether3_outw ( priv ( dev ) - > regs . command | CMD_RXON , REG_COMMAND ) ;
}
static inline int
ether3_probe_bus_8 ( struct net_device * dev , int val )
{
int write_low , write_high , read_low , read_high ;
write_low = val & 255 ;
write_high = val > > 8 ;
printk ( KERN_DEBUG " ether3_probe: write8 [%02X:%02X] " , write_high , write_low ) ;
ether3_outb ( write_low , REG_RECVPTR ) ;
ether3_outb ( write_high , REG_RECVPTR + 4 ) ;
read_low = ether3_inb ( REG_RECVPTR ) ;
read_high = ether3_inb ( REG_RECVPTR + 4 ) ;
printk ( " , read8 [%02X:%02X] \n " , read_high , read_low ) ;
return read_low = = write_low & & read_high = = write_high ;
}
static inline int
ether3_probe_bus_16 ( struct net_device * dev , int val )
{
int read_val ;
ether3_outw ( val , REG_RECVPTR ) ;
read_val = ether3_inw ( REG_RECVPTR ) ;
printk ( KERN_DEBUG " ether3_probe: write16 [%04X], read16 [%04X] \n " , val , read_val ) ;
return read_val = = val ;
}
/*
* Open / initialize the board . This is called ( in the current kernel )
* sometime after booting when the ' ifconfig ' program is run .
*
* This routine should set everything up anew at each open , even
* registers that " should " only need to be set once at boot , so that
* there is non - reboot way to recover if something goes wrong .
*/
static int
ether3_open ( struct net_device * dev )
{
if ( ! is_valid_ether_addr ( dev - > dev_addr ) ) {
printk ( KERN_WARNING " %s: invalid ethernet MAC address \n " ,
dev - > name ) ;
return - EINVAL ;
}
if ( request_irq ( dev - > irq , ether3_interrupt , 0 , " ether3 " , dev ) )
return - EAGAIN ;
ether3_init_for_open ( dev ) ;
netif_start_queue ( dev ) ;
return 0 ;
}
/*
* The inverse routine to ether3_open ( ) .
*/
static int
ether3_close ( struct net_device * dev )
{
netif_stop_queue ( dev ) ;
disable_irq ( dev - > irq ) ;
ether3_outw ( CMD_RXOFF | CMD_TXOFF , REG_COMMAND ) ;
priv ( dev ) - > regs . command = 0 ;
while ( ether3_inw ( REG_STATUS ) & ( STAT_RXON | STAT_TXON ) )
barrier ( ) ;
ether3_outb ( 0x80 , REG_CONFIG2 + 4 ) ;
ether3_outw ( 0 , REG_COMMAND ) ;
free_irq ( dev - > irq , dev ) ;
return 0 ;
}
/*
* Get the current statistics . This may be called with the card open or
* closed .
*/
static struct net_device_stats * ether3_getstats ( struct net_device * dev )
{
return & priv ( dev ) - > stats ;
}
/*
* Set or clear promiscuous / multicast mode filter for this adaptor .
*
* We don ' t attempt any packet filtering . The card may have a SEEQ 8004
* in which does not have the other ethernet address registers present . . .
*/
static void ether3_setmulticastlist ( struct net_device * dev )
{
priv ( dev ) - > regs . config1 & = ~ CFG1_RECVPROMISC ;
if ( dev - > flags & IFF_PROMISC ) {
/* promiscuous mode */
priv ( dev ) - > regs . config1 | = CFG1_RECVPROMISC ;
} else if ( dev - > flags & IFF_ALLMULTI ) {
priv ( dev ) - > regs . config1 | = CFG1_RECVSPECBRMULTI ;
} else
priv ( dev ) - > regs . config1 | = CFG1_RECVSPECBROAD ;
ether3_outw ( priv ( dev ) - > regs . config1 | CFG1_LOCBUFMEM , REG_CONFIG1 ) ;
}
static void ether3_timeout ( struct net_device * dev )
{
unsigned long flags ;
del_timer ( & priv ( dev ) - > timer ) ;
local_irq_save ( flags ) ;
printk ( KERN_ERR " %s: transmit timed out, network cable problem? \n " , dev - > name ) ;
printk ( KERN_ERR " %s: state: { status=%04X cfg1=%04X cfg2=%04X } \n " , dev - > name ,
ether3_inw ( REG_STATUS ) , ether3_inw ( REG_CONFIG1 ) , ether3_inw ( REG_CONFIG2 ) ) ;
printk ( KERN_ERR " %s: { rpr=%04X rea=%04X tpr=%04X } \n " , dev - > name ,
ether3_inw ( REG_RECVPTR ) , ether3_inw ( REG_RECVEND ) , ether3_inw ( REG_TRANSMITPTR ) ) ;
printk ( KERN_ERR " %s: tx head=%X tx tail=%X \n " , dev - > name ,
priv ( dev ) - > tx_head , priv ( dev ) - > tx_tail ) ;
ether3_setbuffer ( dev , buffer_read , priv ( dev ) - > tx_tail ) ;
printk ( KERN_ERR " %s: packet status = %08X \n " , dev - > name , ether3_readlong ( dev ) ) ;
local_irq_restore ( flags ) ;
priv ( dev ) - > regs . config2 | = CFG2_CTRLO ;
priv ( dev ) - > stats . tx_errors + = 1 ;
ether3_outw ( priv ( dev ) - > regs . config2 , REG_CONFIG2 ) ;
priv ( dev ) - > tx_head = priv ( dev ) - > tx_tail = 0 ;
netif_wake_queue ( dev ) ;
}
/*
* Transmit a packet
*/
static int
ether3_sendpacket ( struct sk_buff * skb , struct net_device * dev )
{
unsigned long flags ;
unsigned int length = ETH_ZLEN < skb - > len ? skb - > len : ETH_ZLEN ;
unsigned int ptr , next_ptr ;
if ( priv ( dev ) - > broken ) {
dev_kfree_skb ( skb ) ;
priv ( dev ) - > stats . tx_dropped + + ;
netif_start_queue ( dev ) ;
return 0 ;
}
length = ( length + 1 ) & ~ 1 ;
if ( length ! = skb - > len ) {
2006-06-23 13:06:41 +04:00
if ( skb_padto ( skb , length ) )
2005-04-17 02:20:36 +04:00
goto out ;
}
next_ptr = ( priv ( dev ) - > tx_head + 1 ) & 15 ;
local_irq_save ( flags ) ;
if ( priv ( dev ) - > tx_tail = = next_ptr ) {
local_irq_restore ( flags ) ;
return 1 ; /* unable to queue */
}
dev - > trans_start = jiffies ;
ptr = 0x600 * priv ( dev ) - > tx_head ;
priv ( dev ) - > tx_head = next_ptr ;
next_ptr * = 0x600 ;
# define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
ether3_setbuffer ( dev , buffer_write , next_ptr ) ;
ether3_writelong ( dev , 0 ) ;
ether3_setbuffer ( dev , buffer_write , ptr ) ;
ether3_writelong ( dev , 0 ) ;
ether3_writebuffer ( dev , skb - > data , length ) ;
ether3_writeword ( dev , htons ( next_ptr ) ) ;
ether3_writeword ( dev , TXHDR_CHAINCONTINUE > > 16 ) ;
ether3_setbuffer ( dev , buffer_write , ptr ) ;
ether3_writeword ( dev , htons ( ( ptr + length + 4 ) ) ) ;
ether3_writeword ( dev , TXHDR_FLAGS > > 16 ) ;
ether3_ledon ( dev ) ;
if ( ! ( ether3_inw ( REG_STATUS ) & STAT_TXON ) ) {
ether3_outw ( ptr , REG_TRANSMITPTR ) ;
ether3_outw ( priv ( dev ) - > regs . command | CMD_TXON , REG_COMMAND ) ;
}
next_ptr = ( priv ( dev ) - > tx_head + 1 ) & 15 ;
local_irq_restore ( flags ) ;
dev_kfree_skb ( skb ) ;
if ( priv ( dev ) - > tx_tail = = next_ptr )
netif_stop_queue ( dev ) ;
out :
return 0 ;
}
static irqreturn_t
ether3_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
unsigned int status , handled = IRQ_NONE ;
# if NET_DEBUG > 1
if ( net_debug & DEBUG_INT )
printk ( " eth3irq: %d " , irq ) ;
# endif
status = ether3_inw ( REG_STATUS ) ;
if ( status & STAT_INTRX ) {
ether3_outw ( CMD_ACKINTRX | priv ( dev ) - > regs . command , REG_COMMAND ) ;
ether3_rx ( dev , 12 ) ;
handled = IRQ_HANDLED ;
}
if ( status & STAT_INTTX ) {
ether3_outw ( CMD_ACKINTTX | priv ( dev ) - > regs . command , REG_COMMAND ) ;
ether3_tx ( dev ) ;
handled = IRQ_HANDLED ;
}
# if NET_DEBUG > 1
if ( net_debug & DEBUG_INT )
printk ( " done \n " ) ;
# endif
return handled ;
}
/*
* If we have a good packet ( s ) , get it / them out of the buffers .
*/
static int ether3_rx ( struct net_device * dev , unsigned int maxcnt )
{
unsigned int next_ptr = priv ( dev ) - > rx_head , received = 0 ;
ether3_ledon ( dev ) ;
do {
unsigned int this_ptr , status ;
unsigned char addrs [ 16 ] ;
/*
* read the first 16 bytes from the buffer .
* This contains the status bytes etc and ethernet addresses ,
* and we also check the source ethernet address to see if
* it originated from us .
*/
{
unsigned int temp_ptr ;
ether3_setbuffer ( dev , buffer_read , next_ptr ) ;
temp_ptr = ether3_readword ( dev ) ;
status = ether3_readword ( dev ) ;
if ( ( status & ( RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE ) ) ! =
( RXSTAT_DONE | RXHDR_CHAINCONTINUE ) | | ! temp_ptr )
break ;
this_ptr = next_ptr + 4 ;
next_ptr = ntohs ( temp_ptr ) ;
}
ether3_setbuffer ( dev , buffer_read , this_ptr ) ;
ether3_readbuffer ( dev , addrs + 2 , 12 ) ;
if ( next_ptr < RX_START | | next_ptr > = RX_END ) {
int i ;
printk ( " %s: bad next pointer @%04X: " , dev - > name , priv ( dev ) - > rx_head ) ;
printk ( " %02X %02X %02X %02X " , next_ptr > > 8 , next_ptr & 255 , status & 255 , status > > 8 ) ;
for ( i = 2 ; i < 14 ; i + + )
printk ( " %02X " , addrs [ i ] ) ;
printk ( " \n " ) ;
next_ptr = priv ( dev ) - > rx_head ;
break ;
}
/*
* ignore our own packets . . .
*/
if ( ! ( * ( unsigned long * ) & dev - > dev_addr [ 0 ] ^ * ( unsigned long * ) & addrs [ 2 + 6 ] ) & &
! ( * ( unsigned short * ) & dev - > dev_addr [ 4 ] ^ * ( unsigned short * ) & addrs [ 2 + 10 ] ) ) {
maxcnt + + ; /* compensate for loopedback packet */
ether3_outw ( next_ptr > > 8 , REG_RECVEND ) ;
} else
if ( ! ( status & ( RXSTAT_OVERSIZE | RXSTAT_CRCERROR | RXSTAT_DRIBBLEERROR | RXSTAT_SHORTPACKET ) ) ) {
unsigned int length = next_ptr - this_ptr ;
struct sk_buff * skb ;
if ( next_ptr < = this_ptr )
length + = RX_END - RX_START ;
skb = dev_alloc_skb ( length + 2 ) ;
if ( skb ) {
unsigned char * buf ;
skb - > dev = dev ;
skb_reserve ( skb , 2 ) ;
buf = skb_put ( skb , length ) ;
ether3_readbuffer ( dev , buf + 12 , length - 12 ) ;
ether3_outw ( next_ptr > > 8 , REG_RECVEND ) ;
* ( unsigned short * ) ( buf + 0 ) = * ( unsigned short * ) ( addrs + 2 ) ;
* ( unsigned long * ) ( buf + 2 ) = * ( unsigned long * ) ( addrs + 4 ) ;
* ( unsigned long * ) ( buf + 6 ) = * ( unsigned long * ) ( addrs + 8 ) ;
* ( unsigned short * ) ( buf + 10 ) = * ( unsigned short * ) ( addrs + 12 ) ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
netif_rx ( skb ) ;
received + + ;
} else
goto dropping ;
} else {
struct net_device_stats * stats = & priv ( dev ) - > stats ;
ether3_outw ( next_ptr > > 8 , REG_RECVEND ) ;
if ( status & RXSTAT_OVERSIZE ) stats - > rx_over_errors + + ;
if ( status & RXSTAT_CRCERROR ) stats - > rx_crc_errors + + ;
if ( status & RXSTAT_DRIBBLEERROR ) stats - > rx_fifo_errors + + ;
if ( status & RXSTAT_SHORTPACKET ) stats - > rx_length_errors + + ;
stats - > rx_errors + + ;
}
}
while ( - - maxcnt ) ;
done :
priv ( dev ) - > stats . rx_packets + = received ;
priv ( dev ) - > rx_head = next_ptr ;
/*
* If rx went off line , then that means that the buffer may be full . We
* have dropped at least one packet .
*/
if ( ! ( ether3_inw ( REG_STATUS ) & STAT_RXON ) ) {
priv ( dev ) - > stats . rx_dropped + + ;
ether3_outw ( next_ptr , REG_RECVPTR ) ;
ether3_outw ( priv ( dev ) - > regs . command | CMD_RXON , REG_COMMAND ) ;
}
return maxcnt ;
dropping : {
static unsigned long last_warned ;
ether3_outw ( next_ptr > > 8 , REG_RECVEND ) ;
/*
* Don ' t print this message too many times . . .
*/
if ( time_after ( jiffies , last_warned + 10 * HZ ) ) {
last_warned = jiffies ;
printk ( " %s: memory squeeze, dropping packet. \n " , dev - > name ) ;
}
priv ( dev ) - > stats . rx_dropped + + ;
goto done ;
}
}
/*
* Update stats for the transmitted packet ( s )
*/
static void ether3_tx ( struct net_device * dev )
{
unsigned int tx_tail = priv ( dev ) - > tx_tail ;
int max_work = 14 ;
do {
unsigned long status ;
/*
* Read the packet header
*/
ether3_setbuffer ( dev , buffer_read , tx_tail * 0x600 ) ;
status = ether3_readlong ( dev ) ;
/*
* Check to see if this packet has been transmitted
*/
if ( ( status & ( TXSTAT_DONE | TXHDR_TRANSMIT ) ) ! =
( TXSTAT_DONE | TXHDR_TRANSMIT ) )
break ;
/*
* Update errors
*/
if ( ! ( status & ( TXSTAT_BABBLED | TXSTAT_16COLLISIONS ) ) )
priv ( dev ) - > stats . tx_packets + + ;
else {
priv ( dev ) - > stats . tx_errors + + ;
if ( status & TXSTAT_16COLLISIONS )
priv ( dev ) - > stats . collisions + = 16 ;
if ( status & TXSTAT_BABBLED )
priv ( dev ) - > stats . tx_fifo_errors + + ;
}
tx_tail = ( tx_tail + 1 ) & 15 ;
} while ( - - max_work ) ;
if ( priv ( dev ) - > tx_tail ! = tx_tail ) {
priv ( dev ) - > tx_tail = tx_tail ;
netif_wake_queue ( dev ) ;
}
}
static void __init ether3_banner ( void )
{
static unsigned version_printed = 0 ;
if ( net_debug & & version_printed + + = = 0 )
printk ( KERN_INFO " %s " , version ) ;
}
static int __devinit
ether3_probe ( struct expansion_card * ec , const struct ecard_id * id )
{
const struct ether3_data * data = id - > data ;
struct net_device * dev ;
int i , bus_type , ret ;
ether3_banner ( ) ;
ret = ecard_request_resources ( ec ) ;
if ( ret )
goto out ;
dev = alloc_etherdev ( sizeof ( struct dev_priv ) ) ;
if ( ! dev ) {
ret = - ENOMEM ;
goto release ;
}
SET_MODULE_OWNER ( dev ) ;
SET_NETDEV_DEV ( dev , & ec - > dev ) ;
priv ( dev ) - > base = ioremap ( ecard_resource_start ( ec , ECARD_RES_MEMC ) ,
ecard_resource_len ( ec , ECARD_RES_MEMC ) ) ;
if ( ! priv ( dev ) - > base ) {
ret = - ENOMEM ;
goto free ;
}
ec - > irqaddr = priv ( dev ) - > base + data - > base_offset ;
ec - > irqmask = 0xf0 ;
priv ( dev ) - > seeq = priv ( dev ) - > base + data - > base_offset ;
dev - > irq = ec - > irq ;
ether3_addr ( dev - > dev_addr , ec ) ;
init_timer ( & priv ( dev ) - > timer ) ;
/* Reset card...
*/
ether3_outb ( 0x80 , REG_CONFIG2 + 4 ) ;
bus_type = BUS_UNKNOWN ;
udelay ( 4 ) ;
/* Test using Receive Pointer (16-bit register) to find out
* how the ether3 is connected to the bus . . .
*/
if ( ether3_probe_bus_8 ( dev , 0x100 ) & &
ether3_probe_bus_8 ( dev , 0x201 ) )
bus_type = BUS_8 ;
if ( bus_type = = BUS_UNKNOWN & &
ether3_probe_bus_16 ( dev , 0x101 ) & &
ether3_probe_bus_16 ( dev , 0x201 ) )
bus_type = BUS_16 ;
switch ( bus_type ) {
case BUS_UNKNOWN :
printk ( KERN_ERR " %s: unable to identify bus width \n " , dev - > name ) ;
ret = - ENODEV ;
goto free ;
case BUS_8 :
printk ( KERN_ERR " %s: %s found, but is an unsupported "
" 8-bit card \n " , dev - > name , data - > name ) ;
ret = - ENODEV ;
goto free ;
default :
break ;
}
if ( ether3_init_2 ( dev ) ) {
ret = - ENODEV ;
goto free ;
}
dev - > open = ether3_open ;
dev - > stop = ether3_close ;
dev - > hard_start_xmit = ether3_sendpacket ;
dev - > get_stats = ether3_getstats ;
dev - > set_multicast_list = ether3_setmulticastlist ;
dev - > tx_timeout = ether3_timeout ;
dev - > watchdog_timeo = 5 * HZ / 100 ;
ret = register_netdev ( dev ) ;
if ( ret )
goto free ;
printk ( " %s: %s in slot %d, " , dev - > name , data - > name , ec - > slot_no ) ;
for ( i = 0 ; i < 6 ; i + + )
printk ( " %2.2x%c " , dev - > dev_addr [ i ] , i = = 5 ? ' \n ' : ' : ' ) ;
ecard_set_drvdata ( ec , dev ) ;
return 0 ;
free :
if ( priv ( dev ) - > base )
iounmap ( priv ( dev ) - > base ) ;
free_netdev ( dev ) ;
release :
ecard_release_resources ( ec ) ;
out :
return ret ;
}
static void __devexit ether3_remove ( struct expansion_card * ec )
{
struct net_device * dev = ecard_get_drvdata ( ec ) ;
ecard_set_drvdata ( ec , NULL ) ;
unregister_netdev ( dev ) ;
iounmap ( priv ( dev ) - > base ) ;
free_netdev ( dev ) ;
ecard_release_resources ( ec ) ;
}
static struct ether3_data ether3 = {
. name = " ether3 " ,
. base_offset = 0 ,
} ;
static struct ether3_data etherb = {
. name = " etherb " ,
. base_offset = 0x800 ,
} ;
static const struct ecard_id ether3_ids [ ] = {
{ MANU_ANT2 , PROD_ANT_ETHER3 , & ether3 } ,
{ MANU_ANT , PROD_ANT_ETHER3 , & ether3 } ,
{ MANU_ANT , PROD_ANT_ETHERB , & etherb } ,
{ 0xffff , 0xffff }
} ;
static struct ecard_driver ether3_driver = {
. probe = ether3_probe ,
. remove = __devexit_p ( ether3_remove ) ,
. id_table = ether3_ids ,
. drv = {
. name = " ether3 " ,
} ,
} ;
static int __init ether3_init ( void )
{
return ecard_register_driver ( & ether3_driver ) ;
}
static void __exit ether3_exit ( void )
{
ecard_remove_driver ( & ether3_driver ) ;
}
module_init ( ether3_init ) ;
module_exit ( ether3_exit ) ;
MODULE_LICENSE ( " GPL " ) ;