2005-04-17 02:20:36 +04:00
/*
*
* Alchemy Au1x00 ethernet driver
*
2006-04-19 22:46:21 +04:00
* Copyright 2001 - 2003 , 2006 MontaVista Software Inc .
2005-04-17 02:20:36 +04:00
* Copyright 2002 TimeSys Corp .
* Added ethtool / mii - tool support ,
* Copyright 2004 Matt Porter < mporter @ kernel . crashing . org >
2006-09-13 21:24:59 +04:00
* Update : 2004 Bjoern Riemer , riemer @ fokus . fraunhofer . de
* or riemer @ riemer - nt . de : fixed the link beat detection with
2005-04-17 02:20:36 +04:00
* ioctls ( SIOCGMIIPHY )
2006-06-01 11:41:04 +04:00
* Copyright 2006 Herbert Valerio Riedel < hvr @ gnu . org >
* converted to use linux - 2.6 . x ' s PHY framework
*
2005-04-17 02:20:36 +04:00
* Author : MontaVista Software , Inc .
* ppopov @ mvista . com or source @ mvista . com
*
* # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License ( Version 2 ) as
* published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston MA 02111 - 1307 , USA .
*
* # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
*
2006-09-13 21:24:59 +04:00
*
2005-04-17 02:20:36 +04:00
*/
2009-10-17 06:00:07 +04:00
# include <linux/capability.h>
2007-06-24 17:59:54 +04:00
# include <linux/dma-mapping.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/errno.h>
# include <linux/in.h>
# include <linux/ioport.h>
# include <linux/bitops.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/ethtool.h>
# include <linux/mii.h>
# include <linux/skbuff.h>
# include <linux/delay.h>
2006-05-01 17:37:09 +04:00
# include <linux/crc32.h>
2006-06-01 11:41:04 +04:00
# include <linux/phy.h>
2009-11-10 03:13:38 +03:00
# include <linux/platform_device.h>
2007-10-15 14:11:24 +04:00
# include <asm/cpu.h>
2005-04-17 02:20:36 +04:00
# include <asm/mipsregs.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/processor.h>
2007-10-15 14:11:24 +04:00
# include <au1000.h>
2009-11-10 03:13:38 +03:00
# include <au1xxx_eth.h>
2007-10-15 14:11:24 +04:00
# include <prom.h>
2005-04-17 02:20:36 +04:00
# include "au1000_eth.h"
# ifdef AU1000_ETH_DEBUG
static int au1000_debug = 5 ;
# else
static int au1000_debug = 3 ;
# endif
2006-04-19 22:46:21 +04:00
# define DRV_NAME "au1000_eth"
2006-09-12 01:39:18 +04:00
# define DRV_VERSION "1.6"
2005-04-17 02:20:36 +04:00
# define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
# define DRV_DESC "Au1xxx on-chip Ethernet driver"
MODULE_AUTHOR ( DRV_AUTHOR ) ;
MODULE_DESCRIPTION ( DRV_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
/*
* Theory of operation
*
2006-09-13 21:24:59 +04:00
* The Au1000 MACs use a simple rx and tx descriptor ring scheme .
* There are four receive and four transmit descriptors . These
* descriptors are not in memory ; rather , they are just a set of
2005-04-17 02:20:36 +04:00
* hardware registers .
*
* Since the Au1000 has a coherent data cache , the receive and
2006-09-13 21:24:59 +04:00
* transmit buffers are allocated from the KSEG0 segment . The
2005-04-17 02:20:36 +04:00
* hardware registers , however , are still mapped at KSEG1 to
* make sure there ' s no out - of - order writes , and that all writes
* complete immediately .
*/
/* These addresses are only used if yamon doesn't tell us what
* the mac address is , and the mac address is not passed on the
* command line .
*/
2006-09-13 21:24:59 +04:00
static unsigned char au1000_mac_addr [ 6 ] __devinitdata = {
2005-04-17 02:20:36 +04:00
0x00 , 0x50 , 0xc2 , 0x0c , 0x30 , 0x00
} ;
struct au1000_private * au_macs [ NUM_ETH_INTERFACES ] ;
2006-06-01 11:41:04 +04:00
/*
* board - specific configurations
*
* PHY detection algorithm
*
2009-11-10 03:13:38 +03:00
* If phy_static_config is undefined , the PHY setup is
2006-06-01 11:41:04 +04:00
* autodetected :
*
* mii_probe ( ) first searches the current MAC ' s MII bus for a PHY ,
2009-11-10 03:13:38 +03:00
* selecting the first ( or last , if phy_search_highest_addr is
2006-06-01 11:41:04 +04:00
* defined ) PHY address not already claimed by another netdev .
*
* If nothing was found that way when searching for the 2 nd ethernet
2009-11-10 03:13:38 +03:00
* controller ' s PHY and phy1_search_mac0 is defined , then
2006-06-01 11:41:04 +04:00
* the first MII bus is searched as well for an unclaimed PHY ; this is
* needed in case of a dual - PHY accessible only through the MAC0 ' s MII
* bus .
*
* Finally , if no PHY is found , then the corresponding ethernet
* controller is not registered to the network subsystem .
2005-04-17 02:20:36 +04:00
*/
2009-11-10 03:13:38 +03:00
/* autodetection defaults: phy1_search_mac0 */
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
/* static PHY setup
*
* most boards PHY setup should be detectable properly with the
* autodetection algorithm in mii_probe ( ) , but in some cases ( e . g . if
* you have a switch attached , or want to use the PHY ' s interrupt
* notification capabilities ) you can provide a static PHY
* configuration here
*
* IRQs may only be set , if a PHY address was configured
* If a PHY address is given , also a bus id is required to be set
*
* ps : make sure the used irqs are configured properly in the board
* specific irq - map
*/
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
static void enable_mac ( struct net_device * dev , int force_reset )
{
unsigned long flags ;
struct au1000_private * aup = netdev_priv ( dev ) ;
spin_lock_irqsave ( & aup - > lock , flags ) ;
if ( force_reset | | ( ! aup - > mac_enabled ) ) {
* aup - > enable = MAC_EN_CLOCK_ENABLE ;
au_sync_delay ( 2 ) ;
* aup - > enable = ( MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
| MAC_EN_CLOCK_ENABLE ) ;
au_sync_delay ( 2 ) ;
aup - > mac_enabled = 1 ;
}
spin_unlock_irqrestore ( & aup - > lock , flags ) ;
}
2006-06-01 11:41:04 +04:00
/*
* MII operations
*/
2008-10-13 08:02:19 +04:00
static int au1000_mdio_read ( struct net_device * dev , int phy_addr , int reg )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2006-06-01 11:41:04 +04:00
volatile u32 * const mii_control_reg = & aup - > mac - > mii_control ;
volatile u32 * const mii_data_reg = & aup - > mac - > mii_data ;
2005-04-17 02:20:36 +04:00
u32 timedout = 20 ;
u32 mii_control ;
while ( * mii_control_reg & MAC_MII_BUSY ) {
mdelay ( 1 ) ;
if ( - - timedout = = 0 ) {
2006-09-13 21:24:59 +04:00
printk ( KERN_ERR " %s: read_MII busy timeout!! \n " ,
2005-04-17 02:20:36 +04:00
dev - > name ) ;
return - 1 ;
}
}
2006-09-13 21:24:59 +04:00
mii_control = MAC_SET_MII_SELECT_REG ( reg ) |
2006-06-01 11:41:04 +04:00
MAC_SET_MII_SELECT_PHY ( phy_addr ) | MAC_MII_READ ;
2005-04-17 02:20:36 +04:00
* mii_control_reg = mii_control ;
timedout = 20 ;
while ( * mii_control_reg & MAC_MII_BUSY ) {
mdelay ( 1 ) ;
if ( - - timedout = = 0 ) {
2006-09-13 21:24:59 +04:00
printk ( KERN_ERR " %s: mdio_read busy timeout!! \n " ,
2005-04-17 02:20:36 +04:00
dev - > name ) ;
return - 1 ;
}
}
return ( int ) * mii_data_reg ;
}
2008-10-13 08:02:19 +04:00
static void au1000_mdio_write ( struct net_device * dev , int phy_addr ,
int reg , u16 value )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2006-06-01 11:41:04 +04:00
volatile u32 * const mii_control_reg = & aup - > mac - > mii_control ;
volatile u32 * const mii_data_reg = & aup - > mac - > mii_data ;
2005-04-17 02:20:36 +04:00
u32 timedout = 20 ;
u32 mii_control ;
while ( * mii_control_reg & MAC_MII_BUSY ) {
mdelay ( 1 ) ;
if ( - - timedout = = 0 ) {
2006-09-13 21:24:59 +04:00
printk ( KERN_ERR " %s: mdio_write busy timeout!! \n " ,
2005-04-17 02:20:36 +04:00
dev - > name ) ;
return ;
}
}
2006-09-13 21:24:59 +04:00
mii_control = MAC_SET_MII_SELECT_REG ( reg ) |
2006-06-01 11:41:04 +04:00
MAC_SET_MII_SELECT_PHY ( phy_addr ) | MAC_MII_WRITE ;
2005-04-17 02:20:36 +04:00
* mii_data_reg = value ;
* mii_control_reg = mii_control ;
}
2008-10-13 08:02:19 +04:00
static int au1000_mdiobus_read ( struct mii_bus * bus , int phy_addr , int regnum )
2006-06-01 11:41:04 +04:00
{
/* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
* _NOT_ hold ( e . g . when PHY is accessed through other MAC ' s MII bus ) */
struct net_device * const dev = bus - > priv ;
enable_mac ( dev , 0 ) ; /* make sure the MAC associated with this
* mii_bus is enabled */
2008-10-13 08:02:19 +04:00
return au1000_mdio_read ( dev , phy_addr , regnum ) ;
2006-06-01 11:41:04 +04:00
}
2005-04-17 02:20:36 +04:00
2008-10-13 08:02:19 +04:00
static int au1000_mdiobus_write ( struct mii_bus * bus , int phy_addr , int regnum ,
u16 value )
2005-04-17 02:20:36 +04:00
{
2006-06-01 11:41:04 +04:00
struct net_device * const dev = bus - > priv ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
enable_mac ( dev , 0 ) ; /* make sure the MAC associated with this
* mii_bus is enabled */
2008-10-13 08:02:19 +04:00
au1000_mdio_write ( dev , phy_addr , regnum , value ) ;
2006-06-01 11:41:04 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-10-13 08:02:19 +04:00
static int au1000_mdiobus_reset ( struct mii_bus * bus )
2005-04-17 02:20:36 +04:00
{
2006-06-01 11:41:04 +04:00
struct net_device * const dev = bus - > priv ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
enable_mac ( dev , 0 ) ; /* make sure the MAC associated with this
* mii_bus is enabled */
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
static void hard_stop ( struct net_device * dev )
{
struct au1000_private * aup = netdev_priv ( dev ) ;
if ( au1000_debug > 4 )
printk ( KERN_INFO " %s: hard stop \n " , dev - > name ) ;
aup - > mac - > control & = ~ ( MAC_RX_ENABLE | MAC_TX_ENABLE ) ;
au_sync_delay ( 10 ) ;
}
static void enable_rx_tx ( struct net_device * dev )
{
struct au1000_private * aup = netdev_priv ( dev ) ;
if ( au1000_debug > 4 )
printk ( KERN_INFO " %s: enable_rx_tx \n " , dev - > name ) ;
aup - > mac - > control | = ( MAC_RX_ENABLE | MAC_TX_ENABLE ) ;
au_sync_delay ( 10 ) ;
}
static void
au1000_adjust_link ( struct net_device * dev )
{
struct au1000_private * aup = netdev_priv ( dev ) ;
struct phy_device * phydev = aup - > phy_dev ;
unsigned long flags ;
int status_change = 0 ;
BUG_ON ( ! aup - > phy_dev ) ;
spin_lock_irqsave ( & aup - > lock , flags ) ;
if ( phydev - > link & & ( aup - > old_speed ! = phydev - > speed ) ) {
// speed changed
switch ( phydev - > speed ) {
case SPEED_10 :
case SPEED_100 :
break ;
default :
printk ( KERN_WARNING
" %s: Speed (%d) is not 10/100 ??? \n " ,
dev - > name , phydev - > speed ) ;
break ;
}
aup - > old_speed = phydev - > speed ;
status_change = 1 ;
}
if ( phydev - > link & & ( aup - > old_duplex ! = phydev - > duplex ) ) {
// duplex mode changed
/* switching duplex mode requires to disable rx and tx! */
hard_stop ( dev ) ;
if ( DUPLEX_FULL = = phydev - > duplex )
aup - > mac - > control = ( ( aup - > mac - > control
| MAC_FULL_DUPLEX )
& ~ MAC_DISABLE_RX_OWN ) ;
else
aup - > mac - > control = ( ( aup - > mac - > control
& ~ MAC_FULL_DUPLEX )
| MAC_DISABLE_RX_OWN ) ;
au_sync_delay ( 1 ) ;
enable_rx_tx ( dev ) ;
aup - > old_duplex = phydev - > duplex ;
status_change = 1 ;
}
if ( phydev - > link ! = aup - > old_link ) {
// link state changed
if ( ! phydev - > link ) {
/* link went down */
aup - > old_speed = 0 ;
aup - > old_duplex = - 1 ;
}
aup - > old_link = phydev - > link ;
status_change = 1 ;
}
spin_unlock_irqrestore ( & aup - > lock , flags ) ;
if ( status_change ) {
if ( phydev - > link )
printk ( KERN_INFO " %s: link up (%d/%s) \n " ,
dev - > name , phydev - > speed ,
DUPLEX_FULL = = phydev - > duplex ? " Full " : " Half " ) ;
else
printk ( KERN_INFO " %s: link down \n " , dev - > name ) ;
}
}
2006-06-01 11:41:04 +04:00
static int mii_probe ( struct net_device * dev )
{
2008-11-13 10:37:49 +03:00
struct au1000_private * const aup = netdev_priv ( dev ) ;
2006-06-01 11:41:04 +04:00
struct phy_device * phydev = NULL ;
2009-11-10 03:13:38 +03:00
if ( aup - > phy_static_config ) {
BUG_ON ( aup - > mac_id < 0 | | aup - > mac_id > 1 ) ;
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
if ( aup - > phy_addr )
phydev = aup - > mii_bus - > phy_map [ aup - > phy_addr ] ;
else
printk ( KERN_INFO DRV_NAME " :%s: using PHY-less setup \n " ,
dev - > name ) ;
2006-06-01 11:41:04 +04:00
return 0 ;
2009-11-10 03:13:38 +03:00
} else {
int phy_addr ;
/* find the first (lowest address) PHY on the current MAC's MII bus */
for ( phy_addr = 0 ; phy_addr < PHY_MAX_ADDR ; phy_addr + + )
if ( aup - > mii_bus - > phy_map [ phy_addr ] ) {
phydev = aup - > mii_bus - > phy_map [ phy_addr ] ;
if ( ! aup - > phy_search_highest_addr )
break ; /* break out with first one found */
}
2005-04-17 02:20:36 +04:00
2009-11-10 03:13:38 +03:00
if ( aup - > phy1_search_mac0 ) {
/* try harder to find a PHY */
if ( ! phydev & & ( aup - > mac_id = = 1 ) ) {
/* no PHY found, maybe we have a dual PHY? */
printk ( KERN_INFO DRV_NAME " : no PHY found on MAC1, "
" let's see if it's attached to MAC0... \n " ) ;
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
/* find the first (lowest address) non-attached PHY on
* the MAC0 MII bus */
for ( phy_addr = 0 ; phy_addr < PHY_MAX_ADDR ; phy_addr + + ) {
struct phy_device * const tmp_phydev =
aup - > mii_bus - > phy_map [ phy_addr ] ;
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
if ( aup - > mac_id = = 1 )
break ;
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
if ( ! tmp_phydev )
continue ; /* no PHY here... */
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
if ( tmp_phydev - > attached_dev )
continue ; /* already claimed by MAC0 */
2006-06-01 11:41:04 +04:00
2009-11-10 03:13:38 +03:00
phydev = tmp_phydev ;
break ; /* found it */
}
}
2005-04-17 02:20:36 +04:00
}
}
2006-06-01 11:41:04 +04:00
if ( ! phydev ) {
printk ( KERN_ERR DRV_NAME " :%s: no PHY found \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2006-06-01 11:41:04 +04:00
/* now we are supposed to have a proper phydev, to attach to... */
BUG_ON ( phydev - > attached_dev ) ;
2009-01-27 08:12:58 +03:00
phydev = phy_connect ( dev , dev_name ( & phydev - > dev ) , & au1000_adjust_link ,
0 , PHY_INTERFACE_MODE_MII ) ;
2006-06-01 11:41:04 +04:00
if ( IS_ERR ( phydev ) ) {
printk ( KERN_ERR " %s: Could not attach to PHY \n " , dev - > name ) ;
return PTR_ERR ( phydev ) ;
}
/* mask with MAC supported features */
phydev - > supported & = ( SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full
| SUPPORTED_Autoneg
/* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
| SUPPORTED_MII
| SUPPORTED_TP ) ;
phydev - > advertising = phydev - > supported ;
aup - > old_link = 0 ;
aup - > old_speed = 0 ;
aup - > old_duplex = - 1 ;
aup - > phy_dev = phydev ;
printk ( KERN_INFO " %s: attached PHY driver [%s] "
2009-01-27 08:12:58 +03:00
" (mii_bus:phy_addr=%s, irq=%d) \n " , dev - > name ,
phydev - > drv - > name , dev_name ( & phydev - > dev ) , phydev - > irq ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Buffer allocation / deallocation routines . The buffer descriptor returned
2006-09-13 21:24:59 +04:00
* has the virtual and dma address of a buffer suitable for
2005-04-17 02:20:36 +04:00
* both , receive and transmit operations .
*/
static db_dest_t * GetFreeDB ( struct au1000_private * aup )
{
db_dest_t * pDB ;
pDB = aup - > pDBfree ;
if ( pDB ) {
aup - > pDBfree = pDB - > pnext ;
}
return pDB ;
}
void ReleaseDB ( struct au1000_private * aup , db_dest_t * pDB )
{
db_dest_t * pDBfree = aup - > pDBfree ;
if ( pDBfree )
pDBfree - > pnext = pDB ;
aup - > pDBfree = pDB ;
}
2006-06-01 11:41:04 +04:00
static void reset_mac_unlocked ( struct net_device * dev )
{
2008-11-13 10:37:49 +03:00
struct au1000_private * const aup = netdev_priv ( dev ) ;
2006-06-01 11:41:04 +04:00
int i ;
hard_stop ( dev ) ;
* aup - > enable = MAC_EN_CLOCK_ENABLE ;
au_sync_delay ( 2 ) ;
* aup - > enable = 0 ;
au_sync_delay ( 2 ) ;
2005-04-17 02:20:36 +04:00
aup - > tx_full = 0 ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + ) {
/* reset control bits */
aup - > rx_dma_ring [ i ] - > buff_stat & = ~ 0xf ;
}
for ( i = 0 ; i < NUM_TX_DMA ; i + + ) {
/* reset control bits */
aup - > tx_dma_ring [ i ] - > buff_stat & = ~ 0xf ;
}
2006-06-01 11:41:04 +04:00
aup - > mac_enabled = 0 ;
2005-04-17 02:20:36 +04:00
}
2006-06-01 11:41:04 +04:00
static void reset_mac ( struct net_device * dev )
{
2008-11-13 10:37:49 +03:00
struct au1000_private * const aup = netdev_priv ( dev ) ;
2006-06-01 11:41:04 +04:00
unsigned long flags ;
if ( au1000_debug > 4 )
printk ( KERN_INFO " %s: reset mac, aup %x \n " ,
dev - > name , ( unsigned ) aup ) ;
spin_lock_irqsave ( & aup - > lock , flags ) ;
reset_mac_unlocked ( dev ) ;
spin_unlock_irqrestore ( & aup - > lock , flags ) ;
}
2005-04-17 02:20:36 +04:00
2006-09-13 21:24:59 +04:00
/*
2005-04-17 02:20:36 +04:00
* Setup the receive and transmit " rings " . These pointers are the addresses
* of the rx and tx MAC DMA registers so they are fixed by the hardware - -
* these are not descriptors sitting in memory .
*/
2006-09-13 21:24:59 +04:00
static void
2005-04-17 02:20:36 +04:00
setup_hw_rings ( struct au1000_private * aup , u32 rx_base , u32 tx_base )
{
int i ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + ) {
2006-09-13 21:24:59 +04:00
aup - > rx_dma_ring [ i ] =
2005-04-17 02:20:36 +04:00
( volatile rx_dma_t * ) ( rx_base + sizeof ( rx_dma_t ) * i ) ;
}
for ( i = 0 ; i < NUM_TX_DMA ; i + + ) {
2006-09-13 21:24:59 +04:00
aup - > tx_dma_ring [ i ] =
2005-04-17 02:20:36 +04:00
( volatile tx_dma_t * ) ( tx_base + sizeof ( tx_dma_t ) * i ) ;
}
}
2006-06-01 11:41:04 +04:00
/*
* ethtool operations
*/
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
static int au1000_get_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
if ( aup - > phy_dev )
return phy_ethtool_gset ( aup - > phy_dev , cmd ) ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2006-06-01 11:41:04 +04:00
static int au1000_set_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
if ( ! capable ( CAP_NET_ADMIN ) )
return - EPERM ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
if ( aup - > phy_dev )
return phy_ethtool_sset ( aup - > phy_dev , cmd ) ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
static void
au1000_get_drvinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
strcpy ( info - > driver , DRV_NAME ) ;
strcpy ( info - > version , DRV_VERSION ) ;
info - > fw_version [ 0 ] = ' \0 ' ;
sprintf ( info - > bus_info , " %s %d " , DRV_NAME , aup - > mac_id ) ;
info - > regdump_len = 0 ;
}
2006-09-13 22:30:00 +04:00
static const struct ethtool_ops au1000_ethtool_ops = {
2005-04-17 02:20:36 +04:00
. get_settings = au1000_get_settings ,
. set_settings = au1000_set_settings ,
. get_drvinfo = au1000_get_drvinfo ,
2006-06-01 11:41:04 +04:00
. get_link = ethtool_op_get_link ,
2005-04-17 02:20:36 +04:00
} ;
2009-01-23 01:06:25 +03:00
/*
* Initialize the interface .
*
* When the device powers up , the clocks are disabled and the
* mac is in reset state . When the interface is closed , we
* do the same - - reset the device and disable the clocks to
* conserve power . Thus , whenever au1000_init ( ) is called ,
* the device should already be in reset state .
*/
static int au1000_init ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2009-01-23 01:06:25 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
unsigned long flags ;
int i ;
u32 control ;
2006-04-19 22:46:21 +04:00
2009-01-23 01:06:25 +03:00
if ( au1000_debug > 4 )
printk ( " %s: au1000_init \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
/* bring the device out of reset */
enable_mac ( dev , 1 ) ;
2006-04-19 22:46:21 +04:00
2009-01-23 01:06:25 +03:00
spin_lock_irqsave ( & aup - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
aup - > mac - > control = 0 ;
aup - > tx_head = ( aup - > tx_dma_ring [ 0 ] - > buff_stat & 0xC ) > > 2 ;
aup - > tx_tail = aup - > tx_head ;
aup - > rx_head = ( aup - > rx_dma_ring [ 0 ] - > buff_stat & 0xC ) > > 2 ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
aup - > mac - > mac_addr_high = dev - > dev_addr [ 5 ] < < 8 | dev - > dev_addr [ 4 ] ;
aup - > mac - > mac_addr_low = dev - > dev_addr [ 3 ] < < 24 | dev - > dev_addr [ 2 ] < < 16 |
dev - > dev_addr [ 1 ] < < 8 | dev - > dev_addr [ 0 ] ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + ) {
aup - > rx_dma_ring [ i ] - > buff_stat | = RX_DMA_ENABLE ;
2005-04-17 02:20:36 +04:00
}
2009-01-23 01:06:25 +03:00
au_sync ( ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
control = MAC_RX_ENABLE | MAC_TX_ENABLE ;
# ifndef CONFIG_CPU_LITTLE_ENDIAN
control | = MAC_BIG_ENDIAN ;
# endif
if ( aup - > phy_dev ) {
if ( aup - > phy_dev - > link & & ( DUPLEX_FULL = = aup - > phy_dev - > duplex ) )
control | = MAC_FULL_DUPLEX ;
else
control | = MAC_DISABLE_RX_OWN ;
} else { /* PHY-less op, assume full-duplex */
control | = MAC_FULL_DUPLEX ;
2005-04-17 02:20:36 +04:00
}
2009-01-23 01:06:25 +03:00
aup - > mac - > control = control ;
aup - > mac - > vlan1_tag = 0x8100 ; /* activate vlan support */
au_sync ( ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
spin_unlock_irqrestore ( & aup - > lock , flags ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
static inline void update_rx_stats ( struct net_device * dev , u32 status )
{
struct net_device_stats * ps = & dev - > stats ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
ps - > rx_packets + + ;
if ( status & RX_MCAST_FRAME )
ps - > multicast + + ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
if ( status & RX_ERROR ) {
ps - > rx_errors + + ;
if ( status & RX_MISSED_FRAME )
ps - > rx_missed_errors + + ;
2009-10-06 13:54:18 +04:00
if ( status & ( RX_OVERLEN | RX_RUNT | RX_LEN_ERROR ) )
2009-01-23 01:06:25 +03:00
ps - > rx_length_errors + + ;
if ( status & RX_CRC_ERROR )
ps - > rx_crc_errors + + ;
if ( status & RX_COLL )
ps - > collisions + + ;
2008-10-09 03:29:57 +04:00
}
2009-01-23 01:06:25 +03:00
else
ps - > rx_bytes + = status & RX_FRAME_LEN_MASK ;
2008-10-09 03:29:57 +04:00
2005-04-17 02:20:36 +04:00
}
2006-09-13 21:24:59 +04:00
/*
2009-01-23 01:06:25 +03:00
* Au1000 receive routine .
2005-04-17 02:20:36 +04:00
*/
2009-01-23 01:06:25 +03:00
static int au1000_rx ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2009-01-23 01:06:25 +03:00
struct sk_buff * skb ;
volatile rx_dma_t * prxd ;
u32 buff_stat , status ;
db_dest_t * pDB ;
u32 frmlen ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
if ( au1000_debug > 5 )
printk ( " %s: au1000_rx head %d \n " , dev - > name , aup - > rx_head ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
prxd = aup - > rx_dma_ring [ aup - > rx_head ] ;
buff_stat = prxd - > buff_stat ;
while ( buff_stat & RX_T_DONE ) {
status = prxd - > status ;
pDB = aup - > rx_db_inuse [ aup - > rx_head ] ;
update_rx_stats ( dev , status ) ;
if ( ! ( status & RX_ERROR ) ) {
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
/* good frame */
frmlen = ( status & RX_FRAME_LEN_MASK ) ;
frmlen - = 4 ; /* Remove FCS */
skb = dev_alloc_skb ( frmlen + 2 ) ;
if ( skb = = NULL ) {
printk ( KERN_ERR
" %s: Memory squeeze, dropping packet. \n " ,
dev - > name ) ;
dev - > stats . rx_dropped + + ;
continue ;
}
skb_reserve ( skb , 2 ) ; /* 16 byte IP header align */
skb_copy_to_linear_data ( skb ,
( unsigned char * ) pDB - > vaddr , frmlen ) ;
skb_put ( skb , frmlen ) ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
netif_rx ( skb ) ; /* pass the packet to upper layers */
}
else {
if ( au1000_debug > 4 ) {
if ( status & RX_MISSED_FRAME )
printk ( " rx miss \n " ) ;
if ( status & RX_WDOG_TIMER )
printk ( " rx wdog \n " ) ;
if ( status & RX_RUNT )
printk ( " rx runt \n " ) ;
if ( status & RX_OVERLEN )
printk ( " rx overlen \n " ) ;
if ( status & RX_COLL )
printk ( " rx coll \n " ) ;
if ( status & RX_MII_ERROR )
printk ( " rx mii error \n " ) ;
if ( status & RX_CRC_ERROR )
printk ( " rx crc error \n " ) ;
if ( status & RX_LEN_ERROR )
printk ( " rx len error \n " ) ;
if ( status & RX_U_CNTRL_FRAME )
printk ( " rx u control frame \n " ) ;
}
}
prxd - > buff_stat = ( u32 ) ( pDB - > dma_addr | RX_DMA_ENABLE ) ;
aup - > rx_head = ( aup - > rx_head + 1 ) & ( NUM_RX_DMA - 1 ) ;
au_sync ( ) ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
/* next descriptor */
prxd = aup - > rx_dma_ring [ aup - > rx_head ] ;
buff_stat = prxd - > buff_stat ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2009-01-23 01:06:25 +03:00
static void update_tx_stats ( struct net_device * dev , u32 status )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2009-01-23 01:06:25 +03:00
struct net_device_stats * ps = & dev - > stats ;
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
if ( status & TX_FRAME_ABORTED ) {
if ( ! aup - > phy_dev | | ( DUPLEX_FULL = = aup - > phy_dev - > duplex ) ) {
if ( status & ( TX_JAB_TIMEOUT | TX_UNDERRUN ) ) {
/* any other tx errors are only valid
* in half duplex mode */
ps - > tx_errors + + ;
ps - > tx_aborted_errors + + ;
}
2005-04-17 02:20:36 +04:00
}
2009-01-23 01:06:25 +03:00
else {
ps - > tx_errors + + ;
ps - > tx_aborted_errors + + ;
if ( status & ( TX_NO_CARRIER | TX_LOSS_CARRIER ) )
ps - > tx_carrier_errors + + ;
}
}
}
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
/*
* Called from the interrupt service routine to acknowledge
* the TX DONE bits . This is a must if the irq is setup as
* edge triggered .
*/
static void au1000_tx_ack ( struct net_device * dev )
{
struct au1000_private * aup = netdev_priv ( dev ) ;
volatile tx_dma_t * ptxd ;
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
ptxd = aup - > tx_dma_ring [ aup - > tx_tail ] ;
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
while ( ptxd - > buff_stat & TX_T_DONE ) {
update_tx_stats ( dev , ptxd - > status ) ;
ptxd - > buff_stat & = ~ TX_T_DONE ;
ptxd - > len = 0 ;
au_sync ( ) ;
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
aup - > tx_tail = ( aup - > tx_tail + 1 ) & ( NUM_TX_DMA - 1 ) ;
ptxd = aup - > tx_dma_ring [ aup - > tx_tail ] ;
2006-06-01 11:41:04 +04:00
2009-01-23 01:06:25 +03:00
if ( aup - > tx_full ) {
aup - > tx_full = 0 ;
netif_wake_queue ( dev ) ;
}
2005-04-17 02:20:36 +04:00
}
2009-01-23 01:06:25 +03:00
}
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
/*
* Au1000 interrupt service routine .
*/
static irqreturn_t au1000_interrupt ( int irq , void * dev_id )
{
struct net_device * dev = dev_id ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
/* Handle RX interrupts first to minimize chance of overrun */
au1000_rx ( dev ) ;
au1000_tx_ack ( dev ) ;
return IRQ_RETVAL ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
static int au1000_open ( struct net_device * dev )
{
int retval ;
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( au1000_debug > 4 )
printk ( " %s: open: dev=%p \n " , dev - > name , dev ) ;
2009-11-19 10:29:17 +03:00
if ( ( retval = request_irq ( dev - > irq , au1000_interrupt , 0 ,
2006-06-01 11:41:04 +04:00
dev - > name , dev ) ) ) {
printk ( KERN_ERR " %s: unable to get IRQ %d \n " ,
dev - > name , dev - > irq ) ;
return retval ;
}
2005-04-17 02:20:36 +04:00
if ( ( retval = au1000_init ( dev ) ) ) {
printk ( KERN_ERR " %s: error in au1000_init \n " , dev - > name ) ;
free_irq ( dev - > irq , dev ) ;
return retval ;
}
2006-06-01 11:41:04 +04:00
if ( aup - > phy_dev ) {
/* cause the PHY state machine to schedule a link state check */
aup - > phy_dev - > state = PHY_CHANGELINK ;
phy_start ( aup - > phy_dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-01 11:41:04 +04:00
netif_start_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( au1000_debug > 4 )
printk ( " %s: open: Initialization done. \n " , dev - > name ) ;
return 0 ;
}
static int au1000_close ( struct net_device * dev )
{
2006-06-01 11:41:04 +04:00
unsigned long flags ;
2008-11-13 10:37:49 +03:00
struct au1000_private * const aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( au1000_debug > 4 )
printk ( " %s: close: dev=%p \n " , dev - > name , dev ) ;
2006-06-01 11:41:04 +04:00
if ( aup - > phy_dev )
phy_stop ( aup - > phy_dev ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & aup - > lock , flags ) ;
2006-06-01 11:41:04 +04:00
reset_mac_unlocked ( dev ) ;
2005-04-17 02:20:36 +04:00
/* stop the device */
netif_stop_queue ( dev ) ;
/* disable the interrupt */
free_irq ( dev - > irq , dev ) ;
spin_unlock_irqrestore ( & aup - > lock , flags ) ;
return 0 ;
}
/*
* Au1000 transmit routine .
*/
2009-08-31 23:50:58 +04:00
static netdev_tx_t au1000_tx ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2007-10-04 04:41:50 +04:00
struct net_device_stats * ps = & dev - > stats ;
2005-04-17 02:20:36 +04:00
volatile tx_dma_t * ptxd ;
u32 buff_stat ;
db_dest_t * pDB ;
int i ;
if ( au1000_debug > 5 )
2006-09-13 21:24:59 +04:00
printk ( " %s: tx: aup %x len=%d, data=%p, head %d \n " ,
dev - > name , ( unsigned ) aup , skb - > len ,
2005-04-17 02:20:36 +04:00
skb - > data , aup - > tx_head ) ;
ptxd = aup - > tx_dma_ring [ aup - > tx_head ] ;
buff_stat = ptxd - > buff_stat ;
if ( buff_stat & TX_DMA_ENABLE ) {
/* We've wrapped around and the transmitter is still busy */
netif_stop_queue ( dev ) ;
aup - > tx_full = 1 ;
2009-06-12 10:22:29 +04:00
return NETDEV_TX_BUSY ;
2005-04-17 02:20:36 +04:00
}
else if ( buff_stat & TX_T_DONE ) {
2006-03-22 09:53:52 +03:00
update_tx_stats ( dev , ptxd - > status ) ;
2005-04-17 02:20:36 +04:00
ptxd - > len = 0 ;
}
if ( aup - > tx_full ) {
aup - > tx_full = 0 ;
netif_wake_queue ( dev ) ;
}
pDB = aup - > tx_db_inuse [ aup - > tx_head ] ;
2009-11-10 03:13:38 +03:00
skb_copy_from_linear_data ( skb , ( void * ) pDB - > vaddr , skb - > len ) ;
2005-04-17 02:20:36 +04:00
if ( skb - > len < ETH_ZLEN ) {
2006-09-13 21:24:59 +04:00
for ( i = skb - > len ; i < ETH_ZLEN ; i + + ) {
2005-04-17 02:20:36 +04:00
( ( char * ) pDB - > vaddr ) [ i ] = 0 ;
}
ptxd - > len = ETH_ZLEN ;
}
else
2009-01-23 01:06:25 +03:00
ptxd - > len = skb - > len ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
ps - > tx_packets + + ;
ps - > tx_bytes + = ptxd - > len ;
2005-04-17 02:20:36 +04:00
2009-01-23 01:06:25 +03:00
ptxd - > buff_stat = pDB - > dma_addr | TX_DMA_ENABLE ;
au_sync ( ) ;
dev_kfree_skb ( skb ) ;
aup - > tx_head = ( aup - > tx_head + 1 ) & ( NUM_TX_DMA - 1 ) ;
dev - > trans_start = jiffies ;
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
/*
* The Tx ring has been full longer than the watchdog timeout
* value . The transmitter must be hung ?
*/
static void au1000_tx_timeout ( struct net_device * dev )
{
printk ( KERN_ERR " %s: au1000_tx_timeout: dev=%p \n " , dev - > name , dev ) ;
reset_mac ( dev ) ;
au1000_init ( dev ) ;
dev - > trans_start = jiffies ;
netif_wake_queue ( dev ) ;
}
2009-04-14 22:30:23 +04:00
static void au1000_multicast_list ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2006-09-13 21:24:59 +04:00
if ( au1000_debug > 4 )
2009-04-14 22:30:23 +04:00
printk ( " %s: au1000_multicast_list: flags=%x \n " , dev - > name , dev - > flags ) ;
2005-04-17 02:20:36 +04:00
if ( dev - > flags & IFF_PROMISC ) { /* Set promiscuous. */
aup - > mac - > control | = MAC_PROMISCUOUS ;
} else if ( ( dev - > flags & IFF_ALLMULTI ) | |
2010-02-08 07:30:35 +03:00
netdev_mc_count ( dev ) > MULTICAST_FILTER_LIMIT ) {
2005-04-17 02:20:36 +04:00
aup - > mac - > control | = MAC_PASS_ALL_MULTI ;
aup - > mac - > control & = ~ MAC_PROMISCUOUS ;
printk ( KERN_INFO " %s: Pass all multicast \n " , dev - > name ) ;
} else {
struct dev_mc_list * mclist ;
u32 mc_filter [ 2 ] ; /* Multicast hash filter */
mc_filter [ 1 ] = mc_filter [ 0 ] = 0 ;
2010-02-20 03:13:58 +03:00
netdev_for_each_mc_addr ( mclist , dev )
2006-09-13 21:24:59 +04:00
set_bit ( ether_crc ( ETH_ALEN , mclist - > dmi_addr ) > > 26 ,
2005-04-17 02:20:36 +04:00
( long * ) mc_filter ) ;
aup - > mac - > multi_hash_high = mc_filter [ 1 ] ;
aup - > mac - > multi_hash_low = mc_filter [ 0 ] ;
aup - > mac - > control & = ~ MAC_PROMISCUOUS ;
aup - > mac - > control | = MAC_HASH_MODE ;
}
}
static int au1000_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd )
{
2008-11-13 10:37:49 +03:00
struct au1000_private * aup = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
if ( ! netif_running ( dev ) ) return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
if ( ! aup - > phy_dev ) return - EINVAL ; // PHY not controllable
2005-04-17 02:20:36 +04:00
2006-06-01 11:41:04 +04:00
return phy_mii_ioctl ( aup - > phy_dev , if_mii ( rq ) , cmd ) ;
2005-04-17 02:20:36 +04:00
}
2009-04-14 22:30:23 +04:00
static const struct net_device_ops au1000_netdev_ops = {
. ndo_open = au1000_open ,
. ndo_stop = au1000_close ,
. ndo_start_xmit = au1000_tx ,
. ndo_set_multicast_list = au1000_multicast_list ,
. ndo_do_ioctl = au1000_ioctl ,
. ndo_tx_timeout = au1000_tx_timeout ,
. ndo_set_mac_address = eth_mac_addr ,
. ndo_validate_addr = eth_validate_addr ,
. ndo_change_mtu = eth_change_mtu ,
} ;
2009-11-10 03:13:38 +03:00
static int __devinit au1000_probe ( struct platform_device * pdev )
2009-01-23 01:06:25 +03:00
{
static unsigned version_printed = 0 ;
struct au1000_private * aup = NULL ;
2009-11-10 03:13:38 +03:00
struct au1000_eth_platform_data * pd ;
2009-01-23 01:06:25 +03:00
struct net_device * dev = NULL ;
db_dest_t * pDB , * pDBfree ;
2009-11-10 03:13:38 +03:00
int irq , i , err = 0 ;
struct resource * base , * macen ;
2009-01-23 01:06:25 +03:00
char ethaddr [ 6 ] ;
2009-11-10 03:13:38 +03:00
base = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! base ) {
printk ( KERN_ERR DRV_NAME " : failed to retrieve base register \n " ) ;
err = - ENODEV ;
goto out ;
}
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
macen = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
if ( ! macen ) {
printk ( KERN_ERR DRV_NAME " : failed to retrieve MAC Enable register \n " ) ;
err = - ENODEV ;
goto out ;
}
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
printk ( KERN_ERR DRV_NAME " : failed to retrieve IRQ \n " ) ;
err = - ENODEV ;
goto out ;
}
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
if ( ! request_mem_region ( base - > start , resource_size ( base ) , pdev - > name ) ) {
printk ( KERN_ERR DRV_NAME " : failed to request memory region for base registers \n " ) ;
err = - ENXIO ;
goto out ;
}
if ( ! request_mem_region ( macen - > start , resource_size ( macen ) , pdev - > name ) ) {
printk ( KERN_ERR DRV_NAME " : failed to request memory region for MAC enable register \n " ) ;
err = - ENXIO ;
goto err_request ;
}
2009-01-23 01:06:25 +03:00
dev = alloc_etherdev ( sizeof ( struct au1000_private ) ) ;
if ( ! dev ) {
printk ( KERN_ERR " %s: alloc_etherdev failed \n " , DRV_NAME ) ;
2009-11-10 03:13:38 +03:00
err = - ENOMEM ;
goto err_alloc ;
2009-01-23 01:06:25 +03:00
}
2009-11-10 03:13:38 +03:00
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
platform_set_drvdata ( pdev , dev ) ;
2009-01-23 01:06:25 +03:00
aup = netdev_priv ( dev ) ;
spin_lock_init ( & aup - > lock ) ;
/* Allocate the data buffers */
/* Snooping works fine with eth on all au1xxx */
aup - > vaddr = ( u32 ) dma_alloc_noncoherent ( NULL , MAX_BUF_SIZE *
( NUM_TX_BUFFS + NUM_RX_BUFFS ) ,
& aup - > dma_addr , 0 ) ;
if ( ! aup - > vaddr ) {
2009-11-10 03:13:38 +03:00
printk ( KERN_ERR DRV_NAME " : failed to allocate data buffers \n " ) ;
err = - ENOMEM ;
goto err_vaddr ;
2009-01-23 01:06:25 +03:00
}
/* aup->mac is the base address of the MAC's registers */
2009-11-10 03:13:38 +03:00
aup - > mac = ( volatile mac_reg_t * ) ioremap_nocache ( base - > start , resource_size ( base ) ) ;
if ( ! aup - > mac ) {
printk ( KERN_ERR DRV_NAME " : failed to ioremap MAC registers \n " ) ;
err = - ENXIO ;
goto err_remap1 ;
}
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
/* Setup some variables for quick register address access */
aup - > enable = ( volatile u32 * ) ioremap_nocache ( macen - > start , resource_size ( macen ) ) ;
if ( ! aup - > enable ) {
printk ( KERN_ERR DRV_NAME " : failed to ioremap MAC enable register \n " ) ;
err = - ENXIO ;
goto err_remap2 ;
}
aup - > mac_id = pdev - > id ;
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
if ( pdev - > id = = 0 ) {
2009-01-23 01:06:25 +03:00
if ( prom_get_ethernet_addr ( ethaddr ) = = 0 )
memcpy ( au1000_mac_addr , ethaddr , sizeof ( au1000_mac_addr ) ) ;
else {
printk ( KERN_INFO " %s: No MAC address found \n " ,
dev - > name ) ;
/* Use the hard coded MAC addresses */
}
setup_hw_rings ( aup , MAC0_RX_DMA_ADDR , MAC0_TX_DMA_ADDR ) ;
2009-11-10 03:13:38 +03:00
} else if ( pdev - > id = = 1 )
2009-01-23 01:06:25 +03:00
setup_hw_rings ( aup , MAC1_RX_DMA_ADDR , MAC1_TX_DMA_ADDR ) ;
/*
* Assign to the Ethernet ports two consecutive MAC addresses
* to match those that are printed on their stickers
*/
memcpy ( dev - > dev_addr , au1000_mac_addr , sizeof ( au1000_mac_addr ) ) ;
2009-11-10 03:13:38 +03:00
dev - > dev_addr [ 5 ] + = pdev - > id ;
2009-01-23 01:06:25 +03:00
* aup - > enable = 0 ;
aup - > mac_enabled = 0 ;
2009-11-10 03:13:38 +03:00
pd = pdev - > dev . platform_data ;
if ( ! pd ) {
printk ( KERN_INFO DRV_NAME " : no platform_data passed, PHY search on MAC0 \n " ) ;
aup - > phy1_search_mac0 = 1 ;
} else {
aup - > phy_static_config = pd - > phy_static_config ;
aup - > phy_search_highest_addr = pd - > phy_search_highest_addr ;
aup - > phy1_search_mac0 = pd - > phy1_search_mac0 ;
aup - > phy_addr = pd - > phy_addr ;
aup - > phy_busid = pd - > phy_busid ;
aup - > phy_irq = pd - > phy_irq ;
}
if ( aup - > phy_busid & & aup - > phy_busid > 0 ) {
printk ( KERN_ERR DRV_NAME " : MAC0-associated PHY attached 2nd MACs MII "
" bus not supported yet \n " ) ;
err = - ENODEV ;
goto err_mdiobus_alloc ;
}
2009-01-23 01:06:25 +03:00
aup - > mii_bus = mdiobus_alloc ( ) ;
2009-11-10 03:13:38 +03:00
if ( aup - > mii_bus = = NULL ) {
printk ( KERN_ERR DRV_NAME " : failed to allocate mdiobus structure \n " ) ;
err = - ENOMEM ;
goto err_mdiobus_alloc ;
}
2009-01-23 01:06:25 +03:00
aup - > mii_bus - > priv = dev ;
aup - > mii_bus - > read = au1000_mdiobus_read ;
aup - > mii_bus - > write = au1000_mdiobus_write ;
aup - > mii_bus - > reset = au1000_mdiobus_reset ;
aup - > mii_bus - > name = " au1000_eth_mii " ;
snprintf ( aup - > mii_bus - > id , MII_BUS_ID_SIZE , " %x " , aup - > mac_id ) ;
aup - > mii_bus - > irq = kmalloc ( sizeof ( int ) * PHY_MAX_ADDR , GFP_KERNEL ) ;
2009-08-31 02:40:15 +04:00
if ( aup - > mii_bus - > irq = = NULL )
goto err_out ;
2009-01-23 01:06:25 +03:00
for ( i = 0 ; i < PHY_MAX_ADDR ; + + i )
aup - > mii_bus - > irq [ i ] = PHY_POLL ;
/* if known, set corresponding PHY IRQs */
2009-11-10 03:13:38 +03:00
if ( aup - > phy_static_config )
if ( aup - > phy_irq & & aup - > phy_busid = = aup - > mac_id )
aup - > mii_bus - > irq [ aup - > phy_addr ] = aup - > phy_irq ;
err = mdiobus_register ( aup - > mii_bus ) ;
if ( err ) {
printk ( KERN_ERR DRV_NAME " failed to register MDIO bus \n " ) ;
goto err_mdiobus_reg ;
}
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
if ( mii_probe ( dev ) ! = 0 )
2009-01-23 01:06:25 +03:00
goto err_out ;
pDBfree = NULL ;
/* setup the data buffer descriptors and attach a buffer to each one */
pDB = aup - > db ;
for ( i = 0 ; i < ( NUM_TX_BUFFS + NUM_RX_BUFFS ) ; i + + ) {
pDB - > pnext = pDBfree ;
pDBfree = pDB ;
pDB - > vaddr = ( u32 * ) ( ( unsigned ) aup - > vaddr + MAX_BUF_SIZE * i ) ;
pDB - > dma_addr = ( dma_addr_t ) virt_to_bus ( pDB - > vaddr ) ;
pDB + + ;
}
aup - > pDBfree = pDBfree ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + ) {
pDB = GetFreeDB ( aup ) ;
if ( ! pDB ) {
goto err_out ;
}
aup - > rx_dma_ring [ i ] - > buff_stat = ( unsigned ) pDB - > dma_addr ;
aup - > rx_db_inuse [ i ] = pDB ;
}
for ( i = 0 ; i < NUM_TX_DMA ; i + + ) {
pDB = GetFreeDB ( aup ) ;
if ( ! pDB ) {
goto err_out ;
}
aup - > tx_dma_ring [ i ] - > buff_stat = ( unsigned ) pDB - > dma_addr ;
aup - > tx_dma_ring [ i ] - > len = 0 ;
aup - > tx_db_inuse [ i ] = pDB ;
}
2009-11-10 03:13:38 +03:00
dev - > base_addr = base - > start ;
dev - > irq = irq ;
dev - > netdev_ops = & au1000_netdev_ops ;
SET_ETHTOOL_OPS ( dev , & au1000_ethtool_ops ) ;
dev - > watchdog_timeo = ETH_TX_TIMEOUT ;
2009-01-23 01:06:25 +03:00
/*
* The boot code uses the ethernet controller , so reset it to start
* fresh . au1000_init ( ) expects that the device is in reset state .
*/
reset_mac ( dev ) ;
2009-11-10 03:13:38 +03:00
err = register_netdev ( dev ) ;
if ( err ) {
printk ( KERN_ERR DRV_NAME " %s: Cannot register net device, aborting. \n " ,
dev - > name ) ;
goto err_out ;
}
printk ( " %s: Au1xx0 Ethernet found at 0x%lx, irq %d \n " ,
dev - > name , ( unsigned long ) base - > start , irq ) ;
if ( version_printed + + = = 0 )
printk ( " %s version %s %s \n " , DRV_NAME , DRV_VERSION , DRV_AUTHOR ) ;
return 0 ;
2009-01-23 01:06:25 +03:00
err_out :
2009-11-10 03:13:38 +03:00
if ( aup - > mii_bus ! = NULL )
2009-01-23 01:06:25 +03:00
mdiobus_unregister ( aup - > mii_bus ) ;
/* here we should have a valid dev plus aup-> register addresses
* so we can reset the mac properly . */
reset_mac ( dev ) ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + ) {
if ( aup - > rx_db_inuse [ i ] )
ReleaseDB ( aup , aup - > rx_db_inuse [ i ] ) ;
}
for ( i = 0 ; i < NUM_TX_DMA ; i + + ) {
if ( aup - > tx_db_inuse [ i ] )
ReleaseDB ( aup , aup - > tx_db_inuse [ i ] ) ;
}
2009-11-10 03:13:38 +03:00
err_mdiobus_reg :
mdiobus_free ( aup - > mii_bus ) ;
err_mdiobus_alloc :
iounmap ( aup - > enable ) ;
err_remap2 :
iounmap ( aup - > mac ) ;
err_remap1 :
2009-01-23 01:06:25 +03:00
dma_free_noncoherent ( NULL , MAX_BUF_SIZE * ( NUM_TX_BUFFS + NUM_RX_BUFFS ) ,
( void * ) aup - > vaddr , aup - > dma_addr ) ;
2009-11-10 03:13:38 +03:00
err_vaddr :
2009-01-23 01:06:25 +03:00
free_netdev ( dev ) ;
2009-11-10 03:13:38 +03:00
err_alloc :
release_mem_region ( macen - > start , resource_size ( macen ) ) ;
err_request :
release_mem_region ( base - > start , resource_size ( base ) ) ;
out :
return err ;
2009-01-23 01:06:25 +03:00
}
2009-11-10 03:13:38 +03:00
static int __devexit au1000_remove ( struct platform_device * pdev )
2009-01-23 01:06:25 +03:00
{
2009-11-10 03:13:38 +03:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
struct au1000_private * aup = netdev_priv ( dev ) ;
int i ;
struct resource * base , * macen ;
2009-01-23 01:06:25 +03:00
2009-11-10 03:13:38 +03:00
platform_set_drvdata ( pdev , NULL ) ;
unregister_netdev ( dev ) ;
mdiobus_unregister ( aup - > mii_bus ) ;
mdiobus_free ( aup - > mii_bus ) ;
for ( i = 0 ; i < NUM_RX_DMA ; i + + )
if ( aup - > rx_db_inuse [ i ] )
ReleaseDB ( aup , aup - > rx_db_inuse [ i ] ) ;
for ( i = 0 ; i < NUM_TX_DMA ; i + + )
if ( aup - > tx_db_inuse [ i ] )
ReleaseDB ( aup , aup - > tx_db_inuse [ i ] ) ;
dma_free_noncoherent ( NULL , MAX_BUF_SIZE *
( NUM_TX_BUFFS + NUM_RX_BUFFS ) ,
( void * ) aup - > vaddr , aup - > dma_addr ) ;
iounmap ( aup - > mac ) ;
iounmap ( aup - > enable ) ;
base = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
release_mem_region ( base - > start , resource_size ( base ) ) ;
macen = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
release_mem_region ( macen - > start , resource_size ( macen ) ) ;
free_netdev ( dev ) ;
2009-01-23 01:06:25 +03:00
return 0 ;
}
2009-11-10 03:13:38 +03:00
static struct platform_driver au1000_eth_driver = {
. probe = au1000_probe ,
. remove = __devexit_p ( au1000_remove ) ,
. driver = {
. name = " au1000-eth " ,
. owner = THIS_MODULE ,
} ,
} ;
MODULE_ALIAS ( " platform:au1000-eth " ) ;
static int __init au1000_init_module ( void )
{
return platform_driver_register ( & au1000_eth_driver ) ;
}
static void __exit au1000_exit_module ( void )
2009-01-23 01:06:25 +03:00
{
2009-11-10 03:13:38 +03:00
platform_driver_unregister ( & au1000_eth_driver ) ;
2009-01-23 01:06:25 +03:00
}
2005-04-17 02:20:36 +04:00
module_init ( au1000_init_module ) ;
2009-11-10 03:13:38 +03:00
module_exit ( au1000_exit_module ) ;