Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v6.2.
  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
 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	NULL
147};
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}