189 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * SolidRun DPU driver for control plane4 *5 * Copyright (C) 2022-2023 SolidRun6 *7 * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>8 *9 */10#include <linux/hwmon.h>11 12#include "snet_vdpa.h"13 14/* Monitor offsets */15#define SNET_MON_TMP0_IN_OFF 0x0016#define SNET_MON_TMP0_MAX_OFF 0x0817#define SNET_MON_TMP0_CRIT_OFF 0x1018#define SNET_MON_TMP1_IN_OFF 0x1819#define SNET_MON_TMP1_CRIT_OFF 0x2020#define SNET_MON_CURR_IN_OFF 0x2821#define SNET_MON_CURR_MAX_OFF 0x3022#define SNET_MON_CURR_CRIT_OFF 0x3823#define SNET_MON_PWR_IN_OFF 0x4024#define SNET_MON_VOLT_IN_OFF 0x4825#define SNET_MON_VOLT_CRIT_OFF 0x5026#define SNET_MON_VOLT_LCRIT_OFF 0x5827 28static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)29{30 *out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);31}32 33static umode_t snet_howmon_is_visible(const void *data,34 enum hwmon_sensor_types type,35 u32 attr, int channel)36{37 return 0444;38}39 40static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,41 u32 attr, int channel, long *val)42{43 struct psnet *psnet = dev_get_drvdata(dev);44 int ret = 0;45 46 switch (type) {47 case hwmon_in:48 switch (attr) {49 case hwmon_in_lcrit:50 snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);51 break;52 case hwmon_in_crit:53 snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);54 break;55 case hwmon_in_input:56 snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);57 break;58 default:59 ret = -EOPNOTSUPP;60 break;61 }62 break;63 64 case hwmon_power:65 switch (attr) {66 case hwmon_power_input:67 snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);68 break;69 70 default:71 ret = -EOPNOTSUPP;72 break;73 }74 break;75 76 case hwmon_curr:77 switch (attr) {78 case hwmon_curr_input:79 snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);80 break;81 case hwmon_curr_max:82 snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);83 break;84 case hwmon_curr_crit:85 snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);86 break;87 default:88 ret = -EOPNOTSUPP;89 break;90 }91 break;92 93 case hwmon_temp:94 switch (attr) {95 case hwmon_temp_input:96 if (channel == 0)97 snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);98 else99 snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);100 break;101 case hwmon_temp_max:102 if (channel == 0)103 snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);104 else105 ret = -EOPNOTSUPP;106 break;107 case hwmon_temp_crit:108 if (channel == 0)109 snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);110 else111 snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);112 break;113 114 default:115 ret = -EOPNOTSUPP;116 break;117 }118 break;119 120 default:121 ret = -EOPNOTSUPP;122 break;123 }124 return ret;125}126 127static int snet_hwmon_read_string(struct device *dev,128 enum hwmon_sensor_types type, u32 attr,129 int channel, const char **str)130{131 int ret = 0;132 133 switch (type) {134 case hwmon_in:135 *str = "main_vin";136 break;137 case hwmon_power:138 *str = "soc_pin";139 break;140 case hwmon_curr:141 *str = "soc_iin";142 break;143 case hwmon_temp:144 if (channel == 0)145 *str = "power_stage_temp";146 else147 *str = "ic_junction_temp";148 break;149 default:150 ret = -EOPNOTSUPP;151 break;152 }153 return ret;154}155 156static const struct hwmon_ops snet_hwmon_ops = {157 .is_visible = snet_howmon_is_visible,158 .read = snet_howmon_read,159 .read_string = snet_hwmon_read_string160};161 162static const struct hwmon_channel_info * const snet_hwmon_info[] = {163 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,164 HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),165 HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),166 HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),167 HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),168 NULL169};170 171static const struct hwmon_chip_info snet_hwmono_info = {172 .ops = &snet_hwmon_ops,173 .info = snet_hwmon_info,174};175 176/* Create an HW monitor device */177void psnet_create_hwmon(struct pci_dev *pdev)178{179 struct device *hwmon;180 struct psnet *psnet = pci_get_drvdata(pdev);181 182 snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));183 hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,184 &snet_hwmono_info, NULL);185 /* The monitor is not mandatory, Just alert user in case of an error */186 if (IS_ERR(hwmon))187 SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));188}189