242 lines · c
1/* Broadcom NetXtreme-C/E network driver.2 *3 * Copyright (c) 2023 Broadcom Limited4 *5 * This program is free software; you can redistribute it and/or modify6 * it under the terms of the GNU General Public License as published by7 * 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 21void 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 46static 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 }70drop_req:71 hwrm_req_drop(bp, req);72 return rc;73}74 75static 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 100static 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 142static 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 NULL147};148 149static const struct hwmon_ops bnxt_hwmon_ops = {150 .is_visible = bnxt_hwmon_is_visible,151 .read = bnxt_hwmon_read,152};153 154static const struct hwmon_chip_info bnxt_hwmon_chip_info = {155 .ops = &bnxt_hwmon_ops,156 .info = bnxt_hwmon_info,157};158 159static 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 167static 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 181static DEVICE_ATTR_RO(temp1_shutdown);182static DEVICE_ATTR_RO(temp1_shutdown_alarm);183 184static struct attribute *bnxt_temp_extra_attrs[] = {185 &dev_attr_temp1_shutdown.attr,186 &dev_attr_temp1_shutdown_alarm.attr,187 NULL,188};189 190static 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 204static 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 210void 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 218void 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