// 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>
#define HWMON_NR_SENSOR_TYPES (hwmon_max)
#ifdef _HAS_HWMON_HWMON_T_ENABLE
static u32 fixup_flags_legacy_fw(struct hl_device *hdev, enum hwmon_sensor_types type,
u32 cpucp_flags)
{
u32 flags;
switch (type) {
case hwmon_temp:
flags = (cpucp_flags << 1) | HWMON_T_ENABLE;
break;
case hwmon_in:
flags = (cpucp_flags << 1) | HWMON_I_ENABLE;
break;
case hwmon_curr:
flags = (cpucp_flags << 1) | HWMON_C_ENABLE;
break;
case hwmon_fan:
flags = (cpucp_flags << 1) | HWMON_F_ENABLE;
break;
case hwmon_power:
flags = (cpucp_flags << 1) | HWMON_P_ENABLE;
break;
case hwmon_pwm:
/* enable bit was here from day 1, so no need to adjust */
flags = cpucp_flags;
break;
default:
dev_err_ratelimited(hdev->dev, "unsupported h/w sensor type %d\n", type);
flags = cpucp_flags;
break;
}
return flags;
}
static u32 fixup_attr_legacy_fw(u32 attr)
{
return (attr - 1);
}
#else
static u32 fixup_flags_legacy_fw(struct hl_device *hdev, enum hwmon_sensor_types type,
u32 cpucp_flags)
{
return cpucp_flags;
}
static u32 fixup_attr_legacy_fw(u32 attr)
{
return attr;
}
#endif /* !_HAS_HWMON_HWMON_T_ENABLE */
static u32 adjust_hwmon_flags(struct hl_device *hdev, enum hwmon_sensor_types type, u32 cpucp_flags)
{
u32 flags, cpucp_input_val;
bool use_cpucp_enum;
use_cpucp_enum = (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
CPU_BOOT_DEV_STS0_MAP_HWMON_EN) ? true : false;
/* If f/w is using it's own enum, we need to check if the properties values are aligned.
* If not, it means we need to adjust the values to the new format that is used in the
* kernel since 5.6 (enum values were incremented by 1 by adding a new enable value).
*/
if (use_cpucp_enum) {
switch (type) {
case hwmon_temp:
cpucp_input_val = cpucp_temp_input;
if (cpucp_input_val == hwmon_temp_input)
flags = cpucp_flags;
else
flags = (cpucp_flags << 1) | HWMON_T_ENABLE;
break;
case hwmon_in:
cpucp_input_val = cpucp_in_input;
if (cpucp_input_val == hwmon_in_input)
flags = cpucp_flags;
else
flags = (cpucp_flags << 1) | HWMON_I_ENABLE;
break;
case hwmon_curr:
cpucp_input_val = cpucp_curr_input;
if (cpucp_input_val == hwmon_curr_input)
flags = cpucp_flags;
else
flags = (cpucp_flags << 1) | HWMON_C_ENABLE;
break;
case hwmon_fan:
cpucp_input_val = cpucp_fan_input;
if (cpucp_input_val == hwmon_fan_input)
flags = cpucp_flags;
else
flags = (cpucp_flags << 1) | HWMON_F_ENABLE;
break;
case hwmon_pwm:
/* enable bit was here from day 1, so no need to adjust */
flags = cpucp_flags;
break;
case hwmon_power:
cpucp_input_val = CPUCP_POWER_INPUT;
if (cpucp_input_val == hwmon_power_input)
flags = cpucp_flags;
else
flags = (cpucp_flags << 1) | HWMON_P_ENABLE;
break;
default:
dev_err_ratelimited(hdev->dev, "unsupported h/w sensor type %d\n", type);
flags = cpucp_flags;
break;
}
} else {
flags = fixup_flags_legacy_fw(hdev, type, cpucp_flags);
}
return flags;
}
int hl_build_hwmon_channel_info(struct hl_device *hdev, struct cpucp_sensor *sensors_arr)
{
u32 num_sensors_for_type, flags, num_active_sensor_types = 0, arr_size = 0, *curr_arr;
u32 sensors_by_type_next_index[HWMON_NR_SENSOR_TYPES] = {0};
u32 *sensors_by_type[HWMON_NR_SENSOR_TYPES] = {NULL};
struct hwmon_channel_info **channels_info;
u32 counts[HWMON_NR_SENSOR_TYPES] = {0};
enum hwmon_sensor_types type;
int rc, i, j;
for (i = 0 ; i < CPUCP_MAX_SENSORS ; i++) {
type = le32_to_cpu(sensors_arr[i].type);
if ((type == 0) && (sensors_arr[i].flags ==