2006-09-13 21:24:59 +04:00
/*
* 7990. c - - LANCE ethernet IC generic routines .
2005-04-17 02:20:36 +04:00
* This is an attempt to separate out the bits of various ethernet
2006-09-13 21:24:59 +04:00
* drivers that are common because they all use the AMD 7990 LANCE
2005-04-17 02:20:36 +04:00
* ( Local Area Network Controller for Ethernet ) chip .
*
* Copyright ( C ) 05 / 1998 Peter Maydell < pmaydell @ chiark . greenend . org . uk >
*
* Most of this stuff was obtained by looking at other LANCE drivers ,
* in particular a2065 . [ ch ] . The AMD C - LANCE datasheet was also helpful .
* NB : this was made easy by the fact that Jes Sorensen had cleaned up
2006-09-13 21:24:59 +04:00
* most of a2025 and sunlance with the aim of merging them , so the
2005-04-17 02:20:36 +04:00
* common code was pretty obvious .
*/
# include <linux/crc32.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/in.h>
# include <linux/route.h>
# include <linux/string.h>
# include <linux/skbuff.h>
2005-12-01 14:44:55 +03:00
# include <asm/irq.h>
2005-04-17 02:20:36 +04:00
/* Used for the temporal inet entries and routing */
# include <linux/socket.h>
# include <linux/bitops.h>
# include <asm/io.h>
# include <asm/dma.h>
# include <asm/pgtable.h>
# ifdef CONFIG_HP300
# include <asm/blinken.h>
# endif
# include "7990.h"
2013-12-29 00:11:14 +04:00
# define WRITERAP(lp, x) out_be16(lp->base + LANCE_RAP, (x))
# define WRITERDP(lp, x) out_be16(lp->base + LANCE_RDP, (x))
# define READRDP(lp) in_be16(lp->base + LANCE_RDP)
2005-04-17 02:20:36 +04:00
2016-09-12 17:03:34 +03:00
# if IS_ENABLED(CONFIG_HPLANCE)
2005-04-17 02:20:36 +04:00
# include "hplance.h"
# undef WRITERAP
# undef WRITERDP
# undef READRDP
2016-09-12 17:03:34 +03:00
# if IS_ENABLED(CONFIG_MVME147_NET)
2005-04-17 02:20:36 +04:00
/* Lossage Factor Nine, Mr Sulu. */
2013-12-29 00:11:14 +04:00
# define WRITERAP(lp, x) (lp->writerap(lp, x))
# define WRITERDP(lp, x) (lp->writerdp(lp, x))
# define READRDP(lp) (lp->readrdp(lp))
2005-04-17 02:20:36 +04:00
# else
/* These inlines can be used if only CONFIG_HPLANCE is defined */
static inline void WRITERAP ( struct lance_private * lp , __u16 value )
{
do {
out_be16 ( lp - > base + HPLANCE_REGOFF + LANCE_RAP , value ) ;
} while ( ( in_8 ( lp - > base + HPLANCE_STATUS ) & LE_ACK ) = = 0 ) ;
}
static inline void WRITERDP ( struct lance_private * lp , __u16 value )
{
do {
out_be16 ( lp - > base + HPLANCE_REGOFF + LANCE_RDP , value ) ;
} while ( ( in_8 ( lp - > base + HPLANCE_STATUS ) & LE_ACK ) = = 0 ) ;
}
static inline __u16 READRDP ( struct lance_private * lp )
{
__u16 value ;
do {
value = in_be16 ( lp - > base + HPLANCE_REGOFF + LANCE_RDP ) ;
} while ( ( in_8 ( lp - > base + HPLANCE_STATUS ) & LE_ACK ) = = 0 ) ;
return value ;
}
# endif
2016-09-12 17:03:34 +03:00
# endif /* IS_ENABLED(CONFIG_HPLANCE) */
2005-04-17 02:20:36 +04:00
/* debugging output macros, various flavours */
/* #define TEST_HITS */
# ifdef UNDEF
# define PRINT_RINGS() \
do { \
2013-12-29 00:11:14 +04:00
int t ; \
for ( t = 0 ; t < RX_RING_SIZE ; t + + ) { \
printk ( " R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X \n " , \
t , ib - > brx_ring [ t ] . rmd1_hadr , ib - > brx_ring [ t ] . rmd0 , \
ib - > brx_ring [ t ] . length , \
ib - > brx_ring [ t ] . mblength , ib - > brx_ring [ t ] . rmd1_bits ) ; \
} \
for ( t = 0 ; t < TX_RING_SIZE ; t + + ) { \
printk ( " T%d: @(%02X %04X) len %04X, misc %04X, bits %02X \n " , \
t , ib - > btx_ring [ t ] . tmd1_hadr , ib - > btx_ring [ t ] . tmd0 , \
ib - > btx_ring [ t ] . length , \
ib - > btx_ring [ t ] . misc , ib - > btx_ring [ t ] . tmd1_bits ) ; \
} \
2006-09-13 21:24:59 +04:00
} while ( 0 )
2005-04-17 02:20:36 +04:00
# else
# define PRINT_RINGS()
2006-09-13 21:24:59 +04:00
# endif
2005-04-17 02:20:36 +04:00
/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
2013-12-29 00:11:14 +04:00
static void load_csrs ( struct lance_private * lp )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
volatile struct lance_init_block * aib = lp - > lance_init_block ;
int leptr ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
leptr = LANCE_ADDR ( aib ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
WRITERAP ( lp , LE_CSR1 ) ; /* load address of init block */
WRITERDP ( lp , leptr & 0xFFFF ) ;
WRITERAP ( lp , LE_CSR2 ) ;
WRITERDP ( lp , leptr > > 16 ) ;
WRITERAP ( lp , LE_CSR3 ) ;
WRITERDP ( lp , lp - > busmaster_regval ) ; /* set byteswap/ALEctrl/byte ctrl */
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
/* Point back to csr0 */
WRITERAP ( lp , LE_CSR0 ) ;
2005-04-17 02:20:36 +04:00
}
/* #define to 0 or 1 appropriately */
# define DEBUG_IRING 0
/* Set up the Lance Rx and Tx rings and the init block */
2013-12-29 00:11:14 +04:00
static void lance_init_ring ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
volatile struct lance_init_block * aib ; /* for LANCE_ADDR computations */
int leptr ;
int i ;
aib = lp - > lance_init_block ;
lp - > rx_new = lp - > tx_new = 0 ;
lp - > rx_old = lp - > tx_old = 0 ;
ib - > mode = LE_MO_PROM ; /* normal, enable Tx & Rx */
/* Copy the ethernet address to the lance init block
* Notice that we do a byteswap if we ' re big endian .
* [ I think this is the right criterion ; at least , sunlance ,
* a2065 and atarilance do the byteswap and lance . c ( PC ) doesn ' t .
* However , the datasheet says that the BSWAP bit doesn ' t affect
* the init block , so surely it should be low byte first for
* everybody ? Um . ]
* We could define the ib - > physaddr as three 16 bit values and
* use ( addr [ 1 ] < < 8 ) | addr [ 0 ] & co , but this is more efficient .
*/
2005-04-17 02:20:36 +04:00
# ifdef __BIG_ENDIAN
2013-12-29 00:11:14 +04:00
ib - > phys_addr [ 0 ] = dev - > dev_addr [ 1 ] ;
ib - > phys_addr [ 1 ] = dev - > dev_addr [ 0 ] ;
ib - > phys_addr [ 2 ] = dev - > dev_addr [ 3 ] ;
ib - > phys_addr [ 3 ] = dev - > dev_addr [ 2 ] ;
ib - > phys_addr [ 4 ] = dev - > dev_addr [ 5 ] ;
ib - > phys_addr [ 5 ] = dev - > dev_addr [ 4 ] ;
2005-04-17 02:20:36 +04:00
# else
2013-12-29 00:11:14 +04:00
for ( i = 0 ; i < 6 ; i + + )
ib - > phys_addr [ i ] = dev - > dev_addr [ i ] ;
2006-09-13 21:24:59 +04:00
# endif
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
if ( DEBUG_IRING )
printk ( " TX rings: \n " ) ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
lp - > tx_full = 0 ;
2013-12-29 00:11:14 +04:00
/* Setup the Tx ring entries */
for ( i = 0 ; i < ( 1 < < lp - > lance_log_tx_bufs ) ; i + + ) {
leptr = LANCE_ADDR ( & aib - > tx_buf [ i ] [ 0 ] ) ;
ib - > btx_ring [ i ] . tmd0 = leptr ;
ib - > btx_ring [ i ] . tmd1_hadr = leptr > > 16 ;
ib - > btx_ring [ i ] . tmd1_bits = 0 ;
ib - > btx_ring [ i ] . length = 0xf000 ; /* The ones required by tmd2 */
ib - > btx_ring [ i ] . misc = 0 ;
if ( DEBUG_IRING )
printk ( " %d: 0x%8.8x \n " , i , leptr ) ;
}
/* Setup the Rx ring entries */
if ( DEBUG_IRING )
printk ( " RX rings: \n " ) ;
for ( i = 0 ; i < ( 1 < < lp - > lance_log_rx_bufs ) ; i + + ) {
leptr = LANCE_ADDR ( & aib - > rx_buf [ i ] [ 0 ] ) ;
ib - > brx_ring [ i ] . rmd0 = leptr ;
ib - > brx_ring [ i ] . rmd1_hadr = leptr > > 16 ;
ib - > brx_ring [ i ] . rmd1_bits = LE_R1_OWN ;
/* 0xf000 == bits that must be one (reserved, presumably) */
ib - > brx_ring [ i ] . length = - RX_BUFF_SIZE | 0xf000 ;
ib - > brx_ring [ i ] . mblength = 0 ;
if ( DEBUG_IRING )
printk ( " %d: 0x%8.8x \n " , i , leptr ) ;
}
/* Setup the initialization block */
/* Setup rx descriptor pointer */
leptr = LANCE_ADDR ( & aib - > brx_ring ) ;
ib - > rx_len = ( lp - > lance_log_rx_bufs < < 13 ) | ( leptr > > 16 ) ;
ib - > rx_ptr = leptr ;
if ( DEBUG_IRING )
printk ( " RX ptr: %8.8x \n " , leptr ) ;
/* Setup tx descriptor pointer */
leptr = LANCE_ADDR ( & aib - > btx_ring ) ;
ib - > tx_len = ( lp - > lance_log_tx_bufs < < 13 ) | ( leptr > > 16 ) ;
ib - > tx_ptr = leptr ;
if ( DEBUG_IRING )
printk ( " TX ptr: %8.8x \n " , leptr ) ;
/* Clear the multicast filter */
ib - > filter [ 0 ] = 0 ;
ib - > filter [ 1 ] = 0 ;
PRINT_RINGS ( ) ;
2005-04-17 02:20:36 +04:00
}
/* LANCE must be STOPped before we do this, too... */
2013-12-29 00:11:14 +04:00
static int init_restart_lance ( struct lance_private * lp )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_INIT ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
/* Need a hook here for sunlance ledma stuff */
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
/* Wait for the lance to complete initialization */
for ( i = 0 ; ( i < 100 ) & & ! ( READRDP ( lp ) & ( LE_C0_ERR | LE_C0_IDON ) ) ; i + + )
barrier ( ) ;
if ( ( i = = 100 ) | | ( READRDP ( lp ) & LE_C0_ERR ) ) {
printk ( " LANCE unopened after %d ticks, csr0=%4.4x. \n " , i , READRDP ( lp ) ) ;
return - 1 ;
}
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
/* Clear IDON by writing a "1", enable interrupts and start lance */
WRITERDP ( lp , LE_C0_IDON ) ;
WRITERDP ( lp , LE_C0_INEA | LE_C0_STRT ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2013-12-29 00:11:14 +04:00
static int lance_reset ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
int status ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
/* Stop the lance */
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STOP ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
load_csrs ( lp ) ;
lance_init_ring ( dev ) ;
2016-05-03 17:33:13 +03:00
netif_trans_update ( dev ) ; /* prevent tx timeout */
2013-12-29 00:11:14 +04:00
status = init_restart_lance ( lp ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG_DRIVER
2013-12-29 00:11:14 +04:00
printk ( " Lance restart=%d \n " , status ) ;
2005-04-17 02:20:36 +04:00
# endif
2013-12-29 00:11:14 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2013-12-29 00:11:14 +04:00
static int lance_rx ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
volatile struct lance_rx_desc * rd ;
unsigned char bits ;
2005-04-17 02:20:36 +04:00
# ifdef TEST_HITS
2013-12-29 00:11:14 +04:00
int i ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef TEST_HITS
2013-12-29 00:11:14 +04:00
printk ( " [ " ) ;
for ( i = 0 ; i < RX_RING_SIZE ; i + + ) {
if ( i = = lp - > rx_new )
printk ( " %s " ,
ib - > brx_ring [ i ] . rmd1_bits & LE_R1_OWN ? " _ " : " X " ) ;
else
printk ( " %s " ,
ib - > brx_ring [ i ] . rmd1_bits & LE_R1_OWN ? " . " : " 1 " ) ;
}
printk ( " ] " ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_HP300
blinken_leds ( 0x40 , 0 ) ;
2006-09-13 21:24:59 +04:00
# endif
2013-12-29 00:11:14 +04:00
WRITERDP ( lp , LE_C0_RINT | LE_C0_INEA ) ; /* ack Rx int, reenable ints */
for ( rd = & ib - > brx_ring [ lp - > rx_new ] ; /* For each Rx ring we own... */
! ( ( bits = rd - > rmd1_bits ) & LE_R1_OWN ) ;
rd = & ib - > brx_ring [ lp - > rx_new ] ) {
/* We got an incomplete frame? */
if ( ( bits & LE_R1_POK ) ! = LE_R1_POK ) {
dev - > stats . rx_over_errors + + ;
dev - > stats . rx_errors + + ;
continue ;
} else if ( bits & LE_R1_ERR ) {
/* Count only the end frame as a rx error,
* not the beginning
*/
if ( bits & LE_R1_BUF )
dev - > stats . rx_fifo_errors + + ;
if ( bits & LE_R1_CRC )
dev - > stats . rx_crc_errors + + ;
if ( bits & LE_R1_OFL )
dev - > stats . rx_over_errors + + ;
if ( bits & LE_R1_FRA )
dev - > stats . rx_frame_errors + + ;
if ( bits & LE_R1_EOP )
dev - > stats . rx_errors + + ;
} else {
2008-01-24 13:06:46 +03:00
int len = ( rd - > mblength & 0xfff ) - 4 ;
2012-02-05 06:49:09 +04:00
struct sk_buff * skb = netdev_alloc_skb ( dev , len + 2 ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
if ( ! skb ) {
dev - > stats . rx_dropped + + ;
rd - > mblength = 0 ;
rd - > rmd1_bits = LE_R1_OWN ;
lp - > rx_new = ( lp - > rx_new + 1 ) & lp - > rx_ring_mod_mask ;
return 0 ;
}
skb_reserve ( skb , 2 ) ; /* 16 byte align */
skb_put ( skb , len ) ; /* make room */
skb_copy_to_linear_data ( skb ,
( unsigned char * ) & ( ib - > rx_buf [ lp - > rx_new ] [ 0 ] ) ,
len ) ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
netif_rx ( skb ) ;
2007-10-04 04:41:50 +04:00
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = len ;
2013-12-29 00:11:14 +04:00
}
/* Return the packet to the pool */
rd - > mblength = 0 ;
rd - > rmd1_bits = LE_R1_OWN ;
lp - > rx_new = ( lp - > rx_new + 1 ) & lp - > rx_ring_mod_mask ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
2013-12-29 00:11:14 +04:00
static int lance_tx ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
volatile struct lance_tx_desc * td ;
int i , j ;
int status ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_HP300
blinken_leds ( 0x80 , 0 ) ;
# endif
2013-12-29 00:11:14 +04:00
/* csr0 is 2f3 */
WRITERDP ( lp , LE_C0_TINT | LE_C0_INEA ) ;
/* csr0 is 73 */
j = lp - > tx_old ;
for ( i = j ; i ! = lp - > tx_new ; i = j ) {
td = & ib - > btx_ring [ i ] ;
/* If we hit a packet not owned by us, stop */
if ( td - > tmd1_bits & LE_T1_OWN )
break ;
if ( td - > tmd1_bits & LE_T1_ERR ) {
status = td - > misc ;
dev - > stats . tx_errors + + ;
if ( status & LE_T3_RTY )
dev - > stats . tx_aborted_errors + + ;
if ( status & LE_T3_LCOL )
dev - > stats . tx_window_errors + + ;
if ( status & LE_T3_CLOS ) {
dev - > stats . tx_carrier_errors + + ;
if ( lp - > auto_select ) {
lp - > tpe = 1 - lp - > tpe ;
printk ( " %s: Carrier Lost, trying %s \n " ,
dev - > name ,
lp - > tpe ? " TPE " : " AUI " ) ;
/* Stop the lance */
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STOP ) ;
lance_init_ring ( dev ) ;
load_csrs ( lp ) ;
init_restart_lance ( lp ) ;
return 0 ;
}
}
/* buffer errors and underflows turn off the transmitter */
/* Restart the adapter */
if ( status & ( LE_T3_BUF | LE_T3_UFL ) ) {
dev - > stats . tx_fifo_errors + + ;
printk ( " %s: Tx: ERR_BUF|ERR_UFL, restarting \n " ,
dev - > name ) ;
/* Stop the lance */
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STOP ) ;
lance_init_ring ( dev ) ;
load_csrs ( lp ) ;
init_restart_lance ( lp ) ;
return 0 ;
}
} else if ( ( td - > tmd1_bits & LE_T1_POK ) = = LE_T1_POK ) {
/*
* So we don ' t count the packet more than once .
*/
td - > tmd1_bits & = ~ ( LE_T1_POK ) ;
/* One collision before packet was sent. */
if ( td - > tmd1_bits & LE_T1_EONE )
dev - > stats . collisions + + ;
/* More than one collision, be optimistic. */
if ( td - > tmd1_bits & LE_T1_EMORE )
dev - > stats . collisions + = 2 ;
dev - > stats . tx_packets + + ;
}
j = ( j + 1 ) & lp - > tx_ring_mod_mask ;
}
lp - > tx_old = j ;
WRITERDP ( lp , LE_C0_TINT | LE_C0_INEA ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
static irqreturn_t
2013-12-29 00:11:14 +04:00
lance_interrupt ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct net_device * dev = ( struct net_device * ) dev_id ;
struct lance_private * lp = netdev_priv ( dev ) ;
int csr0 ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
spin_lock ( & lp - > devlock ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
WRITERAP ( lp , LE_CSR0 ) ; /* LANCE Controller Status */
csr0 = READRDP ( lp ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
PRINT_RINGS ( ) ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
if ( ! ( csr0 & LE_C0_INTR ) ) { /* Check if any interrupt has */
spin_unlock ( & lp - > devlock ) ;
return IRQ_NONE ; /* been generated by the Lance. */
2005-04-17 02:20:36 +04:00
}
2013-12-29 00:11:14 +04:00
/* Acknowledge all the interrupt sources ASAP */
WRITERDP ( lp , csr0 & ~ ( LE_C0_INEA | LE_C0_TDMD | LE_C0_STOP | LE_C0_STRT | LE_C0_INIT ) ) ;
if ( ( csr0 & LE_C0_ERR ) ) {
/* Clear the error condition */
WRITERDP ( lp , LE_C0_BABL | LE_C0_ERR | LE_C0_MISS | LE_C0_INEA ) ;
}
if ( csr0 & LE_C0_RINT )
lance_rx ( dev ) ;
if ( csr0 & LE_C0_TINT )
lance_tx ( dev ) ;
/* Log misc errors. */
if ( csr0 & LE_C0_BABL )
dev - > stats . tx_errors + + ; /* Tx babble. */
if ( csr0 & LE_C0_MISS )
dev - > stats . rx_errors + + ; /* Missed a Rx frame. */
if ( csr0 & LE_C0_MERR ) {
printk ( " %s: Bus master arbitration failure, status %4.4x. \n " ,
dev - > name , csr0 ) ;
/* Restart the chip. */
WRITERDP ( lp , LE_C0_STRT ) ;
}
if ( lp - > tx_full & & netif_queue_stopped ( dev ) & & ( TX_BUFFS_AVAIL > = 0 ) ) {
2005-04-17 02:20:36 +04:00
lp - > tx_full = 0 ;
2013-12-29 00:11:14 +04:00
netif_wake_queue ( dev ) ;
}
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR | LE_C0_IDON | LE_C0_INEA ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
spin_unlock ( & lp - > devlock ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
2013-12-29 00:11:14 +04:00
int lance_open ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
int res ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
if ( request_irq ( lp - > irq , lance_interrupt , IRQF_SHARED , lp - > name , dev ) )
return - EAGAIN ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
res = lance_reset ( dev ) ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & lp - > devlock ) ;
2013-12-29 00:11:14 +04:00
netif_start_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
2008-06-10 02:22:16 +04:00
EXPORT_SYMBOL_GPL ( lance_open ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
int lance_close ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
netif_stop_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
/* Stop the LANCE */
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STOP ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
free_irq ( lp - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 02:22:16 +04:00
EXPORT_SYMBOL_GPL ( lance_close ) ;
2005-04-17 02:20:36 +04:00
void lance_tx_timeout ( struct net_device * dev )
{
printk ( " lance_tx_timeout \n " ) ;
lance_reset ( dev ) ;
2016-05-03 17:33:13 +03:00
netif_trans_update ( dev ) ; /* prevent tx timeout */
2013-12-29 00:11:14 +04:00
netif_wake_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 02:22:16 +04:00
EXPORT_SYMBOL_GPL ( lance_tx_timeout ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
int lance_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
int entry , skblen , len ;
static int outs ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2013-12-29 00:11:14 +04:00
netif_stop_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2016-04-24 22:38:12 +03:00
if ( ! TX_BUFFS_AVAIL ) {
dev_consume_skb_any ( skb ) ;
return NETDEV_TX_OK ;
}
2013-12-29 00:11:14 +04:00
skblen = skb - > len ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG_DRIVER
2013-12-29 00:11:14 +04:00
/* dump the packet */
{
int i ;
for ( i = 0 ; i < 64 ; i + + ) {
if ( ( i % 16 ) = = 0 )
printk ( " \n " ) ;
printk ( " %2.2x " , skb - > data [ i ] ) ;
}
}
2005-04-17 02:20:36 +04:00
# endif
2013-12-29 00:11:14 +04:00
len = ( skblen < = ETH_ZLEN ) ? ETH_ZLEN : skblen ;
entry = lp - > tx_new & lp - > tx_ring_mod_mask ;
ib - > btx_ring [ entry ] . length = ( - len ) | 0xf000 ;
ib - > btx_ring [ entry ] . misc = 0 ;
2006-09-13 21:24:59 +04:00
2007-05-02 00:33:05 +04:00
if ( skb - > len < ETH_ZLEN )
memset ( ( void * ) & ib - > tx_buf [ entry ] [ 0 ] , 0 , ETH_ZLEN ) ;
2013-12-29 00:11:14 +04:00
skb_copy_from_linear_data ( skb , ( void * ) & ib - > tx_buf [ entry ] [ 0 ] , skblen ) ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
/* Now, give the packet to the lance */
ib - > btx_ring [ entry ] . tmd1_bits = ( LE_T1_POK | LE_T1_OWN ) ;
lp - > tx_new = ( lp - > tx_new + 1 ) & lp - > tx_ring_mod_mask ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
outs + + ;
/* Kick the lance: transmit now */
WRITERDP ( lp , LE_C0_INEA | LE_C0_TDMD ) ;
2014-03-16 02:48:50 +04:00
dev_consume_skb_any ( skb ) ;
2006-09-13 21:24:59 +04:00
2013-12-29 00:11:14 +04:00
spin_lock_irqsave ( & lp - > devlock , flags ) ;
if ( TX_BUFFS_AVAIL )
netif_start_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
else
lp - > tx_full = 1 ;
2013-12-29 00:11:14 +04:00
spin_unlock_irqrestore ( & lp - > devlock , flags ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 02:22:16 +04:00
EXPORT_SYMBOL_GPL ( lance_start_xmit ) ;
2005-04-17 02:20:36 +04:00
/* taken from the depca driver via a2065.c */
2013-12-29 00:11:14 +04:00
static void lance_load_multicast ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
volatile u16 * mcast_table = ( u16 * ) & ib - > filter ;
2010-04-02 01:22:57 +04:00
struct netdev_hw_addr * ha ;
2013-12-29 00:11:14 +04:00
u32 crc ;
/* set all multicast bits */
if ( dev - > flags & IFF_ALLMULTI ) {
ib - > filter [ 0 ] = 0xffffffff ;
ib - > filter [ 1 ] = 0xffffffff ;
return ;
}
/* clear the multicast filter */
ib - > filter [ 0 ] = 0 ;
ib - > filter [ 1 ] = 0 ;
/* Add addresses */
2010-04-02 01:22:57 +04:00
netdev_for_each_mc_addr ( ha , dev ) {
2011-07-08 02:06:26 +04:00
crc = ether_crc_le ( 6 , ha - > addr ) ;
2013-12-29 00:11:14 +04:00
crc = crc > > 26 ;
mcast_table [ crc > > 4 ] | = 1 < < ( crc & 0xf ) ;
}
2005-04-17 02:20:36 +04:00
}
2013-12-29 00:11:14 +04:00
void lance_set_multicast ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2013-12-29 00:11:14 +04:00
struct lance_private * lp = netdev_priv ( dev ) ;
volatile struct lance_init_block * ib = lp - > init_block ;
2005-04-17 02:20:36 +04:00
int stopped ;
stopped = netif_queue_stopped ( dev ) ;
if ( ! stopped )
2013-12-29 00:11:14 +04:00
netif_stop_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
while ( lp - > tx_old ! = lp - > tx_new )
schedule ( ) ;
2005-04-17 02:20:36 +04:00
2013-12-29 00:11:14 +04:00
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STOP ) ;
lance_init_ring ( dev ) ;
if ( dev - > flags & IFF_PROMISC ) {
ib - > mode | = LE_MO_PROM ;
} else {
ib - > mode & = ~ LE_MO_PROM ;
lance_load_multicast ( dev ) ;
}
load_csrs ( lp ) ;
init_restart_lance ( lp ) ;
2005-04-17 02:20:36 +04:00
if ( ! stopped )
2013-12-29 00:11:14 +04:00
netif_start_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 02:22:16 +04:00
EXPORT_SYMBOL_GPL ( lance_set_multicast ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_NET_POLL_CONTROLLER
void lance_poll ( struct net_device * dev )
{
struct lance_private * lp = netdev_priv ( dev ) ;
2013-12-29 00:11:14 +04:00
spin_lock ( & lp - > devlock ) ;
2005-04-17 02:20:36 +04:00
WRITERAP ( lp , LE_CSR0 ) ;
WRITERDP ( lp , LE_C0_STRT ) ;
2013-12-29 00:11:14 +04:00
spin_unlock ( & lp - > devlock ) ;
2006-10-07 17:16:45 +04:00
lance_interrupt ( dev - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
}
2015-09-29 11:24:03 +03:00
EXPORT_SYMBOL_GPL ( lance_poll ) ;
2005-04-17 02:20:36 +04:00
# endif
MODULE_LICENSE ( " GPL " ) ;