2005-04-17 02:20:36 +04:00
/*
* macsonic . c
*
2005-08-20 09:53:22 +04:00
* ( C ) 2005 Finn Thain
*
* Converted to DMA API , converted to unified driver model , made it work as
* a module again , and from the mac68k project , introduced more 32 - bit cards
* and dhd ' s support for 16 - bit cards .
*
2005-04-17 02:20:36 +04:00
* ( C ) 1998 Alan Cox
*
* Debugging Andreas Ehliar , Michael Schmitz
*
* Based on code
* ( C ) 1996 by Thomas Bogendoerfer ( tsbogend @ bigbug . 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 Mac onboard Sonic ethernet chip .
*
2006-09-13 21:24:59 +04:00
* 98 / 12 / 21 MSch : judged from tests on Q800 , it ' s basically working ,
2005-04-17 02:20:36 +04:00
* but eating up both receive and transmit resources
* and duplicating packets . Needs more testing .
*
* 99 / 01 / 03 MSch : upgraded to version 0.92 of the core driver , fixed .
2006-09-13 21:24:59 +04:00
*
2005-04-17 02:20:36 +04:00
* 00 / 10 / 31 sammy @ oh . verio . com : Updated driver for 2.4 kernels , fixed problems
* on centris .
*/
# include <linux/kernel.h>
2005-08-20 09:53:22 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# 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/nubus.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>
2007-02-09 19:05:22 +03:00
# include <linux/bitrev.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/hwtest.h>
# include <asm/dma.h>
# include <asm/macintosh.h>
# include <asm/macints.h>
# include <asm/mac_via.h>
2005-08-20 09:53:22 +04:00
static char mac_sonic_string [ ] = " macsonic " ;
static struct platform_device * mac_sonic_device ;
2005-04-17 02:20:36 +04:00
# include "sonic.h"
2005-08-20 09:53:22 +04:00
/* These should basically be bus-size and endian independent (since
the SONIC is at least smart enough that it uses the same endianness
as the host , unlike certain less enlightened Macintosh NICs ) */
# define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \
+ lp - > reg_offset ) )
# define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \
+ lp - > reg_offset ) )
/* use 0 for production, 1 for verification, >1 for debug */
# ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG ;
2006-09-13 21:24:59 +04:00
# else
2005-08-20 09:53:22 +04:00
static unsigned int sonic_debug = 1 ;
# endif
2005-04-17 02:20:36 +04:00
static int sonic_version_printed ;
extern int mac_onboard_sonic_probe ( struct net_device * dev ) ;
extern int mac_nubus_sonic_probe ( struct net_device * dev ) ;
/* For onboard SONIC */
# define ONBOARD_SONIC_REGISTERS 0x50F0A000
# define ONBOARD_SONIC_PROM_BASE 0x50f08000
enum macsonic_type {
MACSONIC_DUODOCK ,
MACSONIC_APPLE ,
MACSONIC_APPLE16 ,
MACSONIC_DAYNA ,
MACSONIC_DAYNALINK
} ;
/* For the built-in SONIC in the Duo Dock */
# define DUODOCK_SONIC_REGISTERS 0xe10000
# define DUODOCK_SONIC_PROM_BASE 0xe12000
/* For Apple-style NuBus SONIC */
# define APPLE_SONIC_REGISTERS 0
# define APPLE_SONIC_PROM_BASE 0x40000
/* Daynalink LC SONIC */
# define DAYNALINK_PROM_BASE 0x400000
/* For Dayna-style NuBus SONIC (haven't seen one yet) */
# define DAYNA_SONIC_REGISTERS 0x180000
/* This is what OpenBSD says. However, this is definitely in NuBus
ROM space so we should be able to get it by walking the NuBus
resource directories */
# define DAYNA_SONIC_MAC_ADDR 0xffe004
# define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
/*
* For reversing the PROM address
*/
static inline void bit_reverse_addr ( unsigned char addr [ 6 ] )
{
int i ;
for ( i = 0 ; i < 6 ; i + + )
2006-12-20 00:09:08 +03:00
addr [ i ] = bitrev8 ( addr [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 06:55:56 +04:00
static irqreturn_t macsonic_interrupt ( int irq , void * dev_id )
{
irqreturn_t result ;
unsigned long flags ;
local_irq_save ( flags ) ;
result = sonic_interrupt ( irq , dev_id ) ;
local_irq_restore ( flags ) ;
return result ;
}
static int macsonic_open ( struct net_device * dev )
{
if ( request_irq ( dev - > irq , & sonic_interrupt , IRQ_FLG_FAST , " sonic " , dev ) ) {
printk ( KERN_ERR " %s: unable to get IRQ %d. \n " , dev - > name , dev - > irq ) ;
return - EAGAIN ;
}
/* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
* in at priority level 3. However , we sometimes get the level 2 inter -
* rupt as well , which must prevent re - entrance of the sonic handler .
*/
if ( dev - > irq = = IRQ_AUTO_3 )
if ( request_irq ( IRQ_NUBUS_9 , & macsonic_interrupt , IRQ_FLG_FAST , " sonic " , dev ) ) {
printk ( KERN_ERR " %s: unable to get IRQ %d. \n " , dev - > name , IRQ_NUBUS_9 ) ;
free_irq ( dev - > irq , dev ) ;
return - EAGAIN ;
}
return sonic_open ( dev ) ;
}
static int macsonic_close ( struct net_device * dev )
{
int err ;
err = sonic_close ( dev ) ;
free_irq ( dev - > irq , dev ) ;
if ( dev - > irq = = IRQ_AUTO_3 )
free_irq ( IRQ_NUBUS_9 , dev ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
int __init macsonic_init ( struct net_device * dev )
{
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64 K boundary . */
2005-08-20 09:53:22 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2005-08-20 09:53:22 +04:00
}
2005-04-17 02:20:36 +04:00
/* Now set up the pointers to point to the appropriate places */
2005-08-20 09:53:22 +04:00
lp - > cda = lp - > descriptors ;
lp - > tda = lp - > cda + ( SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
2005-04-17 02:20:36 +04:00
lp - > rda = lp - > tda + ( SIZEOF_SONIC_TD * SONIC_NUM_TDS
2005-08-20 09:53:22 +04:00
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
2005-04-17 02:20:36 +04:00
lp - > rra = lp - > rda + ( SIZEOF_SONIC_RD * SONIC_NUM_RDS
2005-08-20 09:53:22 +04:00
* SONIC_BUS_SCALE ( lp - > dma_bitmode ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
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 ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 06:55:56 +04:00
dev - > open = macsonic_open ;
dev - > stop = macsonic_close ;
2005-04-17 02:20:36 +04:00
dev - > hard_start_xmit = sonic_send_packet ;
dev - > get_stats = sonic_get_stats ;
dev - > set_multicast_list = & sonic_multicast_list ;
2005-08-20 09:53:22 +04:00
dev - > tx_timeout = sonic_tx_timeout ;
dev - > watchdog_timeo = TX_TIMEOUT ;
2005-04-17 02:20:36 +04:00
/*
* clear tally counter
*/
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_CRCT , 0xffff ) ;
SONIC_WRITE ( SONIC_FAET , 0xffff ) ;
SONIC_WRITE ( SONIC_MPT , 0xffff ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
int __init mac_onboard_sonic_ethernet_addr ( struct net_device * dev )
{
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
const int prom_addr = ONBOARD_SONIC_PROM_BASE ;
int i ;
/* On NuBus boards we can sometimes look in the ROM resources.
No such luck for comm - slot / onboard . */
for ( i = 0 ; i < 6 ; i + + )
dev - > dev_addr [ i ] = SONIC_READ_PROM ( i ) ;
/* Most of the time, the address is bit-reversed. The NetBSD
source has a rather long and detailed historical account of
why this is so . */
if ( memcmp ( dev - > dev_addr , " \x08 \x00 \x07 " , 3 ) & &
memcmp ( dev - > dev_addr , " \x00 \xA0 \x40 " , 3 ) & &
2005-08-20 09:53:22 +04:00
memcmp ( dev - > dev_addr , " \x00 \x80 \x19 " , 3 ) & &
2005-04-17 02:20:36 +04:00
memcmp ( dev - > dev_addr , " \x00 \x05 \x02 " , 3 ) )
bit_reverse_addr ( dev - > dev_addr ) ;
else
return 0 ;
/* If we still have what seems to be a bogus address, we'll
look in the CAM . The top entry should be ours . */
/* Danger! This only works if MacOS has already initialized
the card . . . */
if ( memcmp ( dev - > dev_addr , " \x08 \x00 \x07 " , 3 ) & &
memcmp ( dev - > dev_addr , " \x00 \xA0 \x40 " , 3 ) & &
2005-08-20 09:53:22 +04:00
memcmp ( dev - > dev_addr , " \x00 \x80 \x19 " , 3 ) & &
2005-04-17 02:20:36 +04:00
memcmp ( dev - > dev_addr , " \x00 \x05 \x02 " , 3 ) )
{
unsigned short val ;
printk ( KERN_INFO " macsonic: PROM seems to be wrong, trying CAM entry 15 \n " ) ;
2006-09-13 21:24:59 +04:00
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_CMD , SONIC_CR_RST ) ;
SONIC_WRITE ( SONIC_CEP , 15 ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
val = SONIC_READ ( SONIC_CAP2 ) ;
2005-04-17 02:20:36 +04:00
dev - > dev_addr [ 5 ] = val > > 8 ;
dev - > dev_addr [ 4 ] = val & 0xff ;
2005-08-20 09:53:22 +04:00
val = SONIC_READ ( SONIC_CAP1 ) ;
2005-04-17 02:20:36 +04:00
dev - > dev_addr [ 3 ] = val > > 8 ;
dev - > dev_addr [ 2 ] = val & 0xff ;
2005-08-20 09:53:22 +04:00
val = SONIC_READ ( SONIC_CAP0 ) ;
2005-04-17 02:20:36 +04:00
dev - > dev_addr [ 1 ] = val > > 8 ;
dev - > dev_addr [ 0 ] = val & 0xff ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " HW Address from CAM 15: " ) ;
for ( i = 0 ; i < 6 ; i + + ) {
printk ( " %2.2x " , dev - > dev_addr [ i ] ) ;
if ( i < 5 )
printk ( " : " ) ;
}
printk ( " \n " ) ;
} else return 0 ;
if ( memcmp ( dev - > dev_addr , " \x08 \x00 \x07 " , 3 ) & &
memcmp ( dev - > dev_addr , " \x00 \xA0 \x40 " , 3 ) & &
2005-08-20 09:53:22 +04:00
memcmp ( dev - > dev_addr , " \x00 \x80 \x19 " , 3 ) & &
2005-04-17 02:20:36 +04:00
memcmp ( dev - > dev_addr , " \x00 \x05 \x02 " , 3 ) )
{
/*
* Still nonsense . . . messed up someplace !
*/
printk ( KERN_ERR " macsonic: ERROR (INVALID MAC) \n " ) ;
return - EIO ;
} else return 0 ;
}
int __init mac_onboard_sonic_probe ( struct net_device * dev )
{
/* Bwahahaha */
static int once_is_more_than_enough ;
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
int sr ;
int commslot = 0 ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
if ( once_is_more_than_enough )
return - ENODEV ;
once_is_more_than_enough = 1 ;
if ( ! MACH_IS_MAC )
return - ENODEV ;
if ( macintosh_config - > ether_type ! = MAC_ETHER_SONIC )
return - ENODEV ;
2006-09-13 21:24:59 +04:00
2005-08-20 09:53:22 +04:00
printk ( KERN_INFO " Checking for internal Macintosh ethernet (SONIC).. " ) ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
/* Bogus probing, on the models which may or may not have
Ethernet ( BTW , the Ethernet * is * always at the same
address , and nothing else lives there , at least if Apple ' s
documentation is to be believed ) */
if ( macintosh_config - > ident = = MAC_MODEL_Q630 | |
macintosh_config - > ident = = MAC_MODEL_P588 | |
2005-08-20 09:53:22 +04:00
macintosh_config - > ident = = MAC_MODEL_P575 | |
2005-04-17 02:20:36 +04:00
macintosh_config - > ident = = MAC_MODEL_C610 ) {
unsigned long flags ;
int card_present ;
local_irq_save ( flags ) ;
card_present = hwreg_present ( ( void * ) ONBOARD_SONIC_REGISTERS ) ;
local_irq_restore ( flags ) ;
if ( ! card_present ) {
printk ( " none. \n " ) ;
return - ENODEV ;
}
2005-08-20 09:53:22 +04:00
commslot = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-09-13 21:24:59 +04:00
printk ( " yes \n " ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev - > base_addr before using SONIC_READ ( ) or SONIC_WRITE ( ) */
2005-04-17 02:20:36 +04:00
dev - > base_addr = ONBOARD_SONIC_REGISTERS ;
if ( via_alt_mapping )
dev - > irq = IRQ_AUTO_3 ;
else
dev - > irq = IRQ_NUBUS_9 ;
if ( ! sonic_version_printed ) {
printk ( KERN_INFO " %s " , version ) ;
sonic_version_printed = 1 ;
}
printk ( KERN_INFO " %s: onboard / comm-slot SONIC at 0x%08lx \n " ,
2005-08-20 09:53:22 +04:00
lp - > device - > bus_id , dev - > base_addr ) ;
2005-04-17 02:20:36 +04:00
/* The PowerBook's SONIC is 16 bit always. */
if ( macintosh_config - > ident = = MAC_MODEL_PB520 ) {
2005-08-20 09:53:22 +04:00
lp - > reg_offset = 0 ;
lp - > dma_bitmode = SONIC_BITMODE16 ;
sr = SONIC_READ ( SONIC_SR ) ;
} else if ( commslot ) {
2005-04-17 02:20:36 +04:00
/* Some of the comm-slot cards are 16 bit. But some
2005-08-20 09:53:22 +04:00
of them are not . The 32 - bit cards use offset 2 and
have known revisions , we try reading the revision
register at offset 2 , if we don ' t get a known revision
we assume 16 bit at offset 0. */
lp - > reg_offset = 2 ;
lp - > dma_bitmode = SONIC_BITMODE16 ;
sr = SONIC_READ ( SONIC_SR ) ;
2006-09-13 21:24:59 +04:00
if ( sr = = 0x0004 | | sr = = 0x0006 | | sr = = 0x0100 | | sr = = 0x0101 )
2005-08-20 09:53:22 +04:00
/* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
lp - > dma_bitmode = SONIC_BITMODE32 ;
else {
lp - > dma_bitmode = SONIC_BITMODE16 ;
lp - > reg_offset = 0 ;
sr = SONIC_READ ( SONIC_SR ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-20 09:53:22 +04:00
} else {
/* All onboard cards are at offset 2 with 32 bit DMA. */
lp - > reg_offset = 2 ;
lp - > dma_bitmode = SONIC_BITMODE32 ;
sr = SONIC_READ ( SONIC_SR ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-20 09:53:22 +04:00
printk ( KERN_INFO
" %s: revision 0x%04x, using %d bit DMA and register offset %d \n " ,
lp - > device - > bus_id , sr , lp - > dma_bitmode ? 32 : 16 , lp - > reg_offset ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk ( KERN_INFO " %s: DCR: 0x%04x, DCR2: 0x%04x \n " , lp - > device - > bus_id ,
SONIC_READ ( SONIC_DCR ) & 0xffff , SONIC_READ ( SONIC_DCR2 ) & 0xffff ) ;
# endif
2005-04-17 02:20:36 +04:00
/* Software reset, then initialize control registers. */
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_CMD , SONIC_CR_RST ) ;
SONIC_WRITE ( SONIC_DCR , SONIC_DCR_EXBUS | SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
( lp - > dma_bitmode ? SONIC_DCR_DW : 0 ) ) ;
2005-04-17 02:20:36 +04:00
/* This *must* be written back to in order to restore the
2005-08-20 09:53:22 +04:00
* extended programmable output bits , as it may not have been
* initialised since the hardware reset . */
SONIC_WRITE ( SONIC_DCR2 , 0 ) ;
2005-04-17 02:20:36 +04:00
/* Clear *and* disable interrupts to be on the safe side */
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_IMR , 0 ) ;
SONIC_WRITE ( SONIC_ISR , 0x7fff ) ;
2005-04-17 02:20:36 +04:00
/* Now look for the MAC address. */
if ( mac_onboard_sonic_ethernet_addr ( dev ) ! = 0 )
return - ENODEV ;
/* Shared init code */
return macsonic_init ( dev ) ;
}
int __init mac_nubus_sonic_ethernet_addr ( struct net_device * dev ,
unsigned long prom_addr ,
int id )
{
int i ;
for ( i = 0 ; i < 6 ; i + + )
dev - > dev_addr [ i ] = SONIC_READ_PROM ( i ) ;
2005-08-20 09:53:22 +04:00
/* Some of the addresses are bit-reversed */
if ( id ! = MACSONIC_DAYNA )
bit_reverse_addr ( dev - > dev_addr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
int __init macsonic_ident ( struct nubus_dev * ndev )
{
2006-09-13 21:24:59 +04:00
if ( ndev - > dr_hw = = NUBUS_DRHW_ASANTE_LC & &
2005-04-17 02:20:36 +04:00
ndev - > dr_sw = = NUBUS_DRSW_SONIC_LC )
return MACSONIC_DAYNALINK ;
if ( ndev - > dr_hw = = NUBUS_DRHW_SONIC & &
ndev - > dr_sw = = NUBUS_DRSW_APPLE ) {
/* There has to be a better way to do this... */
if ( strstr ( ndev - > board - > name , " DuoDock " ) )
return MACSONIC_DUODOCK ;
else
return MACSONIC_APPLE ;
}
2006-09-13 21:24:59 +04:00
2005-08-20 09:53:22 +04:00
if ( ndev - > dr_hw = = NUBUS_DRHW_SMC9194 & &
ndev - > dr_sw = = NUBUS_DRSW_DAYNA )
return MACSONIC_DAYNA ;
2006-09-13 21:24:59 +04:00
2007-05-02 00:32:53 +04:00
if ( ndev - > dr_hw = = NUBUS_DRHW_APPLE_SONIC_LC & &
2005-08-20 09:53:22 +04:00
ndev - > dr_sw = = 0 ) { /* huh? */
return MACSONIC_APPLE16 ;
}
2005-04-17 02:20:36 +04:00
return - 1 ;
}
int __init mac_nubus_sonic_probe ( struct net_device * dev )
{
static int slots ;
struct nubus_dev * ndev = NULL ;
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
unsigned long base_addr , prom_addr ;
u16 sonic_dcr ;
2005-08-20 09:53:22 +04:00
int id = - 1 ;
int reg_offset , dma_bitmode ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
/* Find the first SONIC that hasn't been initialized already */
while ( ( ndev = nubus_find_type ( NUBUS_CAT_NETWORK ,
NUBUS_TYPE_ETHERNET , ndev ) ) ! = NULL )
{
/* Have we seen it already? */
if ( slots & ( 1 < < ndev - > board - > slot ) )
continue ;
slots | = 1 < < ndev - > board - > slot ;
/* Is it one of ours? */
if ( ( id = macsonic_ident ( ndev ) ) ! = - 1 )
break ;
}
if ( ndev = = NULL )
return - ENODEV ;
switch ( id ) {
case MACSONIC_DUODOCK :
base_addr = ndev - > board - > slot_addr + DUODOCK_SONIC_REGISTERS ;
prom_addr = ndev - > board - > slot_addr + DUODOCK_SONIC_PROM_BASE ;
2005-08-20 09:53:22 +04:00
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 |
SONIC_DCR_TFT0 ;
2005-04-17 02:20:36 +04:00
reg_offset = 2 ;
2005-08-20 09:53:22 +04:00
dma_bitmode = SONIC_BITMODE32 ;
2005-04-17 02:20:36 +04:00
break ;
case MACSONIC_APPLE :
base_addr = ndev - > board - > slot_addr + APPLE_SONIC_REGISTERS ;
prom_addr = ndev - > board - > slot_addr + APPLE_SONIC_PROM_BASE ;
sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 ;
reg_offset = 0 ;
2005-08-20 09:53:22 +04:00
dma_bitmode = SONIC_BITMODE32 ;
2005-04-17 02:20:36 +04:00
break ;
case MACSONIC_APPLE16 :
base_addr = ndev - > board - > slot_addr + APPLE_SONIC_REGISTERS ;
prom_addr = ndev - > board - > slot_addr + APPLE_SONIC_PROM_BASE ;
2005-08-20 09:53:22 +04:00
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
2006-09-13 21:24:59 +04:00
SONIC_DCR_PO1 | SONIC_DCR_BMS ;
2005-04-17 02:20:36 +04:00
reg_offset = 0 ;
2005-08-20 09:53:22 +04:00
dma_bitmode = SONIC_BITMODE16 ;
2005-04-17 02:20:36 +04:00
break ;
case MACSONIC_DAYNALINK :
base_addr = ndev - > board - > slot_addr + APPLE_SONIC_REGISTERS ;
prom_addr = ndev - > board - > slot_addr + DAYNALINK_PROM_BASE ;
2005-08-20 09:53:22 +04:00
sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
2006-09-13 21:24:59 +04:00
SONIC_DCR_PO1 | SONIC_DCR_BMS ;
2005-04-17 02:20:36 +04:00
reg_offset = 0 ;
2005-08-20 09:53:22 +04:00
dma_bitmode = SONIC_BITMODE16 ;
2005-04-17 02:20:36 +04:00
break ;
case MACSONIC_DAYNA :
base_addr = ndev - > board - > slot_addr + DAYNA_SONIC_REGISTERS ;
prom_addr = ndev - > board - > slot_addr + DAYNA_SONIC_MAC_ADDR ;
2005-08-20 09:53:22 +04:00
sonic_dcr = SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 ;
2005-04-17 02:20:36 +04:00
reg_offset = 0 ;
2005-08-20 09:53:22 +04:00
dma_bitmode = SONIC_BITMODE16 ;
2005-04-17 02:20:36 +04:00
break ;
default :
printk ( KERN_ERR " macsonic: WTF, id is %d \n " , id ) ;
return - ENODEV ;
}
2005-08-20 09:53:22 +04:00
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev - > base_addr before using SONIC_READ ( ) or SONIC_WRITE ( ) */
2005-04-17 02:20:36 +04:00
dev - > base_addr = base_addr ;
2005-08-20 09:53:22 +04:00
lp - > reg_offset = reg_offset ;
lp - > dma_bitmode = dma_bitmode ;
2005-04-17 02:20:36 +04:00
dev - > irq = SLOT2IRQ ( ndev - > board - > slot ) ;
if ( ! sonic_version_printed ) {
printk ( KERN_INFO " %s " , version ) ;
sonic_version_printed = 1 ;
}
printk ( KERN_INFO " %s: %s in slot %X \n " ,
2005-08-20 09:53:22 +04:00
lp - > device - > bus_id , ndev - > board - > name , ndev - > board - > slot ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " %s: revision 0x%04x, using %d bit DMA and register offset %d \n " ,
2005-08-20 09:53:22 +04:00
lp - > device - > bus_id , SONIC_READ ( SONIC_SR ) , dma_bitmode ? 32 : 16 , reg_offset ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk ( KERN_INFO " %s: DCR: 0x%04x, DCR2: 0x%04x \n " , lp - > device - > bus_id ,
SONIC_READ ( SONIC_DCR ) & 0xffff , SONIC_READ ( SONIC_DCR2 ) & 0xffff ) ;
# endif
2005-04-17 02:20:36 +04:00
/* Software reset, then initialize control registers. */
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_CMD , SONIC_CR_RST ) ;
SONIC_WRITE ( SONIC_DCR , sonic_dcr | ( dma_bitmode ? SONIC_DCR_DW : 0 ) ) ;
/* This *must* be written back to in order to restore the
* extended programmable output bits , since it may not have been
* initialised since the hardware reset . */
SONIC_WRITE ( SONIC_DCR2 , 0 ) ;
2005-04-17 02:20:36 +04:00
/* Clear *and* disable interrupts to be on the safe side */
2005-08-20 09:53:22 +04:00
SONIC_WRITE ( SONIC_IMR , 0 ) ;
SONIC_WRITE ( SONIC_ISR , 0x7fff ) ;
2005-04-17 02:20:36 +04:00
/* Now look for the MAC address. */
if ( mac_nubus_sonic_ethernet_addr ( dev , prom_addr , id ) ! = 0 )
return - ENODEV ;
2005-08-20 09:53:22 +04:00
/* Shared init code */
return macsonic_init ( dev ) ;
}
2007-05-02 00:33:02 +04:00
static int __init mac_sonic_probe ( struct platform_device * pdev )
2005-08-20 09:53:22 +04:00
{
struct net_device * dev ;
struct sonic_local * lp ;
int err ;
int i ;
dev = alloc_etherdev ( sizeof ( struct sonic_local ) ) ;
if ( ! dev )
return - ENOMEM ;
lp = netdev_priv ( dev ) ;
2007-05-02 00:33:02 +04:00
lp - > device = & pdev - > dev ;
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
2005-08-20 09:53:22 +04:00
SET_MODULE_OWNER ( dev ) ;
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe ( dev ) ;
if ( err = = 0 )
goto found ;
if ( err ! = - ENODEV )
goto out ;
err = mac_nubus_sonic_probe ( dev ) ;
if ( err )
goto out ;
found :
err = register_netdev ( dev ) ;
if ( err )
goto out ;
printk ( " %s: MAC " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 6 ; i + + ) {
printk ( " %2.2x " , dev - > dev_addr [ i ] ) ;
if ( i < 5 )
printk ( " : " ) ;
}
printk ( " IRQ %d \n " , dev - > irq ) ;
2005-08-20 09:53:22 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
out :
free_netdev ( dev ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 09:53:22 +04:00
return err ;
}
MODULE_DESCRIPTION ( " Macintosh SONIC ethernet driver " ) ;
module_param ( sonic_debug , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( sonic_debug , " macsonic debug level (1-4) " ) ;
2005-08-20 09:53:22 +04:00
# include "sonic.c"
2007-05-02 00:33:02 +04:00
static int __devexit mac_sonic_device_remove ( struct platform_device * pdev )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:33:02 +04:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2005-08-20 09:53:22 +04:00
struct sonic_local * lp = netdev_priv ( dev ) ;
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 ) ;
2007-05-02 00:33:02 +04:00
free_netdev ( dev ) ;
2005-08-20 09:53:22 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-11-10 01:32:44 +03:00
static struct platform_driver mac_sonic_driver = {
2005-08-20 09:53:22 +04:00
. probe = mac_sonic_probe ,
. remove = __devexit_p ( mac_sonic_device_remove ) ,
2005-11-10 01:32:44 +03:00
. driver = {
. name = mac_sonic_string ,
} ,
2005-08-20 09:53:22 +04:00
} ;
static int __init mac_sonic_init_module ( void )
{
int err ;
2005-04-17 02:20:36 +04:00
2005-11-10 01:32:44 +03:00
if ( ( err = platform_driver_register ( & mac_sonic_driver ) ) ) {
2005-08-20 09:53:22 +04:00
printk ( KERN_ERR " Driver registration failed \n " ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
2005-11-06 00:21:10 +03:00
mac_sonic_device = platform_device_alloc ( mac_sonic_string , 0 ) ;
2007-05-02 00:33:02 +04:00
if ( ! mac_sonic_device )
2005-08-20 09:53:22 +04:00
goto out_unregister ;
2005-04-17 02:20:36 +04:00
2005-11-06 00:21:10 +03:00
if ( platform_device_add ( mac_sonic_device ) ) {
platform_device_put ( mac_sonic_device ) ;
2005-08-20 09:53:22 +04:00
mac_sonic_device = NULL ;
}
return 0 ;
out_unregister :
2005-12-04 10:28:40 +03:00
platform_driver_unregister ( & mac_sonic_driver ) ;
2005-08-20 09:53:22 +04:00
return - ENOMEM ;
}
static void __exit mac_sonic_cleanup_module ( void )
{
2005-11-10 01:32:44 +03:00
platform_driver_unregister ( & mac_sonic_driver ) ;
2005-08-20 09:53:22 +04:00
if ( mac_sonic_device ) {
platform_device_unregister ( mac_sonic_device ) ;
mac_sonic_device = NULL ;
}
}
module_init ( mac_sonic_init_module ) ;
module_exit ( mac_sonic_cleanup_module ) ;