2005-04-17 02:20:36 +04:00
/*
2005-08-20 09:53:22 +04:00
* jazzsonic . c
*
* ( C ) 2005 Finn Thain
*
* Converted to DMA API , and ( from the mac68k project ) introduced
* dhd ' s support for 16 - bit cards .
2005-04-17 02:20:36 +04:00
*
* ( C ) 1996 , 1998 by Thomas Bogendoerfer ( tsbogend @ alpha . franken . de )
2006-09-13 21:24:59 +04:00
*
2005-04-17 02:20:36 +04:00
* This driver is based on work from Andreas Busse , but most of
* the code is rewritten .
2006-09-13 21:24:59 +04:00
*
2005-04-17 02:20:36 +04:00
* ( C ) 1995 by Andreas Busse ( andy @ waldorf - gmbh . de )
*
* A driver for the onboard Sonic ethernet controller on Mips Jazz
* systems ( Acer Pica - 61 , Mips Magnum 4000 , Olivetti M700 and
* perhaps others , too )
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <linux/in.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
2005-10-29 22:07:23 +04:00
# include <linux/platform_device.h>
2005-08-20 09:53:22 +04:00
# include <linux/dma-mapping.h>
2005-04-17 02:20:36 +04:00
# include <asm/bootinfo.h>
# include <asm/system.h>
# include <asm/pgtable.h>
# include <asm/io.h>
# include <asm/dma.h>
# include <asm/jazz.h>
# include <asm/jazzdma.h>
static char jazz_sonic_string [ ] = " jazzsonic " ;
# define SONIC_MEM_SIZE 0x100
# include "sonic.h"
/*
* Macros to access SONIC registers
*/
2005-08-20 09:53:22 +04:00
# define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
2005-04-17 02:20:36 +04:00
# define SONIC_WRITE(reg,val) \
do { \
2005-08-20 09:53:22 +04:00
* ( ( volatile unsigned int * ) dev - > base_addr + ( reg ) ) = ( val ) ; \
2005-04-17 02:20:36 +04:00
} while ( 0 )
2005-08-20 09:53:22 +04:00
/* use 0 for production, 1 for verification, >1 for debug */
2005-04-17 02:20:36 +04:00
# ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG ;
2006-09-13 21:24:59 +04:00
# else
2005-04-17 02:20:36 +04:00
static unsigned int sonic_debug = 1 ;
# endif
/*
* We cannot use station ( ethernet ) address prefixes to detect the
* sonic controller since these are board manufacturer depended .
2006-09-13 21:24:59 +04:00
* So we check for known Silicon Revision IDs instead .
2005-04-17 02:20:36 +04:00
*/
static unsigned short known_revisions [ ] =
{
0x04 , /* Mips Magnum 4000 */
0xffff /* end of list */
} ;
2007-05-02 06:55:56 +04:00
static int jazzsonic_open ( struct net_device * dev )
{
if ( request_irq ( dev - > irq , & sonic_interrupt , IRQF_DISABLED , " sonic " , dev ) ) {
printk ( KERN_ERR " %s: unable to get IRQ %d. \n " , dev - > name , dev - > irq ) ;
return - EAGAIN ;
}
return sonic_open ( dev ) ;
}
static int jazzsonic_close ( struct net_device * dev )
{
int err ;
err = sonic_close ( dev ) ;
free_irq ( dev - > irq , dev ) ;
return err ;
}
2005-08-20 09:53:22 +04:00
static int __init sonic_probe1 ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
static unsigned version_printed ;
unsigned int silicon_revision ;
unsigned int val ;
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
int err = - ENODEV ;
int i ;
2005-08-20 09:53:22 +04:00
if ( ! request_mem_region ( dev - > base_addr , SONIC_MEM_SIZE , jazz_sonic_string ) )
2005-04-17 02:20:36 +04:00
return - EBUSY ;
2005-08-20 09:53:22 +04:00
2005-04-17 02:20:36 +04:00
/*
* get the Silicon Revision ID . If this is one of the known
* one assume that we found a SONIC ethernet controller at
* the expected location .
*/
silicon_revision = SONIC_READ ( SONIC_SR ) ;
if ( sonic_debug > 1 )
printk ( " SONIC Silicon Revision = 0x%04x \n " , silicon_revision ) ;
i = 0 ;
while ( known_revisions [ i ] ! = 0xffff
& & known_revisions [ i ] ! = silicon_revision )
i + + ;
if ( known_revisions [ i ] = = 0xffff ) {
printk ( " SONIC ethernet controller not found (0x%4x) \n " ,
silicon_revision ) ;
goto out ;
}
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
if ( sonic_debug & & version_printed + + = = 0 )
printk ( version ) ;
2005-08-20 09:53:22 +04:00
printk ( KERN_INFO " %s: Sonic ethernet found at 0x%08lx, " , lp - > device - > bus_id , dev - > base_addr ) ;
2005-04-17 02:20:36 +04:00
/*
* Put the sonic into software reset , then
* retrieve and print the ethernet address .
*/
SONIC_WRITE ( SONIC_CMD , SONIC_CR_RST ) ;
SONIC_WRITE ( SONIC_CEP , 0 ) ;
for ( i = 0 ; i < 3 ; i + + ) {
val = SONIC_READ ( SONIC_CAP0 - i ) ;
dev - > dev_addr [ i * 2 ] = val ;
dev - > dev_addr [ i * 2 + 1 ] = val > > 8 ;
}
err = - ENOMEM ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
/* Initialize the device structure. */
2005-08-20 09:53:22 +04:00
lp - > dma_bitmode = SONIC_BITMODE32 ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64 K boundary . */
if ( ( lp - > descriptors = dma_alloc_coherent ( lp - > device ,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE ( lp - > dma_bitmode ) ,
& lp - > descriptors_laddr , GFP_KERNEL ) ) = = NULL ) {
printk ( KERN_ERR " %s: couldn't alloc DMA memory for descriptors. \n " , lp - > device - > bus_id ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-08-20 09:53:22 +04:00
/* Now set up the pointers to point to the appropriate places */
lp - > cda = lp - > descriptors ;
lp - > tda = lp - > cda + ( SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
lp - > rda = lp - > tda + ( SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
lp - > rra = lp - > rda + ( SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
lp - > cda_laddr = lp - > descriptors_laddr ;
lp - > tda_laddr = lp - > cda_laddr + ( SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
lp - > rda_laddr = lp - > tda_laddr + ( SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
lp - > rra_laddr = lp - > rda_laddr + ( SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
2007-05-02 06:55:56 +04:00
dev - > open = jazzsonic_open ;
dev - > stop = jazzsonic_close ;
2005-04-17 02:20:36 +04:00
dev - > hard_start_xmit = sonic_send_packet ;
2005-08-20 09:53:22 +04:00
dev - > get_stats = sonic_get_stats ;
2005-04-17 02:20:36 +04:00
dev - > set_multicast_list = & sonic_multicast_list ;
2005-08-20 09:53:22 +04:00
dev - > tx_timeout = sonic_tx_timeout ;
2005-04-17 02:20:36 +04:00
dev - > watchdog_timeo = TX_TIMEOUT ;
/*
* clear tally counter
*/
SONIC_WRITE ( SONIC_CRCT , 0xffff ) ;
SONIC_WRITE ( SONIC_FAET , 0xffff ) ;
SONIC_WRITE ( SONIC_MPT , 0xffff ) ;
return 0 ;
out :
2005-08-20 09:53:22 +04:00
release_region ( dev - > base_addr , SONIC_MEM_SIZE ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
/*
* Probe for a SONIC ethernet controller on a Mips Jazz board .
* Actually probing is superfluous but we ' re paranoid .
*/
2005-11-10 01:32:44 +03:00
static int __init jazz_sonic_probe ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
struct sonic_local * lp ;
2007-09-08 23:46:49 +04:00
struct resource * res ;
2005-04-17 02:20:36 +04:00
int err = 0 ;
2007-09-08 23:46:49 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2005-08-20 09:53:22 +04:00
dev = alloc_etherdev ( sizeof ( struct sonic_local ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return - ENOMEM ;
2005-08-20 09:53:22 +04:00
lp = netdev_priv ( dev ) ;
2005-11-10 01:32:44 +03:00
lp - > device = & pdev - > dev ;
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
2005-08-20 09:53:22 +04:00
2005-04-17 02:20:36 +04:00
netdev_boot_setup_check ( dev ) ;
2007-09-08 23:46:49 +04:00
dev - > base_addr = res - > start ;
dev - > irq = platform_get_irq ( pdev , 0 ) ;
err = sonic_probe1 ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( err )
goto out ;
err = register_netdev ( dev ) ;
if ( err )
goto out1 ;
2008-10-28 01:59:26 +03:00
printk ( " %s: MAC %pM IRQ %d \n " , dev - > name , dev - > dev_addr , dev - > irq ) ;
2005-08-20 09:53:22 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
out1 :
release_region ( dev - > base_addr , SONIC_MEM_SIZE ) ;
out :
free_netdev ( dev ) ;
return err ;
}
2005-08-20 09:53:22 +04:00
MODULE_DESCRIPTION ( " Jazz SONIC ethernet driver " ) ;
module_param ( sonic_debug , int , 0 ) ;
MODULE_PARM_DESC ( sonic_debug , " jazzsonic debug level (1-4) " ) ;
2008-04-19 00:50:44 +04:00
MODULE_ALIAS ( " platform:jazzsonic " ) ;
2005-04-17 02:20:36 +04:00
# include "sonic.c"
2005-11-10 01:32:44 +03:00
static int __devexit jazz_sonic_device_remove ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2005-11-10 01:32:44 +03:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:33:02 +04:00
unregister_netdev ( dev ) ;
2005-08-20 09:53:22 +04:00
dma_free_coherent ( lp - > device , SIZEOF_SONIC_DESC * SONIC_BUS_SCALE ( lp - > dma_bitmode ) ,
lp - > descriptors , lp - > descriptors_laddr ) ;
2005-04-17 02:20:36 +04:00
release_region ( dev - > base_addr , SONIC_MEM_SIZE ) ;
2007-05-02 00:33:02 +04:00
free_netdev ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-11-10 01:32:44 +03:00
static struct platform_driver jazz_sonic_driver = {
2005-04-17 02:20:36 +04:00
. probe = jazz_sonic_probe ,
. remove = __devexit_p ( jazz_sonic_device_remove ) ,
2005-11-10 01:32:44 +03:00
. driver = {
. name = jazz_sonic_string ,
2008-04-19 00:50:44 +04:00
. owner = THIS_MODULE ,
2005-11-10 01:32:44 +03:00
} ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-20 09:53:22 +04:00
2005-04-17 02:20:36 +04:00
static int __init jazz_sonic_init_module ( void )
{
2007-09-08 23:46:49 +04:00
return platform_driver_register ( & jazz_sonic_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit jazz_sonic_cleanup_module ( void )
{
2005-11-10 01:32:44 +03:00
platform_driver_unregister ( & jazz_sonic_driver ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( jazz_sonic_init_module ) ;
module_exit ( jazz_sonic_cleanup_module ) ;