1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SolidRun DPU driver for control plane 4 * 5 * Copyright (C) 2022 SolidRun 6 * 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 0x00 16 #define SNET_MON_TMP0_MAX_OFF 0x08 17 #define SNET_MON_TMP0_CRIT_OFF 0x10 18 #define SNET_MON_TMP1_IN_OFF 0x18 19 #define SNET_MON_TMP1_CRIT_OFF 0x20 20 #define SNET_MON_CURR_IN_OFF 0x28 21 #define SNET_MON_CURR_MAX_OFF 0x30 22 #define SNET_MON_CURR_CRIT_OFF 0x38 23 #define SNET_MON_PWR_IN_OFF 0x40 24 #define SNET_MON_VOLT_IN_OFF 0x48 25 #define SNET_MON_VOLT_CRIT_OFF 0x50 26 #define SNET_MON_VOLT_LCRIT_OFF 0x58 27 28 static 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 33 static 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 40 static 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 else 99 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 else 105 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 else 111 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 127 static 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 else 147 *str = "ic_junction_temp"; 148 break; 149 default: 150 ret = -EOPNOTSUPP; 151 break; 152 } 153 return ret; 154 } 155 156 static 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_string 160 }; 161 162 static const struct hwmon_channel_info *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 NULL 169 }; 170 171 static 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 */ 177 void 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