2019-02-16 01:39:19 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2016 - 2019 HabanaLabs , Ltd .
* All Rights Reserved .
*/
# include "habanalabs.h"
# include <linux/pci.h>
# include <linux/hwmon.h>
2019-02-28 11:46:12 +03:00
# define SENSORS_PKT_TIMEOUT 1000000 /* 1s */
2019-02-16 01:39:19 +03:00
# define HWMON_NR_SENSOR_TYPES (hwmon_pwm + 1)
int hl_build_hwmon_channel_info ( struct hl_device * hdev ,
struct armcp_sensor * sensors_arr )
{
u32 counts [ HWMON_NR_SENSOR_TYPES ] = { 0 } ;
2019-02-28 11:46:23 +03:00
u32 * sensors_by_type [ HWMON_NR_SENSOR_TYPES ] = { NULL } ;
2019-02-16 01:39:19 +03:00
u32 sensors_by_type_next_index [ HWMON_NR_SENSOR_TYPES ] = { 0 } ;
struct hwmon_channel_info * * channels_info ;
u32 num_sensors_for_type , num_active_sensor_types = 0 ,
arr_size = 0 , * curr_arr ;
enum hwmon_sensor_types type ;
int rc , i , j ;
for ( i = 0 ; i < ARMCP_MAX_SENSORS ; i + + ) {
2019-08-08 17:05:45 +03:00
type = le32_to_cpu ( sensors_arr [ i ] . type ) ;
2019-02-16 01:39:19 +03:00
if ( ( type = = 0 ) & & ( sensors_arr [ i ] . flags = = 0 ) )
break ;
if ( type > = HWMON_NR_SENSOR_TYPES ) {
dev_err ( hdev - > dev ,
" Got wrong sensor type %d from device \n " , type ) ;
return - EINVAL ;
}
counts [ type ] + + ;
arr_size + + ;
}
for ( i = 0 ; i < HWMON_NR_SENSOR_TYPES ; i + + ) {
if ( counts [ i ] = = 0 )
continue ;
num_sensors_for_type = counts [ i ] + 1 ;
curr_arr = kcalloc ( num_sensors_for_type , sizeof ( * curr_arr ) ,
GFP_KERNEL ) ;
if ( ! curr_arr ) {
rc = - ENOMEM ;
goto sensors_type_err ;
}
num_active_sensor_types + + ;
sensors_by_type [ i ] = curr_arr ;
}
for ( i = 0 ; i < arr_size ; i + + ) {
2019-08-08 17:05:45 +03:00
type = le32_to_cpu ( sensors_arr [ i ] . type ) ;
2019-02-16 01:39:19 +03:00
curr_arr = sensors_by_type [ type ] ;
curr_arr [ sensors_by_type_next_index [ type ] + + ] =
2019-08-08 17:05:45 +03:00
le32_to_cpu ( sensors_arr [ i ] . flags ) ;
2019-02-16 01:39:19 +03:00
}
channels_info = kcalloc ( num_active_sensor_types + 1 ,
sizeof ( * channels_info ) , GFP_KERNEL ) ;
if ( ! channels_info ) {
rc = - ENOMEM ;
goto channels_info_array_err ;
}
for ( i = 0 ; i < num_active_sensor_types ; i + + ) {
channels_info [ i ] = kzalloc ( sizeof ( * channels_info [ i ] ) ,
GFP_KERNEL ) ;
if ( ! channels_info [ i ] ) {
rc = - ENOMEM ;
goto channel_info_err ;
}
}
for ( i = 0 , j = 0 ; i < HWMON_NR_SENSOR_TYPES ; i + + ) {
if ( ! sensors_by_type [ i ] )
continue ;
channels_info [ j ] - > type = i ;
channels_info [ j ] - > config = sensors_by_type [ i ] ;
j + + ;
}
hdev - > hl_chip_info - > info =
( const struct hwmon_channel_info * * ) channels_info ;
return 0 ;
channel_info_err :
for ( i = 0 ; i < num_active_sensor_types ; i + + )
if ( channels_info [ i ] ) {
kfree ( channels_info [ i ] - > config ) ;
kfree ( channels_info [ i ] ) ;
}
kfree ( channels_info ) ;
channels_info_array_err :
sensors_type_err :
for ( i = 0 ; i < HWMON_NR_SENSOR_TYPES ; i + + )
kfree ( sensors_by_type [ i ] ) ;
return rc ;
}
static int hl_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * val )
{
struct hl_device * hdev = dev_get_drvdata ( dev ) ;
2020-01-23 19:03:04 +03:00
int rc ;
2019-02-16 01:39:19 +03:00
2019-02-16 01:39:20 +03:00
if ( hl_device_disabled_or_in_reset ( hdev ) )
2019-02-16 01:39:19 +03:00
return - ENODEV ;
switch ( type ) {
case hwmon_temp :
switch ( attr ) {
case hwmon_temp_input :
case hwmon_temp_max :
case hwmon_temp_crit :
case hwmon_temp_max_hyst :
case hwmon_temp_crit_hyst :
2020-01-21 16:02:06 +03:00
case hwmon_temp_offset :
2020-01-28 16:19:38 +03:00
case hwmon_temp_highest :
2019-02-16 01:39:19 +03:00
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
rc = hl_get_temperature ( hdev , channel , attr , val ) ;
2019-02-16 01:39:19 +03:00
break ;
case hwmon_in :
switch ( attr ) {
case hwmon_in_input :
case hwmon_in_min :
case hwmon_in_max :
2020-01-28 16:19:38 +03:00
case hwmon_in_highest :
2019-02-16 01:39:19 +03:00
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
rc = hl_get_voltage ( hdev , channel , attr , val ) ;
2019-02-16 01:39:19 +03:00
break ;
case hwmon_curr :
switch ( attr ) {
case hwmon_curr_input :
case hwmon_curr_min :
case hwmon_curr_max :
2020-01-28 16:19:38 +03:00
case hwmon_curr_highest :
2019-02-16 01:39:19 +03:00
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
rc = hl_get_current ( hdev , channel , attr , val ) ;
2019-02-16 01:39:19 +03:00
break ;
case hwmon_fan :
switch ( attr ) {
case hwmon_fan_input :
case hwmon_fan_min :
case hwmon_fan_max :
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
rc = hl_get_fan_speed ( hdev , channel , attr , val ) ;
2019-02-16 01:39:19 +03:00
break ;
case hwmon_pwm :
switch ( attr ) {
case hwmon_pwm_input :
case hwmon_pwm_enable :
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
rc = hl_get_pwm_info ( hdev , channel , attr , val ) ;
2019-02-16 01:39:19 +03:00
break ;
default :
return - EINVAL ;
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
static int hl_write ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long val )
{
struct hl_device * hdev = dev_get_drvdata ( dev ) ;
2019-02-16 01:39:20 +03:00
if ( hl_device_disabled_or_in_reset ( hdev ) )
2019-02-16 01:39:19 +03:00
return - ENODEV ;
switch ( type ) {
2020-01-21 16:02:06 +03:00
case hwmon_temp :
switch ( attr ) {
case hwmon_temp_offset :
2020-04-16 16:43:26 +03:00
case hwmon_temp_reset_history :
2020-01-21 16:02:06 +03:00
break ;
default :
return - EINVAL ;
}
hl_set_temperature ( hdev , channel , attr , val ) ;
break ;
2019-02-16 01:39:19 +03:00
case hwmon_pwm :
switch ( attr ) {
case hwmon_pwm_input :
case hwmon_pwm_enable :
break ;
default :
return - EINVAL ;
}
hl_set_pwm_info ( hdev , channel , attr , val ) ;
break ;
2020-04-16 16:43:26 +03:00
case hwmon_in :
switch ( attr ) {
case hwmon_in_reset_history :
break ;
default :
return - EINVAL ;
}
hl_set_voltage ( hdev , channel , attr , val ) ;
break ;
case hwmon_curr :
switch ( attr ) {
case hwmon_curr_reset_history :
break ;
default :
return - EINVAL ;
}
hl_set_current ( hdev , channel , attr , val ) ;
break ;
2019-02-16 01:39:19 +03:00
default :
return - EINVAL ;
}
return 0 ;
}
static umode_t hl_is_visible ( const void * data , enum hwmon_sensor_types type ,
u32 attr , int channel )
{
switch ( type ) {
case hwmon_temp :
switch ( attr ) {
case hwmon_temp_input :
case hwmon_temp_max :
case hwmon_temp_max_hyst :
case hwmon_temp_crit :
case hwmon_temp_crit_hyst :
2020-01-28 16:19:38 +03:00
case hwmon_temp_highest :
2019-02-16 01:39:19 +03:00
return 0444 ;
2020-01-21 16:02:06 +03:00
case hwmon_temp_offset :
return 0644 ;
2020-04-16 16:43:26 +03:00
case hwmon_temp_reset_history :
return 0200 ;
2019-02-16 01:39:19 +03:00
}
break ;
case hwmon_in :
switch ( attr ) {
case hwmon_in_input :
case hwmon_in_min :
case hwmon_in_max :
2020-01-28 16:19:38 +03:00
case hwmon_in_highest :
2019-02-16 01:39:19 +03:00
return 0444 ;
2020-04-16 16:43:26 +03:00
case hwmon_in_reset_history :
return 0200 ;
2019-02-16 01:39:19 +03:00
}
break ;
case hwmon_curr :
switch ( attr ) {
case hwmon_curr_input :
case hwmon_curr_min :
case hwmon_curr_max :
2020-01-28 16:19:38 +03:00
case hwmon_curr_highest :
2019-02-16 01:39:19 +03:00
return 0444 ;
2020-04-16 16:43:26 +03:00
case hwmon_curr_reset_history :
return 0200 ;
2019-02-16 01:39:19 +03:00
}
break ;
case hwmon_fan :
switch ( attr ) {
case hwmon_fan_input :
case hwmon_fan_min :
case hwmon_fan_max :
return 0444 ;
}
break ;
case hwmon_pwm :
switch ( attr ) {
case hwmon_pwm_input :
case hwmon_pwm_enable :
return 0644 ;
}
break ;
default :
break ;
}
return 0 ;
}
static const struct hwmon_ops hl_hwmon_ops = {
. is_visible = hl_is_visible ,
. read = hl_read ,
. write = hl_write
} ;
2020-01-23 19:03:04 +03:00
int hl_get_temperature ( struct hl_device * hdev ,
int sensor_index , u32 attr , long * value )
2019-02-16 01:39:19 +03:00
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_TEMPERATURE_GET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
2020-01-23 19:03:04 +03:00
SENSORS_PKT_TIMEOUT , value ) ;
2019-02-16 01:39:19 +03:00
if ( rc ) {
dev_err ( hdev - > dev ,
" Failed to get temperature from sensor %d, error %d \n " ,
sensor_index , rc ) ;
2020-01-23 19:03:04 +03:00
* value = 0 ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
2020-01-21 16:02:06 +03:00
int hl_set_temperature ( struct hl_device * hdev ,
int sensor_index , u32 attr , long value )
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_TEMPERATURE_SET < <
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
pkt . value = __cpu_to_le64 ( value ) ;
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
SENSORS_PKT_TIMEOUT , NULL ) ;
if ( rc )
dev_err ( hdev - > dev ,
" Failed to set temperature of sensor %d, error %d \n " ,
sensor_index , rc ) ;
return rc ;
}
2020-01-23 19:03:04 +03:00
int hl_get_voltage ( struct hl_device * hdev ,
int sensor_index , u32 attr , long * value )
2019-02-16 01:39:19 +03:00
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_VOLTAGE_GET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
2020-01-23 19:03:04 +03:00
SENSORS_PKT_TIMEOUT , value ) ;
2019-02-16 01:39:19 +03:00
if ( rc ) {
dev_err ( hdev - > dev ,
" Failed to get voltage from sensor %d, error %d \n " ,
sensor_index , rc ) ;
2020-01-23 19:03:04 +03:00
* value = 0 ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
int hl_get_current ( struct hl_device * hdev ,
int sensor_index , u32 attr , long * value )
2019-02-16 01:39:19 +03:00
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_CURRENT_GET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
2020-01-23 19:03:04 +03:00
SENSORS_PKT_TIMEOUT , value ) ;
2019-02-16 01:39:19 +03:00
if ( rc ) {
dev_err ( hdev - > dev ,
" Failed to get current from sensor %d, error %d \n " ,
sensor_index , rc ) ;
2020-01-23 19:03:04 +03:00
* value = 0 ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
int hl_get_fan_speed ( struct hl_device * hdev ,
int sensor_index , u32 attr , long * value )
2019-02-16 01:39:19 +03:00
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_FAN_SPEED_GET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
2020-01-23 19:03:04 +03:00
SENSORS_PKT_TIMEOUT , value ) ;
2019-02-16 01:39:19 +03:00
if ( rc ) {
dev_err ( hdev - > dev ,
" Failed to get fan speed from sensor %d, error %d \n " ,
sensor_index , rc ) ;
2020-01-23 19:03:04 +03:00
* value = 0 ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
int hl_get_pwm_info ( struct hl_device * hdev ,
int sensor_index , u32 attr , long * value )
2019-02-16 01:39:19 +03:00
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_PWM_GET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
2020-01-23 19:03:04 +03:00
SENSORS_PKT_TIMEOUT , value ) ;
2019-02-16 01:39:19 +03:00
if ( rc ) {
dev_err ( hdev - > dev ,
" Failed to get pwm info from sensor %d, error %d \n " ,
sensor_index , rc ) ;
2020-01-23 19:03:04 +03:00
* value = 0 ;
2019-02-16 01:39:19 +03:00
}
2020-01-23 19:03:04 +03:00
return rc ;
2019-02-16 01:39:19 +03:00
}
void hl_set_pwm_info ( struct hl_device * hdev , int sensor_index , u32 attr ,
long value )
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
2019-08-08 17:00:54 +03:00
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_PWM_SET < <
2019-02-28 11:46:24 +03:00
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
2019-08-08 17:00:54 +03:00
pkt . value = cpu_to_le64 ( value ) ;
2019-02-16 01:39:19 +03:00
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
SENSORS_PKT_TIMEOUT , NULL ) ;
if ( rc )
dev_err ( hdev - > dev ,
" Failed to set pwm info to sensor %d, error %d \n " ,
sensor_index , rc ) ;
}
2020-04-16 16:43:26 +03:00
int hl_set_voltage ( struct hl_device * hdev ,
int sensor_index , u32 attr , long value )
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_VOLTAGE_SET < <
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
pkt . value = __cpu_to_le64 ( value ) ;
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
SENSORS_PKT_TIMEOUT , NULL ) ;
if ( rc )
dev_err ( hdev - > dev ,
" Failed to set voltage of sensor %d, error %d \n " ,
sensor_index , rc ) ;
return rc ;
}
int hl_set_current ( struct hl_device * hdev ,
int sensor_index , u32 attr , long value )
{
struct armcp_packet pkt ;
int rc ;
memset ( & pkt , 0 , sizeof ( pkt ) ) ;
pkt . ctl = cpu_to_le32 ( ARMCP_PACKET_CURRENT_SET < <
ARMCP_PKT_CTL_OPCODE_SHIFT ) ;
pkt . sensor_index = __cpu_to_le16 ( sensor_index ) ;
pkt . type = __cpu_to_le16 ( attr ) ;
pkt . value = __cpu_to_le64 ( value ) ;
rc = hdev - > asic_funcs - > send_cpu_message ( hdev , ( u32 * ) & pkt , sizeof ( pkt ) ,
SENSORS_PKT_TIMEOUT , NULL ) ;
if ( rc )
dev_err ( hdev - > dev ,
" Failed to set current of sensor %d, error %d \n " ,
sensor_index , rc ) ;
return rc ;
}
2019-02-16 01:39:19 +03:00
int hl_hwmon_init ( struct hl_device * hdev )
{
struct device * dev = hdev - > pdev ? & hdev - > pdev - > dev : hdev - > dev ;
2019-08-30 14:26:49 +03:00
struct asic_fixed_properties * prop = & hdev - > asic_prop ;
2019-02-16 01:39:19 +03:00
int rc ;
if ( ( hdev - > hwmon_initialized ) | | ! ( hdev - > fw_loading ) )
return 0 ;
if ( hdev - > hl_chip_info - > info ) {
hdev - > hl_chip_info - > ops = & hl_hwmon_ops ;
hdev - > hwmon_dev = hwmon_device_register_with_info ( dev ,
2019-08-30 14:26:49 +03:00
prop - > armcp_info . card_name , hdev ,
hdev - > hl_chip_info , NULL ) ;
2019-02-16 01:39:19 +03:00
if ( IS_ERR ( hdev - > hwmon_dev ) ) {
rc = PTR_ERR ( hdev - > hwmon_dev ) ;
dev_err ( hdev - > dev ,
" Unable to register hwmon device: %d \n " , rc ) ;
return rc ;
}
dev_info ( hdev - > dev , " %s: add sensors information \n " ,
dev_name ( hdev - > hwmon_dev ) ) ;
hdev - > hwmon_initialized = true ;
} else {
dev_info ( hdev - > dev , " no available sensors \n " ) ;
}
return 0 ;
}
void hl_hwmon_fini ( struct hl_device * hdev )
{
if ( ! hdev - > hwmon_initialized )
return ;
hwmon_device_unregister ( hdev - > hwmon_dev ) ;
}