2008-11-05 00:35:37 +00:00
/***************************************************************************
*
* Copyright ( C ) 2004 - 2008 SMSC
* Copyright ( C ) 2005 - 2008 ARM
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that 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
2013-12-06 06:28:43 -08:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2008-11-05 00:35:37 +00:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rewritten , heavily based on smsc911x simple driver by SMSC .
* Partly uses io macros from smc91x . c by Nicolas Pitre
*
* Supported devices :
* LAN9115 , LAN9116 , LAN9117 , LAN9118
* LAN9215 , LAN9216 , LAN9217 , LAN9218
* LAN9210 , LAN9211
* LAN9220 , LAN9221
2011-10-12 02:29:39 +00:00
* LAN89218
2008-11-05 00:35:37 +00:00
*
*/
2011-03-25 14:21:22 +00:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-11-05 00:35:37 +00:00
# include <linux/crc32.h>
2012-12-19 17:03:48 +00:00
# include <linux/clk.h>
2008-11-05 00:35:37 +00:00
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/etherdevice.h>
# include <linux/ethtool.h>
# include <linux/init.h>
2011-06-06 10:43:46 +00:00
# include <linux/interrupt.h>
2008-11-05 00:35:37 +00:00
# include <linux/ioport.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/platform_device.h>
2011-11-24 01:03:07 +00:00
# include <linux/regulator/consumer.h>
2008-11-05 00:35:37 +00:00
# include <linux/sched.h>
# include <linux/timer.h>
# include <linux/bug.h>
# include <linux/bitops.h>
# include <linux/irq.h>
# include <linux/io.h>
2009-04-27 21:32:16 +00:00
# include <linux/swab.h>
2008-11-05 00:35:37 +00:00
# include <linux/phy.h>
# include <linux/smsc911x.h>
2009-08-05 08:29:31 +00:00
# include <linux/device.h>
2011-07-30 08:26:00 +00:00
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_gpio.h>
# include <linux/of_net.h>
2015-08-12 17:06:27 -05:00
# include <linux/acpi.h>
2014-11-24 19:58:17 +01:00
# include <linux/pm_runtime.h>
2015-08-12 17:06:27 -05:00
# include <linux/property.h>
2016-09-07 15:53:42 +02:00
# include <linux/gpio/consumer.h>
2014-11-24 19:58:17 +01:00
2008-11-05 00:35:37 +00:00
# include "smsc911x.h"
# define SMSC_CHIPNAME "smsc911x"
# define SMSC_MDIONAME "smsc911x-mdio"
# define SMSC_DRV_VERSION "2008-10-21"
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( SMSC_DRV_VERSION ) ;
2010-09-26 18:50:05 -07:00
MODULE_ALIAS ( " platform:smsc911x " ) ;
2008-11-05 00:35:37 +00:00
# if USE_DEBUG > 0
static int debug = 16 ;
# else
static int debug = 3 ;
# endif
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0=none,...,16=all) " ) ;
2011-04-13 17:13:00 -07:00
struct smsc911x_data ;
struct smsc911x_ops {
u32 ( * reg_read ) ( struct smsc911x_data * pdata , u32 reg ) ;
void ( * reg_write ) ( struct smsc911x_data * pdata , u32 reg , u32 val ) ;
void ( * rx_readfifo ) ( struct smsc911x_data * pdata ,
unsigned int * buf , unsigned int wordcount ) ;
void ( * tx_writefifo ) ( struct smsc911x_data * pdata ,
unsigned int * buf , unsigned int wordcount ) ;
} ;
2011-11-24 01:03:07 +00:00
# define SMSC911X_NUM_SUPPLIES 2
2008-11-05 00:35:37 +00:00
struct smsc911x_data {
void __iomem * ioaddr ;
unsigned int idrev ;
/* used to decide which workarounds apply */
unsigned int generation ;
/* device configuration (copied from platform_data during probe) */
2008-11-05 00:35:38 +00:00
struct smsc911x_platform_config config ;
2008-11-05 00:35:37 +00:00
/* This needs to be acquired before calling any of below:
* smsc911x_mac_read ( ) , smsc911x_mac_write ( )
*/
spinlock_t mac_lock ;
2010-07-19 13:36:21 -07:00
/* spinlock to ensure register accesses are serialised */
2008-11-05 00:35:37 +00:00
spinlock_t dev_lock ;
struct mii_bus * mii_bus ;
unsigned int using_extphy ;
int last_duplex ;
int last_carrier ;
u32 msg_enable ;
unsigned int gpio_setting ;
unsigned int gpio_orig_setting ;
struct net_device * dev ;
struct napi_struct napi ;
unsigned int software_irq_signal ;
# ifdef USE_PHY_WORK_AROUND
# define MIN_PACKET_SIZE (64)
char loopback_tx_pkt [ MIN_PACKET_SIZE ] ;
char loopback_rx_pkt [ MIN_PACKET_SIZE ] ;
unsigned int resetcount ;
# endif
/* Members for Multicast filter workaround */
unsigned int multicast_update_pending ;
unsigned int set_bits_mask ;
unsigned int clear_bits_mask ;
unsigned int hashhi ;
unsigned int hashlo ;
2011-04-13 17:13:00 -07:00
/* register access functions */
const struct smsc911x_ops * ops ;
2011-11-24 01:03:07 +00:00
/* regulators */
struct regulator_bulk_data supplies [ SMSC911X_NUM_SUPPLIES ] ;
2012-12-19 17:03:48 +00:00
2016-09-07 15:53:42 +02:00
/* Reset GPIO */
struct gpio_desc * reset_gpiod ;
2012-12-19 17:03:48 +00:00
/* clock */
struct clk * clk ;
2008-11-05 00:35:37 +00:00
} ;
2011-04-13 17:13:00 -07:00
/* Easy access to information */
# define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift))
2010-07-19 13:36:21 -07:00
static inline u32 __smsc911x_reg_read ( struct smsc911x_data * pdata , u32 reg )
2008-11-05 00:35:37 +00:00
{
2008-11-05 00:35:38 +00:00
if ( pdata - > config . flags & SMSC911X_USE_32BIT )
return readl ( pdata - > ioaddr + reg ) ;
2010-07-19 13:36:21 -07:00
if ( pdata - > config . flags & SMSC911X_USE_16BIT )
return ( ( readw ( pdata - > ioaddr + reg ) & 0xFFFF ) |
2008-11-05 00:35:38 +00:00
( ( readw ( pdata - > ioaddr + reg + 2 ) & 0xFFFF ) < < 16 ) ) ;
2008-11-05 00:35:37 +00:00
2008-11-05 00:35:38 +00:00
BUG ( ) ;
2009-01-11 00:14:27 -08:00
return 0 ;
2008-11-05 00:35:37 +00:00
}
2011-04-13 17:13:00 -07:00
static inline u32
__smsc911x_reg_read_shift ( struct smsc911x_data * pdata , u32 reg )
{
if ( pdata - > config . flags & SMSC911X_USE_32BIT )
return readl ( pdata - > ioaddr + __smsc_shift ( pdata , reg ) ) ;
if ( pdata - > config . flags & SMSC911X_USE_16BIT )
return ( readw ( pdata - > ioaddr +
__smsc_shift ( pdata , reg ) ) & 0xFFFF ) |
( ( readw ( pdata - > ioaddr +
__smsc_shift ( pdata , reg + 2 ) ) & 0xFFFF ) < < 16 ) ;
BUG ( ) ;
return 0 ;
}
2010-07-19 13:36:21 -07:00
static inline u32 smsc911x_reg_read ( struct smsc911x_data * pdata , u32 reg )
{
u32 data ;
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
2011-04-13 17:13:00 -07:00
data = pdata - > ops - > reg_read ( pdata , reg ) ;
2010-07-19 13:36:21 -07:00
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
return data ;
}
static inline void __smsc911x_reg_write ( struct smsc911x_data * pdata , u32 reg ,
u32 val )
2008-11-05 00:35:37 +00:00
{
2008-11-05 00:35:38 +00:00
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
writel ( val , pdata - > ioaddr + reg ) ;
return ;
}
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
writew ( val & 0xFFFF , pdata - > ioaddr + reg ) ;
writew ( ( val > > 16 ) & 0xFFFF , pdata - > ioaddr + reg + 2 ) ;
return ;
}
2008-11-05 00:35:37 +00:00
2008-11-05 00:35:38 +00:00
BUG ( ) ;
2008-11-05 00:35:37 +00:00
}
2011-04-13 17:13:00 -07:00
static inline void
__smsc911x_reg_write_shift ( struct smsc911x_data * pdata , u32 reg , u32 val )
{
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
writel ( val , pdata - > ioaddr + __smsc_shift ( pdata , reg ) ) ;
return ;
}
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
writew ( val & 0xFFFF ,
pdata - > ioaddr + __smsc_shift ( pdata , reg ) ) ;
writew ( ( val > > 16 ) & 0xFFFF ,
pdata - > ioaddr + __smsc_shift ( pdata , reg + 2 ) ) ;
return ;
}
BUG ( ) ;
}
2010-07-19 13:36:21 -07:00
static inline void smsc911x_reg_write ( struct smsc911x_data * pdata , u32 reg ,
u32 val )
{
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
2011-04-13 17:13:00 -07:00
pdata - > ops - > reg_write ( pdata , reg , val ) ;
2010-07-19 13:36:21 -07:00
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
}
2008-11-05 00:35:37 +00:00
/* Writes a packet to the TX_DATA_FIFO */
static inline void
smsc911x_tx_writefifo ( struct smsc911x_data * pdata , unsigned int * buf ,
unsigned int wordcount )
{
2010-07-19 13:36:21 -07:00
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
2009-04-27 21:32:16 +00:00
if ( pdata - > config . flags & SMSC911X_SWAP_FIFO ) {
while ( wordcount - - )
2010-07-19 13:36:21 -07:00
__smsc911x_reg_write ( pdata , TX_DATA_FIFO ,
swab32 ( * buf + + ) ) ;
goto out ;
2009-04-27 21:32:16 +00:00
}
2008-11-05 00:35:38 +00:00
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
2012-12-11 04:49:49 +00:00
iowrite32_rep ( pdata - > ioaddr + TX_DATA_FIFO , buf , wordcount ) ;
2010-07-19 13:36:21 -07:00
goto out ;
2008-11-05 00:35:38 +00:00
}
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
while ( wordcount - - )
2010-07-19 13:36:21 -07:00
__smsc911x_reg_write ( pdata , TX_DATA_FIFO , * buf + + ) ;
goto out ;
2008-11-05 00:35:38 +00:00
}
BUG ( ) ;
2010-07-19 13:36:21 -07:00
out :
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
2008-11-05 00:35:37 +00:00
}
2011-04-13 17:13:00 -07:00
/* Writes a packet to the TX_DATA_FIFO - shifted version */
static inline void
smsc911x_tx_writefifo_shift ( struct smsc911x_data * pdata , unsigned int * buf ,
unsigned int wordcount )
{
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
if ( pdata - > config . flags & SMSC911X_SWAP_FIFO ) {
while ( wordcount - - )
__smsc911x_reg_write_shift ( pdata , TX_DATA_FIFO ,
swab32 ( * buf + + ) ) ;
goto out ;
}
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
2012-12-11 04:49:49 +00:00
iowrite32_rep ( pdata - > ioaddr + __smsc_shift ( pdata ,
2011-04-13 17:13:00 -07:00
TX_DATA_FIFO ) , buf , wordcount ) ;
goto out ;
}
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
while ( wordcount - - )
__smsc911x_reg_write_shift ( pdata ,
TX_DATA_FIFO , * buf + + ) ;
goto out ;
}
BUG ( ) ;
out :
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
}
2008-11-05 00:35:37 +00:00
/* Reads a packet out of the RX_DATA_FIFO */
static inline void
smsc911x_rx_readfifo ( struct smsc911x_data * pdata , unsigned int * buf ,
unsigned int wordcount )
{
2010-07-19 13:36:21 -07:00
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
2009-04-27 21:32:16 +00:00
if ( pdata - > config . flags & SMSC911X_SWAP_FIFO ) {
while ( wordcount - - )
2010-07-19 13:36:21 -07:00
* buf + + = swab32 ( __smsc911x_reg_read ( pdata ,
RX_DATA_FIFO ) ) ;
goto out ;
2009-04-27 21:32:16 +00:00
}
2008-11-05 00:35:38 +00:00
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
2012-12-11 04:49:49 +00:00
ioread32_rep ( pdata - > ioaddr + RX_DATA_FIFO , buf , wordcount ) ;
2010-07-19 13:36:21 -07:00
goto out ;
2008-11-05 00:35:38 +00:00
}
2008-11-05 00:35:37 +00:00
2008-11-05 00:35:38 +00:00
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
while ( wordcount - - )
2010-07-19 13:36:21 -07:00
* buf + + = __smsc911x_reg_read ( pdata , RX_DATA_FIFO ) ;
goto out ;
2008-11-05 00:35:38 +00:00
}
BUG ( ) ;
2010-07-19 13:36:21 -07:00
out :
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
2008-11-05 00:35:38 +00:00
}
2008-11-05 00:35:37 +00:00
2011-04-13 17:13:00 -07:00
/* Reads a packet out of the RX_DATA_FIFO - shifted version */
static inline void
smsc911x_rx_readfifo_shift ( struct smsc911x_data * pdata , unsigned int * buf ,
unsigned int wordcount )
{
unsigned long flags ;
spin_lock_irqsave ( & pdata - > dev_lock , flags ) ;
if ( pdata - > config . flags & SMSC911X_SWAP_FIFO ) {
while ( wordcount - - )
* buf + + = swab32 ( __smsc911x_reg_read_shift ( pdata ,
RX_DATA_FIFO ) ) ;
goto out ;
}
if ( pdata - > config . flags & SMSC911X_USE_32BIT ) {
2012-12-11 04:49:49 +00:00
ioread32_rep ( pdata - > ioaddr + __smsc_shift ( pdata ,
2011-04-13 17:13:00 -07:00
RX_DATA_FIFO ) , buf , wordcount ) ;
goto out ;
}
if ( pdata - > config . flags & SMSC911X_USE_16BIT ) {
while ( wordcount - - )
* buf + + = __smsc911x_reg_read_shift ( pdata ,
RX_DATA_FIFO ) ;
goto out ;
}
BUG ( ) ;
out :
spin_unlock_irqrestore ( & pdata - > dev_lock , flags ) ;
}
2011-11-24 01:03:07 +00:00
/*
2012-12-19 17:03:48 +00:00
* enable regulator and clock resources .
2011-11-24 01:03:07 +00:00
*/
static int smsc911x_enable_resources ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
int ret = 0 ;
ret = regulator_bulk_enable ( ARRAY_SIZE ( pdata - > supplies ) ,
pdata - > supplies ) ;
if ( ret )
netdev_err ( ndev , " failed to enable regulators %d \n " ,
ret ) ;
2012-12-19 17:03:48 +00:00
if ( ! IS_ERR ( pdata - > clk ) ) {
ret = clk_prepare_enable ( pdata - > clk ) ;
if ( ret < 0 )
netdev_err ( ndev , " failed to enable clock %d \n " , ret ) ;
}
2011-11-24 01:03:07 +00:00
return ret ;
}
/*
* disable resources , currently just regulators .
*/
static int smsc911x_disable_resources ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
int ret = 0 ;
ret = regulator_bulk_disable ( ARRAY_SIZE ( pdata - > supplies ) ,
pdata - > supplies ) ;
2012-12-19 17:03:48 +00:00
if ( ! IS_ERR ( pdata - > clk ) )
clk_disable_unprepare ( pdata - > clk ) ;
2011-11-24 01:03:07 +00:00
return ret ;
}
/*
* Request resources , currently just regulators .
*
* The SMSC911x has two power pins : vddvario and vdd33a , in designs where
* these are not always - on we need to request regulators to be turned on
* before we can try to access the device registers .
*/
static int smsc911x_request_resources ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
int ret = 0 ;
/* Request regulators */
pdata - > supplies [ 0 ] . supply = " vdd33a " ;
pdata - > supplies [ 1 ] . supply = " vddvario " ;
ret = regulator_bulk_get ( & pdev - > dev ,
ARRAY_SIZE ( pdata - > supplies ) ,
pdata - > supplies ) ;
if ( ret )
netdev_err ( ndev , " couldn't get regulators %d \n " ,
ret ) ;
2012-12-19 17:03:48 +00:00
2016-09-07 15:53:42 +02:00
/* Request optional RESET GPIO */
pdata - > reset_gpiod = devm_gpiod_get_optional ( & pdev - > dev ,
" reset " ,
GPIOD_OUT_LOW ) ;
2012-12-19 17:03:48 +00:00
/* Request clock */
pdata - > clk = clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( pdata - > clk ) )
2014-03-24 12:57:25 -03:00
dev_dbg ( & pdev - > dev , " couldn't get clock %li \n " ,
PTR_ERR ( pdata - > clk ) ) ;
2012-12-19 17:03:48 +00:00
2011-11-24 01:03:07 +00:00
return ret ;
}
/*
* Free resources , currently just regulators .
*
*/
static void smsc911x_free_resources ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
/* Free regulators */
regulator_bulk_free ( ARRAY_SIZE ( pdata - > supplies ) ,
pdata - > supplies ) ;
2012-12-19 17:03:48 +00:00
/* Free clock */
if ( ! IS_ERR ( pdata - > clk ) ) {
clk_put ( pdata - > clk ) ;
pdata - > clk = NULL ;
}
2011-11-24 01:03:07 +00:00
}
2008-11-05 00:35:37 +00:00
/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read
* and smsc911x_mac_write , so assumes mac_lock is held */
static int smsc911x_mac_complete ( struct smsc911x_data * pdata )
{
int i ;
u32 val ;
SMSC_ASSERT_MAC_LOCK ( pdata ) ;
for ( i = 0 ; i < 40 ; i + + ) {
val = smsc911x_reg_read ( pdata , MAC_CSR_CMD ) ;
if ( ! ( val & MAC_CSR_CMD_CSR_BUSY_ ) )
return 0 ;
}
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Timed out waiting for MAC not BUSY. "
" MAC_CSR_CMD: 0x%08X " , val ) ;
2008-11-05 00:35:37 +00:00
return - EIO ;
}
/* Fetches a MAC register value. Assumes mac_lock is acquired */
static u32 smsc911x_mac_read ( struct smsc911x_data * pdata , unsigned int offset )
{
unsigned int temp ;
SMSC_ASSERT_MAC_LOCK ( pdata ) ;
temp = smsc911x_reg_read ( pdata , MAC_CSR_CMD ) ;
if ( unlikely ( temp & MAC_CSR_CMD_CSR_BUSY_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " MAC busy at entry " ) ;
2008-11-05 00:35:37 +00:00
return 0xFFFFFFFF ;
}
/* Send the MAC cmd */
smsc911x_reg_write ( pdata , MAC_CSR_CMD , ( ( offset & 0xFF ) |
MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_ ) ) ;
/* Workaround for hardware read-after-write restriction */
temp = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
/* Wait for the read to complete */
if ( likely ( smsc911x_mac_complete ( pdata ) = = 0 ) )
return smsc911x_reg_read ( pdata , MAC_CSR_DATA ) ;
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " MAC busy after read " ) ;
2008-11-05 00:35:37 +00:00
return 0xFFFFFFFF ;
}
/* Set a mac register, mac_lock must be acquired before calling */
static void smsc911x_mac_write ( struct smsc911x_data * pdata ,
unsigned int offset , u32 val )
{
unsigned int temp ;
SMSC_ASSERT_MAC_LOCK ( pdata ) ;
temp = smsc911x_reg_read ( pdata , MAC_CSR_CMD ) ;
if ( unlikely ( temp & MAC_CSR_CMD_CSR_BUSY_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw ,
" smsc911x_mac_write failed, MAC busy at entry " ) ;
2008-11-05 00:35:37 +00:00
return ;
}
/* Send data to write */
smsc911x_reg_write ( pdata , MAC_CSR_DATA , val ) ;
/* Write the actual data */
smsc911x_reg_write ( pdata , MAC_CSR_CMD , ( ( offset & 0xFF ) |
MAC_CSR_CMD_CSR_BUSY_ ) ) ;
/* Workaround for hardware read-after-write restriction */
temp = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
/* Wait for the write to complete */
if ( likely ( smsc911x_mac_complete ( pdata ) = = 0 ) )
return ;
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " smsc911x_mac_write failed, MAC busy after write " ) ;
2008-11-05 00:35:37 +00:00
}
/* Get a phy register */
static int smsc911x_mii_read ( struct mii_bus * bus , int phyaddr , int regidx )
{
struct smsc911x_data * pdata = ( struct smsc911x_data * ) bus - > priv ;
unsigned long flags ;
unsigned int addr ;
int i , reg ;
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
/* Confirm MII not busy */
if ( unlikely ( smsc911x_mac_read ( pdata , MII_ACC ) & MII_ACC_MII_BUSY_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " MII is busy in smsc911x_mii_read??? " ) ;
2008-11-05 00:35:37 +00:00
reg = - EIO ;
goto out ;
}
/* Set the address, index & direction (read from PHY) */
addr = ( ( phyaddr & 0x1F ) < < 11 ) | ( ( regidx & 0x1F ) < < 6 ) ;
smsc911x_mac_write ( pdata , MII_ACC , addr ) ;
/* Wait for read to complete w/ timeout */
for ( i = 0 ; i < 100 ; i + + )
if ( ! ( smsc911x_mac_read ( pdata , MII_ACC ) & MII_ACC_MII_BUSY_ ) ) {
reg = smsc911x_mac_read ( pdata , MII_DATA ) ;
goto out ;
}
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Timed out waiting for MII read to finish " ) ;
2008-11-05 00:35:37 +00:00
reg = - EIO ;
out :
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
return reg ;
}
/* Set a phy register */
static int smsc911x_mii_write ( struct mii_bus * bus , int phyaddr , int regidx ,
u16 val )
{
struct smsc911x_data * pdata = ( struct smsc911x_data * ) bus - > priv ;
unsigned long flags ;
unsigned int addr ;
int i , reg ;
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
/* Confirm MII not busy */
if ( unlikely ( smsc911x_mac_read ( pdata , MII_ACC ) & MII_ACC_MII_BUSY_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " MII is busy in smsc911x_mii_write??? " ) ;
2008-11-05 00:35:37 +00:00
reg = - EIO ;
goto out ;
}
/* Put the data to write in the MAC */
smsc911x_mac_write ( pdata , MII_DATA , val ) ;
/* Set the address, index & direction (write to PHY) */
addr = ( ( phyaddr & 0x1F ) < < 11 ) | ( ( regidx & 0x1F ) < < 6 ) |
MII_ACC_MII_WRITE_ ;
smsc911x_mac_write ( pdata , MII_ACC , addr ) ;
/* Wait for write to complete w/ timeout */
for ( i = 0 ; i < 100 ; i + + )
if ( ! ( smsc911x_mac_read ( pdata , MII_ACC ) & MII_ACC_MII_BUSY_ ) ) {
reg = 0 ;
goto out ;
}
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Timed out waiting for MII write to finish " ) ;
2008-11-05 00:35:37 +00:00
reg = - EIO ;
out :
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
return reg ;
}
2009-01-27 06:51:11 +00:00
/* Switch to external phy. Assumes tx and rx are stopped. */
static void smsc911x_phy_enable_external ( struct smsc911x_data * pdata )
2008-11-05 00:35:37 +00:00
{
unsigned int hwcfg = smsc911x_reg_read ( pdata , HW_CFG ) ;
2009-01-27 06:51:11 +00:00
/* Disable phy clocks to the MAC */
hwcfg & = ( ~ HW_CFG_PHY_CLK_SEL_ ) ;
hwcfg | = HW_CFG_PHY_CLK_SEL_CLK_DIS_ ;
smsc911x_reg_write ( pdata , HW_CFG , hwcfg ) ;
udelay ( 10 ) ; /* Enough time for clocks to stop */
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:11 +00:00
/* Switch to external phy */
hwcfg | = HW_CFG_EXT_PHY_EN_ ;
smsc911x_reg_write ( pdata , HW_CFG , hwcfg ) ;
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:11 +00:00
/* Enable phy clocks to the MAC */
hwcfg & = ( ~ HW_CFG_PHY_CLK_SEL_ ) ;
hwcfg | = HW_CFG_PHY_CLK_SEL_EXT_PHY_ ;
smsc911x_reg_write ( pdata , HW_CFG , hwcfg ) ;
udelay ( 10 ) ; /* Enough time for clocks to restart */
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:11 +00:00
hwcfg | = HW_CFG_SMI_SEL_ ;
smsc911x_reg_write ( pdata , HW_CFG , hwcfg ) ;
}
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:11 +00:00
/* Autodetects and enables external phy if present on supported chips.
* autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY
* or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags . */
static void smsc911x_phy_initialise_external ( struct smsc911x_data * pdata )
{
unsigned int hwcfg = smsc911x_reg_read ( pdata , HW_CFG ) ;
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:11 +00:00
if ( pdata - > config . flags & SMSC911X_FORCE_INTERNAL_PHY ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " Forcing internal PHY " ) ;
2009-01-27 06:51:11 +00:00
pdata - > using_extphy = 0 ;
} else if ( pdata - > config . flags & SMSC911X_FORCE_EXTERNAL_PHY ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " Forcing external PHY " ) ;
2009-01-27 06:51:11 +00:00
smsc911x_phy_enable_external ( pdata ) ;
pdata - > using_extphy = 1 ;
} else if ( hwcfg & HW_CFG_EXT_PHY_DET_ ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw ,
" HW_CFG EXT_PHY_DET set, using external PHY " ) ;
2009-01-27 06:51:11 +00:00
smsc911x_phy_enable_external ( pdata ) ;
2008-11-05 00:35:37 +00:00
pdata - > using_extphy = 1 ;
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw ,
" HW_CFG EXT_PHY_DET clear, using internal PHY " ) ;
2009-01-27 06:51:11 +00:00
pdata - > using_extphy = 0 ;
2008-11-05 00:35:37 +00:00
}
}
/* Fetches a tx status out of the status fifo */
static unsigned int smsc911x_tx_get_txstatus ( struct smsc911x_data * pdata )
{
unsigned int result =
smsc911x_reg_read ( pdata , TX_FIFO_INF ) & TX_FIFO_INF_TSUSED_ ;
if ( result ! = 0 )
result = smsc911x_reg_read ( pdata , TX_STATUS_FIFO ) ;
return result ;
}
/* Fetches the next rx status */
static unsigned int smsc911x_rx_get_rxstatus ( struct smsc911x_data * pdata )
{
unsigned int result =
smsc911x_reg_read ( pdata , RX_FIFO_INF ) & RX_FIFO_INF_RXSUSED_ ;
if ( result ! = 0 )
result = smsc911x_reg_read ( pdata , RX_STATUS_FIFO ) ;
return result ;
}
# ifdef USE_PHY_WORK_AROUND
static int smsc911x_phy_check_loopbackpkt ( struct smsc911x_data * pdata )
{
unsigned int tries ;
u32 wrsz ;
u32 rdsz ;
ulong bufp ;
for ( tries = 0 ; tries < 10 ; tries + + ) {
unsigned int txcmd_a ;
unsigned int txcmd_b ;
unsigned int status ;
unsigned int pktlength ;
unsigned int i ;
/* Zero-out rx packet memory */
memset ( pdata - > loopback_rx_pkt , 0 , MIN_PACKET_SIZE ) ;
/* Write tx packet to 118 */
txcmd_a = ( u32 ) ( ( ulong ) pdata - > loopback_tx_pkt & 0x03 ) < < 16 ;
txcmd_a | = TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ ;
txcmd_a | = MIN_PACKET_SIZE ;
txcmd_b = MIN_PACKET_SIZE < < 16 | MIN_PACKET_SIZE ;
smsc911x_reg_write ( pdata , TX_DATA_FIFO , txcmd_a ) ;
smsc911x_reg_write ( pdata , TX_DATA_FIFO , txcmd_b ) ;
bufp = ( ulong ) pdata - > loopback_tx_pkt & ( ~ 0x3 ) ;
wrsz = MIN_PACKET_SIZE + 3 ;
wrsz + = ( u32 ) ( ( ulong ) pdata - > loopback_tx_pkt & 0x3 ) ;
wrsz > > = 2 ;
2011-04-13 17:13:00 -07:00
pdata - > ops - > tx_writefifo ( pdata , ( unsigned int * ) bufp , wrsz ) ;
2008-11-05 00:35:37 +00:00
/* Wait till transmit is done */
i = 60 ;
do {
udelay ( 5 ) ;
status = smsc911x_tx_get_txstatus ( pdata ) ;
} while ( ( i - - ) & & ( ! status ) ) ;
if ( ! status ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw ,
" Failed to transmit during loopback test " ) ;
2008-11-05 00:35:37 +00:00
continue ;
}
if ( status & TX_STS_ES_ ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw ,
" Transmit encountered errors during loopback test " ) ;
2008-11-05 00:35:37 +00:00
continue ;
}
/* Wait till receive is done */
i = 60 ;
do {
udelay ( 5 ) ;
status = smsc911x_rx_get_rxstatus ( pdata ) ;
} while ( ( i - - ) & & ( ! status ) ) ;
if ( ! status ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw ,
" Failed to receive during loopback test " ) ;
2008-11-05 00:35:37 +00:00
continue ;
}
if ( status & RX_STS_ES_ ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw ,
" Receive encountered errors during loopback test " ) ;
2008-11-05 00:35:37 +00:00
continue ;
}
pktlength = ( ( status & 0x3FFF0000UL ) > > 16 ) ;
bufp = ( ulong ) pdata - > loopback_rx_pkt ;
rdsz = pktlength + 3 ;
rdsz + = ( u32 ) ( ( ulong ) pdata - > loopback_rx_pkt & 0x3 ) ;
rdsz > > = 2 ;
2011-04-13 17:13:00 -07:00
pdata - > ops - > rx_readfifo ( pdata , ( unsigned int * ) bufp , rdsz ) ;
2008-11-05 00:35:37 +00:00
if ( pktlength ! = ( MIN_PACKET_SIZE + 4 ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Unexpected packet size "
" during loop back test, size=%d, will retry " ,
pktlength ) ;
2008-11-05 00:35:37 +00:00
} else {
unsigned int j ;
int mismatch = 0 ;
for ( j = 0 ; j < MIN_PACKET_SIZE ; j + + ) {
if ( pdata - > loopback_tx_pkt [ j ]
! = pdata - > loopback_rx_pkt [ j ] ) {
mismatch = 1 ;
break ;
}
}
if ( ! mismatch ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " Successfully verified "
2008-11-05 00:35:37 +00:00
" loopback packet " ) ;
return 0 ;
} else {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Data mismatch "
" during loop back test, will retry " ) ;
2008-11-05 00:35:37 +00:00
}
}
}
return - EIO ;
}
static int smsc911x_phy_reset ( struct smsc911x_data * pdata )
{
unsigned int temp ;
unsigned int i = 100000 ;
2015-11-13 09:46:59 +03:00
temp = smsc911x_reg_read ( pdata , PMT_CTRL ) ;
smsc911x_reg_write ( pdata , PMT_CTRL , temp | PMT_CTRL_PHY_RST_ ) ;
2008-11-05 00:35:37 +00:00
do {
msleep ( 1 ) ;
2015-11-13 09:46:59 +03:00
temp = smsc911x_reg_read ( pdata , PMT_CTRL ) ;
} while ( ( i - - ) & & ( temp & PMT_CTRL_PHY_RST_ ) ) ;
2008-11-05 00:35:37 +00:00
2015-11-13 09:46:59 +03:00
if ( unlikely ( temp & PMT_CTRL_PHY_RST_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " PHY reset failed to complete " ) ;
2008-11-05 00:35:37 +00:00
return - EIO ;
}
/* Extra delay required because the phy may not be completed with
* its reset when BMCR_RESET is cleared . Specs say 256 uS is
* enough delay but using 1 ms here to be safe */
msleep ( 1 ) ;
return 0 ;
}
static int smsc911x_phy_loopbacktest ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
2016-07-03 01:14:20 +02:00
struct phy_device * phy_dev = dev - > phydev ;
2008-11-05 00:35:37 +00:00
int result = - EIO ;
unsigned int i , val ;
unsigned long flags ;
/* Initialise tx packet using broadcast destination address */
2015-03-02 19:54:47 -08:00
eth_broadcast_addr ( pdata - > loopback_tx_pkt ) ;
2008-11-05 00:35:37 +00:00
/* Use incrementing source address */
for ( i = 6 ; i < 12 ; i + + )
pdata - > loopback_tx_pkt [ i ] = ( char ) i ;
/* Set length type field */
pdata - > loopback_tx_pkt [ 12 ] = 0x00 ;
pdata - > loopback_tx_pkt [ 13 ] = 0x00 ;
for ( i = 14 ; i < MIN_PACKET_SIZE ; i + + )
pdata - > loopback_tx_pkt [ i ] = ( char ) i ;
val = smsc911x_reg_read ( pdata , HW_CFG ) ;
val & = HW_CFG_TX_FIF_SZ_ ;
val | = HW_CFG_SF_ ;
smsc911x_reg_write ( pdata , HW_CFG , val ) ;
smsc911x_reg_write ( pdata , TX_CFG , TX_CFG_TX_ON_ ) ;
smsc911x_reg_write ( pdata , RX_CFG ,
( u32 ) ( ( ulong ) pdata - > loopback_rx_pkt & 0x03 ) < < 8 ) ;
for ( i = 0 ; i < 10 ; i + + ) {
/* Set PHY to 10/FD, no ANEG, and loopback mode */
2016-01-06 20:11:16 +01:00
smsc911x_mii_write ( phy_dev - > mdio . bus , phy_dev - > mdio . addr ,
MII_BMCR , BMCR_LOOPBACK | BMCR_FULLDPLX ) ;
2008-11-05 00:35:37 +00:00
/* Enable MAC tx/rx, FD */
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
smsc911x_mac_write ( pdata , MAC_CR , MAC_CR_FDPX_
| MAC_CR_TXEN_ | MAC_CR_RXEN_ ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
if ( smsc911x_phy_check_loopbackpkt ( pdata ) = = 0 ) {
result = 0 ;
break ;
}
pdata - > resetcount + + ;
/* Disable MAC rx */
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
smsc911x_mac_write ( pdata , MAC_CR , 0 ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
smsc911x_phy_reset ( pdata ) ;
}
/* Disable MAC */
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
smsc911x_mac_write ( pdata , MAC_CR , 0 ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
/* Cancel PHY loopback mode */
2016-01-06 20:11:16 +01:00
smsc911x_mii_write ( phy_dev - > mdio . bus , phy_dev - > mdio . addr , MII_BMCR , 0 ) ;
2008-11-05 00:35:37 +00:00
smsc911x_reg_write ( pdata , TX_CFG , 0 ) ;
smsc911x_reg_write ( pdata , RX_CFG , 0 ) ;
return result ;
}
# endif /* USE_PHY_WORK_AROUND */
static void smsc911x_phy_update_flowcontrol ( struct smsc911x_data * pdata )
{
2016-07-03 01:14:20 +02:00
struct net_device * ndev = pdata - > dev ;
struct phy_device * phy_dev = ndev - > phydev ;
2008-11-05 00:35:37 +00:00
u32 afc = smsc911x_reg_read ( pdata , AFC_CFG ) ;
u32 flow ;
unsigned long flags ;
if ( phy_dev - > duplex = = DUPLEX_FULL ) {
u16 lcladv = phy_read ( phy_dev , MII_ADVERTISE ) ;
u16 rmtadv = phy_read ( phy_dev , MII_LPA ) ;
2008-12-16 02:00:48 -08:00
u8 cap = mii_resolve_flowctrl_fdx ( lcladv , rmtadv ) ;
2008-11-05 00:35:37 +00:00
if ( cap & FLOW_CTRL_RX )
flow = 0xFFFF0002 ;
else
flow = 0 ;
if ( cap & FLOW_CTRL_TX )
afc | = 0xF ;
else
afc & = ~ 0xF ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " rx pause %s, tx pause %s " ,
( cap & FLOW_CTRL_RX ? " enabled " : " disabled " ) ,
( cap & FLOW_CTRL_TX ? " enabled " : " disabled " ) ) ;
2008-11-05 00:35:37 +00:00
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " half duplex " ) ;
2008-11-05 00:35:37 +00:00
flow = 0 ;
afc | = 0xF ;
}
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
smsc911x_mac_write ( pdata , FLOW , flow ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
smsc911x_reg_write ( pdata , AFC_CFG , afc ) ;
}
/* Update link mode if anything has changed. Called periodically when the
* PHY is in polling mode , even if nothing has changed . */
static void smsc911x_phy_adjust_link ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
2016-07-03 01:14:20 +02:00
struct phy_device * phy_dev = dev - > phydev ;
2008-11-05 00:35:37 +00:00
unsigned long flags ;
int carrier ;
if ( phy_dev - > duplex ! = pdata - > last_duplex ) {
unsigned int mac_cr ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " duplex state has changed " ) ;
2008-11-05 00:35:37 +00:00
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
mac_cr = smsc911x_mac_read ( pdata , MAC_CR ) ;
if ( phy_dev - > duplex ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw ,
" configuring for full duplex mode " ) ;
2008-11-05 00:35:37 +00:00
mac_cr | = MAC_CR_FDPX_ ;
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw ,
" configuring for half duplex mode " ) ;
2008-11-05 00:35:37 +00:00
mac_cr & = ~ MAC_CR_FDPX_ ;
}
smsc911x_mac_write ( pdata , MAC_CR , mac_cr ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
smsc911x_phy_update_flowcontrol ( pdata ) ;
pdata - > last_duplex = phy_dev - > duplex ;
}
carrier = netif_carrier_ok ( dev ) ;
if ( carrier ! = pdata - > last_carrier ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " carrier state has changed " ) ;
2008-11-05 00:35:37 +00:00
if ( carrier ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " configuring for carrier OK " ) ;
2008-11-05 00:35:37 +00:00
if ( ( pdata - > gpio_orig_setting & GPIO_CFG_LED1_EN_ ) & &
( ! pdata - > using_extphy ) ) {
2010-03-16 11:47:56 +01:00
/* Restore original GPIO configuration */
2008-11-05 00:35:37 +00:00
pdata - > gpio_setting = pdata - > gpio_orig_setting ;
smsc911x_reg_write ( pdata , GPIO_CFG ,
pdata - > gpio_setting ) ;
}
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " configuring for no carrier " ) ;
2008-11-05 00:35:37 +00:00
/* Check global setting that LED1
* usage is 10 / 100 indicator */
pdata - > gpio_setting = smsc911x_reg_read ( pdata ,
GPIO_CFG ) ;
2009-12-03 07:58:21 +00:00
if ( ( pdata - > gpio_setting & GPIO_CFG_LED1_EN_ ) & &
( ! pdata - > using_extphy ) ) {
2008-11-05 00:35:37 +00:00
/* Force 10/100 LED off, after saving
2010-03-16 11:47:56 +01:00
* original GPIO configuration */
2008-11-05 00:35:37 +00:00
pdata - > gpio_orig_setting = pdata - > gpio_setting ;
pdata - > gpio_setting & = ~ GPIO_CFG_LED1_EN_ ;
pdata - > gpio_setting | = ( GPIO_CFG_GPIOBUF0_
| GPIO_CFG_GPIODIR0_
| GPIO_CFG_GPIOD0_ ) ;
smsc911x_reg_write ( pdata , GPIO_CFG ,
pdata - > gpio_setting ) ;
}
}
pdata - > last_carrier = carrier ;
}
}
static int smsc911x_mii_probe ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
struct phy_device * phydev = NULL ;
2010-02-16 21:54:58 +00:00
int ret ;
2008-11-05 00:35:37 +00:00
/* find the first phy */
2010-02-16 21:54:58 +00:00
phydev = phy_find_first ( pdata - > mii_bus ) ;
2008-11-05 00:35:37 +00:00
if ( ! phydev ) {
2011-03-25 14:21:22 +00:00
netdev_err ( dev , " no PHY found \n " ) ;
2008-11-05 00:35:37 +00:00
return - ENODEV ;
}
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe , " PHY: addr %d, phy_id 0x%08X " ,
2016-01-06 20:11:16 +01:00
phydev - > mdio . addr , phydev - > phy_id ) ;
2010-02-16 21:54:58 +00:00
2013-01-14 00:52:52 +00:00
ret = phy_connect_direct ( dev , phydev , & smsc911x_phy_adjust_link ,
pdata - > config . phy_interface ) ;
2008-11-05 00:35:37 +00:00
2010-02-16 21:54:58 +00:00
if ( ret ) {
2011-03-25 14:21:22 +00:00
netdev_err ( dev , " Could not attach to PHY \n " ) ;
2010-02-16 21:54:58 +00:00
return ret ;
2008-11-05 00:35:37 +00:00
}
2016-01-06 20:11:13 +01:00
phy_attached_info ( phydev ) ;
2008-11-05 00:35:37 +00:00
/* mask with MAC supported features */
phydev - > supported & = ( PHY_BASIC_FEATURES | SUPPORTED_Pause |
SUPPORTED_Asym_Pause ) ;
phydev - > advertising = phydev - > supported ;
pdata - > last_duplex = - 1 ;
pdata - > last_carrier = - 1 ;
# ifdef USE_PHY_WORK_AROUND
if ( smsc911x_phy_loopbacktest ( dev ) < 0 ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Failed Loop Back Test " ) ;
2015-10-29 09:45:22 +03:00
phy_disconnect ( phydev ) ;
2008-11-05 00:35:37 +00:00
return - ENODEV ;
}
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " Passed Loop Back Test " ) ;
2008-11-05 00:35:37 +00:00
# endif /* USE_PHY_WORK_AROUND */
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " phy initialised successfully " ) ;
2008-11-05 00:35:37 +00:00
return 0 ;
}
2012-12-03 09:23:38 -05:00
static int smsc911x_mii_init ( struct platform_device * pdev ,
2012-12-06 14:30:56 +00:00
struct net_device * dev )
2008-11-05 00:35:37 +00:00
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
2016-01-06 20:11:15 +01:00
int err = - ENXIO ;
2008-11-05 00:35:37 +00:00
pdata - > mii_bus = mdiobus_alloc ( ) ;
if ( ! pdata - > mii_bus ) {
err = - ENOMEM ;
goto err_out_1 ;
}
pdata - > mii_bus - > name = SMSC_MDIONAME ;
2012-01-09 23:59:19 +00:00
snprintf ( pdata - > mii_bus - > id , MII_BUS_ID_SIZE , " %s-%x " ,
pdev - > name , pdev - > id ) ;
2008-11-05 00:35:37 +00:00
pdata - > mii_bus - > priv = pdata ;
pdata - > mii_bus - > read = smsc911x_mii_read ;
pdata - > mii_bus - > write = smsc911x_mii_write ;
pdata - > mii_bus - > parent = & pdev - > dev ;
switch ( pdata - > idrev & 0xFFFF0000 ) {
case 0x01170000 :
case 0x01150000 :
case 0x117A0000 :
case 0x115A0000 :
/* External PHY supported, try to autodetect */
2009-01-27 06:51:11 +00:00
smsc911x_phy_initialise_external ( pdata ) ;
2008-11-05 00:35:37 +00:00
break ;
default :
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " External PHY is not supported, "
" using internal PHY " ) ;
2009-01-27 06:51:11 +00:00
pdata - > using_extphy = 0 ;
2008-11-05 00:35:37 +00:00
break ;
}
if ( ! pdata - > using_extphy ) {
/* Mask all PHYs except ID 1 (internal) */
pdata - > mii_bus - > phy_mask = ~ ( 1 < < 1 ) ;
}
if ( mdiobus_register ( pdata - > mii_bus ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe , " Error registering mii bus " ) ;
2008-11-05 00:35:37 +00:00
goto err_out_free_bus_2 ;
}
return 0 ;
err_out_free_bus_2 :
mdiobus_free ( pdata - > mii_bus ) ;
err_out_1 :
return err ;
}
/* Gets the number of tx statuses in the fifo */
static unsigned int smsc911x_tx_get_txstatcount ( struct smsc911x_data * pdata )
{
return ( smsc911x_reg_read ( pdata , TX_FIFO_INF )
& TX_FIFO_INF_TSUSED_ ) > > 16 ;
}
/* Reads tx statuses and increments counters where necessary */
static void smsc911x_tx_update_txcounters ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
unsigned int tx_stat ;
while ( ( tx_stat = smsc911x_tx_get_txstatus ( pdata ) ) ! = 0 ) {
if ( unlikely ( tx_stat & 0x80000000 ) ) {
/* In this driver the packet tag is used as the packet
* length . Since a packet length can never reach the
* size of 0x8000 , this bit is reserved . It is worth
* noting that the " reserved bit " in the warning above
* does not reference a hardware defined reserved bit
* but rather a driver defined one .
*/
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Packet tag reserved bit is high " ) ;
2008-11-05 00:35:37 +00:00
} else {
2009-03-19 00:24:44 +00:00
if ( unlikely ( tx_stat & TX_STS_ES_ ) ) {
2008-11-05 00:35:37 +00:00
dev - > stats . tx_errors + + ;
} else {
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = ( tx_stat > > 16 ) ;
}
2009-03-19 00:24:44 +00:00
if ( unlikely ( tx_stat & TX_STS_EXCESS_COL_ ) ) {
2008-11-05 00:35:37 +00:00
dev - > stats . collisions + = 16 ;
dev - > stats . tx_aborted_errors + = 1 ;
} else {
dev - > stats . collisions + =
( ( tx_stat > > 3 ) & 0xF ) ;
}
2009-03-19 00:24:44 +00:00
if ( unlikely ( tx_stat & TX_STS_LOST_CARRIER_ ) )
2008-11-05 00:35:37 +00:00
dev - > stats . tx_carrier_errors + = 1 ;
2009-03-19 00:24:44 +00:00
if ( unlikely ( tx_stat & TX_STS_LATE_COL_ ) ) {
2008-11-05 00:35:37 +00:00
dev - > stats . collisions + + ;
dev - > stats . tx_aborted_errors + + ;
}
}
}
}
/* Increments the Rx error counters */
static void
smsc911x_rx_counterrors ( struct net_device * dev , unsigned int rxstat )
{
int crc_err = 0 ;
2009-03-19 00:24:44 +00:00
if ( unlikely ( rxstat & RX_STS_ES_ ) ) {
2008-11-05 00:35:37 +00:00
dev - > stats . rx_errors + + ;
2009-03-19 00:24:44 +00:00
if ( unlikely ( rxstat & RX_STS_CRC_ERR_ ) ) {
2008-11-05 00:35:37 +00:00
dev - > stats . rx_crc_errors + + ;
crc_err = 1 ;
}
}
if ( likely ( ! crc_err ) ) {
2009-03-19 00:24:44 +00:00
if ( unlikely ( ( rxstat & RX_STS_FRAME_TYPE_ ) & &
( rxstat & RX_STS_LENGTH_ERR_ ) ) )
2008-11-05 00:35:37 +00:00
dev - > stats . rx_length_errors + + ;
if ( rxstat & RX_STS_MCAST_ )
dev - > stats . multicast + + ;
}
}
/* Quickly dumps bad packets */
static void
2012-04-12 05:54:09 +00:00
smsc911x_rx_fastforward ( struct smsc911x_data * pdata , unsigned int pktwords )
2008-11-05 00:35:37 +00:00
{
if ( likely ( pktwords > = 4 ) ) {
unsigned int timeout = 500 ;
unsigned int val ;
smsc911x_reg_write ( pdata , RX_DP_CTRL , RX_DP_CTRL_RX_FFWD_ ) ;
do {
udelay ( 1 ) ;
val = smsc911x_reg_read ( pdata , RX_DP_CTRL ) ;
2009-03-04 07:33:24 +00:00
} while ( ( val & RX_DP_CTRL_RX_FFWD_ ) & & - - timeout ) ;
2008-11-05 00:35:37 +00:00
if ( unlikely ( timeout = = 0 ) )
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " Timed out waiting for "
" RX FFWD to finish, RX_DP_CTRL: 0x%08X " , val ) ;
2008-11-05 00:35:37 +00:00
} else {
unsigned int temp ;
while ( pktwords - - )
temp = smsc911x_reg_read ( pdata , RX_DATA_FIFO ) ;
}
}
/* NAPI poll function */
static int smsc911x_poll ( struct napi_struct * napi , int budget )
{
struct smsc911x_data * pdata =
container_of ( napi , struct smsc911x_data , napi ) ;
struct net_device * dev = pdata - > dev ;
int npackets = 0 ;
2009-11-12 02:14:38 +00:00
while ( npackets < budget ) {
2008-11-05 00:35:37 +00:00
unsigned int pktlength ;
unsigned int pktwords ;
struct sk_buff * skb ;
unsigned int rxstat = smsc911x_rx_get_rxstatus ( pdata ) ;
if ( ! rxstat ) {
unsigned int temp ;
/* We processed all packets available. Tell NAPI it can
* stop polling then re - enable rx interrupts */
smsc911x_reg_write ( pdata , INT_STS , INT_STS_RSFL_ ) ;
2009-01-19 16:43:59 -08:00
napi_complete ( napi ) ;
2008-11-05 00:35:37 +00:00
temp = smsc911x_reg_read ( pdata , INT_EN ) ;
temp | = INT_EN_RSFL_EN_ ;
smsc911x_reg_write ( pdata , INT_EN , temp ) ;
break ;
}
/* Count packet for NAPI scheduling, even if it has an error.
* Error packets still require cycles to discard */
npackets + + ;
pktlength = ( ( rxstat & 0x3FFF0000 ) > > 16 ) ;
pktwords = ( pktlength + NET_IP_ALIGN + 3 ) > > 2 ;
smsc911x_rx_counterrors ( dev , rxstat ) ;
if ( unlikely ( rxstat & RX_STS_ES_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , rx_err ,
" Discarding packet with error bit set " ) ;
2008-11-05 00:35:37 +00:00
/* Packet has an error, discard it and continue with
* the next */
smsc911x_rx_fastforward ( pdata , pktwords ) ;
dev - > stats . rx_dropped + + ;
continue ;
}
2012-04-12 05:54:09 +00:00
skb = netdev_alloc_skb ( dev , pktwords < < 2 ) ;
2008-11-05 00:35:37 +00:00
if ( unlikely ( ! skb ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , rx_err ,
" Unable to allocate skb for rx packet " ) ;
2008-11-05 00:35:37 +00:00
/* Drop the packet and stop this polling iteration */
smsc911x_rx_fastforward ( pdata , pktwords ) ;
dev - > stats . rx_dropped + + ;
break ;
}
2012-04-12 05:54:09 +00:00
pdata - > ops - > rx_readfifo ( pdata ,
( unsigned int * ) skb - > data , pktwords ) ;
2008-11-05 00:35:37 +00:00
/* Align IP on 16B boundary */
skb_reserve ( skb , NET_IP_ALIGN ) ;
skb_put ( skb , pktlength - 4 ) ;
skb - > protocol = eth_type_trans ( skb , dev ) ;
2010-09-02 13:07:41 -07:00
skb_checksum_none_assert ( skb ) ;
2008-11-05 00:35:37 +00:00
netif_receive_skb ( skb ) ;
/* Update counters */
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = ( pktlength - 4 ) ;
}
/* Return total received packets */
return npackets ;
}
/* Returns hash bit number for given MAC address
* Example :
* 01 00 5 E 00 00 01 - > returns bit number 31 */
static unsigned int smsc911x_hash ( char addr [ ETH_ALEN ] )
{
return ( ether_crc ( ETH_ALEN , addr ) > > 26 ) & 0x3f ;
}
static void smsc911x_rx_multicast_update ( struct smsc911x_data * pdata )
{
/* Performs the multicast & mac_cr update. This is called when
* safe on the current hardware , and with the mac_lock held */
unsigned int mac_cr ;
SMSC_ASSERT_MAC_LOCK ( pdata ) ;
mac_cr = smsc911x_mac_read ( pdata , MAC_CR ) ;
mac_cr | = pdata - > set_bits_mask ;
mac_cr & = ~ ( pdata - > clear_bits_mask ) ;
smsc911x_mac_write ( pdata , MAC_CR , mac_cr ) ;
smsc911x_mac_write ( pdata , HASHH , pdata - > hashhi ) ;
smsc911x_mac_write ( pdata , HASHL , pdata - > hashlo ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X " ,
mac_cr , pdata - > hashhi , pdata - > hashlo ) ;
2008-11-05 00:35:37 +00:00
}
static void smsc911x_rx_multicast_update_workaround ( struct smsc911x_data * pdata )
{
unsigned int mac_cr ;
/* This function is only called for older LAN911x devices
* ( revA or revB ) , where MAC_CR , HASHH and HASHL should not
* be modified during Rx - newer devices immediately update the
* registers .
*
* This is called from interrupt context */
spin_lock ( & pdata - > mac_lock ) ;
/* Check Rx has stopped */
if ( smsc911x_mac_read ( pdata , MAC_CR ) & MAC_CR_RXEN_ )
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , drv , " Rx not stopped " ) ;
2008-11-05 00:35:37 +00:00
/* Perform the update - safe to do now Rx has stopped */
smsc911x_rx_multicast_update ( pdata ) ;
/* Re-enable Rx */
mac_cr = smsc911x_mac_read ( pdata , MAC_CR ) ;
mac_cr | = MAC_CR_RXEN_ ;
smsc911x_mac_write ( pdata , MAC_CR , mac_cr ) ;
pdata - > multicast_update_pending = 0 ;
spin_unlock ( & pdata - > mac_lock ) ;
}
2014-11-13 09:14:34 +01:00
static int smsc911x_phy_general_power_up ( struct smsc911x_data * pdata )
{
2016-07-03 01:14:20 +02:00
struct net_device * ndev = pdata - > dev ;
struct phy_device * phy_dev = ndev - > phydev ;
2014-11-13 09:14:34 +01:00
int rc = 0 ;
2016-07-03 01:14:20 +02:00
if ( ! phy_dev )
2014-11-13 09:14:34 +01:00
return rc ;
/* If the internal PHY is in General Power-Down mode, all, except the
* management interface , is powered - down and stays in that condition as
* long as Phy register bit 0.11 is HIGH .
*
* In that case , clear the bit 0.11 , so the PHY powers up and we can
* access to the phy registers .
*/
2016-07-03 01:14:20 +02:00
rc = phy_read ( phy_dev , MII_BMCR ) ;
2014-11-13 09:14:34 +01:00
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed reading PHY control reg " ) ;
return rc ;
}
/* If the PHY general power-down bit is not set is not necessary to
* disable the general power down - mode .
*/
if ( rc & BMCR_PDOWN ) {
2016-07-03 01:14:20 +02:00
rc = phy_write ( phy_dev , MII_BMCR , rc & ~ BMCR_PDOWN ) ;
2014-11-13 09:14:34 +01:00
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed writing PHY control reg " ) ;
return rc ;
}
usleep_range ( 1000 , 1500 ) ;
}
return 0 ;
}
2012-01-03 13:36:19 +00:00
static int smsc911x_phy_disable_energy_detect ( struct smsc911x_data * pdata )
{
2016-07-03 01:14:20 +02:00
struct net_device * ndev = pdata - > dev ;
struct phy_device * phy_dev = ndev - > phydev ;
2012-01-03 13:36:19 +00:00
int rc = 0 ;
2016-07-03 01:14:20 +02:00
if ( ! phy_dev )
2012-01-03 13:36:19 +00:00
return rc ;
2016-07-03 01:14:20 +02:00
rc = phy_read ( phy_dev , MII_LAN83C185_CTRL_STATUS ) ;
2012-01-03 13:36:19 +00:00
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed reading PHY control reg " ) ;
return rc ;
}
2014-11-13 05:26:19 +04:00
/* Only disable if energy detect mode is already enabled */
if ( rc & MII_LAN83C185_EDPWRDOWN ) {
2012-01-03 13:36:19 +00:00
/* Disable energy detect mode for this SMSC Transceivers */
2016-07-03 01:14:20 +02:00
rc = phy_write ( phy_dev , MII_LAN83C185_CTRL_STATUS ,
2012-01-03 13:36:19 +00:00
rc & ( ~ MII_LAN83C185_EDPWRDOWN ) ) ;
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed writing PHY control reg " ) ;
return rc ;
}
2014-11-13 05:26:20 +04:00
/* Allow PHY to wakeup */
mdelay ( 2 ) ;
2012-01-03 13:36:19 +00:00
}
return 0 ;
}
static int smsc911x_phy_enable_energy_detect ( struct smsc911x_data * pdata )
{
2016-07-03 01:14:20 +02:00
struct net_device * ndev = pdata - > dev ;
struct phy_device * phy_dev = ndev - > phydev ;
2012-01-03 13:36:19 +00:00
int rc = 0 ;
2016-07-03 01:14:20 +02:00
if ( ! phy_dev )
2012-01-03 13:36:19 +00:00
return rc ;
2016-07-03 01:14:20 +02:00
rc = phy_read ( phy_dev , MII_LAN83C185_CTRL_STATUS ) ;
2012-01-03 13:36:19 +00:00
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed reading PHY control reg " ) ;
return rc ;
}
/* Only enable if energy detect mode is already disabled */
if ( ! ( rc & MII_LAN83C185_EDPWRDOWN ) ) {
/* Enable energy detect mode for this SMSC Transceivers */
2016-07-03 01:14:20 +02:00
rc = phy_write ( phy_dev , MII_LAN83C185_CTRL_STATUS ,
2012-01-03 13:36:19 +00:00
rc | MII_LAN83C185_EDPWRDOWN ) ;
if ( rc < 0 ) {
SMSC_WARN ( pdata , drv , " Failed writing PHY control reg " ) ;
return rc ;
}
}
return 0 ;
}
2008-11-05 00:35:37 +00:00
static int smsc911x_soft_reset ( struct smsc911x_data * pdata )
{
unsigned int timeout ;
unsigned int temp ;
2012-01-03 13:36:19 +00:00
int ret ;
2014-11-13 09:14:34 +01:00
/*
* Make sure to power - up the PHY chip before doing a reset , otherwise
* the reset fails .
*/
ret = smsc911x_phy_general_power_up ( pdata ) ;
if ( ret ) {
SMSC_WARN ( pdata , drv , " Failed to power-up the PHY chip " ) ;
return ret ;
}
2012-01-03 13:36:19 +00:00
/*
* LAN9210 / LAN9211 / LAN9220 / LAN9221 chips have an internal PHY that
* are initialized in a Energy Detect Power - Down mode that prevents
* the MAC chip to be software reseted . So we have to wakeup the PHY
* before .
*/
if ( pdata - > generation = = 4 ) {
ret = smsc911x_phy_disable_energy_detect ( pdata ) ;
if ( ret ) {
SMSC_WARN ( pdata , drv , " Failed to wakeup the PHY chip " ) ;
return ret ;
}
}
2008-11-05 00:35:37 +00:00
/* Reset the LAN911x */
smsc911x_reg_write ( pdata , HW_CFG , HW_CFG_SRST_ ) ;
timeout = 10 ;
do {
udelay ( 10 ) ;
temp = smsc911x_reg_read ( pdata , HW_CFG ) ;
} while ( ( - - timeout ) & & ( temp & HW_CFG_SRST_ ) ) ;
if ( unlikely ( temp & HW_CFG_SRST_ ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , drv , " Failed to complete reset " ) ;
2008-11-05 00:35:37 +00:00
return - EIO ;
}
2012-01-03 13:36:19 +00:00
if ( pdata - > generation = = 4 ) {
ret = smsc911x_phy_enable_energy_detect ( pdata ) ;
if ( ret ) {
SMSC_WARN ( pdata , drv , " Failed to wakeup the PHY chip " ) ;
return ret ;
}
}
2008-11-05 00:35:37 +00:00
return 0 ;
}
/* Sets the device MAC address to dev_addr, called with mac_lock held */
static void
2009-03-19 00:24:46 +00:00
smsc911x_set_hw_mac_address ( struct smsc911x_data * pdata , u8 dev_addr [ 6 ] )
2008-11-05 00:35:37 +00:00
{
u32 mac_high16 = ( dev_addr [ 5 ] < < 8 ) | dev_addr [ 4 ] ;
u32 mac_low32 = ( dev_addr [ 3 ] < < 24 ) | ( dev_addr [ 2 ] < < 16 ) |
( dev_addr [ 1 ] < < 8 ) | dev_addr [ 0 ] ;
SMSC_ASSERT_MAC_LOCK ( pdata ) ;
smsc911x_mac_write ( pdata , ADDRH , mac_high16 ) ;
smsc911x_mac_write ( pdata , ADDRL , mac_low32 ) ;
}
2012-06-22 01:10:15 +00:00
static void smsc911x_disable_irq_chip ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
smsc911x_reg_write ( pdata , INT_EN , 0 ) ;
smsc911x_reg_write ( pdata , INT_STS , 0xFFFFFFFF ) ;
}
2016-09-01 15:15:08 -05:00
static irqreturn_t smsc911x_irqhandler ( int irq , void * dev_id )
{
struct net_device * dev = dev_id ;
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
u32 intsts = smsc911x_reg_read ( pdata , INT_STS ) ;
u32 inten = smsc911x_reg_read ( pdata , INT_EN ) ;
int serviced = IRQ_NONE ;
u32 temp ;
if ( unlikely ( intsts & inten & INT_STS_SW_INT_ ) ) {
temp = smsc911x_reg_read ( pdata , INT_EN ) ;
temp & = ( ~ INT_EN_SW_INT_EN_ ) ;
smsc911x_reg_write ( pdata , INT_EN , temp ) ;
smsc911x_reg_write ( pdata , INT_STS , INT_STS_SW_INT_ ) ;
pdata - > software_irq_signal = 1 ;
smp_wmb ( ) ;
serviced = IRQ_HANDLED ;
}
if ( unlikely ( intsts & inten & INT_STS_RXSTOP_INT_ ) ) {
/* Called when there is a multicast update scheduled and
* it is now safe to complete the update */
SMSC_TRACE ( pdata , intr , " RX Stop interrupt " ) ;
smsc911x_reg_write ( pdata , INT_STS , INT_STS_RXSTOP_INT_ ) ;
if ( pdata - > multicast_update_pending )
smsc911x_rx_multicast_update_workaround ( pdata ) ;
serviced = IRQ_HANDLED ;
}
if ( intsts & inten & INT_STS_TDFA_ ) {
temp = smsc911x_reg_read ( pdata , FIFO_INT ) ;
temp | = FIFO_INT_TX_AVAIL_LEVEL_ ;
smsc911x_reg_write ( pdata , FIFO_INT , temp ) ;
smsc911x_reg_write ( pdata , INT_STS , INT_STS_TDFA_ ) ;
netif_wake_queue ( dev ) ;
serviced = IRQ_HANDLED ;
}
if ( unlikely ( intsts & inten & INT_STS_RXE_ ) ) {
SMSC_TRACE ( pdata , intr , " RX Error interrupt " ) ;
smsc911x_reg_write ( pdata , INT_STS , INT_STS_RXE_ ) ;
serviced = IRQ_HANDLED ;
}
if ( likely ( intsts & inten & INT_STS_RSFL_ ) ) {
if ( likely ( napi_schedule_prep ( & pdata - > napi ) ) ) {
/* Disable Rx interrupts */
temp = smsc911x_reg_read ( pdata , INT_EN ) ;
temp & = ( ~ INT_EN_RSFL_EN_ ) ;
smsc911x_reg_write ( pdata , INT_EN , temp ) ;
/* Schedule a NAPI poll */
__napi_schedule ( & pdata - > napi ) ;
} else {
SMSC_WARN ( pdata , rx_err , " napi_schedule_prep failed " ) ;
}
serviced = IRQ_HANDLED ;
}
return serviced ;
}
2008-11-05 00:35:37 +00:00
static int smsc911x_open ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
unsigned int timeout ;
unsigned int temp ;
unsigned int intcfg ;
2016-09-01 15:15:06 -05:00
int retval ;
2016-09-01 15:15:09 -05:00
int irq_flags ;
2008-11-05 00:35:37 +00:00
2016-09-01 15:15:07 -05:00
/* find and start the given phy */
2016-07-03 01:14:20 +02:00
if ( ! dev - > phydev ) {
2016-09-01 15:15:07 -05:00
retval = smsc911x_mii_probe ( dev ) ;
if ( retval < 0 ) {
SMSC_WARN ( pdata , probe , " Error starting phy " ) ;
goto out ;
}
2008-11-05 00:35:37 +00:00
}
/* Reset the LAN911x */
2016-09-01 15:15:06 -05:00
retval = smsc911x_soft_reset ( pdata ) ;
if ( retval ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , hw , " soft reset failed " ) ;
2016-09-01 15:15:07 -05:00
goto mii_free_out ;
2008-11-05 00:35:37 +00:00
}
smsc911x_reg_write ( pdata , HW_CFG , 0x00050000 ) ;
smsc911x_reg_write ( pdata , AFC_CFG , 0x006E3740 ) ;
2011-03-02 04:07:21 +00:00
/* Increase the legal frame size of VLAN tagged frames to 1522 bytes */
spin_lock_irq ( & pdata - > mac_lock ) ;
smsc911x_mac_write ( pdata , VLAN1 , ETH_P_8021Q ) ;
spin_unlock_irq ( & pdata - > mac_lock ) ;
2008-11-05 00:35:37 +00:00
/* Make sure EEPROM has finished loading before setting GPIO_CFG */
timeout = 50 ;
2009-03-04 07:33:25 +00:00
while ( ( smsc911x_reg_read ( pdata , E2P_CMD ) & E2P_CMD_EPC_BUSY_ ) & &
- - timeout ) {
2008-11-05 00:35:37 +00:00
udelay ( 10 ) ;
}
if ( unlikely ( timeout = = 0 ) )
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , ifup ,
" Timed out waiting for EEPROM busy bit to clear " ) ;
2008-11-05 00:35:37 +00:00
smsc911x_reg_write ( pdata , GPIO_CFG , 0x70070000 ) ;
/* The soft reset above cleared the device's MAC address,
* restore it from local copy ( set in probe ) */
spin_lock_irq ( & pdata - > mac_lock ) ;
2009-03-19 00:24:46 +00:00
smsc911x_set_hw_mac_address ( pdata , dev - > dev_addr ) ;
2008-11-05 00:35:37 +00:00
spin_unlock_irq ( & pdata - > mac_lock ) ;
/* Initialise irqs, but leave all sources disabled */
2012-06-22 01:10:15 +00:00
smsc911x_disable_irq_chip ( dev ) ;
2008-11-05 00:35:37 +00:00
/* Set interrupt deassertion to 100uS */
intcfg = ( ( 10 < < 24 ) | INT_CFG_IRQ_EN_ ) ;
2008-11-05 00:35:38 +00:00
if ( pdata - > config . irq_polarity ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " irq polarity: active high " ) ;
2008-11-05 00:35:37 +00:00
intcfg | = INT_CFG_IRQ_POL_ ;
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " irq polarity: active low " ) ;
2008-11-05 00:35:37 +00:00
}
2008-11-05 00:35:38 +00:00
if ( pdata - > config . irq_type ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " irq type: push-pull " ) ;
2008-11-05 00:35:37 +00:00
intcfg | = INT_CFG_IRQ_TYPE_ ;
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " irq type: open drain " ) ;
2008-11-05 00:35:37 +00:00
}
smsc911x_reg_write ( pdata , INT_CFG , intcfg ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " Testing irq handler using IRQ %d " , dev - > irq ) ;
2008-11-05 00:35:37 +00:00
pdata - > software_irq_signal = 0 ;
smp_wmb ( ) ;
2016-09-01 15:15:09 -05:00
irq_flags = irq_get_trigger_type ( dev - > irq ) ;
retval = request_irq ( dev - > irq , smsc911x_irqhandler ,
irq_flags | IRQF_SHARED , dev - > name , dev ) ;
if ( retval ) {
SMSC_WARN ( pdata , probe ,
" Unable to claim requested irq: %d " , dev - > irq ) ;
goto mii_free_out ;
}
2008-11-05 00:35:37 +00:00
temp = smsc911x_reg_read ( pdata , INT_EN ) ;
temp | = INT_EN_SW_INT_EN_ ;
smsc911x_reg_write ( pdata , INT_EN , temp ) ;
timeout = 1000 ;
while ( timeout - - ) {
if ( pdata - > software_irq_signal )
break ;
msleep ( 1 ) ;
}
if ( ! pdata - > software_irq_signal ) {
2011-03-25 14:21:22 +00:00
netdev_warn ( dev , " ISR failed signaling test (IRQ %d) \n " ,
dev - > irq ) ;
2016-09-01 15:15:06 -05:00
retval = - ENODEV ;
2016-09-01 15:15:09 -05:00
goto irq_stop_out ;
2008-11-05 00:35:37 +00:00
}
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifup , " IRQ handler passed test using IRQ %d " ,
dev - > irq ) ;
2008-11-05 00:35:37 +00:00
2011-03-25 14:21:22 +00:00
netdev_info ( dev , " SMSC911x/921x identified at %#08lx, IRQ: %d \n " ,
( unsigned long ) pdata - > ioaddr , dev - > irq ) ;
2008-11-05 00:35:37 +00:00
2009-03-18 23:37:18 -07:00
/* Reset the last known duplex and carrier */
pdata - > last_duplex = - 1 ;
pdata - > last_carrier = - 1 ;
2008-11-05 00:35:37 +00:00
/* Bring the PHY up */
2016-07-03 01:14:20 +02:00
phy_start ( dev - > phydev ) ;
2008-11-05 00:35:37 +00:00
temp = smsc911x_reg_read ( pdata , HW_CFG ) ;
/* Preserve TX FIFO size and external PHY configuration */
temp & = ( HW_CFG_TX_FIF_SZ_ | 0x00000FFF ) ;
temp | = HW_CFG_SF_ ;
smsc911x_reg_write ( pdata , HW_CFG , temp ) ;
temp = smsc911x_reg_read ( pdata , FIFO_INT ) ;
temp | = FIFO_INT_TX_AVAIL_LEVEL_ ;
temp & = ~ ( FIFO_INT_RX_STS_LEVEL_ ) ;
smsc911x_reg_write ( pdata , FIFO_INT , temp ) ;
/* set RX Data offset to 2 bytes for alignment */
2012-04-12 05:54:09 +00:00
smsc911x_reg_write ( pdata , RX_CFG , ( NET_IP_ALIGN < < 8 ) ) ;
2008-11-05 00:35:37 +00:00
/* enable NAPI polling before enabling RX interrupts */
napi_enable ( & pdata - > napi ) ;
temp = smsc911x_reg_read ( pdata , INT_EN ) ;
2009-01-26 21:33:16 -08:00
temp | = ( INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_ ) ;
2008-11-05 00:35:37 +00:00
smsc911x_reg_write ( pdata , INT_EN , temp ) ;
spin_lock_irq ( & pdata - > mac_lock ) ;
temp = smsc911x_mac_read ( pdata , MAC_CR ) ;
temp | = ( MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_ ) ;
smsc911x_mac_write ( pdata , MAC_CR , temp ) ;
spin_unlock_irq ( & pdata - > mac_lock ) ;
smsc911x_reg_write ( pdata , TX_CFG , TX_CFG_TX_ON_ ) ;
netif_start_queue ( dev ) ;
return 0 ;
2016-09-01 15:15:07 -05:00
2016-09-01 15:15:09 -05:00
irq_stop_out :
free_irq ( dev - > irq , dev ) ;
2016-09-01 15:15:07 -05:00
mii_free_out :
phy_disconnect ( dev - > phydev ) ;
dev - > phydev = NULL ;
2016-09-01 15:15:06 -05:00
out :
return retval ;
2008-11-05 00:35:37 +00:00
}
/* Entry point for stopping the interface */
static int smsc911x_stop ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
unsigned int temp ;
/* Disable all device interrupts */
temp = smsc911x_reg_read ( pdata , INT_CFG ) ;
temp & = ~ INT_CFG_IRQ_EN_ ;
smsc911x_reg_write ( pdata , INT_CFG , temp ) ;
/* Stop Tx and Rx polling */
netif_stop_queue ( dev ) ;
napi_disable ( & pdata - > napi ) ;
/* At this point all Rx and Tx activity is stopped */
dev - > stats . rx_dropped + = smsc911x_reg_read ( pdata , RX_DROP ) ;
smsc911x_tx_update_txcounters ( dev ) ;
2016-09-01 15:15:09 -05:00
free_irq ( dev - > irq , dev ) ;
2008-11-05 00:35:37 +00:00
/* Bring the PHY down */
2016-09-01 15:15:07 -05:00
if ( dev - > phydev ) {
2016-07-03 01:14:20 +02:00
phy_stop ( dev - > phydev ) ;
2016-09-01 15:15:07 -05:00
phy_disconnect ( dev - > phydev ) ;
dev - > phydev = NULL ;
}
netif_carrier_off ( dev ) ;
2008-11-05 00:35:37 +00:00
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifdown , " Interface stopped " ) ;
2008-11-05 00:35:37 +00:00
return 0 ;
}
/* Entry point for transmitting a packet */
static int smsc911x_hard_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
unsigned int freespace ;
unsigned int tx_cmd_a ;
unsigned int tx_cmd_b ;
unsigned int temp ;
u32 wrsz ;
ulong bufp ;
freespace = smsc911x_reg_read ( pdata , TX_FIFO_INF ) & TX_FIFO_INF_TDFREE_ ;
if ( unlikely ( freespace < TX_FIFO_LOW_THRESHOLD ) )
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , tx_err ,
" Tx data fifo low, space available: %d " , freespace ) ;
2008-11-05 00:35:37 +00:00
/* Word alignment adjustment */
tx_cmd_a = ( u32 ) ( ( ulong ) skb - > data & 0x03 ) < < 16 ;
tx_cmd_a | = TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ ;
tx_cmd_a | = ( unsigned int ) skb - > len ;
tx_cmd_b = ( ( unsigned int ) skb - > len ) < < 16 ;
tx_cmd_b | = ( unsigned int ) skb - > len ;
smsc911x_reg_write ( pdata , TX_DATA_FIFO , tx_cmd_a ) ;
smsc911x_reg_write ( pdata , TX_DATA_FIFO , tx_cmd_b ) ;
bufp = ( ulong ) skb - > data & ( ~ 0x3 ) ;
wrsz = ( u32 ) skb - > len + 3 ;
wrsz + = ( u32 ) ( ( ulong ) skb - > data & 0x3 ) ;
wrsz > > = 2 ;
2011-04-13 17:13:00 -07:00
pdata - > ops - > tx_writefifo ( pdata , ( unsigned int * ) bufp , wrsz ) ;
2008-11-05 00:35:37 +00:00
freespace - = ( skb - > len + 32 ) ;
2011-06-19 21:51:30 +00:00
skb_tx_timestamp ( skb ) ;
2014-03-15 18:08:52 -07:00
dev_consume_skb_any ( skb ) ;
2008-11-05 00:35:37 +00:00
if ( unlikely ( smsc911x_tx_get_txstatcount ( pdata ) > = 30 ) )
smsc911x_tx_update_txcounters ( dev ) ;
if ( freespace < TX_FIFO_LOW_THRESHOLD ) {
netif_stop_queue ( dev ) ;
temp = smsc911x_reg_read ( pdata , FIFO_INT ) ;
temp & = 0x00FFFFFF ;
temp | = 0x32000000 ;
smsc911x_reg_write ( pdata , FIFO_INT , temp ) ;
}
return NETDEV_TX_OK ;
}
/* Entry point for getting status counters */
static struct net_device_stats * smsc911x_get_stats ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
smsc911x_tx_update_txcounters ( dev ) ;
dev - > stats . rx_dropped + = smsc911x_reg_read ( pdata , RX_DROP ) ;
return & dev - > stats ;
}
/* Entry point for setting addressing modes */
static void smsc911x_set_multicast_list ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
unsigned long flags ;
if ( dev - > flags & IFF_PROMISC ) {
/* Enabling promiscuous mode */
pdata - > set_bits_mask = MAC_CR_PRMS_ ;
pdata - > clear_bits_mask = ( MAC_CR_MCPAS_ | MAC_CR_HPFILT_ ) ;
pdata - > hashhi = 0 ;
pdata - > hashlo = 0 ;
} else if ( dev - > flags & IFF_ALLMULTI ) {
/* Enabling all multicast mode */
pdata - > set_bits_mask = MAC_CR_MCPAS_ ;
pdata - > clear_bits_mask = ( MAC_CR_PRMS_ | MAC_CR_HPFILT_ ) ;
pdata - > hashhi = 0 ;
pdata - > hashlo = 0 ;
2010-02-08 04:30:35 +00:00
} else if ( ! netdev_mc_empty ( dev ) ) {
2008-11-05 00:35:37 +00:00
/* Enabling specific multicast addresses */
unsigned int hash_high = 0 ;
unsigned int hash_low = 0 ;
2010-04-01 21:22:57 +00:00
struct netdev_hw_addr * ha ;
2008-11-05 00:35:37 +00:00
pdata - > set_bits_mask = MAC_CR_HPFILT_ ;
pdata - > clear_bits_mask = ( MAC_CR_PRMS_ | MAC_CR_MCPAS_ ) ;
2010-04-01 21:22:57 +00:00
netdev_for_each_mc_addr ( ha , dev ) {
unsigned int bitnum = smsc911x_hash ( ha - > addr ) ;
2010-02-17 23:22:38 +00:00
unsigned int mask = 0x01 < < ( bitnum & 0x1F ) ;
if ( bitnum & 0x20 )
hash_high | = mask ;
else
hash_low | = mask ;
2008-11-05 00:35:37 +00:00
}
pdata - > hashhi = hash_high ;
pdata - > hashlo = hash_low ;
} else {
/* Enabling local MAC address only */
pdata - > set_bits_mask = 0 ;
pdata - > clear_bits_mask =
( MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_ ) ;
pdata - > hashhi = 0 ;
pdata - > hashlo = 0 ;
}
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
if ( pdata - > generation < = 1 ) {
/* Older hardware revision - cannot change these flags while
* receiving data */
if ( ! pdata - > multicast_update_pending ) {
unsigned int temp ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , hw , " scheduling mcast update " ) ;
2008-11-05 00:35:37 +00:00
pdata - > multicast_update_pending = 1 ;
/* Request the hardware to stop, then perform the
* update when we get an RX_STOP interrupt */
temp = smsc911x_mac_read ( pdata , MAC_CR ) ;
temp & = ~ ( MAC_CR_RXEN_ ) ;
smsc911x_mac_write ( pdata , MAC_CR , temp ) ;
} else {
/* There is another update pending, this should now
* use the newer values */
}
} else {
/* Newer hardware revision - can write immediately */
smsc911x_rx_multicast_update ( pdata ) ;
}
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
}
# ifdef CONFIG_NET_POLL_CONTROLLER
2008-12-12 22:31:16 -08:00
static void smsc911x_poll_controller ( struct net_device * dev )
2008-11-05 00:35:37 +00:00
{
disable_irq ( dev - > irq ) ;
smsc911x_irqhandler ( 0 , dev ) ;
enable_irq ( dev - > irq ) ;
}
# endif /* CONFIG_NET_POLL_CONTROLLER */
2009-03-19 00:24:46 +00:00
static int smsc911x_set_mac_address ( struct net_device * dev , void * p )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
struct sockaddr * addr = p ;
/* On older hardware revisions we cannot change the mac address
* registers while receiving data . Newer devices can safely change
* this at any time . */
if ( pdata - > generation < = 1 & & netif_running ( dev ) )
return - EBUSY ;
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
memcpy ( dev - > dev_addr , addr - > sa_data , ETH_ALEN ) ;
spin_lock_irq ( & pdata - > mac_lock ) ;
smsc911x_set_hw_mac_address ( pdata , dev - > dev_addr ) ;
spin_unlock_irq ( & pdata - > mac_lock ) ;
2011-03-25 14:21:22 +00:00
netdev_info ( dev , " MAC Address: %pM \n " , dev - > dev_addr ) ;
2009-03-19 00:24:46 +00:00
return 0 ;
}
2008-11-05 00:35:37 +00:00
/* Standard ioctls for mii-tool */
static int smsc911x_do_ioctl ( struct net_device * dev , struct ifreq * ifr , int cmd )
{
2016-07-03 01:14:20 +02:00
if ( ! netif_running ( dev ) | | ! dev - > phydev )
2008-11-05 00:35:37 +00:00
return - EINVAL ;
2016-07-03 01:14:20 +02:00
return phy_mii_ioctl ( dev - > phydev , ifr , cmd ) ;
2008-11-05 00:35:37 +00:00
}
static void smsc911x_ethtool_getdrvinfo ( struct net_device * dev ,
struct ethtool_drvinfo * info )
{
strlcpy ( info - > driver , SMSC_CHIPNAME , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , SMSC_DRV_VERSION , sizeof ( info - > version ) ) ;
2009-01-26 21:12:58 -08:00
strlcpy ( info - > bus_info , dev_name ( dev - > dev . parent ) ,
2008-11-05 00:35:37 +00:00
sizeof ( info - > bus_info ) ) ;
}
static int smsc911x_ethtool_nwayreset ( struct net_device * dev )
{
2016-07-03 01:14:20 +02:00
return phy_start_aneg ( dev - > phydev ) ;
2008-11-05 00:35:37 +00:00
}
static u32 smsc911x_ethtool_getmsglevel ( struct net_device * dev )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
return pdata - > msg_enable ;
}
static void smsc911x_ethtool_setmsglevel ( struct net_device * dev , u32 level )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
pdata - > msg_enable = level ;
}
static int smsc911x_ethtool_getregslen ( struct net_device * dev )
{
return ( ( ( E2P_DATA - ID_REV ) / 4 + 1 ) + ( WUCSR - MAC_CR ) + 1 + 32 ) *
sizeof ( u32 ) ;
}
static void
smsc911x_ethtool_getregs ( struct net_device * dev , struct ethtool_regs * regs ,
void * buf )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
2016-07-03 01:14:20 +02:00
struct phy_device * phy_dev = dev - > phydev ;
2008-11-05 00:35:37 +00:00
unsigned long flags ;
unsigned int i ;
unsigned int j = 0 ;
u32 * data = buf ;
regs - > version = pdata - > idrev ;
for ( i = ID_REV ; i < = E2P_DATA ; i + = ( sizeof ( u32 ) ) )
data [ j + + ] = smsc911x_reg_read ( pdata , i ) ;
for ( i = MAC_CR ; i < = WUCSR ; i + + ) {
spin_lock_irqsave ( & pdata - > mac_lock , flags ) ;
data [ j + + ] = smsc911x_mac_read ( pdata , i ) ;
spin_unlock_irqrestore ( & pdata - > mac_lock , flags ) ;
}
for ( i = 0 ; i < = 31 ; i + + )
2016-01-06 20:11:16 +01:00
data [ j + + ] = smsc911x_mii_read ( phy_dev - > mdio . bus ,
phy_dev - > mdio . addr , i ) ;
2008-11-05 00:35:37 +00:00
}
static void smsc911x_eeprom_enable_access ( struct smsc911x_data * pdata )
{
unsigned int temp = smsc911x_reg_read ( pdata , GPIO_CFG ) ;
temp & = ~ GPIO_CFG_EEPR_EN_ ;
smsc911x_reg_write ( pdata , GPIO_CFG , temp ) ;
msleep ( 1 ) ;
}
static int smsc911x_eeprom_send_cmd ( struct smsc911x_data * pdata , u32 op )
{
int timeout = 100 ;
u32 e2cmd ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , drv , " op 0x%08x " , op ) ;
2008-11-05 00:35:37 +00:00
if ( smsc911x_reg_read ( pdata , E2P_CMD ) & E2P_CMD_EPC_BUSY_ ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , drv , " Busy at start " ) ;
2008-11-05 00:35:37 +00:00
return - EBUSY ;
}
e2cmd = op | E2P_CMD_EPC_BUSY_ ;
smsc911x_reg_write ( pdata , E2P_CMD , e2cmd ) ;
do {
msleep ( 1 ) ;
e2cmd = smsc911x_reg_read ( pdata , E2P_CMD ) ;
2009-02-20 00:52:19 -08:00
} while ( ( e2cmd & E2P_CMD_EPC_BUSY_ ) & & ( - - timeout ) ) ;
2008-11-05 00:35:37 +00:00
if ( ! timeout ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , drv , " TIMED OUT " ) ;
2008-11-05 00:35:37 +00:00
return - EAGAIN ;
}
if ( e2cmd & E2P_CMD_EPC_TIMEOUT_ ) {
2011-04-11 13:44:25 -07:00
SMSC_TRACE ( pdata , drv , " Error occurred during eeprom operation " ) ;
2008-11-05 00:35:37 +00:00
return - EINVAL ;
}
return 0 ;
}
static int smsc911x_eeprom_read_location ( struct smsc911x_data * pdata ,
u8 address , u8 * data )
{
u32 op = E2P_CMD_EPC_CMD_READ_ | address ;
int ret ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , drv , " address 0x%x " , address ) ;
2008-11-05 00:35:37 +00:00
ret = smsc911x_eeprom_send_cmd ( pdata , op ) ;
if ( ! ret )
data [ address ] = smsc911x_reg_read ( pdata , E2P_DATA ) ;
return ret ;
}
static int smsc911x_eeprom_write_location ( struct smsc911x_data * pdata ,
u8 address , u8 data )
{
u32 op = E2P_CMD_EPC_CMD_ERASE_ | address ;
2009-03-26 07:14:36 +00:00
u32 temp ;
2008-11-05 00:35:37 +00:00
int ret ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , drv , " address 0x%x, data 0x%x " , address , data ) ;
2008-11-05 00:35:37 +00:00
ret = smsc911x_eeprom_send_cmd ( pdata , op ) ;
if ( ! ret ) {
op = E2P_CMD_EPC_CMD_WRITE_ | address ;
smsc911x_reg_write ( pdata , E2P_DATA , ( u32 ) data ) ;
2009-03-26 07:14:36 +00:00
/* Workaround for hardware read-after-write restriction */
temp = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
2008-11-05 00:35:37 +00:00
ret = smsc911x_eeprom_send_cmd ( pdata , op ) ;
}
return ret ;
}
static int smsc911x_ethtool_get_eeprom_len ( struct net_device * dev )
{
return SMSC911X_EEPROM_SIZE ;
}
static int smsc911x_ethtool_get_eeprom ( struct net_device * dev ,
struct ethtool_eeprom * eeprom , u8 * data )
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
u8 eeprom_data [ SMSC911X_EEPROM_SIZE ] ;
int len ;
int i ;
smsc911x_eeprom_enable_access ( pdata ) ;
len = min ( eeprom - > len , SMSC911X_EEPROM_SIZE ) ;
for ( i = 0 ; i < len ; i + + ) {
int ret = smsc911x_eeprom_read_location ( pdata , i , eeprom_data ) ;
if ( ret < 0 ) {
eeprom - > len = 0 ;
return ret ;
}
}
memcpy ( data , & eeprom_data [ eeprom - > offset ] , len ) ;
eeprom - > len = len ;
return 0 ;
}
static int smsc911x_ethtool_set_eeprom ( struct net_device * dev ,
struct ethtool_eeprom * eeprom , u8 * data )
{
int ret ;
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
smsc911x_eeprom_enable_access ( pdata ) ;
smsc911x_eeprom_send_cmd ( pdata , E2P_CMD_EPC_CMD_EWEN_ ) ;
ret = smsc911x_eeprom_write_location ( pdata , eeprom - > offset , * data ) ;
smsc911x_eeprom_send_cmd ( pdata , E2P_CMD_EPC_CMD_EWDS_ ) ;
/* Single byte write, according to man page */
eeprom - > len = 1 ;
return ret ;
}
2008-12-25 16:41:09 -08:00
static const struct ethtool_ops smsc911x_ethtool_ops = {
2008-11-05 00:35:37 +00:00
. get_link = ethtool_op_get_link ,
. get_drvinfo = smsc911x_ethtool_getdrvinfo ,
. nway_reset = smsc911x_ethtool_nwayreset ,
. get_msglevel = smsc911x_ethtool_getmsglevel ,
. set_msglevel = smsc911x_ethtool_setmsglevel ,
. get_regs_len = smsc911x_ethtool_getregslen ,
. get_regs = smsc911x_ethtool_getregs ,
. get_eeprom_len = smsc911x_ethtool_get_eeprom_len ,
. get_eeprom = smsc911x_ethtool_get_eeprom ,
. set_eeprom = smsc911x_ethtool_set_eeprom ,
2012-04-03 22:59:36 +00:00
. get_ts_info = ethtool_op_get_ts_info ,
2016-07-03 01:14:21 +02:00
. get_link_ksettings = phy_ethtool_get_link_ksettings ,
. set_link_ksettings = phy_ethtool_set_link_ksettings ,
2008-11-05 00:35:37 +00:00
} ;
2008-12-25 16:40:47 -08:00
static const struct net_device_ops smsc911x_netdev_ops = {
. ndo_open = smsc911x_open ,
. ndo_stop = smsc911x_stop ,
. ndo_start_xmit = smsc911x_hard_start_xmit ,
. ndo_get_stats = smsc911x_get_stats ,
2011-08-16 06:29:01 +00:00
. ndo_set_rx_mode = smsc911x_set_multicast_list ,
2008-12-25 16:40:47 -08:00
. ndo_do_ioctl = smsc911x_do_ioctl ,
. ndo_validate_addr = eth_validate_addr ,
2009-03-19 00:24:46 +00:00
. ndo_set_mac_address = smsc911x_set_mac_address ,
2008-12-25 16:40:47 -08:00
# ifdef CONFIG_NET_POLL_CONTROLLER
. ndo_poll_controller = smsc911x_poll_controller ,
# endif
} ;
2009-01-27 06:51:12 +00:00
/* copies the current mac address from hardware to dev->dev_addr */
2012-12-03 09:23:38 -05:00
static void smsc911x_read_mac_address ( struct net_device * dev )
2009-01-27 06:51:12 +00:00
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
u32 mac_high16 = smsc911x_mac_read ( pdata , ADDRH ) ;
u32 mac_low32 = smsc911x_mac_read ( pdata , ADDRL ) ;
dev - > dev_addr [ 0 ] = ( u8 ) ( mac_low32 ) ;
dev - > dev_addr [ 1 ] = ( u8 ) ( mac_low32 > > 8 ) ;
dev - > dev_addr [ 2 ] = ( u8 ) ( mac_low32 > > 16 ) ;
dev - > dev_addr [ 3 ] = ( u8 ) ( mac_low32 > > 24 ) ;
dev - > dev_addr [ 4 ] = ( u8 ) ( mac_high16 ) ;
dev - > dev_addr [ 5 ] = ( u8 ) ( mac_high16 > > 8 ) ;
}
2008-11-05 00:35:37 +00:00
/* Initializing private device structures, only called from probe */
2012-12-03 09:23:38 -05:00
static int smsc911x_init ( struct net_device * dev )
2008-11-05 00:35:37 +00:00
{
struct smsc911x_data * pdata = netdev_priv ( dev ) ;
2012-11-14 01:41:38 +00:00
unsigned int byte_test , mask ;
2011-10-25 22:05:43 +00:00
unsigned int to = 100 ;
2008-11-05 00:35:37 +00:00
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe , " Driver Parameters: " ) ;
SMSC_TRACE ( pdata , probe , " LAN base: 0x%08lX " ,
( unsigned long ) pdata - > ioaddr ) ;
SMSC_TRACE ( pdata , probe , " IRQ: %d " , dev - > irq ) ;
SMSC_TRACE ( pdata , probe , " PHY will be autodetected. " ) ;
2008-11-05 00:35:37 +00:00
spin_lock_init ( & pdata - > dev_lock ) ;
2011-04-05 06:52:49 +00:00
spin_lock_init ( & pdata - > mac_lock ) ;
2008-11-05 00:35:37 +00:00
2013-03-18 21:01:38 +00:00
if ( pdata - > ioaddr = = NULL ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe , " pdata->ioaddr: 0x00000000 " ) ;
2008-11-05 00:35:37 +00:00
return - ENODEV ;
}
2011-10-25 22:05:43 +00:00
/*
* poll the READY bit in PMT_CTRL . Any other access to the device is
* forbidden while this bit isn ' t set . Try for 100 ms
2012-11-14 01:41:38 +00:00
*
* Note that this test is done before the WORD_SWAP register is
* programmed . So in some configurations the READY bit is at 16 before
* WORD_SWAP is written to . This issue is worked around by waiting
* until either bit 0 or bit 16 gets set in PMT_CTRL .
*
* SMSC has confirmed that checking bit 16 ( marked as reserved in
* the datasheet ) is fine since these bits " will either never be set
* or can only go high after READY does ( so also indicate the device
* is ready ) " .
2011-10-25 22:05:43 +00:00
*/
2012-11-14 01:41:38 +00:00
mask = PMT_CTRL_READY_ | swahw32 ( PMT_CTRL_READY_ ) ;
while ( ! ( smsc911x_reg_read ( pdata , PMT_CTRL ) & mask ) & & - - to )
2011-10-25 22:05:43 +00:00
udelay ( 1000 ) ;
2012-11-14 01:41:38 +00:00
2011-10-25 22:05:43 +00:00
if ( to = = 0 ) {
2013-11-01 08:53:33 -04:00
netdev_err ( dev , " Device not READY in 100ms aborting \n " ) ;
2011-10-25 22:05:43 +00:00
return - ENODEV ;
}
2008-11-05 00:35:37 +00:00
/* Check byte ordering */
byte_test = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe , " BYTE_TEST: 0x%08X " , byte_test ) ;
2008-11-05 00:35:37 +00:00
if ( byte_test = = 0x43218765 ) {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe , " BYTE_TEST looks swapped, "
" applying WORD_SWAP " ) ;
2008-11-05 00:35:37 +00:00
smsc911x_reg_write ( pdata , WORD_SWAP , 0xffffffff ) ;
/* 1 dummy read of BYTE_TEST is needed after a write to
* WORD_SWAP before its contents are valid */
byte_test = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
byte_test = smsc911x_reg_read ( pdata , BYTE_TEST ) ;
}
if ( byte_test ! = 0x87654321 ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , drv , " BYTE_TEST: 0x%08X " , byte_test ) ;
2008-11-05 00:35:37 +00:00
if ( ( ( byte_test > > 16 ) & 0xFFFF ) = = ( byte_test & 0xFFFF ) ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe ,
" top 16 bits equal to bottom 16 bits " ) ;
SMSC_TRACE ( pdata , probe ,
" This may mean the chip is set "
" for 32 bit while the bus is reading 16 bit " ) ;
2008-11-05 00:35:37 +00:00
}
return - ENODEV ;
}
/* Default generation to zero (all workarounds apply) */
pdata - > generation = 0 ;
pdata - > idrev = smsc911x_reg_read ( pdata , ID_REV ) ;
switch ( pdata - > idrev & 0xFFFF0000 ) {
case 0x01180000 :
case 0x01170000 :
case 0x01160000 :
case 0x01150000 :
2011-10-12 02:29:39 +00:00
case 0x218A0000 :
2008-11-05 00:35:37 +00:00
/* LAN911[5678] family */
pdata - > generation = pdata - > idrev & 0x0000FFFF ;
break ;
case 0x118A0000 :
case 0x117A0000 :
case 0x116A0000 :
case 0x115A0000 :
/* LAN921[5678] family */
pdata - > generation = 3 ;
break ;
case 0x92100000 :
case 0x92110000 :
case 0x92200000 :
case 0x92210000 :
/* LAN9210/LAN9211/LAN9220/LAN9221 */
pdata - > generation = 4 ;
break ;
default :
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe , " LAN911x not identified, idrev: 0x%08X " ,
pdata - > idrev ) ;
2008-11-05 00:35:37 +00:00
return - ENODEV ;
}
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
" LAN911x identified, idrev: 0x%08X, generation: %d " ,
pdata - > idrev , pdata - > generation ) ;
2008-11-05 00:35:37 +00:00
if ( pdata - > generation = = 0 )
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe ,
" This driver is not intended for this chip revision " ) ;
2008-11-05 00:35:37 +00:00
2009-01-27 06:51:12 +00:00
/* workaround for platforms without an eeprom, where the mac address
* is stored elsewhere and set by the bootloader . This saves the
* mac address before resetting the device */
2011-04-05 06:52:49 +00:00
if ( pdata - > config . flags & SMSC911X_SAVE_MAC_ADDRESS ) {
spin_lock_irq ( & pdata - > mac_lock ) ;
2009-01-27 06:51:12 +00:00
smsc911x_read_mac_address ( dev ) ;
2011-04-05 06:52:49 +00:00
spin_unlock_irq ( & pdata - > mac_lock ) ;
}
2009-01-27 06:51:12 +00:00
2008-11-05 00:35:37 +00:00
/* Reset the LAN911x */
2015-11-13 09:46:59 +03:00
if ( smsc911x_phy_reset ( pdata ) | | smsc911x_soft_reset ( pdata ) )
2008-11-05 00:35:37 +00:00
return - ENODEV ;
dev - > flags | = IFF_MULTICAST ;
netif_napi_add ( dev , & pdata - > napi , smsc911x_poll , SMSC_NAPI_WEIGHT ) ;
2008-12-25 16:40:47 -08:00
dev - > netdev_ops = & smsc911x_netdev_ops ;
2008-11-05 00:35:37 +00:00
dev - > ethtool_ops = & smsc911x_ethtool_ops ;
return 0 ;
}
2012-12-03 09:23:38 -05:00
static int smsc911x_drv_remove ( struct platform_device * pdev )
2008-11-05 00:35:37 +00:00
{
struct net_device * dev ;
struct smsc911x_data * pdata ;
struct resource * res ;
dev = platform_get_drvdata ( pdev ) ;
BUG_ON ( ! dev ) ;
pdata = netdev_priv ( dev ) ;
BUG_ON ( ! pdata ) ;
BUG_ON ( ! pdata - > ioaddr ) ;
2016-09-01 15:15:07 -05:00
WARN_ON ( dev - > phydev ) ;
2008-11-05 00:35:37 +00:00
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , ifdown , " Stopping driver " ) ;
2008-11-05 00:35:37 +00:00
mdiobus_unregister ( pdata - > mii_bus ) ;
mdiobus_free ( pdata - > mii_bus ) ;
unregister_netdev ( dev ) ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
" smsc911x-memory " ) ;
if ( ! res )
2008-12-25 16:44:01 -08:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2008-11-05 00:35:37 +00:00
2009-07-04 11:31:47 +00:00
release_mem_region ( res - > start , resource_size ( res ) ) ;
2008-11-05 00:35:37 +00:00
iounmap ( pdata - > ioaddr ) ;
2011-11-24 01:03:07 +00:00
( void ) smsc911x_disable_resources ( pdev ) ;
smsc911x_free_resources ( pdev ) ;
2008-11-05 00:35:37 +00:00
free_netdev ( dev ) ;
2014-11-24 19:58:17 +01:00
pm_runtime_put ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2008-11-05 00:35:37 +00:00
return 0 ;
}
2011-04-13 17:13:00 -07:00
/* standard register acces */
static const struct smsc911x_ops standard_smsc911x_ops = {
. reg_read = __smsc911x_reg_read ,
. reg_write = __smsc911x_reg_write ,
. rx_readfifo = smsc911x_rx_readfifo ,
. tx_writefifo = smsc911x_tx_writefifo ,
} ;
/* shifted register access */
static const struct smsc911x_ops shifted_smsc911x_ops = {
. reg_read = __smsc911x_reg_read_shift ,
. reg_write = __smsc911x_reg_write_shift ,
. rx_readfifo = smsc911x_rx_readfifo_shift ,
. tx_writefifo = smsc911x_tx_writefifo_shift ,
} ;
2015-08-12 17:06:27 -05:00
static int smsc911x_probe_config ( struct smsc911x_platform_config * config ,
struct device * dev )
2011-07-30 08:26:00 +00:00
{
2015-08-17 13:45:36 -07:00
int phy_interface ;
2011-07-30 08:26:00 +00:00
u32 width = 0 ;
2015-08-26 20:27:05 -07:00
int err ;
2011-07-30 08:26:00 +00:00
2015-08-17 13:45:36 -07:00
phy_interface = device_get_phy_mode ( dev ) ;
if ( phy_interface < 0 )
2015-08-26 20:27:05 -07:00
phy_interface = PHY_INTERFACE_MODE_NA ;
2015-08-17 13:45:36 -07:00
config - > phy_interface = phy_interface ;
2011-07-30 08:26:00 +00:00
2015-08-12 17:06:27 -05:00
device_get_mac_address ( dev , config - > mac , ETH_ALEN ) ;
2011-07-30 08:26:00 +00:00
2015-08-26 20:27:05 -07:00
err = device_property_read_u32 ( dev , " reg-io-width " , & width ) ;
if ( err = = - ENXIO )
return err ;
if ( ! err & & width = = 4 )
2011-07-30 08:26:00 +00:00
config - > flags | = SMSC911X_USE_32BIT ;
2011-09-13 00:49:29 +00:00
else
config - > flags | = SMSC911X_USE_16BIT ;
2011-07-30 08:26:00 +00:00
2015-08-26 20:27:05 -07:00
device_property_read_u32 ( dev , " reg-shift " , & config - > shift ) ;
2015-08-12 17:06:27 -05:00
if ( device_property_present ( dev , " smsc,irq-active-high " ) )
2011-07-30 08:26:00 +00:00
config - > irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH ;
2015-08-12 17:06:27 -05:00
if ( device_property_present ( dev , " smsc,irq-push-pull " ) )
2011-07-30 08:26:00 +00:00
config - > irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL ;
2015-08-12 17:06:27 -05:00
if ( device_property_present ( dev , " smsc,force-internal-phy " ) )
2011-07-30 08:26:00 +00:00
config - > flags | = SMSC911X_FORCE_INTERNAL_PHY ;
2015-08-12 17:06:27 -05:00
if ( device_property_present ( dev , " smsc,force-external-phy " ) )
2011-07-30 08:26:00 +00:00
config - > flags | = SMSC911X_FORCE_EXTERNAL_PHY ;
2015-08-12 17:06:27 -05:00
if ( device_property_present ( dev , " smsc,save-mac-address " ) )
2011-07-30 08:26:00 +00:00
config - > flags | = SMSC911X_SAVE_MAC_ADDRESS ;
return 0 ;
}
2012-12-03 09:23:38 -05:00
static int smsc911x_drv_probe ( struct platform_device * pdev )
2008-11-05 00:35:37 +00:00
{
struct net_device * dev ;
struct smsc911x_data * pdata ;
2013-08-30 14:02:57 +09:00
struct smsc911x_platform_config * config = dev_get_platdata ( & pdev - > dev ) ;
2015-05-04 14:39:49 +05:30
struct resource * res ;
2016-09-01 15:15:09 -05:00
int res_size , irq ;
2008-11-05 00:35:37 +00:00
int retval ;
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
" smsc911x-memory " ) ;
if ( ! res )
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
2011-03-25 14:21:22 +00:00
pr_warn ( " Could not allocate resource \n " ) ;
2008-11-05 00:35:37 +00:00
retval = - ENODEV ;
goto out_0 ;
}
2009-07-04 11:31:47 +00:00
res_size = resource_size ( res ) ;
2008-11-05 00:35:37 +00:00
2015-05-04 14:39:49 +05:30
irq = platform_get_irq ( pdev , 0 ) ;
2015-08-28 11:50:15 -07:00
if ( irq = = - EPROBE_DEFER ) {
retval = - EPROBE_DEFER ;
goto out_0 ;
} else if ( irq < = 0 ) {
2011-03-25 14:21:22 +00:00
pr_warn ( " Could not allocate irq resource \n " ) ;
2009-01-27 06:51:09 +00:00
retval = - ENODEV ;
goto out_0 ;
}
2008-11-05 00:35:37 +00:00
if ( ! request_mem_region ( res - > start , res_size , SMSC_CHIPNAME ) ) {
retval = - EBUSY ;
goto out_0 ;
}
dev = alloc_etherdev ( sizeof ( struct smsc911x_data ) ) ;
if ( ! dev ) {
retval = - ENOMEM ;
goto out_release_io_1 ;
}
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
pdata = netdev_priv ( dev ) ;
2015-05-04 14:39:49 +05:30
dev - > irq = irq ;
2008-11-05 00:35:37 +00:00
pdata - > ioaddr = ioremap_nocache ( res - > start , res_size ) ;
pdata - > dev = dev ;
pdata - > msg_enable = ( ( 1 < < debug ) - 1 ) ;
2011-11-24 01:03:07 +00:00
platform_set_drvdata ( pdev , dev ) ;
retval = smsc911x_request_resources ( pdev ) ;
if ( retval )
2012-05-29 18:47:37 +00:00
goto out_request_resources_fail ;
2011-11-24 01:03:07 +00:00
retval = smsc911x_enable_resources ( pdev ) ;
if ( retval )
2012-05-29 18:47:37 +00:00
goto out_enable_resources_fail ;
2011-11-24 01:03:07 +00:00
2008-11-05 00:35:37 +00:00
if ( pdata - > ioaddr = = NULL ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe , " Error smsc911x base address invalid " ) ;
2008-11-05 00:35:37 +00:00
retval = - ENOMEM ;
2011-11-24 01:03:07 +00:00
goto out_disable_resources ;
2008-11-05 00:35:37 +00:00
}
2015-08-12 17:06:27 -05:00
retval = smsc911x_probe_config ( & pdata - > config , & pdev - > dev ) ;
2011-07-30 08:26:00 +00:00
if ( retval & & config ) {
/* copy config parameters across to pdata */
memcpy ( & pdata - > config , config , sizeof ( pdata - > config ) ) ;
retval = 0 ;
}
if ( retval ) {
SMSC_WARN ( pdata , probe , " Error smsc911x config not found " ) ;
2011-11-24 01:03:07 +00:00
goto out_disable_resources ;
2011-07-30 08:26:00 +00:00
}
2011-04-13 17:13:00 -07:00
/* assume standard, non-shifted, access to HW registers */
pdata - > ops = & standard_smsc911x_ops ;
/* apply the right access if shifting is needed */
2011-07-30 08:26:00 +00:00
if ( pdata - > config . shift )
2011-04-13 17:13:00 -07:00
pdata - > ops = & shifted_smsc911x_ops ;
2014-11-24 19:58:17 +01:00
pm_runtime_enable ( & pdev - > dev ) ;
pm_runtime_get_sync ( & pdev - > dev ) ;
2008-11-05 00:35:37 +00:00
retval = smsc911x_init ( dev ) ;
if ( retval < 0 )
2011-11-24 01:03:07 +00:00
goto out_disable_resources ;
2008-11-05 00:35:37 +00:00
2014-06-03 22:13:48 +05:30
netif_carrier_off ( dev ) ;
2008-11-05 00:35:37 +00:00
2016-09-01 15:15:07 -05:00
retval = smsc911x_mii_init ( pdev , dev ) ;
2008-11-05 00:35:37 +00:00
if ( retval ) {
2016-09-01 15:15:07 -05:00
SMSC_WARN ( pdata , probe , " Error %i initialising mii " , retval ) ;
2012-04-19 10:36:33 +00:00
goto out_disable_resources ;
2008-11-05 00:35:37 +00:00
}
retval = register_netdev ( dev ) ;
if ( retval ) {
2011-03-25 14:21:22 +00:00
SMSC_WARN ( pdata , probe , " Error %i registering device " , retval ) ;
2016-09-01 15:15:09 -05:00
goto out_disable_resources ;
2008-11-05 00:35:37 +00:00
} else {
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
" Network interface: \" %s \" " , dev - > name ) ;
2008-11-05 00:35:37 +00:00
}
spin_lock_irq ( & pdata - > mac_lock ) ;
/* Check if mac address has been specified when bringing interface up */
if ( is_valid_ether_addr ( dev - > dev_addr ) ) {
2009-03-19 00:24:46 +00:00
smsc911x_set_hw_mac_address ( pdata , dev - > dev_addr ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
" MAC Address is specified by configuration " ) ;
2009-10-13 07:25:49 +00:00
} else if ( is_valid_ether_addr ( pdata - > config . mac ) ) {
2013-10-01 19:04:40 -07:00
memcpy ( dev - > dev_addr , pdata - > config . mac , ETH_ALEN ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
" MAC Address specified by platform data " ) ;
2008-11-05 00:35:37 +00:00
} else {
/* Try reading mac address from device. if EEPROM is present
* it will already have been set */
2010-10-27 17:28:58 +01:00
smsc_get_mac ( dev ) ;
2008-11-05 00:35:37 +00:00
if ( is_valid_ether_addr ( dev - > dev_addr ) ) {
/* eeprom values are valid so use them */
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
" Mac Address is read from LAN911x EEPROM " ) ;
2008-11-05 00:35:37 +00:00
} else {
/* eeprom values are invalid, generate random MAC */
2012-02-15 06:45:40 +00:00
eth_hw_addr_random ( dev ) ;
2009-03-19 00:24:46 +00:00
smsc911x_set_hw_mac_address ( pdata , dev - > dev_addr ) ;
2011-03-25 14:21:22 +00:00
SMSC_TRACE ( pdata , probe ,
2012-07-12 19:33:06 +00:00
" MAC Address is set to eth_random_addr " ) ;
2008-11-05 00:35:37 +00:00
}
}
spin_unlock_irq ( & pdata - > mac_lock ) ;
2011-03-25 14:21:22 +00:00
netdev_info ( dev , " MAC Address: %pM \n " , dev - > dev_addr ) ;
2008-11-05 00:35:37 +00:00
return 0 ;
2011-11-24 01:03:07 +00:00
out_disable_resources :
2014-11-24 19:58:17 +01:00
pm_runtime_put ( & pdev - > dev ) ;
pm_runtime_disable ( & pdev - > dev ) ;
2011-11-24 01:03:07 +00:00
( void ) smsc911x_disable_resources ( pdev ) ;
2012-05-29 18:47:37 +00:00
out_enable_resources_fail :
2011-11-24 01:03:07 +00:00
smsc911x_free_resources ( pdev ) ;
2012-05-29 18:47:37 +00:00
out_request_resources_fail :
2008-11-05 00:35:37 +00:00
iounmap ( pdata - > ioaddr ) ;
free_netdev ( dev ) ;
out_release_io_1 :
2009-07-04 11:31:47 +00:00
release_mem_region ( res - > start , resource_size ( res ) ) ;
2008-11-05 00:35:37 +00:00
out_0 :
return retval ;
}
2009-05-05 12:22:53 -07:00
# ifdef CONFIG_PM
/* This implementation assumes the devices remains powered on its VDDVARIO
* pins during suspend . */
2009-08-05 08:29:31 +00:00
/* TODO: implement freeze/thaw callbacks for hibernation.*/
static int smsc911x_suspend ( struct device * dev )
2009-05-05 12:22:53 -07:00
{
2009-08-05 08:29:31 +00:00
struct net_device * ndev = dev_get_drvdata ( dev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
2009-05-05 12:22:53 -07:00
/* enable wake on LAN, energy detection and the external PME
* signal . */
smsc911x_reg_write ( pdata , PMT_CTRL ,
PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ |
PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_ ) ;
return 0 ;
}
2009-08-05 08:29:31 +00:00
static int smsc911x_resume ( struct device * dev )
2009-05-05 12:22:53 -07:00
{
2009-08-05 08:29:31 +00:00
struct net_device * ndev = dev_get_drvdata ( dev ) ;
struct smsc911x_data * pdata = netdev_priv ( ndev ) ;
2009-05-05 12:22:53 -07:00
unsigned int to = 100 ;
/* Note 3.11 from the datasheet:
* " When the LAN9220 is in a power saving state, a write of any
* data to the BYTE_TEST register will wake - up the device . "
*/
smsc911x_reg_write ( pdata , BYTE_TEST , 0 ) ;
/* poll the READY bit in PMT_CTRL. Any other access to the device is
* forbidden while this bit isn ' t set . Try for 100 ms and return - EIO
* if it failed . */
while ( ! ( smsc911x_reg_read ( pdata , PMT_CTRL ) & PMT_CTRL_READY_ ) & & - - to )
udelay ( 1000 ) ;
return ( to = = 0 ) ? - EIO : 0 ;
}
2009-12-14 18:00:08 -08:00
static const struct dev_pm_ops smsc911x_pm_ops = {
2009-08-05 08:29:31 +00:00
. suspend = smsc911x_suspend ,
. resume = smsc911x_resume ,
} ;
# define SMSC911X_PM_OPS (&smsc911x_pm_ops)
2009-05-05 12:22:53 -07:00
# else
2009-08-05 08:29:31 +00:00
# define SMSC911X_PM_OPS NULL
2009-05-05 12:22:53 -07:00
# endif
2012-12-19 01:17:10 +00:00
# ifdef CONFIG_OF
2011-07-30 08:26:00 +00:00
static const struct of_device_id smsc911x_dt_ids [ ] = {
{ . compatible = " smsc,lan9115 " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , smsc911x_dt_ids ) ;
2012-12-19 01:17:10 +00:00
# endif
2011-07-30 08:26:00 +00:00
2015-08-12 17:06:27 -05:00
static const struct acpi_device_id smsc911x_acpi_match [ ] = {
{ " ARMH9118 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , smsc911x_acpi_match ) ;
2008-11-05 00:35:37 +00:00
static struct platform_driver smsc911x_driver = {
. probe = smsc911x_drv_probe ,
2012-12-03 09:23:38 -05:00
. remove = smsc911x_drv_remove ,
2008-11-05 00:35:37 +00:00
. driver = {
2009-08-05 08:29:31 +00:00
. name = SMSC_CHIPNAME ,
. pm = SMSC911X_PM_OPS ,
2012-12-19 01:17:10 +00:00
. of_match_table = of_match_ptr ( smsc911x_dt_ids ) ,
2015-08-12 17:06:27 -05:00
. acpi_match_table = ACPI_PTR ( smsc911x_acpi_match ) ,
2008-11-05 00:35:37 +00:00
} ,
} ;
/* Entry point for loading the module */
static int __init smsc911x_init_module ( void )
{
2010-10-27 17:28:58 +01:00
SMSC_INITIALIZE ( ) ;
2008-11-05 00:35:37 +00:00
return platform_driver_register ( & smsc911x_driver ) ;
}
/* entry point for unloading the module */
static void __exit smsc911x_cleanup_module ( void )
{
platform_driver_unregister ( & smsc911x_driver ) ;
}
module_init ( smsc911x_init_module ) ;
module_exit ( smsc911x_cleanup_module ) ;