2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-01-06 20:25:39 +00:00
/****************************************************************************
2013-08-29 23:32:48 +01:00
* Driver for Solarflare network controllers and boards
* Copyright 2011 - 2013 Solarflare Communications Inc .
2012-01-06 20:25:39 +00:00
*/
# include <linux/bitops.h>
# include <linux/slab.h>
# include <linux/hwmon.h>
# include <linux/stat.h>
# include "net_driver.h"
# include "mcdi.h"
# include "mcdi_pcol.h"
# include "nic.h"
enum efx_hwmon_type {
EFX_HWMON_UNKNOWN ,
EFX_HWMON_TEMP , /* temperature */
EFX_HWMON_COOL , /* cooling device, probably a heatsink */
2012-11-28 23:11:18 +00:00
EFX_HWMON_IN , /* voltage */
EFX_HWMON_CURR , /* current */
EFX_HWMON_POWER , /* power */
2013-09-30 10:52:49 +01:00
EFX_HWMON_TYPES_COUNT
} ;
static const char * const efx_hwmon_unit [ EFX_HWMON_TYPES_COUNT ] = {
[ EFX_HWMON_TEMP ] = " degC " ,
[ EFX_HWMON_COOL ] = " rpm " , /* though nonsense for a heatsink */
[ EFX_HWMON_IN ] = " mV " ,
[ EFX_HWMON_CURR ] = " mA " ,
[ EFX_HWMON_POWER ] = " W " ,
2012-01-06 20:25:39 +00:00
} ;
static const struct {
const char * label ;
enum efx_hwmon_type hwmon_type ;
int port ;
2013-08-08 11:14:20 +01:00
} efx_mcdi_sensor_type [ ] = {
2012-11-28 23:11:18 +00:00
# define SENSOR(name, label, hwmon_type, port) \
[ MC_CMD_SENSOR_ # # name ] = { label , EFX_HWMON_ # # hwmon_type , port }
2013-10-03 19:06:18 +01:00
SENSOR ( CONTROLLER_TEMP , " Controller board temp. " , TEMP , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( PHY_COMMON_TEMP , " PHY temp. " , TEMP , - 1 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( CONTROLLER_COOLING , " Controller heat sink " , COOL , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( PHY0_TEMP , " PHY temp. " , TEMP , 0 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( PHY0_COOLING , " PHY heat sink " , COOL , 0 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( PHY1_TEMP , " PHY temp. " , TEMP , 1 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( PHY1_COOLING , " PHY heat sink " , COOL , 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( IN_1V0 , " 1.0V supply " , IN , - 1 ) ,
SENSOR ( IN_1V2 , " 1.2V supply " , IN , - 1 ) ,
SENSOR ( IN_1V8 , " 1.8V supply " , IN , - 1 ) ,
SENSOR ( IN_2V5 , " 2.5V supply " , IN , - 1 ) ,
SENSOR ( IN_3V3 , " 3.3V supply " , IN , - 1 ) ,
SENSOR ( IN_12V0 , " 12.0V supply " , IN , - 1 ) ,
SENSOR ( IN_1V2A , " 1.2V analogue supply " , IN , - 1 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( IN_VREF , " Ref. voltage " , IN , - 1 ) ,
SENSOR ( OUT_VAOE , " AOE FPGA supply " , IN , - 1 ) ,
SENSOR ( AOE_TEMP , " AOE FPGA temp. " , TEMP , - 1 ) ,
SENSOR ( PSU_AOE_TEMP , " AOE regulator temp. " , TEMP , - 1 ) ,
SENSOR ( PSU_TEMP , " Controller regulator temp. " ,
TEMP , - 1 ) ,
SENSOR ( FAN_0 , " Fan 0 " , COOL , - 1 ) ,
SENSOR ( FAN_1 , " Fan 1 " , COOL , - 1 ) ,
SENSOR ( FAN_2 , " Fan 2 " , COOL , - 1 ) ,
SENSOR ( FAN_3 , " Fan 3 " , COOL , - 1 ) ,
SENSOR ( FAN_4 , " Fan 4 " , COOL , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( IN_VAOE , " AOE input supply " , IN , - 1 ) ,
SENSOR ( OUT_IAOE , " AOE output current " , CURR , - 1 ) ,
SENSOR ( IN_IAOE , " AOE input current " , CURR , - 1 ) ,
SENSOR ( NIC_POWER , " Board power use " , POWER , - 1 ) ,
SENSOR ( IN_0V9 , " 0.9V supply " , IN , - 1 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( IN_I0V9 , " 0.9V supply current " , CURR , - 1 ) ,
SENSOR ( IN_I1V2 , " 1.2V supply current " , CURR , - 1 ) ,
SENSOR ( IN_0V9_ADC , " 0.9V supply (ext. ADC) " , IN , - 1 ) ,
SENSOR ( CONTROLLER_2_TEMP , " Controller board temp. 2 " , TEMP , - 1 ) ,
SENSOR ( VREG_INTERNAL_TEMP , " Regulator die temp. " , TEMP , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( VREG_0V9_TEMP , " 0.9V regulator temp. " , TEMP , - 1 ) ,
SENSOR ( VREG_1V2_TEMP , " 1.2V regulator temp. " , TEMP , - 1 ) ,
2013-10-03 19:06:18 +01:00
SENSOR ( CONTROLLER_VPTAT ,
" Controller PTAT voltage (int. ADC) " , IN , - 1 ) ,
SENSOR ( CONTROLLER_INTERNAL_TEMP ,
" Controller die temp. (int. ADC) " , TEMP , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( CONTROLLER_VPTAT_EXTADC ,
2013-10-03 19:06:18 +01:00
" Controller PTAT voltage (ext. ADC) " , IN , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( CONTROLLER_INTERNAL_TEMP_EXTADC ,
2013-10-03 19:06:18 +01:00
" Controller die temp. (ext. ADC) " , TEMP , - 1 ) ,
2012-11-28 23:11:18 +00:00
SENSOR ( AMBIENT_TEMP , " Ambient temp. " , TEMP , - 1 ) ,
SENSOR ( AIRFLOW , " Air flow raw " , IN , - 1 ) ,
2013-12-04 20:17:28 +00:00
SENSOR ( VDD08D_VSS08D_CSR , " 0.9V die (int. ADC) " , IN , - 1 ) ,
SENSOR ( VDD08D_VSS08D_CSR_EXTADC , " 0.9V die (ext. ADC) " , IN , - 1 ) ,
SENSOR ( HOTPOINT_TEMP , " Controller board temp. (hotpoint) " , TEMP , - 1 ) ,
2012-01-06 20:25:39 +00:00
# undef SENSOR
} ;
static const char * const sensor_status_names [ ] = {
[ MC_CMD_SENSOR_STATE_OK ] = " OK " ,
[ MC_CMD_SENSOR_STATE_WARNING ] = " Warning " ,
[ MC_CMD_SENSOR_STATE_FATAL ] = " Fatal " ,
[ MC_CMD_SENSOR_STATE_BROKEN ] = " Device failure " ,
2013-07-03 09:47:34 +01:00
[ MC_CMD_SENSOR_STATE_NO_READING ] = " No reading " ,
2012-01-06 20:25:39 +00:00
} ;
void efx_mcdi_sensor_event ( struct efx_nic * efx , efx_qword_t * ev )
{
unsigned int type , state , value ;
2013-09-30 10:52:49 +01:00
enum efx_hwmon_type hwmon_type = EFX_HWMON_UNKNOWN ;
const char * name = NULL , * state_txt , * unit ;
2012-01-06 20:25:39 +00:00
type = EFX_QWORD_FIELD ( * ev , MCDI_EVENT_SENSOREVT_MONITOR ) ;
state = EFX_QWORD_FIELD ( * ev , MCDI_EVENT_SENSOREVT_STATE ) ;
value = EFX_QWORD_FIELD ( * ev , MCDI_EVENT_SENSOREVT_VALUE ) ;
/* Deal gracefully with the board having more drivers than we
* know about , but do not expect new sensor states . */
2013-09-30 10:52:49 +01:00
if ( type < ARRAY_SIZE ( efx_mcdi_sensor_type ) ) {
2012-01-06 20:25:39 +00:00
name = efx_mcdi_sensor_type [ type ] . label ;
2013-09-30 10:52:49 +01:00
hwmon_type = efx_mcdi_sensor_type [ type ] . hwmon_type ;
}
2012-01-06 20:25:39 +00:00
if ( ! name )
name = " No sensor name available " ;
2016-12-02 15:51:33 +00:00
EFX_WARN_ON_PARANOID ( state > = ARRAY_SIZE ( sensor_status_names ) ) ;
2012-01-06 20:25:39 +00:00
state_txt = sensor_status_names [ state ] ;
2016-12-02 15:51:33 +00:00
EFX_WARN_ON_PARANOID ( hwmon_type > = EFX_HWMON_TYPES_COUNT ) ;
2013-09-30 10:52:49 +01:00
unit = efx_hwmon_unit [ hwmon_type ] ;
if ( ! unit )
unit = " " ;
2012-01-06 20:25:39 +00:00
netif_err ( efx , hw , efx - > net_dev ,
2013-09-30 10:52:49 +01:00
" Sensor %d (%s) reports condition '%s' for value %d%s \n " ,
type , name , state_txt , value , unit ) ;
2012-01-06 20:25:39 +00:00
}
# ifdef CONFIG_SFC_MCDI_MON
struct efx_mcdi_mon_attribute {
struct device_attribute dev_attr ;
unsigned int index ;
unsigned int type ;
2013-08-08 11:14:20 +01:00
enum efx_hwmon_type hwmon_type ;
2012-01-06 20:25:39 +00:00
unsigned int limit_value ;
char name [ 12 ] ;
} ;
static int efx_mcdi_mon_update ( struct efx_nic * efx )
{
struct efx_mcdi_mon * hwmon = efx_mcdi_mon ( efx ) ;
2013-08-08 11:14:20 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_READ_SENSORS_EXT_IN_LEN ) ;
2012-01-06 20:25:39 +00:00
int rc ;
2013-08-08 11:14:20 +01:00
MCDI_SET_QWORD ( inbuf , READ_SENSORS_EXT_IN_DMA_ADDR ,
2012-10-10 23:20:17 +01:00
hwmon - > dma_buf . dma_addr ) ;
2013-08-08 11:14:20 +01:00
MCDI_SET_DWORD ( inbuf , READ_SENSORS_EXT_IN_LENGTH , hwmon - > dma_buf . len ) ;
2012-01-06 20:25:39 +00:00
rc = efx_mcdi_rpc ( efx , MC_CMD_READ_SENSORS ,
inbuf , sizeof ( inbuf ) , NULL , 0 , NULL ) ;
if ( rc = = 0 )
hwmon - > last_update = jiffies ;
return rc ;
}
static int efx_mcdi_mon_get_entry ( struct device * dev , unsigned int index ,
efx_dword_t * entry )
{
2013-11-27 18:54:31 -08:00
struct efx_nic * efx = dev_get_drvdata ( dev - > parent ) ;
2012-01-06 20:25:39 +00:00
struct efx_mcdi_mon * hwmon = efx_mcdi_mon ( efx ) ;
int rc ;
BUILD_BUG_ON ( MC_CMD_READ_SENSORS_OUT_LEN ! = 0 ) ;
mutex_lock ( & hwmon - > update_lock ) ;
/* Use cached value if last update was < 1 s ago */
if ( time_before ( jiffies , hwmon - > last_update + HZ ) )
rc = 0 ;
else
rc = efx_mcdi_mon_update ( efx ) ;
/* Copy out the requested entry */
* entry = ( ( efx_dword_t * ) hwmon - > dma_buf . addr ) [ index ] ;
mutex_unlock ( & hwmon - > update_lock ) ;
return rc ;
}
static ssize_t efx_mcdi_mon_show_value ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct efx_mcdi_mon_attribute * mon_attr =
container_of ( attr , struct efx_mcdi_mon_attribute , dev_attr ) ;
efx_dword_t entry ;
2013-07-03 09:47:34 +01:00
unsigned int value , state ;
2012-01-06 20:25:39 +00:00
int rc ;
rc = efx_mcdi_mon_get_entry ( dev , mon_attr - > index , & entry ) ;
if ( rc )
return rc ;
2013-07-03 09:47:34 +01:00
state = EFX_DWORD_FIELD ( entry , MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE ) ;
if ( state = = MC_CMD_SENSOR_STATE_NO_READING )
return - EBUSY ;
2012-01-06 20:25:39 +00:00
value = EFX_DWORD_FIELD ( entry , MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE ) ;
2012-11-28 23:11:18 +00:00
switch ( mon_attr - > hwmon_type ) {
case EFX_HWMON_TEMP :
/* Convert temperature from degrees to milli-degrees Celsius */
2012-01-06 20:25:39 +00:00
value * = 1000 ;
2012-11-28 23:11:18 +00:00
break ;
case EFX_HWMON_POWER :
/* Convert power from watts to microwatts */
value * = 1000000 ;
break ;
default :
/* No conversion needed */
break ;
}
2012-01-06 20:25:39 +00:00
return sprintf ( buf , " %u \n " , value ) ;
}
static ssize_t efx_mcdi_mon_show_limit ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct efx_mcdi_mon_attribute * mon_attr =
container_of ( attr , struct efx_mcdi_mon_attribute , dev_attr ) ;
unsigned int value ;
value = mon_attr - > limit_value ;
2012-11-28 23:11:18 +00:00
switch ( mon_attr - > hwmon_type ) {
case EFX_HWMON_TEMP :
/* Convert temperature from degrees to milli-degrees Celsius */
2012-01-06 20:25:39 +00:00
value * = 1000 ;
2012-11-28 23:11:18 +00:00
break ;
case EFX_HWMON_POWER :
/* Convert power from watts to microwatts */
value * = 1000000 ;
break ;
default :
/* No conversion needed */
break ;
}
2012-01-06 20:25:39 +00:00
return sprintf ( buf , " %u \n " , value ) ;
}
static ssize_t efx_mcdi_mon_show_alarm ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct efx_mcdi_mon_attribute * mon_attr =
container_of ( attr , struct efx_mcdi_mon_attribute , dev_attr ) ;
efx_dword_t entry ;
int state ;
int rc ;
rc = efx_mcdi_mon_get_entry ( dev , mon_attr - > index , & entry ) ;
if ( rc )
return rc ;
state = EFX_DWORD_FIELD ( entry , MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE ) ;
return sprintf ( buf , " %d \n " , state ! = MC_CMD_SENSOR_STATE_OK ) ;
}
static ssize_t efx_mcdi_mon_show_label ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct efx_mcdi_mon_attribute * mon_attr =
container_of ( attr , struct efx_mcdi_mon_attribute , dev_attr ) ;
return sprintf ( buf , " %s \n " ,
efx_mcdi_sensor_type [ mon_attr - > type ] . label ) ;
}
2013-11-27 18:54:31 -08:00
static void
2012-01-06 20:25:39 +00:00
efx_mcdi_mon_add_attr ( struct efx_nic * efx , const char * name ,
ssize_t ( * reader ) ( struct device * ,
struct device_attribute * , char * ) ,
unsigned int index , unsigned int type ,
unsigned int limit_value )
{
struct efx_mcdi_mon * hwmon = efx_mcdi_mon ( efx ) ;
struct efx_mcdi_mon_attribute * attr = & hwmon - > attrs [ hwmon - > n_attrs ] ;
strlcpy ( attr - > name , name , sizeof ( attr - > name ) ) ;
attr - > index = index ;
attr - > type = type ;
2013-08-08 11:14:20 +01:00
if ( type < ARRAY_SIZE ( efx_mcdi_sensor_type ) )
attr - > hwmon_type = efx_mcdi_sensor_type [ type ] . hwmon_type ;
else
attr - > hwmon_type = EFX_HWMON_UNKNOWN ;
2012-01-06 20:25:39 +00:00
attr - > limit_value = limit_value ;
2012-07-19 07:04:45 +00:00
sysfs_attr_init ( & attr - > dev_attr . attr ) ;
2012-01-06 20:25:39 +00:00
attr - > dev_attr . attr . name = attr - > name ;
2018-03-23 16:34:44 -07:00
attr - > dev_attr . attr . mode = 0444 ;
2012-01-06 20:25:39 +00:00
attr - > dev_attr . show = reader ;
2013-11-27 18:54:31 -08:00
hwmon - > group . attrs [ hwmon - > n_attrs + + ] = & attr - > dev_attr . attr ;
2012-01-06 20:25:39 +00:00
}
int efx_mcdi_mon_probe ( struct efx_nic * efx )
{
2012-11-28 23:11:18 +00:00
unsigned int n_temp = 0 , n_cool = 0 , n_in = 0 , n_curr = 0 , n_power = 0 ;
2012-01-06 20:25:39 +00:00
struct efx_mcdi_mon * hwmon = efx_mcdi_mon ( efx ) ;
2013-08-08 11:14:20 +01:00
MCDI_DECLARE_BUF ( inbuf , MC_CMD_SENSOR_INFO_EXT_IN_LEN ) ;
2012-09-14 17:30:10 +01:00
MCDI_DECLARE_BUF ( outbuf , MC_CMD_SENSOR_INFO_OUT_LENMAX ) ;
2013-08-08 11:14:20 +01:00
unsigned int n_pages , n_sensors , n_attrs , page ;
2012-01-06 20:25:39 +00:00
size_t outlen ;
char name [ 12 ] ;
u32 mask ;
2013-08-08 11:14:20 +01:00
int rc , i , j , type ;
2012-01-06 20:25:39 +00:00
2013-08-08 11:14:20 +01:00
/* Find out how many sensors are present */
n_sensors = 0 ;
page = 0 ;
do {
MCDI_SET_DWORD ( inbuf , SENSOR_INFO_EXT_IN_PAGE , page ) ;
2012-01-06 20:25:39 +00:00
2013-08-08 11:14:20 +01:00
rc = efx_mcdi_rpc ( efx , MC_CMD_SENSOR_INFO , inbuf , sizeof ( inbuf ) ,
outbuf , sizeof ( outbuf ) , & outlen ) ;
if ( rc )
return rc ;
if ( outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN )
return - EIO ;
mask = MCDI_DWORD ( outbuf , SENSOR_INFO_OUT_MASK ) ;
n_sensors + = hweight32 ( mask & ~ ( 1 < < MC_CMD_SENSOR_PAGE0_NEXT ) ) ;
+ + page ;
} while ( mask & ( 1 < < MC_CMD_SENSOR_PAGE0_NEXT ) ) ;
n_pages = page ;
/* Don't create a device if there are none */
if ( n_sensors = = 0 )
2012-01-06 20:25:39 +00:00
return 0 ;
2013-08-08 11:14:20 +01:00
rc = efx_nic_alloc_buffer (
efx , & hwmon - > dma_buf ,
n_sensors * MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_LEN ,
GFP_KERNEL ) ;
2012-01-06 20:25:39 +00:00
if ( rc )
return rc ;
mutex_init ( & hwmon - > update_lock ) ;
efx_mcdi_mon_update ( efx ) ;
/* Allocate space for the maximum possible number of
2013-11-27 18:54:31 -08:00
* attributes for this set of sensors :
2012-01-06 20:25:39 +00:00
* value , min , max , crit , alarm and label for each sensor .
*/
2013-11-27 18:54:31 -08:00
n_attrs = 6 * n_sensors ;
2012-01-06 20:25:39 +00:00
hwmon - > attrs = kcalloc ( n_attrs , sizeof ( * hwmon - > attrs ) , GFP_KERNEL ) ;
if ( ! hwmon - > attrs ) {
rc = - ENOMEM ;
goto fail ;
}
2013-11-27 18:54:31 -08:00
hwmon - > group . attrs = kcalloc ( n_attrs + 1 , sizeof ( struct attribute * ) ,
GFP_KERNEL ) ;
if ( ! hwmon - > group . attrs ) {
rc = - ENOMEM ;
2012-01-06 20:25:39 +00:00
goto fail ;
}
2013-08-08 11:14:20 +01:00
for ( i = 0 , j = - 1 , type = - 1 ; ; i + + ) {
enum efx_hwmon_type hwmon_type ;
2012-01-06 20:25:39 +00:00
const char * hwmon_prefix ;
unsigned hwmon_index ;
u16 min1 , max1 , min2 , max2 ;
/* Find next sensor type or exit if there is none */
2013-08-08 11:14:20 +01:00
do {
2012-01-06 20:25:39 +00:00
type + + ;
2013-08-08 11:14:20 +01:00
if ( ( type % 32 ) = = 0 ) {
page = type / 32 ;
j = - 1 ;
if ( page = = n_pages )
2013-11-27 18:54:31 -08:00
goto hwmon_register ;
2013-08-08 11:14:20 +01:00
MCDI_SET_DWORD ( inbuf , SENSOR_INFO_EXT_IN_PAGE ,
page ) ;
rc = efx_mcdi_rpc ( efx , MC_CMD_SENSOR_INFO ,
inbuf , sizeof ( inbuf ) ,
outbuf , sizeof ( outbuf ) ,
& outlen ) ;
if ( rc )
goto fail ;
if ( outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN ) {
rc = - EIO ;
goto fail ;
}
mask = ( MCDI_DWORD ( outbuf ,
SENSOR_INFO_OUT_MASK ) &
~ ( 1 < < MC_CMD_SENSOR_PAGE0_NEXT ) ) ;
/* Check again for short response */
if ( outlen <
MC_CMD_SENSOR_INFO_OUT_LEN ( hweight32 ( mask ) ) ) {
rc = - EIO ;
goto fail ;
}
}
} while ( ! ( mask & ( 1 < < type % 32 ) ) ) ;
j + + ;
if ( type < ARRAY_SIZE ( efx_mcdi_sensor_type ) ) {
hwmon_type = efx_mcdi_sensor_type [ type ] . hwmon_type ;
/* Skip sensors specific to a different port */
if ( hwmon_type ! = EFX_HWMON_UNKNOWN & &
efx_mcdi_sensor_type [ type ] . port > = 0 & &
efx_mcdi_sensor_type [ type ] . port ! =
efx_port_num ( efx ) )
continue ;
} else {
hwmon_type = EFX_HWMON_UNKNOWN ;
}
2012-01-06 20:25:39 +00:00
2013-08-08 11:14:20 +01:00
switch ( hwmon_type ) {
2012-01-06 20:25:39 +00:00
case EFX_HWMON_TEMP :
hwmon_prefix = " temp " ;
hwmon_index = + + n_temp ; /* 1-based */
break ;
case EFX_HWMON_COOL :
/* This is likely to be a heatsink, but there
* is no convention for representing cooling
* devices other than fans .
*/
hwmon_prefix = " fan " ;
hwmon_index = + + n_cool ; /* 1-based */
break ;
default :
hwmon_prefix = " in " ;
hwmon_index = n_in + + ; /* 0-based */
break ;
2012-11-28 23:11:18 +00:00
case EFX_HWMON_CURR :
hwmon_prefix = " curr " ;
hwmon_index = + + n_curr ; /* 1-based */
break ;
case EFX_HWMON_POWER :
hwmon_prefix = " power " ;
hwmon_index = + + n_power ; /* 1-based */
break ;
2012-01-06 20:25:39 +00:00
}
min1 = MCDI_ARRAY_FIELD ( outbuf , SENSOR_ENTRY ,
2013-08-08 11:14:20 +01:00
SENSOR_INFO_ENTRY , j , MIN1 ) ;
2012-01-06 20:25:39 +00:00
max1 = MCDI_ARRAY_FIELD ( outbuf , SENSOR_ENTRY ,
2013-08-08 11:14:20 +01:00
SENSOR_INFO_ENTRY , j , MAX1 ) ;
2012-01-06 20:25:39 +00:00
min2 = MCDI_ARRAY_FIELD ( outbuf , SENSOR_ENTRY ,
2013-08-08 11:14:20 +01:00
SENSOR_INFO_ENTRY , j , MIN2 ) ;
2012-01-06 20:25:39 +00:00
max2 = MCDI_ARRAY_FIELD ( outbuf , SENSOR_ENTRY ,
2013-08-08 11:14:20 +01:00
SENSOR_INFO_ENTRY , j , MAX2 ) ;
2012-01-06 20:25:39 +00:00
if ( min1 ! = max1 ) {
snprintf ( name , sizeof ( name ) , " %s%u_input " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-01-06 20:25:39 +00:00
efx , name , efx_mcdi_mon_show_value , i , type , 0 ) ;
2012-11-28 23:11:18 +00:00
if ( hwmon_type ! = EFX_HWMON_POWER ) {
snprintf ( name , sizeof ( name ) , " %s%u_min " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-11-28 23:11:18 +00:00
efx , name , efx_mcdi_mon_show_limit ,
i , type , min1 ) ;
}
2012-01-06 20:25:39 +00:00
snprintf ( name , sizeof ( name ) , " %s%u_max " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-01-06 20:25:39 +00:00
efx , name , efx_mcdi_mon_show_limit ,
i , type , max1 ) ;
if ( min2 ! = max2 ) {
/* Assume max2 is critical value.
* But we have no good way to expose min2 .
*/
snprintf ( name , sizeof ( name ) , " %s%u_crit " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-01-06 20:25:39 +00:00
efx , name , efx_mcdi_mon_show_limit ,
i , type , max2 ) ;
}
}
snprintf ( name , sizeof ( name ) , " %s%u_alarm " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-01-06 20:25:39 +00:00
efx , name , efx_mcdi_mon_show_alarm , i , type , 0 ) ;
2013-08-08 11:14:20 +01:00
if ( type < ARRAY_SIZE ( efx_mcdi_sensor_type ) & &
efx_mcdi_sensor_type [ type ] . label ) {
2012-01-06 20:25:39 +00:00
snprintf ( name , sizeof ( name ) , " %s%u_label " ,
hwmon_prefix , hwmon_index ) ;
2013-11-27 18:54:31 -08:00
efx_mcdi_mon_add_attr (
2012-01-06 20:25:39 +00:00
efx , name , efx_mcdi_mon_show_label , i , type , 0 ) ;
}
}
2013-11-27 18:54:31 -08:00
hwmon_register :
hwmon - > groups [ 0 ] = & hwmon - > group ;
hwmon - > device = hwmon_device_register_with_groups ( & efx - > pci_dev - > dev ,
KBUILD_MODNAME , NULL ,
hwmon - > groups ) ;
if ( IS_ERR ( hwmon - > device ) ) {
rc = PTR_ERR ( hwmon - > device ) ;
goto fail ;
}
return 0 ;
2012-01-06 20:25:39 +00:00
fail :
efx_mcdi_mon_remove ( efx ) ;
return rc ;
}
void efx_mcdi_mon_remove ( struct efx_nic * efx )
{
2012-09-13 01:11:24 +01:00
struct efx_mcdi_mon * hwmon = efx_mcdi_mon ( efx ) ;
2012-01-06 20:25:39 +00:00
if ( hwmon - > device )
hwmon_device_unregister ( hwmon - > device ) ;
2013-11-27 18:54:31 -08:00
kfree ( hwmon - > attrs ) ;
kfree ( hwmon - > group . attrs ) ;
2012-01-06 20:25:39 +00:00
efx_nic_free_buffer ( efx , & hwmon - > dma_buf ) ;
}
# endif /* CONFIG_SFC_MCDI_MON */