1 /* Broadcom NetXtreme-C/E network driver. 2 * 3 * Copyright (c) 2023 Broadcom Limited 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation. 8 */ 9 10 #include <linux/dev_printk.h> 11 #include <linux/errno.h> 12 #include <linux/hwmon.h> 13 #include <linux/hwmon-sysfs.h> 14 #include <linux/pci.h> 15 16 #include "bnxt_hsi.h" 17 #include "bnxt.h" 18 #include "bnxt_hwrm.h" 19 #include "bnxt_hwmon.h" 20 21 void bnxt_hwmon_notify_event(struct bnxt *bp) 22 { 23 u32 attr; 24 25 if (!bp->hwmon_dev) 26 return; 27 28 switch (bp->thermal_threshold_type) { 29 case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_WARN: 30 attr = hwmon_temp_max_alarm; 31 break; 32 case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_CRITICAL: 33 attr = hwmon_temp_crit_alarm; 34 break; 35 case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_FATAL: 36 case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_SHUTDOWN: 37 attr = hwmon_temp_emergency_alarm; 38 break; 39 default: 40 return; 41 } 42 43 hwmon_notify_event(&bp->pdev->dev, hwmon_temp, attr, 0); 44 } 45 46 static int bnxt_hwrm_temp_query(struct bnxt *bp, u8 *temp) 47 { 48 struct hwrm_temp_monitor_query_output *resp; 49 struct hwrm_temp_monitor_query_input *req; 50 int rc; 51 52 rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY); 53 if (rc) 54 return rc; 55 resp = hwrm_req_hold(bp, req); 56 rc = hwrm_req_send_silent(bp, req); 57 if (rc) 58 goto drop_req; 59 60 if (temp) { 61 *temp = resp->temp; 62 } else if (resp->flags & 63 TEMP_MONITOR_QUERY_RESP_FLAGS_THRESHOLD_VALUES_AVAILABLE) { 64 bp->fw_cap |= BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED; 65 bp->warn_thresh_temp = resp->warn_threshold; 66 bp->crit_thresh_temp = resp->critical_threshold; 67 bp->fatal_thresh_temp = resp->fatal_threshold; 68 bp->shutdown_thresh_temp = resp->shutdown_threshold; 69 } 70 drop_req: 71 hwrm_req_drop(bp, req); 72 return rc; 73 } 74 75 static umode_t bnxt_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, 76 u32 attr, int channel) 77 { 78 const struct bnxt *bp = _data; 79 80 if (type != hwmon_temp) 81 return 0; 82 83 switch (attr) { 84 case hwmon_temp_input: 85 return 0444; 86 case hwmon_temp_max: 87 case hwmon_temp_crit: 88 case hwmon_temp_emergency: 89 case hwmon_temp_max_alarm: 90 case hwmon_temp_crit_alarm: 91 case hwmon_temp_emergency_alarm: 92 if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED)) 93 return 0; 94 return 0444; 95 default: 96 return 0; 97 } 98 } 99 100 static int bnxt_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 101 int channel, long *val) 102 { 103 struct bnxt *bp = dev_get_drvdata(dev); 104 u8 temp = 0; 105 int rc; 106 107 switch (attr) { 108 case hwmon_temp_input: 109 rc = bnxt_hwrm_temp_query(bp, &temp); 110 if (!rc) 111 *val = temp * 1000; 112 return rc; 113 case hwmon_temp_max: 114 *val = bp->warn_thresh_temp * 1000; 115 return 0; 116 case hwmon_temp_crit: 117 *val = bp->crit_thresh_temp * 1000; 118 return 0; 119 case hwmon_temp_emergency: 120 *val = bp->fatal_thresh_temp * 1000; 121 return 0; 122 case hwmon_temp_max_alarm: 123 rc = bnxt_hwrm_temp_query(bp, &temp); 124 if (!rc) 125 *val = temp >= bp->warn_thresh_temp; 126 return rc; 127 case hwmon_temp_crit_alarm: 128 rc = bnxt_hwrm_temp_query(bp, &temp); 129 if (!rc) 130 *val = temp >= bp->crit_thresh_temp; 131 return rc; 132 case hwmon_temp_emergency_alarm: 133 rc = bnxt_hwrm_temp_query(bp, &temp); 134 if (!rc) 135 *val = temp >= bp->fatal_thresh_temp; 136 return rc; 137 default: 138 return -EOPNOTSUPP; 139 } 140 } 141 142 static const struct hwmon_channel_info *bnxt_hwmon_info[] = { 143 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | 144 HWMON_T_EMERGENCY | HWMON_T_MAX_ALARM | 145 HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM), 146 NULL 147 }; 148 149 static const struct hwmon_ops bnxt_hwmon_ops = { 150 .is_visible = bnxt_hwmon_is_visible, 151 .read = bnxt_hwmon_read, 152 }; 153 154 static const struct hwmon_chip_info bnxt_hwmon_chip_info = { 155 .ops = &bnxt_hwmon_ops, 156 .info = bnxt_hwmon_info, 157 }; 158 159 static ssize_t temp1_shutdown_show(struct device *dev, 160 struct device_attribute *attr, char *buf) 161 { 162 struct bnxt *bp = dev_get_drvdata(dev); 163 164 return sysfs_emit(buf, "%u\n", bp->shutdown_thresh_temp * 1000); 165 } 166 167 static ssize_t temp1_shutdown_alarm_show(struct device *dev, 168 struct device_attribute *attr, char *buf) 169 { 170 struct bnxt *bp = dev_get_drvdata(dev); 171 u8 temp; 172 int rc; 173 174 rc = bnxt_hwrm_temp_query(bp, &temp); 175 if (rc) 176 return -EIO; 177 178 return sysfs_emit(buf, "%u\n", temp >= bp->shutdown_thresh_temp); 179 } 180 181 static DEVICE_ATTR_RO(temp1_shutdown); 182 static DEVICE_ATTR_RO(temp1_shutdown_alarm); 183 184 static struct attribute *bnxt_temp_extra_attrs[] = { 185 &dev_attr_temp1_shutdown.attr, 186 &dev_attr_temp1_shutdown_alarm.attr, 187 NULL, 188 }; 189 190 static umode_t bnxt_temp_extra_attrs_visible(struct kobject *kobj, 191 struct attribute *attr, int index) 192 { 193 struct device *dev = kobj_to_dev(kobj); 194 struct bnxt *bp = dev_get_drvdata(dev); 195 196 /* Shutdown temperature setting in NVM is optional */ 197 if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED) || 198 !bp->shutdown_thresh_temp) 199 return 0; 200 201 return attr->mode; 202 } 203 204 static const struct attribute_group bnxt_temp_extra_group = { 205 .attrs = bnxt_temp_extra_attrs, 206 .is_visible = bnxt_temp_extra_attrs_visible, 207 }; 208 __ATTRIBUTE_GROUPS(bnxt_temp_extra); 209 210 void bnxt_hwmon_uninit(struct bnxt *bp) 211 { 212 if (bp->hwmon_dev) { 213 hwmon_device_unregister(bp->hwmon_dev); 214 bp->hwmon_dev = NULL; 215 } 216 } 217 218 void bnxt_hwmon_init(struct bnxt *bp) 219 { 220 struct pci_dev *pdev = bp->pdev; 221 int rc; 222 223 /* temp1_xxx is only sensor, ensure not registered if it will fail */ 224 rc = bnxt_hwrm_temp_query(bp, NULL); 225 if (rc == -EACCES || rc == -EOPNOTSUPP) { 226 bnxt_hwmon_uninit(bp); 227 return; 228 } 229 230 if (bp->hwmon_dev) 231 return; 232 233 bp->hwmon_dev = hwmon_device_register_with_info(&pdev->dev, 234 DRV_MODULE_NAME, bp, 235 &bnxt_hwmon_chip_info, 236 bnxt_temp_extra_groups); 237 if (IS_ERR(bp->hwmon_dev)) { 238 bp->hwmon_dev = NULL; 239 dev_warn(&pdev->dev, "Cannot register hwmon device\n"); 240 } 241 } 242