Merge tag 'net-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[drm/drm-misc.git] / drivers / net / ethernet / broadcom / bnxt / bnxt_hwmon.c
blob669d24ba0e87f697960872dcbf829b4b6e1e78b8
1 /* Broadcom NetXtreme-C/E network driver.
3 * Copyright (c) 2023 Broadcom Limited
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 */
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>
16 #include "bnxt_hsi.h"
17 #include "bnxt.h"
18 #include "bnxt_hwrm.h"
19 #include "bnxt_hwmon.h"
21 void bnxt_hwmon_notify_event(struct bnxt *bp)
23 u32 attr;
25 if (!bp->hwmon_dev)
26 return;
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;
43 hwmon_notify_event(&bp->pdev->dev, hwmon_temp, attr, 0);
46 static int bnxt_hwrm_temp_query(struct bnxt *bp, u8 *temp)
48 struct hwrm_temp_monitor_query_output *resp;
49 struct hwrm_temp_monitor_query_input *req;
50 int rc;
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;
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;
70 drop_req:
71 hwrm_req_drop(bp, req);
72 return rc;
75 static umode_t bnxt_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type,
76 u32 attr, int channel)
78 const struct bnxt *bp = _data;
80 if (type != hwmon_temp)
81 return 0;
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;
100 static int bnxt_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
101 int channel, long *val)
103 struct bnxt *bp = dev_get_drvdata(dev);
104 u8 temp = 0;
105 int rc;
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;
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
149 static const struct hwmon_ops bnxt_hwmon_ops = {
150 .is_visible = bnxt_hwmon_is_visible,
151 .read = bnxt_hwmon_read,
154 static const struct hwmon_chip_info bnxt_hwmon_chip_info = {
155 .ops = &bnxt_hwmon_ops,
156 .info = bnxt_hwmon_info,
159 static ssize_t temp1_shutdown_show(struct device *dev,
160 struct device_attribute *attr, char *buf)
162 struct bnxt *bp = dev_get_drvdata(dev);
164 return sysfs_emit(buf, "%u\n", bp->shutdown_thresh_temp * 1000);
167 static ssize_t temp1_shutdown_alarm_show(struct device *dev,
168 struct device_attribute *attr, char *buf)
170 struct bnxt *bp = dev_get_drvdata(dev);
171 u8 temp;
172 int rc;
174 rc = bnxt_hwrm_temp_query(bp, &temp);
175 if (rc)
176 return -EIO;
178 return sysfs_emit(buf, "%u\n", temp >= bp->shutdown_thresh_temp);
181 static DEVICE_ATTR_RO(temp1_shutdown);
182 static DEVICE_ATTR_RO(temp1_shutdown_alarm);
184 static struct attribute *bnxt_temp_extra_attrs[] = {
185 &dev_attr_temp1_shutdown.attr,
186 &dev_attr_temp1_shutdown_alarm.attr,
187 NULL,
190 static umode_t bnxt_temp_extra_attrs_visible(struct kobject *kobj,
191 struct attribute *attr, int index)
193 struct device *dev = kobj_to_dev(kobj);
194 struct bnxt *bp = dev_get_drvdata(dev);
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;
201 return attr->mode;
204 static const struct attribute_group bnxt_temp_extra_group = {
205 .attrs = bnxt_temp_extra_attrs,
206 .is_visible = bnxt_temp_extra_attrs_visible,
208 __ATTRIBUTE_GROUPS(bnxt_temp_extra);
210 void bnxt_hwmon_uninit(struct bnxt *bp)
212 if (bp->hwmon_dev) {
213 hwmon_device_unregister(bp->hwmon_dev);
214 bp->hwmon_dev = NULL;
218 void bnxt_hwmon_init(struct bnxt *bp)
220 struct pci_dev *pdev = bp->pdev;
221 int rc;
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;
230 if (bp->hwmon_dev)
231 return;
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");