2005-04-17 02:20:36 +04:00
/*
* Amiga Linux / m68k and Linux / PPC Zorro NS8390 Ethernet Driver
*
* ( C ) Copyright 1998 - 2000 by some Elitist 680 x0 Users ( TM )
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* This program is based on all the other NE2000 drivers for Linux
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of the Linux
* distribution for more details .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* The Ariadne II and X - Surf are Zorro - II boards containing Realtek RTL8019AS
* Ethernet Controllers .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/zorro.h>
2006-01-10 05:37:15 +03:00
# include <linux/jiffies.h>
2005-04-17 02:20:36 +04:00
# include <asm/system.h>
# include <asm/irq.h>
# include <asm/amigaints.h>
# include <asm/amigahw.h>
2006-10-10 03:19:36 +04:00
# define EI_SHIFT(x) (ei_local->reg_offset[x])
# define ei_inb(port) in_8(port)
# define ei_outb(val,port) out_8(port,val)
# define ei_inb_p(port) in_8(port)
# define ei_outb_p(val,port) out_8(port,val)
2005-04-17 02:20:36 +04:00
2006-10-10 03:19:36 +04:00
static const char version [ ] =
" 8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov) \n " ;
# include "lib8390.c"
2005-04-17 02:20:36 +04:00
# define DRV_NAME "zorro8390"
# define NE_BASE (dev->base_addr)
# define NE_CMD (0x00*2)
# define NE_DATAPORT (0x10*2) /* NatSemi-defined port window offset. */
# define NE_RESET (0x1f*2) /* Issue a read to reset, a write to clear. */
# define NE_IO_EXTENT (0x20*2)
# define NE_EN0_ISR (0x07*2)
# define NE_EN0_DCFG (0x0e*2)
# define NE_EN0_RSARLO (0x08*2)
# define NE_EN0_RSARHI (0x09*2)
# define NE_EN0_RCNTLO (0x0a*2)
# define NE_EN0_RXCR (0x0c*2)
# define NE_EN0_TXCR (0x0d*2)
# define NE_EN0_RCNTHI (0x0b*2)
# define NE_EN0_IMR (0x0f*2)
# define NESM_START_PG 0x40 /* First page of TX buffer */
# define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
# define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8))
static struct card_info {
zorro_id id ;
const char * name ;
unsigned int offset ;
} cards [ ] __devinitdata = {
{ ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2 , " Ariadne II " , 0x0600 } ,
{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF , " X-Surf " , 0x8600 } ,
} ;
static int __devinit zorro8390_init_one ( struct zorro_dev * z ,
const struct zorro_device_id * ent ) ;
static int __devinit zorro8390_init ( struct net_device * dev ,
unsigned long board , const char * name ,
unsigned long ioaddr ) ;
static int zorro8390_open ( struct net_device * dev ) ;
static int zorro8390_close ( struct net_device * dev ) ;
static void zorro8390_reset_8390 ( struct net_device * dev ) ;
static void zorro8390_get_8390_hdr ( struct net_device * dev ,
struct e8390_pkt_hdr * hdr , int ring_page ) ;
static void zorro8390_block_input ( struct net_device * dev , int count ,
struct sk_buff * skb , int ring_offset ) ;
static void zorro8390_block_output ( struct net_device * dev , const int count ,
const unsigned char * buf ,
const int start_page ) ;
static void __devexit zorro8390_remove_one ( struct zorro_dev * z ) ;
static struct zorro_device_id zorro8390_zorro_tbl [ ] __devinitdata = {
{ ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2 , } ,
{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF , } ,
{ 0 }
} ;
static struct zorro_driver zorro8390_driver = {
. name = " zorro8390 " ,
. id_table = zorro8390_zorro_tbl ,
. probe = zorro8390_init_one ,
. remove = __devexit_p ( zorro8390_remove_one ) ,
} ;
static int __devinit zorro8390_init_one ( struct zorro_dev * z ,
const struct zorro_device_id * ent )
{
struct net_device * dev ;
unsigned long board , ioaddr ;
int err , i ;
for ( i = ARRAY_SIZE ( cards ) - 1 ; i > = 0 ; i - - )
if ( z - > id = = cards [ i ] . id )
break ;
board = z - > resource . start ;
ioaddr = board + cards [ i ] . offset ;
2006-10-10 03:19:36 +04:00
dev = ____alloc_ei_netdev ( 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return - ENOMEM ;
if ( ! request_mem_region ( ioaddr , NE_IO_EXTENT * 2 , DRV_NAME ) ) {
free_netdev ( dev ) ;
return - EBUSY ;
}
if ( ( err = zorro8390_init ( dev , board , cards [ i ] . name ,
ZTWO_VADDR ( ioaddr ) ) ) ) {
release_mem_region ( ioaddr , NE_IO_EXTENT * 2 ) ;
free_netdev ( dev ) ;
return err ;
}
zorro_set_drvdata ( z , dev ) ;
return 0 ;
}
static int __devinit zorro8390_init ( struct net_device * dev ,
unsigned long board , const char * name ,
unsigned long ioaddr )
{
int i ;
int err ;
unsigned char SA_prom [ 32 ] ;
int start_page , stop_page ;
static u32 zorro8390_offsets [ 16 ] = {
0x00 , 0x02 , 0x04 , 0x06 , 0x08 , 0x0a , 0x0c , 0x0e ,
0x10 , 0x12 , 0x14 , 0x16 , 0x18 , 0x1a , 0x1c , 0x1e ,
} ;
2007-10-04 04:59:30 +04:00
DECLARE_MAC_BUF ( mac ) ;
2005-04-17 02:20:36 +04:00
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
unsigned long reset_start_time = jiffies ;
z_writeb ( z_readb ( ioaddr + NE_RESET ) , ioaddr + NE_RESET ) ;
while ( ( z_readb ( ioaddr + NE_EN0_ISR ) & ENISR_RESET ) = = 0 )
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , reset_start_time + 2 * HZ / 100 ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " not found (no reset ack). \n " ) ;
return - ENODEV ;
}
z_writeb ( 0xff , ioaddr + NE_EN0_ISR ) ; /* Ack all intr. */
}
/* Read the 16 bytes of station address PROM.
We must first initialize registers , similar to NS8390_init ( eifdev , 0 ) .
We can ' t reliably read the SAPROM address without this .
( I learned the hard way ! ) . */
{
struct {
u32 value ;
u32 offset ;
} program_seq [ ] = {
{ E8390_NODMA + E8390_PAGE0 + E8390_STOP , NE_CMD } , /* Select page 0*/
{ 0x48 , NE_EN0_DCFG } , /* Set byte-wide (0x48) access. */
{ 0x00 , NE_EN0_RCNTLO } , /* Clear the count regs. */
{ 0x00 , NE_EN0_RCNTHI } ,
{ 0x00 , NE_EN0_IMR } , /* Mask completion irq. */
{ 0xFF , NE_EN0_ISR } ,
{ E8390_RXOFF , NE_EN0_RXCR } , /* 0x20 Set to monitor */
{ E8390_TXOFF , NE_EN0_TXCR } , /* 0x02 and loopback mode. */
{ 32 , NE_EN0_RCNTLO } ,
{ 0x00 , NE_EN0_RCNTHI } ,
{ 0x00 , NE_EN0_RSARLO } , /* DMA starting at 0x0000. */
{ 0x00 , NE_EN0_RSARHI } ,
{ E8390_RREAD + E8390_START , NE_CMD } ,
} ;
2007-09-02 14:30:18 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( program_seq ) ; i + + ) {
2005-04-17 02:20:36 +04:00
z_writeb ( program_seq [ i ] . value , ioaddr + program_seq [ i ] . offset ) ;
}
}
for ( i = 0 ; i < 16 ; i + + ) {
SA_prom [ i ] = z_readb ( ioaddr + NE_DATAPORT ) ;
( void ) z_readb ( ioaddr + NE_DATAPORT ) ;
}
/* We must set the 8390 for word mode. */
z_writeb ( 0x49 , ioaddr + NE_EN0_DCFG ) ;
start_page = NESM_START_PG ;
stop_page = NESM_STOP_PG ;
dev - > base_addr = ioaddr ;
dev - > irq = IRQ_AMIGA_PORTS ;
/* Install the Interrupt handler */
2006-10-10 03:19:36 +04:00
i = request_irq ( IRQ_AMIGA_PORTS , __ei_interrupt , IRQF_SHARED , DRV_NAME , dev ) ;
2005-04-17 02:20:36 +04:00
if ( i ) return i ;
2007-10-04 04:59:30 +04:00
for ( i = 0 ; i < ETHER_ADDR_LEN ; i + + )
dev - > dev_addr [ i ] = SA_prom [ i ] ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
2007-10-04 04:59:30 +04:00
printk ( " %s " , print_mac ( mac , dev - > dev_addr ) ) ;
2005-04-17 02:20:36 +04:00
# endif
ei_status . name = name ;
ei_status . tx_start_page = start_page ;
ei_status . stop_page = stop_page ;
ei_status . word16 = 1 ;
ei_status . rx_start_page = start_page + TX_PAGES ;
ei_status . reset_8390 = & zorro8390_reset_8390 ;
ei_status . block_input = & zorro8390_block_input ;
ei_status . block_output = & zorro8390_block_output ;
ei_status . get_8390_hdr = & zorro8390_get_8390_hdr ;
ei_status . reg_offset = zorro8390_offsets ;
dev - > open = & zorro8390_open ;
dev - > stop = & zorro8390_close ;
# ifdef CONFIG_NET_POLL_CONTROLLER
2006-10-10 03:19:36 +04:00
dev - > poll_controller = __ei_poll ;
2005-04-17 02:20:36 +04:00
# endif
2006-10-10 03:19:36 +04:00
__NS8390_init ( dev , 0 ) ;
2005-04-17 02:20:36 +04:00
err = register_netdev ( dev ) ;
if ( err ) {
free_irq ( IRQ_AMIGA_PORTS , dev ) ;
return err ;
}
2007-10-04 04:59:30 +04:00
printk ( KERN_INFO " %s: %s at 0x%08lx, Ethernet Address %s \n " ,
dev - > name , name , board , print_mac ( mac , dev - > dev_addr ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int zorro8390_open ( struct net_device * dev )
{
2006-10-10 03:19:36 +04:00
__ei_open ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int zorro8390_close ( struct net_device * dev )
{
if ( ei_debug > 1 )
printk ( KERN_DEBUG " %s: Shutting down ethercard. \n " , dev - > name ) ;
2006-10-10 03:19:36 +04:00
__ei_close ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Hard reset the card. This used to pause for the same period that a
8390 reset command required , but that shouldn ' t be necessary . */
static void zorro8390_reset_8390 ( struct net_device * dev )
{
unsigned long reset_start_time = jiffies ;
if ( ei_debug > 1 )
printk ( KERN_DEBUG " resetting the 8390 t=%ld... \n " , jiffies ) ;
z_writeb ( z_readb ( NE_BASE + NE_RESET ) , NE_BASE + NE_RESET ) ;
ei_status . txing = 0 ;
ei_status . dmaing = 0 ;
/* This check _should_not_ be necessary, omit eventually. */
while ( ( z_readb ( NE_BASE + NE_EN0_ISR ) & ENISR_RESET ) = = 0 )
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , reset_start_time + 2 * HZ / 100 ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " %s: ne_reset_8390() did not complete. \n " ,
dev - > name ) ;
break ;
}
z_writeb ( ENISR_RESET , NE_BASE + NE_EN0_ISR ) ; /* Ack intr. */
}
/* Grab the 8390 specific header. Similar to the block_input routine, but
we don ' t need to be concerned with ring wrap as the header will be at
the start of a page , so we optimize accordingly . */
static void zorro8390_get_8390_hdr ( struct net_device * dev ,
struct e8390_pkt_hdr * hdr , int ring_page )
{
int nic_base = dev - > base_addr ;
int cnt ;
short * ptrs ;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if ( ei_status . dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in ne_get_8390_hdr "
" [DMAstat:%d][irqlock:%d]. \n " , dev - > name , ei_status . dmaing ,
ei_status . irqlock ) ;
return ;
}
ei_status . dmaing | = 0x01 ;
z_writeb ( E8390_NODMA + E8390_PAGE0 + E8390_START , nic_base + NE_CMD ) ;
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ;
z_writeb ( sizeof ( struct e8390_pkt_hdr ) , nic_base + NE_EN0_RCNTLO ) ;
z_writeb ( 0 , nic_base + NE_EN0_RCNTHI ) ;
z_writeb ( 0 , nic_base + NE_EN0_RSARLO ) ; /* On page boundary */
z_writeb ( ring_page , nic_base + NE_EN0_RSARHI ) ;
z_writeb ( E8390_RREAD + E8390_START , nic_base + NE_CMD ) ;
ptrs = ( short * ) hdr ;
for ( cnt = 0 ; cnt < ( sizeof ( struct e8390_pkt_hdr ) > > 1 ) ; cnt + + )
* ptrs + + = z_readw ( NE_BASE + NE_DATAPORT ) ;
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ; /* Ack intr. */
hdr - > count = WORDSWAP ( hdr - > count ) ;
ei_status . dmaing & = ~ 0x01 ;
}
/* Block input and output, similar to the Crynwr packet driver. If you
are porting to a new ethercard , look at the packet driver source for hints .
The NEx000 doesn ' t share the on - board packet memory - - you have to put
the packet out through the " remote DMA " dataport using z_writeb . */
static void zorro8390_block_input ( struct net_device * dev , int count ,
struct sk_buff * skb , int ring_offset )
{
int nic_base = dev - > base_addr ;
char * buf = skb - > data ;
short * ptrs ;
int cnt ;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if ( ei_status . dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in ne_block_input "
" [DMAstat:%d][irqlock:%d]. \n " ,
dev - > name , ei_status . dmaing , ei_status . irqlock ) ;
return ;
}
ei_status . dmaing | = 0x01 ;
z_writeb ( E8390_NODMA + E8390_PAGE0 + E8390_START , nic_base + NE_CMD ) ;
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ;
z_writeb ( count & 0xff , nic_base + NE_EN0_RCNTLO ) ;
z_writeb ( count > > 8 , nic_base + NE_EN0_RCNTHI ) ;
z_writeb ( ring_offset & 0xff , nic_base + NE_EN0_RSARLO ) ;
z_writeb ( ring_offset > > 8 , nic_base + NE_EN0_RSARHI ) ;
z_writeb ( E8390_RREAD + E8390_START , nic_base + NE_CMD ) ;
ptrs = ( short * ) buf ;
for ( cnt = 0 ; cnt < ( count > > 1 ) ; cnt + + )
* ptrs + + = z_readw ( NE_BASE + NE_DATAPORT ) ;
if ( count & 0x01 )
buf [ count - 1 ] = z_readb ( NE_BASE + NE_DATAPORT ) ;
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ; /* Ack intr. */
ei_status . dmaing & = ~ 0x01 ;
}
static void zorro8390_block_output ( struct net_device * dev , int count ,
const unsigned char * buf ,
const int start_page )
{
int nic_base = NE_BASE ;
unsigned long dma_start ;
short * ptrs ;
int cnt ;
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390 ?
I should check someday . */
if ( count & 0x01 )
count + + ;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if ( ei_status . dmaing ) {
printk ( KERN_ERR " %s: DMAing conflict in ne_block_output. "
" [DMAstat:%d][irqlock:%d] \n " , dev - > name , ei_status . dmaing ,
ei_status . irqlock ) ;
return ;
}
ei_status . dmaing | = 0x01 ;
/* We should already be in page 0, but to be safe... */
z_writeb ( E8390_PAGE0 + E8390_START + E8390_NODMA , nic_base + NE_CMD ) ;
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ;
/* Now the normal output. */
z_writeb ( count & 0xff , nic_base + NE_EN0_RCNTLO ) ;
z_writeb ( count > > 8 , nic_base + NE_EN0_RCNTHI ) ;
z_writeb ( 0x00 , nic_base + NE_EN0_RSARLO ) ;
z_writeb ( start_page , nic_base + NE_EN0_RSARHI ) ;
z_writeb ( E8390_RWRITE + E8390_START , nic_base + NE_CMD ) ;
ptrs = ( short * ) buf ;
for ( cnt = 0 ; cnt < count > > 1 ; cnt + + )
z_writew ( * ptrs + + , NE_BASE + NE_DATAPORT ) ;
dma_start = jiffies ;
while ( ( z_readb ( NE_BASE + NE_EN0_ISR ) & ENISR_RDC ) = = 0 )
2006-01-10 05:37:15 +03:00
if ( time_after ( jiffies , dma_start + 2 * HZ / 100 ) ) { /* 20ms */
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting for Tx RDC. \n " ,
dev - > name ) ;
zorro8390_reset_8390 ( dev ) ;
2006-10-10 03:19:36 +04:00
__NS8390_init ( dev , 1 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
z_writeb ( ENISR_RDC , nic_base + NE_EN0_ISR ) ; /* Ack intr. */
ei_status . dmaing & = ~ 0x01 ;
return ;
}
static void __devexit zorro8390_remove_one ( struct zorro_dev * z )
{
struct net_device * dev = zorro_get_drvdata ( z ) ;
unregister_netdev ( dev ) ;
free_irq ( IRQ_AMIGA_PORTS , dev ) ;
release_mem_region ( ZTWO_PADDR ( dev - > base_addr ) , NE_IO_EXTENT * 2 ) ;
free_netdev ( dev ) ;
}
static int __init zorro8390_init_module ( void )
{
2006-03-25 14:07:20 +03:00
return zorro_register_driver ( & zorro8390_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit zorro8390_cleanup_module ( void )
{
zorro_unregister_driver ( & zorro8390_driver ) ;
}
module_init ( zorro8390_init_module ) ;
module_exit ( zorro8390_cleanup_module ) ;
MODULE_LICENSE ( " GPL " ) ;