2008-04-27 15:55:59 +04:00
/****************************************************************************
2013-08-30 02:32:48 +04:00
* Driver for Solarflare network controllers and boards
* Copyright 2007 - 2012 Solarflare Communications Inc .
2008-04-27 15:55:59 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation , incorporated herein by reference .
*/
2009-10-23 12:29:33 +04:00
# include <linux/rtnetlink.h>
2008-04-27 15:55:59 +04:00
# include "net_driver.h"
# include "phy.h"
# include "efx.h"
2009-11-29 18:12:08 +03:00
# include "nic.h"
2008-11-04 23:34:56 +03:00
# include "workarounds.h"
2008-04-27 15:55:59 +04:00
/* Macros for unpacking the board revision */
/* The revision info is in host byte order. */
2009-10-23 12:29:16 +04:00
# define FALCON_BOARD_TYPE(_rev) (_rev >> 8)
# define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
# define FALCON_BOARD_MINOR(_rev) (_rev & 0xf)
/* Board types */
2009-10-23 12:29:33 +04:00
# define FALCON_BOARD_SFE4001 0x01
2009-10-23 12:29:16 +04:00
# define FALCON_BOARD_SFE4002 0x02
2010-09-22 14:00:47 +04:00
# define FALCON_BOARD_SFE4003 0x03
2009-10-23 12:29:16 +04:00
# define FALCON_BOARD_SFN4112F 0x52
2008-04-27 15:55:59 +04:00
2010-02-19 16:34:03 +03:00
/* Board temperature is about 15°C above ambient when air flow is
2010-12-02 16:46:24 +03:00
* limited . The maximum acceptable ambient temperature varies
* depending on the PHY specifications but the critical temperature
* above which we should shut down to avoid damage is 80 ° C . */
2010-02-19 16:34:03 +03:00
# define FALCON_BOARD_TEMP_BIAS 15
2010-12-02 16:46:24 +03:00
# define FALCON_BOARD_TEMP_CRIT (80 + FALCON_BOARD_TEMP_BIAS)
2010-02-19 16:34:03 +03:00
/* SFC4000 datasheet says: 'The maximum permitted junction temperature
* is 125 ° C ; the thermal design of the environment for the SFC4000
* should aim to keep this well below 100 ° C . ' */
2010-12-02 16:46:24 +03:00
# define FALCON_JUNC_TEMP_MIN 0
2010-02-19 16:34:03 +03:00
# define FALCON_JUNC_TEMP_MAX 90
2010-12-02 16:46:24 +03:00
# define FALCON_JUNC_TEMP_CRIT 125
2010-02-19 16:34:03 +03:00
2008-11-04 23:34:56 +03:00
/*****************************************************************************
* Support for LM87 sensor chip used on several boards
*/
2010-12-02 16:46:24 +03:00
# define LM87_REG_TEMP_HW_INT_LOCK 0x13
# define LM87_REG_TEMP_HW_EXT_LOCK 0x14
# define LM87_REG_TEMP_HW_INT 0x17
# define LM87_REG_TEMP_HW_EXT 0x18
# define LM87_REG_TEMP_EXT1 0x26
# define LM87_REG_TEMP_INT 0x27
2008-11-04 23:34:56 +03:00
# define LM87_REG_ALARMS1 0x41
# define LM87_REG_ALARMS2 0x42
# define LM87_IN_LIMITS(nr, _min, _max) \
0x2B + ( nr ) * 2 , _max , 0x2C + ( nr ) * 2 , _min
# define LM87_AIN_LIMITS(nr, _min, _max) \
0x3B + ( nr ) , _max , 0x1A + ( nr ) , _min
# define LM87_TEMP_INT_LIMITS(_min, _max) \
0x39 , _max , 0x3A , _min
# define LM87_TEMP_EXT1_LIMITS(_min, _max) \
0x37 , _max , 0x38 , _min
# define LM87_ALARM_TEMP_INT 0x10
# define LM87_ALARM_TEMP_EXT1 0x20
# if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
2010-12-02 16:46:24 +03:00
static int efx_poke_lm87 ( struct i2c_client * client , const u8 * reg_values )
{
while ( * reg_values ) {
u8 reg = * reg_values + + ;
u8 value = * reg_values + + ;
int rc = i2c_smbus_write_byte_data ( client , reg , value ) ;
if ( rc )
return rc ;
}
return 0 ;
}
static const u8 falcon_lm87_common_regs [ ] = {
LM87_REG_TEMP_HW_INT_LOCK , FALCON_BOARD_TEMP_CRIT ,
LM87_REG_TEMP_HW_INT , FALCON_BOARD_TEMP_CRIT ,
LM87_TEMP_EXT1_LIMITS ( FALCON_JUNC_TEMP_MIN , FALCON_JUNC_TEMP_MAX ) ,
LM87_REG_TEMP_HW_EXT_LOCK , FALCON_JUNC_TEMP_CRIT ,
LM87_REG_TEMP_HW_EXT , FALCON_JUNC_TEMP_CRIT ,
0
} ;
2012-01-05 23:05:20 +04:00
static int efx_init_lm87 ( struct efx_nic * efx , const struct i2c_board_info * info ,
2008-11-04 23:34:56 +03:00
const u8 * reg_values )
{
2009-11-23 19:06:02 +03:00
struct falcon_board * board = falcon_board ( efx ) ;
struct i2c_client * client = i2c_new_device ( & board - > i2c_adap , info ) ;
2008-11-04 23:34:56 +03:00
int rc ;
if ( ! client )
return - EIO ;
2010-12-02 16:46:31 +03:00
/* Read-to-clear alarm/interrupt status */
i2c_smbus_read_byte_data ( client , LM87_REG_ALARMS1 ) ;
i2c_smbus_read_byte_data ( client , LM87_REG_ALARMS2 ) ;
2010-12-02 16:46:24 +03:00
rc = efx_poke_lm87 ( client , reg_values ) ;
if ( rc )
goto err ;
rc = efx_poke_lm87 ( client , falcon_lm87_common_regs ) ;
if ( rc )
goto err ;
2008-11-04 23:34:56 +03:00
2009-11-23 19:06:02 +03:00
board - > hwmon_client = client ;
2008-11-04 23:34:56 +03:00
return 0 ;
err :
i2c_unregister_device ( client ) ;
return rc ;
}
static void efx_fini_lm87 ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
i2c_unregister_device ( falcon_board ( efx ) - > hwmon_client ) ;
2008-11-04 23:34:56 +03:00
}
static int efx_check_lm87 ( struct efx_nic * efx , unsigned mask )
{
2009-11-23 19:05:12 +03:00
struct i2c_client * client = falcon_board ( efx ) - > hwmon_client ;
2010-12-02 16:46:24 +03:00
bool temp_crit , elec_fault , is_failure ;
u16 alarms ;
s32 reg ;
2008-11-04 23:34:56 +03:00
/* If link is up then do not monitor temperature */
2009-11-23 19:06:30 +03:00
if ( EFX_WORKAROUND_7884 ( efx ) & & efx - > link_state . up )
2008-11-04 23:34:56 +03:00
return 0 ;
2010-12-02 16:46:24 +03:00
reg = i2c_smbus_read_byte_data ( client , LM87_REG_ALARMS1 ) ;
if ( reg < 0 )
return reg ;
alarms = reg ;
reg = i2c_smbus_read_byte_data ( client , LM87_REG_ALARMS2 ) ;
if ( reg < 0 )
return reg ;
alarms | = reg < < 8 ;
alarms & = mask ;
temp_crit = false ;
if ( alarms & LM87_ALARM_TEMP_INT ) {
reg = i2c_smbus_read_byte_data ( client , LM87_REG_TEMP_INT ) ;
if ( reg < 0 )
return reg ;
if ( reg > FALCON_BOARD_TEMP_CRIT )
temp_crit = true ;
}
if ( alarms & LM87_ALARM_TEMP_EXT1 ) {
reg = i2c_smbus_read_byte_data ( client , LM87_REG_TEMP_EXT1 ) ;
if ( reg < 0 )
return reg ;
if ( reg > FALCON_JUNC_TEMP_CRIT )
temp_crit = true ;
}
elec_fault = alarms & ~ ( LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1 ) ;
is_failure = temp_crit | | elec_fault ;
if ( alarms )
2010-06-23 15:30:07 +04:00
netif_err ( efx , hw , efx - > net_dev ,
2010-12-02 16:46:24 +03:00
" LM87 detected a hardware %s (status %02x:%02x) "
" %s%s%s%s \n " ,
is_failure ? " failure " : " problem " ,
alarms & 0xff , alarms > > 8 ,
( alarms & LM87_ALARM_TEMP_INT ) ?
2010-06-25 11:06:29 +04:00
" ; board is overheating " : " " ,
2010-12-02 16:46:24 +03:00
( alarms & LM87_ALARM_TEMP_EXT1 ) ?
2010-06-25 11:06:29 +04:00
" ; controller is overheating " : " " ,
2010-12-02 16:46:24 +03:00
temp_crit ? " ; reached critical temperature " : " " ,
elec_fault ? " ; electrical fault " : " " ) ;
2008-11-04 23:34:56 +03:00
2010-12-02 16:46:24 +03:00
return is_failure ? - ERANGE : 0 ;
2008-11-04 23:34:56 +03:00
}
# else /* !CONFIG_SENSORS_LM87 */
static inline int
2012-01-05 23:05:20 +04:00
efx_init_lm87 ( struct efx_nic * efx , const struct i2c_board_info * info ,
2008-11-04 23:34:56 +03:00
const u8 * reg_values )
{
return 0 ;
}
static inline void efx_fini_lm87 ( struct efx_nic * efx )
{
}
static inline int efx_check_lm87 ( struct efx_nic * efx , unsigned mask )
{
return 0 ;
}
# endif /* CONFIG_SENSORS_LM87 */
2009-10-23 12:29:33 +04:00
/*****************************************************************************
2010-09-22 14:00:11 +04:00
* Support for the SFE4001 NIC .
2009-10-23 12:29:33 +04:00
*
* The SFE4001 does not power - up fully at reset due to its high power
* consumption . We control its power via a PCA9539 I / O expander .
2010-09-22 14:00:11 +04:00
* It also has a MAX6647 temperature monitor which we expose to
2009-10-23 12:29:33 +04:00
* the lm90 driver .
*
* This also provides minimal support for reflashing the PHY , which is
* initiated by resetting it with the FLASH_CFG_1 pin pulled down .
* On SFE4001 rev A2 and later this is connected to the 3 V3X output of
2010-09-22 14:00:11 +04:00
* the IO - expander .
2009-10-23 12:29:33 +04:00
* We represent reflash mode as PHY_MODE_SPECIAL and make it mutually
* exclusive with the network device being open .
*/
/**************************************************************************
2009-11-25 19:09:04 +03:00
* Support for I2C IO Expander device on SFE4001
2009-10-23 12:29:33 +04:00
*/
# define PCA9539 0x74
# define P0_IN 0x00
# define P0_OUT 0x02
# define P0_INVERT 0x04
# define P0_CONFIG 0x06
# define P0_EN_1V0X_LBN 0
# define P0_EN_1V0X_WIDTH 1
# define P0_EN_1V2_LBN 1
# define P0_EN_1V2_WIDTH 1
# define P0_EN_2V5_LBN 2
# define P0_EN_2V5_WIDTH 1
# define P0_EN_3V3X_LBN 3
# define P0_EN_3V3X_WIDTH 1
# define P0_EN_5V_LBN 4
# define P0_EN_5V_WIDTH 1
# define P0_SHORTEN_JTAG_LBN 5
# define P0_SHORTEN_JTAG_WIDTH 1
# define P0_X_TRST_LBN 6
# define P0_X_TRST_WIDTH 1
# define P0_DSP_RESET_LBN 7
# define P0_DSP_RESET_WIDTH 1
# define P1_IN 0x01
# define P1_OUT 0x03
# define P1_INVERT 0x05
# define P1_CONFIG 0x07
# define P1_AFE_PWD_LBN 0
# define P1_AFE_PWD_WIDTH 1
# define P1_DSP_PWD25_LBN 1
# define P1_DSP_PWD25_WIDTH 1
# define P1_RESERVED_LBN 2
# define P1_RESERVED_WIDTH 2
# define P1_SPARE_LBN 4
# define P1_SPARE_WIDTH 4
/* Temperature Sensor */
# define MAX664X_REG_RSL 0x02
# define MAX664X_REG_WLHO 0x0B
static void sfe4001_poweroff ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
struct i2c_client * ioexp_client = falcon_board ( efx ) - > ioexp_client ;
struct i2c_client * hwmon_client = falcon_board ( efx ) - > hwmon_client ;
2009-10-23 12:29:33 +04:00
/* Turn off all power rails and disable outputs */
i2c_smbus_write_byte_data ( ioexp_client , P0_OUT , 0xff ) ;
i2c_smbus_write_byte_data ( ioexp_client , P1_CONFIG , 0xff ) ;
i2c_smbus_write_byte_data ( ioexp_client , P0_CONFIG , 0xff ) ;
/* Clear any over-temperature alert */
i2c_smbus_read_byte_data ( hwmon_client , MAX664X_REG_RSL ) ;
}
static int sfe4001_poweron ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
struct i2c_client * ioexp_client = falcon_board ( efx ) - > ioexp_client ;
struct i2c_client * hwmon_client = falcon_board ( efx ) - > hwmon_client ;
2009-10-23 12:29:33 +04:00
unsigned int i , j ;
int rc ;
u8 out ;
/* Clear any previous over-temperature alert */
rc = i2c_smbus_read_byte_data ( hwmon_client , MAX664X_REG_RSL ) ;
if ( rc < 0 )
return rc ;
/* Enable port 0 and port 1 outputs on IO expander */
rc = i2c_smbus_write_byte_data ( ioexp_client , P0_CONFIG , 0x00 ) ;
if ( rc )
return rc ;
rc = i2c_smbus_write_byte_data ( ioexp_client , P1_CONFIG ,
0xff & ~ ( 1 < < P1_SPARE_LBN ) ) ;
if ( rc )
goto fail_on ;
/* If PHY power is on, turn it all off and wait 1 second to
* ensure a full reset .
*/
rc = i2c_smbus_read_byte_data ( ioexp_client , P0_OUT ) ;
if ( rc < 0 )
goto fail_on ;
out = 0xff & ~ ( ( 0 < < P0_EN_1V2_LBN ) | ( 0 < < P0_EN_2V5_LBN ) |
( 0 < < P0_EN_3V3X_LBN ) | ( 0 < < P0_EN_5V_LBN ) |
( 0 < < P0_EN_1V0X_LBN ) ) ;
if ( rc ! = out ) {
2010-06-23 15:30:07 +04:00
netif_info ( efx , hw , efx - > net_dev , " power-cycling PHY \n " ) ;
2009-10-23 12:29:33 +04:00
rc = i2c_smbus_write_byte_data ( ioexp_client , P0_OUT , out ) ;
if ( rc )
goto fail_on ;
schedule_timeout_uninterruptible ( HZ ) ;
}
for ( i = 0 ; i < 20 ; + + i ) {
/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
out = 0xff & ~ ( ( 1 < < P0_EN_1V2_LBN ) | ( 1 < < P0_EN_2V5_LBN ) |
( 1 < < P0_EN_3V3X_LBN ) | ( 1 < < P0_EN_5V_LBN ) |
( 1 < < P0_X_TRST_LBN ) ) ;
if ( efx - > phy_mode & PHY_MODE_SPECIAL )
out | = 1 < < P0_EN_3V3X_LBN ;
rc = i2c_smbus_write_byte_data ( ioexp_client , P0_OUT , out ) ;
if ( rc )
goto fail_on ;
msleep ( 10 ) ;
/* Turn on 1V power rail */
out & = ~ ( 1 < < P0_EN_1V0X_LBN ) ;
rc = i2c_smbus_write_byte_data ( ioexp_client , P0_OUT , out ) ;
if ( rc )
goto fail_on ;
2010-06-23 15:30:07 +04:00
netif_info ( efx , hw , efx - > net_dev ,
" waiting for DSP boot (attempt %d)... \n " , i ) ;
2009-10-23 12:29:33 +04:00
/* In flash config mode, DSP does not turn on AFE, so
* just wait 1 second .
*/
if ( efx - > phy_mode & PHY_MODE_SPECIAL ) {
schedule_timeout_uninterruptible ( HZ ) ;
return 0 ;
}
for ( j = 0 ; j < 10 ; + + j ) {
msleep ( 100 ) ;
/* Check DSP has asserted AFE power line */
rc = i2c_smbus_read_byte_data ( ioexp_client , P1_IN ) ;
if ( rc < 0 )
goto fail_on ;
if ( rc & ( 1 < < P1_AFE_PWD_LBN ) )
return 0 ;
}
}
2010-06-23 15:30:07 +04:00
netif_info ( efx , hw , efx - > net_dev , " timed out waiting for DSP boot \n " ) ;
2009-10-23 12:29:33 +04:00
rc = - ETIMEDOUT ;
fail_on :
sfe4001_poweroff ( efx ) ;
return rc ;
}
static ssize_t show_phy_flash_cfg ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct efx_nic * efx = pci_get_drvdata ( to_pci_dev ( dev ) ) ;
return sprintf ( buf , " %d \n " , ! ! ( efx - > phy_mode & PHY_MODE_SPECIAL ) ) ;
}
static ssize_t set_phy_flash_cfg ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct efx_nic * efx = pci_get_drvdata ( to_pci_dev ( dev ) ) ;
enum efx_phy_mode old_mode , new_mode ;
int err ;
rtnl_lock ( ) ;
old_mode = efx - > phy_mode ;
if ( count = = 0 | | * buf = = ' 0 ' )
new_mode = old_mode & ~ PHY_MODE_SPECIAL ;
else
new_mode = PHY_MODE_SPECIAL ;
2010-12-02 16:46:14 +03:00
if ( ! ( ( old_mode ^ new_mode ) & PHY_MODE_SPECIAL ) ) {
2009-10-23 12:29:33 +04:00
err = 0 ;
2012-07-27 22:31:16 +04:00
} else if ( efx - > state ! = STATE_READY | | netif_running ( efx - > net_dev ) ) {
2009-10-23 12:29:33 +04:00
err = - EBUSY ;
} else {
/* Reset the PHY, reconfigure the MAC and enable/disable
* MAC stats accordingly . */
efx - > phy_mode = new_mode ;
if ( new_mode & PHY_MODE_SPECIAL )
2009-11-25 19:11:35 +03:00
falcon_stop_nic_stats ( efx ) ;
2010-09-22 14:00:11 +04:00
err = sfe4001_poweron ( efx ) ;
2009-11-29 06:42:41 +03:00
if ( ! err )
err = efx_reconfigure_port ( efx ) ;
2009-10-23 12:29:33 +04:00
if ( ! ( new_mode & PHY_MODE_SPECIAL ) )
2009-11-25 19:11:35 +03:00
falcon_start_nic_stats ( efx ) ;
2009-10-23 12:29:33 +04:00
}
rtnl_unlock ( ) ;
return err ? err : count ;
}
static DEVICE_ATTR ( phy_flash_cfg , 0644 , show_phy_flash_cfg , set_phy_flash_cfg ) ;
static void sfe4001_fini ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
struct falcon_board * board = falcon_board ( efx ) ;
2010-06-23 15:30:07 +04:00
netif_info ( efx , drv , efx - > net_dev , " %s \n " , __func__ ) ;
2009-10-23 12:29:33 +04:00
device_remove_file ( & efx - > pci_dev - > dev , & dev_attr_phy_flash_cfg ) ;
sfe4001_poweroff ( efx ) ;
2009-11-23 19:05:12 +03:00
i2c_unregister_device ( board - > ioexp_client ) ;
i2c_unregister_device ( board - > hwmon_client ) ;
2009-10-23 12:29:33 +04:00
}
static int sfe4001_check_hw ( struct efx_nic * efx )
{
2010-12-02 16:47:51 +03:00
struct falcon_nic_data * nic_data = efx - > nic_data ;
2009-10-23 12:29:33 +04:00
s32 status ;
/* If XAUI link is up then do not monitor */
2010-12-02 16:47:51 +03:00
if ( EFX_WORKAROUND_7884 ( efx ) & & ! nic_data - > xmac_poll_required )
2009-10-23 12:29:33 +04:00
return 0 ;
/* Check the powered status of the PHY. Lack of power implies that
* the MAX6647 has shut down power to it , probably due to a temp .
* alarm . Reading the power status rather than the MAX6647 status
* directly because the later is read - to - clear and would thus
* start to power up the PHY again when polled , causing us to blip
* the power undesirably .
* We know we can read from the IO expander because we did
* it during power - on . Assume failure now is bad news . */
2009-11-23 19:05:12 +03:00
status = i2c_smbus_read_byte_data ( falcon_board ( efx ) - > ioexp_client , P1_IN ) ;
2009-10-23 12:29:33 +04:00
if ( status > = 0 & &
( status & ( ( 1 < < P1_AFE_PWD_LBN ) | ( 1 < < P1_DSP_PWD25_LBN ) ) ) ! = 0 )
return 0 ;
/* Use board power control, not PHY power control */
sfe4001_poweroff ( efx ) ;
efx - > phy_mode = PHY_MODE_OFF ;
return ( status < 0 ) ? - EIO : - ERANGE ;
}
2012-01-05 23:05:20 +04:00
static const struct i2c_board_info sfe4001_hwmon_info = {
2009-10-23 12:29:33 +04:00
I2C_BOARD_INFO ( " max6647 " , 0x4e ) ,
} ;
/* This board uses an I2C expander to provider power to the PHY, which needs to
* be turned on before the PHY can be used .
* Context : Process context , rtnl lock held
*/
static int sfe4001_init ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
struct falcon_board * board = falcon_board ( efx ) ;
2009-10-23 12:29:33 +04:00
int rc ;
# if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE)
2009-11-23 19:05:12 +03:00
board - > hwmon_client =
2009-11-23 19:06:02 +03:00
i2c_new_device ( & board - > i2c_adap , & sfe4001_hwmon_info ) ;
2009-10-23 12:29:33 +04:00
# else
2009-11-23 19:05:12 +03:00
board - > hwmon_client =
2009-11-23 19:06:02 +03:00
i2c_new_dummy ( & board - > i2c_adap , sfe4001_hwmon_info . addr ) ;
2009-10-23 12:29:33 +04:00
# endif
2009-11-23 19:05:12 +03:00
if ( ! board - > hwmon_client )
2009-10-23 12:29:33 +04:00
return - EIO ;
/* Raise board/PHY high limit from 85 to 90 degrees Celsius */
2009-11-23 19:05:12 +03:00
rc = i2c_smbus_write_byte_data ( board - > hwmon_client ,
2009-10-23 12:29:33 +04:00
MAX664X_REG_WLHO , 90 ) ;
if ( rc )
goto fail_hwmon ;
2009-11-23 19:06:02 +03:00
board - > ioexp_client = i2c_new_dummy ( & board - > i2c_adap , PCA9539 ) ;
2009-11-23 19:05:12 +03:00
if ( ! board - > ioexp_client ) {
2009-10-23 12:29:33 +04:00
rc = - EIO ;
goto fail_hwmon ;
}
if ( efx - > phy_mode & PHY_MODE_SPECIAL ) {
/* PHY won't generate a 156.25 MHz clock and MAC stats fetch
* will fail . */
2009-11-25 19:11:35 +03:00
falcon_stop_nic_stats ( efx ) ;
2009-10-23 12:29:33 +04:00
}
rc = sfe4001_poweron ( efx ) ;
if ( rc )
goto fail_ioexp ;
rc = device_create_file ( & efx - > pci_dev - > dev , & dev_attr_phy_flash_cfg ) ;
if ( rc )
goto fail_on ;
2010-06-23 15:30:07 +04:00
netif_info ( efx , hw , efx - > net_dev , " PHY is powered on \n " ) ;
2009-10-23 12:29:33 +04:00
return 0 ;
fail_on :
sfe4001_poweroff ( efx ) ;
fail_ioexp :
2009-11-23 19:05:12 +03:00
i2c_unregister_device ( board - > ioexp_client ) ;
2009-10-23 12:29:33 +04:00
fail_hwmon :
2009-11-23 19:05:12 +03:00
i2c_unregister_device ( board - > hwmon_client ) ;
2009-10-23 12:29:33 +04:00
return rc ;
}
2008-04-27 15:55:59 +04:00
/*****************************************************************************
* Support for the SFE4002
*
*/
2008-11-04 23:34:56 +03:00
static u8 sfe4002_lm87_channel = 0x03 ; /* use AIN not FAN inputs */
static const u8 sfe4002_lm87_regs [ ] = {
2010-02-19 16:34:03 +03:00
LM87_IN_LIMITS ( 0 , 0x7c , 0x99 ) , /* 2.5V: 1.8V +/- 10% */
LM87_IN_LIMITS ( 1 , 0x4c , 0x5e ) , /* Vccp1: 1.2V +/- 10% */
LM87_IN_LIMITS ( 2 , 0xac , 0xd4 ) , /* 3.3V: 3.3V +/- 10% */
LM87_IN_LIMITS ( 3 , 0xac , 0xd4 ) , /* 5V: 5.0V +/- 10% */
LM87_IN_LIMITS ( 4 , 0xac , 0xe0 ) , /* 12V: 10.8-14V */
LM87_IN_LIMITS ( 5 , 0x3f , 0x4f ) , /* Vccp2: 1.0V +/- 10% */
LM87_AIN_LIMITS ( 0 , 0x98 , 0xbb ) , /* AIN1: 1.66V +/- 10% */
LM87_AIN_LIMITS ( 1 , 0x8a , 0xa9 ) , /* AIN2: 1.5V +/- 10% */
LM87_TEMP_INT_LIMITS ( 0 , 80 + FALCON_BOARD_TEMP_BIAS ) ,
LM87_TEMP_EXT1_LIMITS ( 0 , FALCON_JUNC_TEMP_MAX ) ,
2008-11-04 23:34:56 +03:00
0
} ;
2012-01-05 23:05:20 +04:00
static const struct i2c_board_info sfe4002_hwmon_info = {
2008-11-04 23:34:56 +03:00
I2C_BOARD_INFO ( " lm87 " , 0x2e ) ,
. platform_data = & sfe4002_lm87_channel ,
} ;
2008-04-27 15:55:59 +04:00
/****************************************************************************/
/* LED allocations. Note that on rev A0 boards the schematic and the reality
* differ : red and green are swapped . Below is the fixed ( A1 ) layout ( there
* are only 3 A0 boards in existence , so no real reason to make this
* conditional ) .
*/
# define SFE4002_FAULT_LED (2) /* Red */
# define SFE4002_RX_LED (0) /* Green */
# define SFE4002_TX_LED (1) /* Amber */
2009-11-23 19:04:23 +03:00
static void sfe4002_init_phy ( struct efx_nic * efx )
2008-04-27 15:55:59 +04:00
{
/* Set the TX and RX LEDs to reflect status and activity, and the
* fault LED off */
2009-10-23 12:33:42 +04:00
falcon_qt202x_set_led ( efx , SFE4002_TX_LED ,
QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT ) ;
falcon_qt202x_set_led ( efx , SFE4002_RX_LED ,
QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT ) ;
falcon_qt202x_set_led ( efx , SFE4002_FAULT_LED , QUAKE_LED_OFF ) ;
2008-04-27 15:55:59 +04:00
}
2009-11-23 19:03:45 +03:00
static void sfe4002_set_id_led ( struct efx_nic * efx , enum efx_led_mode mode )
2008-04-27 15:55:59 +04:00
{
2009-11-23 19:03:45 +03:00
falcon_qt202x_set_led (
efx , SFE4002_FAULT_LED ,
( mode = = EFX_LED_ON ) ? QUAKE_LED_ON : QUAKE_LED_OFF ) ;
2008-04-27 15:55:59 +04:00
}
2008-11-04 23:34:56 +03:00
static int sfe4002_check_hw ( struct efx_nic * efx )
{
2009-11-23 19:05:12 +03:00
struct falcon_board * board = falcon_board ( efx ) ;
2008-11-04 23:34:56 +03:00
/* A0 board rev. 4002s report a temperature fault the whole time
* ( bad sensor ) so we mask it out . */
unsigned alarm_mask =
2009-11-23 19:05:12 +03:00
( board - > major = = 0 & & board - > minor = = 0 ) ?
2008-11-04 23:34:56 +03:00
~ LM87_ALARM_TEMP_EXT1 : ~ 0 ;
return efx_check_lm87 ( efx , alarm_mask ) ;
}
2008-04-27 15:55:59 +04:00
static int sfe4002_init ( struct efx_nic * efx )
{
2009-11-25 19:09:41 +03:00
return efx_init_lm87 ( efx , & sfe4002_hwmon_info , sfe4002_lm87_regs ) ;
2008-04-27 15:55:59 +04:00
}
2009-02-27 16:08:18 +03:00
/*****************************************************************************
* Support for the SFN4112F
*
*/
static u8 sfn4112f_lm87_channel = 0x03 ; /* use AIN not FAN inputs */
static const u8 sfn4112f_lm87_regs [ ] = {
2010-02-19 16:34:03 +03:00
LM87_IN_LIMITS ( 0 , 0x7c , 0x99 ) , /* 2.5V: 1.8V +/- 10% */
LM87_IN_LIMITS ( 1 , 0x4c , 0x5e ) , /* Vccp1: 1.2V +/- 10% */
LM87_IN_LIMITS ( 2 , 0xac , 0xd4 ) , /* 3.3V: 3.3V +/- 10% */
LM87_IN_LIMITS ( 4 , 0xac , 0xe0 ) , /* 12V: 10.8-14V */
LM87_IN_LIMITS ( 5 , 0x3f , 0x4f ) , /* Vccp2: 1.0V +/- 10% */
LM87_AIN_LIMITS ( 1 , 0x8a , 0xa9 ) , /* AIN2: 1.5V +/- 10% */
LM87_TEMP_INT_LIMITS ( 0 , 60 + FALCON_BOARD_TEMP_BIAS ) ,
LM87_TEMP_EXT1_LIMITS ( 0 , FALCON_JUNC_TEMP_MAX ) ,
2009-02-27 16:08:18 +03:00
0
} ;
2012-01-05 23:05:20 +04:00
static const struct i2c_board_info sfn4112f_hwmon_info = {
2009-02-27 16:08:18 +03:00
I2C_BOARD_INFO ( " lm87 " , 0x2e ) ,
. platform_data = & sfn4112f_lm87_channel ,
} ;
# define SFN4112F_ACT_LED 0
# define SFN4112F_LINK_LED 1
2009-11-23 19:04:23 +03:00
static void sfn4112f_init_phy ( struct efx_nic * efx )
2009-02-27 16:08:18 +03:00
{
2009-10-23 12:33:42 +04:00
falcon_qt202x_set_led ( efx , SFN4112F_ACT_LED ,
QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT ) ;
falcon_qt202x_set_led ( efx , SFN4112F_LINK_LED ,
QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT ) ;
2009-02-27 16:08:18 +03:00
}
2009-11-23 19:03:45 +03:00
static void sfn4112f_set_id_led ( struct efx_nic * efx , enum efx_led_mode mode )
2009-02-27 16:08:18 +03:00
{
2009-11-23 19:03:45 +03:00
int reg ;
switch ( mode ) {
case EFX_LED_OFF :
reg = QUAKE_LED_OFF ;
break ;
case EFX_LED_ON :
reg = QUAKE_LED_ON ;
break ;
default :
reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT ;
break ;
}
falcon_qt202x_set_led ( efx , SFN4112F_LINK_LED , reg ) ;
2009-02-27 16:08:18 +03:00
}
static int sfn4112f_check_hw ( struct efx_nic * efx )
{
/* Mask out unused sensors */
return efx_check_lm87 ( efx , ~ 0x48 ) ;
}
static int sfn4112f_init ( struct efx_nic * efx )
{
2009-11-25 19:09:41 +03:00
return efx_init_lm87 ( efx , & sfn4112f_hwmon_info , sfn4112f_lm87_regs ) ;
2009-02-27 16:08:18 +03:00
}
2010-09-22 14:00:47 +04:00
/*****************************************************************************
* Support for the SFE4003
*
*/
static u8 sfe4003_lm87_channel = 0x03 ; /* use AIN not FAN inputs */
static const u8 sfe4003_lm87_regs [ ] = {
LM87_IN_LIMITS ( 0 , 0x67 , 0x7f ) , /* 2.5V: 1.5V +/- 10% */
LM87_IN_LIMITS ( 1 , 0x4c , 0x5e ) , /* Vccp1: 1.2V +/- 10% */
LM87_IN_LIMITS ( 2 , 0xac , 0xd4 ) , /* 3.3V: 3.3V +/- 10% */
LM87_IN_LIMITS ( 4 , 0xac , 0xe0 ) , /* 12V: 10.8-14V */
LM87_IN_LIMITS ( 5 , 0x3f , 0x4f ) , /* Vccp2: 1.0V +/- 10% */
LM87_TEMP_INT_LIMITS ( 0 , 70 + FALCON_BOARD_TEMP_BIAS ) ,
0
} ;
2012-01-05 23:05:20 +04:00
static const struct i2c_board_info sfe4003_hwmon_info = {
2010-09-22 14:00:47 +04:00
I2C_BOARD_INFO ( " lm87 " , 0x2e ) ,
. platform_data = & sfe4003_lm87_channel ,
} ;
/* Board-specific LED info. */
# define SFE4003_RED_LED_GPIO 11
# define SFE4003_LED_ON 1
# define SFE4003_LED_OFF 0
static void sfe4003_set_id_led ( struct efx_nic * efx , enum efx_led_mode mode )
{
struct falcon_board * board = falcon_board ( efx ) ;
/* The LEDs were not wired to GPIOs before A3 */
if ( board - > minor < 3 & & board - > major = = 0 )
return ;
falcon_txc_set_gpio_val (
efx , SFE4003_RED_LED_GPIO ,
( mode = = EFX_LED_ON ) ? SFE4003_LED_ON : SFE4003_LED_OFF ) ;
}
static void sfe4003_init_phy ( struct efx_nic * efx )
{
struct falcon_board * board = falcon_board ( efx ) ;
/* The LEDs were not wired to GPIOs before A3 */
if ( board - > minor < 3 & & board - > major = = 0 )
return ;
falcon_txc_set_gpio_dir ( efx , SFE4003_RED_LED_GPIO , TXC_GPIO_DIR_OUTPUT ) ;
falcon_txc_set_gpio_val ( efx , SFE4003_RED_LED_GPIO , SFE4003_LED_OFF ) ;
}
static int sfe4003_check_hw ( struct efx_nic * efx )
{
struct falcon_board * board = falcon_board ( efx ) ;
/* A0/A1/A2 board rev. 4003s report a temperature fault the whole time
* ( bad sensor ) so we mask it out . */
unsigned alarm_mask =
( board - > major = = 0 & & board - > minor < = 2 ) ?
~ LM87_ALARM_TEMP_EXT1 : ~ 0 ;
return efx_check_lm87 ( efx , alarm_mask ) ;
}
static int sfe4003_init ( struct efx_nic * efx )
{
return efx_init_lm87 ( efx , & sfe4003_hwmon_info , sfe4003_lm87_regs ) ;
}
2009-11-25 19:09:41 +03:00
static const struct falcon_board_type board_types [ ] = {
{
. id = FALCON_BOARD_SFE4001 ,
. init = sfe4001_init ,
. init_phy = efx_port_dummy_op_void ,
. fini = sfe4001_fini ,
. set_id_led = tenxpress_set_id_led ,
. monitor = sfe4001_check_hw ,
} ,
{
. id = FALCON_BOARD_SFE4002 ,
. init = sfe4002_init ,
. init_phy = sfe4002_init_phy ,
. fini = efx_fini_lm87 ,
. set_id_led = sfe4002_set_id_led ,
. monitor = sfe4002_check_hw ,
} ,
2010-09-22 14:00:47 +04:00
{
. id = FALCON_BOARD_SFE4003 ,
. init = sfe4003_init ,
. init_phy = sfe4003_init_phy ,
. fini = efx_fini_lm87 ,
. set_id_led = sfe4003_set_id_led ,
. monitor = sfe4003_check_hw ,
} ,
2009-11-25 19:09:41 +03:00
{
. id = FALCON_BOARD_SFN4112F ,
. init = sfn4112f_init ,
. init_phy = sfn4112f_init_phy ,
. fini = efx_fini_lm87 ,
. set_id_led = sfn4112f_set_id_led ,
. monitor = sfn4112f_check_hw ,
} ,
2008-04-27 15:55:59 +04:00
} ;
2010-04-28 13:01:50 +04:00
int falcon_probe_board ( struct efx_nic * efx , u16 revision_info )
2008-04-27 15:55:59 +04:00
{
2009-11-23 19:05:12 +03:00
struct falcon_board * board = falcon_board ( efx ) ;
2009-11-25 19:09:41 +03:00
u8 type_id = FALCON_BOARD_TYPE ( revision_info ) ;
2008-12-13 08:48:09 +03:00
int i ;
2008-04-27 15:55:59 +04:00
2009-11-23 19:05:12 +03:00
board - > major = FALCON_BOARD_MAJOR ( revision_info ) ;
board - > minor = FALCON_BOARD_MINOR ( revision_info ) ;
2008-04-27 15:55:59 +04:00
2009-11-25 19:09:41 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( board_types ) ; i + + )
if ( board_types [ i ] . id = = type_id )
board - > type = & board_types [ i ] ;
2008-04-27 15:55:59 +04:00
2009-11-25 19:09:41 +03:00
if ( board - > type ) {
2010-04-28 13:01:50 +04:00
return 0 ;
2008-12-13 08:48:09 +03:00
} else {
2010-06-23 15:30:07 +04:00
netif_err ( efx , probe , efx - > net_dev , " unknown board type %d \n " ,
type_id ) ;
2010-04-28 13:01:50 +04:00
return - ENODEV ;
2008-12-13 08:48:09 +03:00
}
2008-04-27 15:55:59 +04:00
}