// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2023, Intel Corporation. */ #include "ice.h" #include "ice_hwmon.h" #include "ice_adminq_cmd.h" #include #define TEMP_FROM_REG(reg) ((reg) * 1000) static const struct hwmon_channel_info *ice_hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_EMERGENCY), NULL }; static int ice_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { struct ice_aqc_get_sensor_reading_resp resp; struct ice_pf *pf = dev_get_drvdata(dev); int ret; if (type != hwmon_temp) return -EOPNOTSUPP; ret = ice_aq_get_sensor_reading(&pf->hw, &resp); if (ret) { dev_warn_ratelimited(dev, "%s HW read failure (%d)\n", __func__, ret); return ret; } switch (attr) { case hwmon_temp_input: *val = TEMP_FROM_REG(resp.data.s0f0.temp); break; case hwmon_temp_max: *val = TEMP_FROM_REG(resp.data.s0f0.temp_warning_threshold); break; case hwmon_temp_crit: *val = TEMP_FROM_REG(resp.data.s0f0.temp_critical_threshold); break; case hwmon_temp_emergency: *val = TEMP_FROM_REG(resp.data.s0f0.temp_fatal_threshold); break; default: dev_dbg(dev, "%s unsupported attribute (%d)\n", __func__, attr); return -EOPNOTSUPP; } return 0; } static umode_t ice_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) { if (type != hwmon_temp) return 0; switch (attr) { case hwmon_temp_input: case hwmon_temp_crit: case hwmon_temp_max: case hwmon_temp_emergency: return 0444; } return 0; } static const struct hwmon_ops ice_hwmon_ops = { .is_visible = ice_hwmon_is_visible, .read = ice_hwmon_read }; static const struct hwmon_chip_info ice_chip_info = { .ops = &ice_hwmon_ops, .info = ice_hwmon_info }; static bool ice_is_internal_reading_supported(struct ice_pf *pf) { /* Only the first PF will report temperature for a chip. * Note that internal temp reading is not supported * for older FW (< v4.30). */ if (pf->hw.pf_id) return false; unsigned long sensors = pf->hw.dev_caps.supported_sensors; return _test_bit(ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT, &sensors); }; void ice_hwmon_init(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct device *hdev; if (!ice_is_internal_reading_supported(pf)) return; hdev = hwmon_device_register_with_info(dev, "ice", pf, &ice_chip_info, NULL); if (IS_ERR(hdev)) { dev_warn(dev, "hwmon_device_register_with_info returns error (%ld)", PTR_ERR(hdev)); return; } pf->hwmon_dev = hdev; } void ice_hwmon_exit(struct ice_pf *pf) { if (!pf->hwmon_dev) return; hwmon_device_unregister(pf->hwmon_dev); }