Path: blob/master/drivers/accel/habanalabs/common/hwmon.c
26436 views
// SPDX-License-Identifier: GPL-2.012/*3* Copyright 2016-2019 HabanaLabs, Ltd.4* All Rights Reserved.5*/67#include "habanalabs.h"89#include <linux/pci.h>10#include <linux/hwmon.h>1112#define HWMON_NR_SENSOR_TYPES (hwmon_max)1314#ifdef _HAS_HWMON_HWMON_T_ENABLE1516static u32 fixup_flags_legacy_fw(struct hl_device *hdev, enum hwmon_sensor_types type,17u32 cpucp_flags)18{19u32 flags;2021switch (type) {22case hwmon_temp:23flags = (cpucp_flags << 1) | HWMON_T_ENABLE;24break;2526case hwmon_in:27flags = (cpucp_flags << 1) | HWMON_I_ENABLE;28break;2930case hwmon_curr:31flags = (cpucp_flags << 1) | HWMON_C_ENABLE;32break;3334case hwmon_fan:35flags = (cpucp_flags << 1) | HWMON_F_ENABLE;36break;3738case hwmon_power:39flags = (cpucp_flags << 1) | HWMON_P_ENABLE;40break;4142case hwmon_pwm:43/* enable bit was here from day 1, so no need to adjust */44flags = cpucp_flags;45break;4647default:48dev_err_ratelimited(hdev->dev, "unsupported h/w sensor type %d\n", type);49flags = cpucp_flags;50break;51}5253return flags;54}5556static u32 fixup_attr_legacy_fw(u32 attr)57{58return (attr - 1);59}6061#else6263static u32 fixup_flags_legacy_fw(struct hl_device *hdev, enum hwmon_sensor_types type,64u32 cpucp_flags)65{66return cpucp_flags;67}6869static u32 fixup_attr_legacy_fw(u32 attr)70{71return attr;72}7374#endif /* !_HAS_HWMON_HWMON_T_ENABLE */7576static u32 adjust_hwmon_flags(struct hl_device *hdev, enum hwmon_sensor_types type, u32 cpucp_flags)77{78u32 flags, cpucp_input_val;79bool use_cpucp_enum;8081use_cpucp_enum = (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &82CPU_BOOT_DEV_STS0_MAP_HWMON_EN) ? true : false;8384/* If f/w is using it's own enum, we need to check if the properties values are aligned.85* If not, it means we need to adjust the values to the new format that is used in the86* kernel since 5.6 (enum values were incremented by 1 by adding a new enable value).87*/88if (use_cpucp_enum) {89switch (type) {90case hwmon_temp:91cpucp_input_val = cpucp_temp_input;92if (cpucp_input_val == hwmon_temp_input)93flags = cpucp_flags;94else95flags = (cpucp_flags << 1) | HWMON_T_ENABLE;96break;9798case hwmon_in:99cpucp_input_val = cpucp_in_input;100if (cpucp_input_val == hwmon_in_input)101flags = cpucp_flags;102else103flags = (cpucp_flags << 1) | HWMON_I_ENABLE;104break;105106case hwmon_curr:107cpucp_input_val = cpucp_curr_input;108if (cpucp_input_val == hwmon_curr_input)109flags = cpucp_flags;110else111flags = (cpucp_flags << 1) | HWMON_C_ENABLE;112break;113114case hwmon_fan:115cpucp_input_val = cpucp_fan_input;116if (cpucp_input_val == hwmon_fan_input)117flags = cpucp_flags;118else119flags = (cpucp_flags << 1) | HWMON_F_ENABLE;120break;121122case hwmon_pwm:123/* enable bit was here from day 1, so no need to adjust */124flags = cpucp_flags;125break;126127case hwmon_power:128cpucp_input_val = CPUCP_POWER_INPUT;129if (cpucp_input_val == hwmon_power_input)130flags = cpucp_flags;131else132flags = (cpucp_flags << 1) | HWMON_P_ENABLE;133break;134135default:136dev_err_ratelimited(hdev->dev, "unsupported h/w sensor type %d\n", type);137flags = cpucp_flags;138break;139}140} else {141flags = fixup_flags_legacy_fw(hdev, type, cpucp_flags);142}143144return flags;145}146147int hl_build_hwmon_channel_info(struct hl_device *hdev, struct cpucp_sensor *sensors_arr)148{149u32 num_sensors_for_type, flags, num_active_sensor_types = 0, arr_size = 0, *curr_arr;150u32 sensors_by_type_next_index[HWMON_NR_SENSOR_TYPES] = {0};151u32 *sensors_by_type[HWMON_NR_SENSOR_TYPES] = {NULL};152struct hwmon_channel_info **channels_info;153u32 counts[HWMON_NR_SENSOR_TYPES] = {0};154enum hwmon_sensor_types type;155int rc, i, j;156157for (i = 0 ; i < CPUCP_MAX_SENSORS ; i++) {158type = le32_to_cpu(sensors_arr[i].type);159160if ((type == 0) && (sensors_arr[i].flags == 0))161break;162163if (type >= HWMON_NR_SENSOR_TYPES) {164dev_err_ratelimited(hdev->dev,165"Got wrong sensor type %d from device\n", type);166return -EINVAL;167}168169counts[type]++;170arr_size++;171}172173for (i = 0 ; i < HWMON_NR_SENSOR_TYPES ; i++) {174if (counts[i] == 0)175continue;176177num_sensors_for_type = counts[i] + 1;178dev_dbg(hdev->dev, "num_sensors_for_type %d = %d\n", i, num_sensors_for_type);179180curr_arr = kcalloc(num_sensors_for_type, sizeof(*curr_arr), GFP_KERNEL);181if (!curr_arr) {182rc = -ENOMEM;183goto sensors_type_err;184}185186num_active_sensor_types++;187sensors_by_type[i] = curr_arr;188}189190for (i = 0 ; i < arr_size ; i++) {191type = le32_to_cpu(sensors_arr[i].type);192curr_arr = sensors_by_type[type];193flags = adjust_hwmon_flags(hdev, type, le32_to_cpu(sensors_arr[i].flags));194curr_arr[sensors_by_type_next_index[type]++] = flags;195}196197channels_info = kcalloc(num_active_sensor_types + 1, sizeof(struct hwmon_channel_info *),198GFP_KERNEL);199if (!channels_info) {200rc = -ENOMEM;201goto channels_info_array_err;202}203204for (i = 0 ; i < num_active_sensor_types ; i++) {205channels_info[i] = kzalloc(sizeof(*channels_info[i]), GFP_KERNEL);206if (!channels_info[i]) {207rc = -ENOMEM;208goto channel_info_err;209}210}211212for (i = 0, j = 0 ; i < HWMON_NR_SENSOR_TYPES ; i++) {213if (!sensors_by_type[i])214continue;215216channels_info[j]->type = i;217channels_info[j]->config = sensors_by_type[i];218j++;219}220221hdev->hl_chip_info->info = (const struct hwmon_channel_info **)channels_info;222223return 0;224225channel_info_err:226for (i = 0 ; i < num_active_sensor_types ; i++) {227if (channels_info[i]) {228kfree(channels_info[i]->config);229kfree(channels_info[i]);230}231}232kfree(channels_info);233234channels_info_array_err:235sensors_type_err:236for (i = 0 ; i < HWMON_NR_SENSOR_TYPES ; i++)237kfree(sensors_by_type[i]);238239return rc;240}241242static int hl_read(struct device *dev, enum hwmon_sensor_types type,243u32 attr, int channel, long *val)244{245struct hl_device *hdev = dev_get_drvdata(dev);246bool use_cpucp_enum;247u32 cpucp_attr;248int rc;249250if (!hl_device_operational(hdev, NULL))251return -ENODEV;252253use_cpucp_enum = (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &254CPU_BOOT_DEV_STS0_MAP_HWMON_EN) ? true : false;255256switch (type) {257case hwmon_temp:258switch (attr) {259case hwmon_temp_input:260cpucp_attr = cpucp_temp_input;261break;262case hwmon_temp_max:263cpucp_attr = cpucp_temp_max;264break;265case hwmon_temp_crit:266cpucp_attr = cpucp_temp_crit;267break;268case hwmon_temp_max_hyst:269cpucp_attr = cpucp_temp_max_hyst;270break;271case hwmon_temp_crit_hyst:272cpucp_attr = cpucp_temp_crit_hyst;273break;274case hwmon_temp_offset:275cpucp_attr = cpucp_temp_offset;276break;277case hwmon_temp_highest:278cpucp_attr = cpucp_temp_highest;279break;280default:281return -EINVAL;282}283284if (use_cpucp_enum)285rc = hl_get_temperature(hdev, channel, cpucp_attr, val);286else287rc = hl_get_temperature(hdev, channel, fixup_attr_legacy_fw(attr), val);288break;289case hwmon_in:290switch (attr) {291case hwmon_in_input:292cpucp_attr = cpucp_in_input;293break;294case hwmon_in_min:295cpucp_attr = cpucp_in_min;296break;297case hwmon_in_max:298cpucp_attr = cpucp_in_max;299break;300case hwmon_in_highest:301cpucp_attr = cpucp_in_highest;302break;303default:304return -EINVAL;305}306307if (use_cpucp_enum)308rc = hl_get_voltage(hdev, channel, cpucp_attr, val);309else310rc = hl_get_voltage(hdev, channel, fixup_attr_legacy_fw(attr), val);311break;312case hwmon_curr:313switch (attr) {314case hwmon_curr_input:315cpucp_attr = cpucp_curr_input;316break;317case hwmon_curr_min:318cpucp_attr = cpucp_curr_min;319break;320case hwmon_curr_max:321cpucp_attr = cpucp_curr_max;322break;323case hwmon_curr_highest:324cpucp_attr = cpucp_curr_highest;325break;326default:327return -EINVAL;328}329330if (use_cpucp_enum)331rc = hl_get_current(hdev, channel, cpucp_attr, val);332else333rc = hl_get_current(hdev, channel, fixup_attr_legacy_fw(attr), val);334break;335case hwmon_fan:336switch (attr) {337case hwmon_fan_input:338cpucp_attr = cpucp_fan_input;339break;340case hwmon_fan_min:341cpucp_attr = cpucp_fan_min;342break;343case hwmon_fan_max:344cpucp_attr = cpucp_fan_max;345break;346default:347return -EINVAL;348}349350if (use_cpucp_enum)351rc = hl_get_fan_speed(hdev, channel, cpucp_attr, val);352else353rc = hl_get_fan_speed(hdev, channel, fixup_attr_legacy_fw(attr), val);354break;355case hwmon_pwm:356switch (attr) {357case hwmon_pwm_input:358cpucp_attr = cpucp_pwm_input;359break;360case hwmon_pwm_enable:361cpucp_attr = cpucp_pwm_enable;362break;363default:364return -EINVAL;365}366367if (use_cpucp_enum)368rc = hl_get_pwm_info(hdev, channel, cpucp_attr, val);369else370/* no need for fixup as pwm was aligned from day 1 */371rc = hl_get_pwm_info(hdev, channel, attr, val);372break;373case hwmon_power:374switch (attr) {375case hwmon_power_input:376cpucp_attr = CPUCP_POWER_INPUT;377break;378case hwmon_power_input_highest:379cpucp_attr = CPUCP_POWER_INPUT_HIGHEST;380break;381default:382return -EINVAL;383}384385if (use_cpucp_enum)386rc = hl_get_power(hdev, channel, cpucp_attr, val);387else388rc = hl_get_power(hdev, channel, fixup_attr_legacy_fw(attr), val);389break;390default:391return -EINVAL;392}393return rc;394}395396static int hl_write(struct device *dev, enum hwmon_sensor_types type,397u32 attr, int channel, long val)398{399struct hl_device *hdev = dev_get_drvdata(dev);400u32 cpucp_attr;401bool use_cpucp_enum = (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &402CPU_BOOT_DEV_STS0_MAP_HWMON_EN) ? true : false;403404if (!hl_device_operational(hdev, NULL))405return -ENODEV;406407switch (type) {408case hwmon_temp:409switch (attr) {410case hwmon_temp_offset:411cpucp_attr = cpucp_temp_offset;412break;413case hwmon_temp_reset_history:414cpucp_attr = cpucp_temp_reset_history;415break;416default:417return -EINVAL;418}419420if (use_cpucp_enum)421hl_set_temperature(hdev, channel, cpucp_attr, val);422else423hl_set_temperature(hdev, channel, fixup_attr_legacy_fw(attr), val);424break;425case hwmon_pwm:426switch (attr) {427case hwmon_pwm_input:428cpucp_attr = cpucp_pwm_input;429break;430case hwmon_pwm_enable:431cpucp_attr = cpucp_pwm_enable;432break;433default:434return -EINVAL;435}436437if (use_cpucp_enum)438hl_set_pwm_info(hdev, channel, cpucp_attr, val);439else440/* no need for fixup as pwm was aligned from day 1 */441hl_set_pwm_info(hdev, channel, attr, val);442break;443case hwmon_in:444switch (attr) {445case hwmon_in_reset_history:446cpucp_attr = cpucp_in_reset_history;447break;448default:449return -EINVAL;450}451452if (use_cpucp_enum)453hl_set_voltage(hdev, channel, cpucp_attr, val);454else455hl_set_voltage(hdev, channel, fixup_attr_legacy_fw(attr), val);456break;457case hwmon_curr:458switch (attr) {459case hwmon_curr_reset_history:460cpucp_attr = cpucp_curr_reset_history;461break;462default:463return -EINVAL;464}465466if (use_cpucp_enum)467hl_set_current(hdev, channel, cpucp_attr, val);468else469hl_set_current(hdev, channel, fixup_attr_legacy_fw(attr), val);470break;471case hwmon_power:472switch (attr) {473case hwmon_power_reset_history:474cpucp_attr = CPUCP_POWER_RESET_INPUT_HISTORY;475break;476default:477return -EINVAL;478}479480if (use_cpucp_enum)481hl_set_power(hdev, channel, cpucp_attr, val);482else483hl_set_power(hdev, channel, fixup_attr_legacy_fw(attr), val);484break;485default:486return -EINVAL;487}488return 0;489}490491static umode_t hl_is_visible(const void *data, enum hwmon_sensor_types type,492u32 attr, int channel)493{494switch (type) {495case hwmon_temp:496switch (attr) {497case hwmon_temp_input:498case hwmon_temp_max:499case hwmon_temp_max_hyst:500case hwmon_temp_crit:501case hwmon_temp_crit_hyst:502case hwmon_temp_highest:503return 0444;504case hwmon_temp_offset:505return 0644;506case hwmon_temp_reset_history:507return 0200;508}509break;510case hwmon_in:511switch (attr) {512case hwmon_in_input:513case hwmon_in_min:514case hwmon_in_max:515case hwmon_in_highest:516return 0444;517case hwmon_in_reset_history:518return 0200;519}520break;521case hwmon_curr:522switch (attr) {523case hwmon_curr_input:524case hwmon_curr_min:525case hwmon_curr_max:526case hwmon_curr_highest:527return 0444;528case hwmon_curr_reset_history:529return 0200;530}531break;532case hwmon_fan:533switch (attr) {534case hwmon_fan_input:535case hwmon_fan_min:536case hwmon_fan_max:537return 0444;538}539break;540case hwmon_pwm:541switch (attr) {542case hwmon_pwm_input:543case hwmon_pwm_enable:544return 0644;545}546break;547case hwmon_power:548switch (attr) {549case hwmon_power_input:550case hwmon_power_input_highest:551return 0444;552case hwmon_power_reset_history:553return 0200;554}555break;556default:557break;558}559return 0;560}561562static const struct hwmon_ops hl_hwmon_ops = {563.is_visible = hl_is_visible,564.read = hl_read,565.write = hl_write566};567568int hl_get_temperature(struct hl_device *hdev,569int sensor_index, u32 attr, long *value)570{571struct cpucp_packet pkt;572u64 result;573int rc;574575memset(&pkt, 0, sizeof(pkt));576577pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEMPERATURE_GET <<578CPUCP_PKT_CTL_OPCODE_SHIFT);579pkt.sensor_index = __cpu_to_le16(sensor_index);580pkt.type = __cpu_to_le16(attr);581rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),5820, &result);583584*value = (long) result;585586if (rc) {587if (rc != -EAGAIN)588dev_err_ratelimited(hdev->dev,589"Failed to get temperature from sensor %d, error %d\n",590sensor_index, rc);591*value = 0;592}593594return rc;595}596597int hl_set_temperature(struct hl_device *hdev,598int sensor_index, u32 attr, long value)599{600struct cpucp_packet pkt;601int rc;602603memset(&pkt, 0, sizeof(pkt));604605pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEMPERATURE_SET <<606CPUCP_PKT_CTL_OPCODE_SHIFT);607pkt.sensor_index = __cpu_to_le16(sensor_index);608pkt.type = __cpu_to_le16(attr);609pkt.value = __cpu_to_le64(value);610611rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),6120, NULL);613if (rc && rc != -EAGAIN)614dev_err_ratelimited(hdev->dev,615"Failed to set temperature of sensor %d, error %d\n",616sensor_index, rc);617618return rc;619}620621int hl_get_voltage(struct hl_device *hdev,622int sensor_index, u32 attr, long *value)623{624struct cpucp_packet pkt;625u64 result;626int rc;627628memset(&pkt, 0, sizeof(pkt));629630pkt.ctl = cpu_to_le32(CPUCP_PACKET_VOLTAGE_GET <<631CPUCP_PKT_CTL_OPCODE_SHIFT);632pkt.sensor_index = __cpu_to_le16(sensor_index);633pkt.type = __cpu_to_le16(attr);634635rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),6360, &result);637638*value = (long) result;639640if (rc) {641if (rc != -EAGAIN)642dev_err_ratelimited(hdev->dev,643"Failed to get voltage from sensor %d, error %d\n",644sensor_index, rc);645*value = 0;646}647648return rc;649}650651int hl_get_current(struct hl_device *hdev,652int sensor_index, u32 attr, long *value)653{654struct cpucp_packet pkt;655u64 result;656int rc;657658memset(&pkt, 0, sizeof(pkt));659660pkt.ctl = cpu_to_le32(CPUCP_PACKET_CURRENT_GET <<661CPUCP_PKT_CTL_OPCODE_SHIFT);662pkt.sensor_index = __cpu_to_le16(sensor_index);663pkt.type = __cpu_to_le16(attr);664665rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),6660, &result);667668*value = (long) result;669670if (rc) {671if (rc != -EAGAIN)672dev_err_ratelimited(hdev->dev,673"Failed to get current from sensor %d, error %d\n",674sensor_index, rc);675*value = 0;676}677678return rc;679}680681int hl_get_fan_speed(struct hl_device *hdev,682int sensor_index, u32 attr, long *value)683{684struct cpucp_packet pkt;685u64 result;686int rc;687688memset(&pkt, 0, sizeof(pkt));689690pkt.ctl = cpu_to_le32(CPUCP_PACKET_FAN_SPEED_GET <<691CPUCP_PKT_CTL_OPCODE_SHIFT);692pkt.sensor_index = __cpu_to_le16(sensor_index);693pkt.type = __cpu_to_le16(attr);694695rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),6960, &result);697698*value = (long) result;699700if (rc) {701if (rc != -EAGAIN)702dev_err_ratelimited(hdev->dev,703"Failed to get fan speed from sensor %d, error %d\n",704sensor_index, rc);705*value = 0;706}707708return rc;709}710711int hl_get_pwm_info(struct hl_device *hdev,712int sensor_index, u32 attr, long *value)713{714struct cpucp_packet pkt;715u64 result;716int rc;717718memset(&pkt, 0, sizeof(pkt));719720pkt.ctl = cpu_to_le32(CPUCP_PACKET_PWM_GET <<721CPUCP_PKT_CTL_OPCODE_SHIFT);722pkt.sensor_index = __cpu_to_le16(sensor_index);723pkt.type = __cpu_to_le16(attr);724725rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),7260, &result);727728*value = (long) result;729730if (rc) {731if (rc != -EAGAIN)732dev_err_ratelimited(hdev->dev,733"Failed to get pwm info from sensor %d, error %d\n",734sensor_index, rc);735*value = 0;736}737738return rc;739}740741void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,742long value)743{744struct cpucp_packet pkt;745int rc;746747memset(&pkt, 0, sizeof(pkt));748749pkt.ctl = cpu_to_le32(CPUCP_PACKET_PWM_SET <<750CPUCP_PKT_CTL_OPCODE_SHIFT);751pkt.sensor_index = __cpu_to_le16(sensor_index);752pkt.type = __cpu_to_le16(attr);753pkt.value = cpu_to_le64(value);754755rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),7560, NULL);757if (rc && rc != -EAGAIN)758dev_err_ratelimited(hdev->dev,759"Failed to set pwm info to sensor %d, error %d\n",760sensor_index, rc);761}762763int hl_set_voltage(struct hl_device *hdev,764int sensor_index, u32 attr, long value)765{766struct cpucp_packet pkt;767int rc;768769memset(&pkt, 0, sizeof(pkt));770771pkt.ctl = cpu_to_le32(CPUCP_PACKET_VOLTAGE_SET <<772CPUCP_PKT_CTL_OPCODE_SHIFT);773pkt.sensor_index = __cpu_to_le16(sensor_index);774pkt.type = __cpu_to_le16(attr);775pkt.value = __cpu_to_le64(value);776777rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),7780, NULL);779if (rc && rc != -EAGAIN)780dev_err_ratelimited(hdev->dev,781"Failed to set voltage of sensor %d, error %d\n",782sensor_index, rc);783784return rc;785}786787int hl_set_current(struct hl_device *hdev,788int sensor_index, u32 attr, long value)789{790struct cpucp_packet pkt;791int rc;792793memset(&pkt, 0, sizeof(pkt));794795pkt.ctl = cpu_to_le32(CPUCP_PACKET_CURRENT_SET <<796CPUCP_PKT_CTL_OPCODE_SHIFT);797pkt.sensor_index = __cpu_to_le16(sensor_index);798pkt.type = __cpu_to_le16(attr);799pkt.value = __cpu_to_le64(value);800801rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);802if (rc && rc != -EAGAIN)803dev_err_ratelimited(hdev->dev,804"Failed to set current of sensor %d, error %d\n",805sensor_index, rc);806807return rc;808}809810int hl_set_power(struct hl_device *hdev,811int sensor_index, u32 attr, long value)812{813struct cpucp_packet pkt;814struct asic_fixed_properties *prop = &hdev->asic_prop;815int rc;816817memset(&pkt, 0, sizeof(pkt));818819if (prop->use_get_power_for_reset_history)820pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<821CPUCP_PKT_CTL_OPCODE_SHIFT);822else823pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_SET <<824CPUCP_PKT_CTL_OPCODE_SHIFT);825826pkt.sensor_index = __cpu_to_le16(sensor_index);827pkt.type = __cpu_to_le16(attr);828pkt.value = __cpu_to_le64(value);829830rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),8310, NULL);832if (rc && rc != -EAGAIN)833dev_err_ratelimited(hdev->dev,834"Failed to set power of sensor %d, error %d\n",835sensor_index, rc);836837return rc;838}839840int hl_get_power(struct hl_device *hdev,841int sensor_index, u32 attr, long *value)842{843struct cpucp_packet pkt;844u64 result;845int rc;846847memset(&pkt, 0, sizeof(pkt));848849pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<850CPUCP_PKT_CTL_OPCODE_SHIFT);851pkt.sensor_index = __cpu_to_le16(sensor_index);852pkt.type = __cpu_to_le16(attr);853854rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),8550, &result);856857*value = (long) result;858859if (rc) {860if (rc != -EAGAIN)861dev_err_ratelimited(hdev->dev,862"Failed to get power of sensor %d, error %d\n",863sensor_index, rc);864*value = 0;865}866867return rc;868}869870int hl_hwmon_init(struct hl_device *hdev)871{872struct device *dev = hdev->pdev ? &hdev->pdev->dev : hdev->dev;873struct asic_fixed_properties *prop = &hdev->asic_prop;874int rc;875876if ((hdev->hwmon_initialized) || !(hdev->cpu_queues_enable))877return 0;878879if (hdev->hl_chip_info->info) {880hdev->hl_chip_info->ops = &hl_hwmon_ops;881882hdev->hwmon_dev = hwmon_device_register_with_info(dev,883prop->cpucp_info.card_name, hdev,884hdev->hl_chip_info, NULL);885if (IS_ERR(hdev->hwmon_dev)) {886rc = PTR_ERR(hdev->hwmon_dev);887dev_err(hdev->dev,888"Unable to register hwmon device: %d\n", rc);889return rc;890}891892dev_info(hdev->dev, "%s: add sensors information\n",893dev_name(hdev->hwmon_dev));894895hdev->hwmon_initialized = true;896} else {897dev_info(hdev->dev, "no available sensors\n");898}899900return 0;901}902903void hl_hwmon_fini(struct hl_device *hdev)904{905if (!hdev->hwmon_initialized)906return;907908hwmon_device_unregister(hdev->hwmon_dev);909}910911void hl_hwmon_release_resources(struct hl_device *hdev)912{913const struct hwmon_channel_info * const *channel_info_arr;914int i = 0;915916if (!hdev->hl_chip_info->info)917return;918919channel_info_arr = hdev->hl_chip_info->info;920921while (channel_info_arr[i]) {922kfree(channel_info_arr[i]->config);923kfree(channel_info_arr[i]);924i++;925}926927kfree(channel_info_arr);928929hdev->hl_chip_info->info = NULL;930}931932933