xref: /linux/drivers/net/ethernet/broadcom/bnxt/bnxt_hwmon.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1a47f3b39SKalesh AP /* Broadcom NetXtreme-C/E network driver.
2a47f3b39SKalesh AP  *
3a47f3b39SKalesh AP  * Copyright (c) 2023 Broadcom Limited
4a47f3b39SKalesh AP  *
5a47f3b39SKalesh AP  * This program is free software; you can redistribute it and/or modify
6a47f3b39SKalesh AP  * it under the terms of the GNU General Public License as published by
7a47f3b39SKalesh AP  * the Free Software Foundation.
8a47f3b39SKalesh AP  */
9a47f3b39SKalesh AP 
10a47f3b39SKalesh AP #include <linux/dev_printk.h>
11a47f3b39SKalesh AP #include <linux/errno.h>
12a47f3b39SKalesh AP #include <linux/hwmon.h>
13a47f3b39SKalesh AP #include <linux/hwmon-sysfs.h>
14a47f3b39SKalesh AP #include <linux/pci.h>
15a47f3b39SKalesh AP 
16a47f3b39SKalesh AP #include "bnxt_hsi.h"
17a47f3b39SKalesh AP #include "bnxt.h"
18a47f3b39SKalesh AP #include "bnxt_hwrm.h"
19a47f3b39SKalesh AP #include "bnxt_hwmon.h"
20a47f3b39SKalesh AP 
bnxt_hwmon_notify_event(struct bnxt * bp)21*55862094SKalesh AP void bnxt_hwmon_notify_event(struct bnxt *bp)
22a19b4801SKalesh AP {
23a19b4801SKalesh AP 	u32 attr;
24a19b4801SKalesh AP 
25a19b4801SKalesh AP 	if (!bp->hwmon_dev)
26a19b4801SKalesh AP 		return;
27a19b4801SKalesh AP 
28*55862094SKalesh AP 	switch (bp->thermal_threshold_type) {
29a19b4801SKalesh AP 	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_WARN:
30a19b4801SKalesh AP 		attr = hwmon_temp_max_alarm;
31a19b4801SKalesh AP 		break;
32a19b4801SKalesh AP 	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_CRITICAL:
33a19b4801SKalesh AP 		attr = hwmon_temp_crit_alarm;
34a19b4801SKalesh AP 		break;
35a19b4801SKalesh AP 	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_FATAL:
36a19b4801SKalesh AP 	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_SHUTDOWN:
37a19b4801SKalesh AP 		attr = hwmon_temp_emergency_alarm;
38a19b4801SKalesh AP 		break;
39a19b4801SKalesh AP 	default:
40a19b4801SKalesh AP 		return;
41a19b4801SKalesh AP 	}
42a19b4801SKalesh AP 
43a19b4801SKalesh AP 	hwmon_notify_event(&bp->pdev->dev, hwmon_temp, attr, 0);
44a19b4801SKalesh AP }
45a19b4801SKalesh AP 
bnxt_hwrm_temp_query(struct bnxt * bp,u8 * temp)46847da8b1SKalesh AP static int bnxt_hwrm_temp_query(struct bnxt *bp, u8 *temp)
47a47f3b39SKalesh AP {
48a47f3b39SKalesh AP 	struct hwrm_temp_monitor_query_output *resp;
49a47f3b39SKalesh AP 	struct hwrm_temp_monitor_query_input *req;
50a47f3b39SKalesh AP 	int rc;
51a47f3b39SKalesh AP 
52a47f3b39SKalesh AP 	rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY);
53a47f3b39SKalesh AP 	if (rc)
54a47f3b39SKalesh AP 		return rc;
55a47f3b39SKalesh AP 	resp = hwrm_req_hold(bp, req);
56847da8b1SKalesh AP 	rc = hwrm_req_send_silent(bp, req);
57a47f3b39SKalesh AP 	if (rc)
58847da8b1SKalesh AP 		goto drop_req;
59a47f3b39SKalesh AP 
60cd13244fSKalesh AP 	if (temp) {
61847da8b1SKalesh AP 		*temp = resp->temp;
62cd13244fSKalesh AP 	} else if (resp->flags &
63cd13244fSKalesh AP 		   TEMP_MONITOR_QUERY_RESP_FLAGS_THRESHOLD_VALUES_AVAILABLE) {
64cd13244fSKalesh AP 		bp->fw_cap |= BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED;
65cd13244fSKalesh AP 		bp->warn_thresh_temp = resp->warn_threshold;
66cd13244fSKalesh AP 		bp->crit_thresh_temp = resp->critical_threshold;
67cd13244fSKalesh AP 		bp->fatal_thresh_temp = resp->fatal_threshold;
68cd13244fSKalesh AP 		bp->shutdown_thresh_temp = resp->shutdown_threshold;
69cd13244fSKalesh AP 	}
70847da8b1SKalesh AP drop_req:
71847da8b1SKalesh AP 	hwrm_req_drop(bp, req);
72847da8b1SKalesh AP 	return rc;
73847da8b1SKalesh AP }
74847da8b1SKalesh AP 
bnxt_hwmon_is_visible(const void * _data,enum hwmon_sensor_types type,u32 attr,int channel)75847da8b1SKalesh AP static umode_t bnxt_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type,
76847da8b1SKalesh AP 				     u32 attr, int channel)
77847da8b1SKalesh AP {
78cd13244fSKalesh AP 	const struct bnxt *bp = _data;
79cd13244fSKalesh AP 
80847da8b1SKalesh AP 	if (type != hwmon_temp)
81847da8b1SKalesh AP 		return 0;
82847da8b1SKalesh AP 
83847da8b1SKalesh AP 	switch (attr) {
84847da8b1SKalesh AP 	case hwmon_temp_input:
85847da8b1SKalesh AP 		return 0444;
86cd13244fSKalesh AP 	case hwmon_temp_max:
87cd13244fSKalesh AP 	case hwmon_temp_crit:
88cd13244fSKalesh AP 	case hwmon_temp_emergency:
89cd13244fSKalesh AP 	case hwmon_temp_max_alarm:
90cd13244fSKalesh AP 	case hwmon_temp_crit_alarm:
91cd13244fSKalesh AP 	case hwmon_temp_emergency_alarm:
92cd13244fSKalesh AP 		if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED))
93cd13244fSKalesh AP 			return 0;
94cd13244fSKalesh AP 		return 0444;
95847da8b1SKalesh AP 	default:
96847da8b1SKalesh AP 		return 0;
97847da8b1SKalesh AP 	}
98847da8b1SKalesh AP }
99847da8b1SKalesh AP 
bnxt_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)100847da8b1SKalesh AP static int bnxt_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
101847da8b1SKalesh AP 			   int channel, long *val)
102847da8b1SKalesh AP {
103847da8b1SKalesh AP 	struct bnxt *bp = dev_get_drvdata(dev);
104847da8b1SKalesh AP 	u8 temp = 0;
105847da8b1SKalesh AP 	int rc;
106847da8b1SKalesh AP 
107847da8b1SKalesh AP 	switch (attr) {
108847da8b1SKalesh AP 	case hwmon_temp_input:
109847da8b1SKalesh AP 		rc = bnxt_hwrm_temp_query(bp, &temp);
110847da8b1SKalesh AP 		if (!rc)
111847da8b1SKalesh AP 			*val = temp * 1000;
112847da8b1SKalesh AP 		return rc;
113cd13244fSKalesh AP 	case hwmon_temp_max:
114cd13244fSKalesh AP 		*val = bp->warn_thresh_temp * 1000;
115cd13244fSKalesh AP 		return 0;
116cd13244fSKalesh AP 	case hwmon_temp_crit:
117cd13244fSKalesh AP 		*val = bp->crit_thresh_temp * 1000;
118cd13244fSKalesh AP 		return 0;
119cd13244fSKalesh AP 	case hwmon_temp_emergency:
120cd13244fSKalesh AP 		*val = bp->fatal_thresh_temp * 1000;
121cd13244fSKalesh AP 		return 0;
122cd13244fSKalesh AP 	case hwmon_temp_max_alarm:
123cd13244fSKalesh AP 		rc = bnxt_hwrm_temp_query(bp, &temp);
124cd13244fSKalesh AP 		if (!rc)
125cd13244fSKalesh AP 			*val = temp >= bp->warn_thresh_temp;
126cd13244fSKalesh AP 		return rc;
127cd13244fSKalesh AP 	case hwmon_temp_crit_alarm:
128cd13244fSKalesh AP 		rc = bnxt_hwrm_temp_query(bp, &temp);
129cd13244fSKalesh AP 		if (!rc)
130cd13244fSKalesh AP 			*val = temp >= bp->crit_thresh_temp;
131cd13244fSKalesh AP 		return rc;
132cd13244fSKalesh AP 	case hwmon_temp_emergency_alarm:
133cd13244fSKalesh AP 		rc = bnxt_hwrm_temp_query(bp, &temp);
134cd13244fSKalesh AP 		if (!rc)
135cd13244fSKalesh AP 			*val = temp >= bp->fatal_thresh_temp;
136cd13244fSKalesh AP 		return rc;
137847da8b1SKalesh AP 	default:
138847da8b1SKalesh AP 		return -EOPNOTSUPP;
139847da8b1SKalesh AP 	}
140847da8b1SKalesh AP }
141847da8b1SKalesh AP 
142847da8b1SKalesh AP static const struct hwmon_channel_info *bnxt_hwmon_info[] = {
143cd13244fSKalesh AP 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
144cd13244fSKalesh AP 			   HWMON_T_EMERGENCY | HWMON_T_MAX_ALARM |
145cd13244fSKalesh AP 			   HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM),
146a47f3b39SKalesh AP 	NULL
147a47f3b39SKalesh AP };
148847da8b1SKalesh AP 
149847da8b1SKalesh AP static const struct hwmon_ops bnxt_hwmon_ops = {
150847da8b1SKalesh AP 	.is_visible     = bnxt_hwmon_is_visible,
151847da8b1SKalesh AP 	.read           = bnxt_hwmon_read,
152847da8b1SKalesh AP };
153847da8b1SKalesh AP 
154847da8b1SKalesh AP static const struct hwmon_chip_info bnxt_hwmon_chip_info = {
155847da8b1SKalesh AP 	.ops    = &bnxt_hwmon_ops,
156847da8b1SKalesh AP 	.info   = bnxt_hwmon_info,
157847da8b1SKalesh AP };
158a47f3b39SKalesh AP 
temp1_shutdown_show(struct device * dev,struct device_attribute * attr,char * buf)1593d9cf962SKalesh AP static ssize_t temp1_shutdown_show(struct device *dev,
1603d9cf962SKalesh AP 				   struct device_attribute *attr, char *buf)
1613d9cf962SKalesh AP {
1623d9cf962SKalesh AP 	struct bnxt *bp = dev_get_drvdata(dev);
1633d9cf962SKalesh AP 
1643d9cf962SKalesh AP 	return sysfs_emit(buf, "%u\n", bp->shutdown_thresh_temp * 1000);
1653d9cf962SKalesh AP }
1663d9cf962SKalesh AP 
temp1_shutdown_alarm_show(struct device * dev,struct device_attribute * attr,char * buf)1673d9cf962SKalesh AP static ssize_t temp1_shutdown_alarm_show(struct device *dev,
1683d9cf962SKalesh AP 					 struct device_attribute *attr, char *buf)
1693d9cf962SKalesh AP {
1703d9cf962SKalesh AP 	struct bnxt *bp = dev_get_drvdata(dev);
1713d9cf962SKalesh AP 	u8 temp;
1723d9cf962SKalesh AP 	int rc;
1733d9cf962SKalesh AP 
1743d9cf962SKalesh AP 	rc = bnxt_hwrm_temp_query(bp, &temp);
1753d9cf962SKalesh AP 	if (rc)
1763d9cf962SKalesh AP 		return -EIO;
1773d9cf962SKalesh AP 
1783d9cf962SKalesh AP 	return sysfs_emit(buf, "%u\n", temp >= bp->shutdown_thresh_temp);
1793d9cf962SKalesh AP }
1803d9cf962SKalesh AP 
1813d9cf962SKalesh AP static DEVICE_ATTR_RO(temp1_shutdown);
1823d9cf962SKalesh AP static DEVICE_ATTR_RO(temp1_shutdown_alarm);
1833d9cf962SKalesh AP 
1843d9cf962SKalesh AP static struct attribute *bnxt_temp_extra_attrs[] = {
1853d9cf962SKalesh AP 	&dev_attr_temp1_shutdown.attr,
1863d9cf962SKalesh AP 	&dev_attr_temp1_shutdown_alarm.attr,
1873d9cf962SKalesh AP 	NULL,
1883d9cf962SKalesh AP };
1893d9cf962SKalesh AP 
bnxt_temp_extra_attrs_visible(struct kobject * kobj,struct attribute * attr,int index)1903d9cf962SKalesh AP static umode_t bnxt_temp_extra_attrs_visible(struct kobject *kobj,
1913d9cf962SKalesh AP 					     struct attribute *attr, int index)
1923d9cf962SKalesh AP {
1933d9cf962SKalesh AP 	struct device *dev = kobj_to_dev(kobj);
1943d9cf962SKalesh AP 	struct bnxt *bp = dev_get_drvdata(dev);
1953d9cf962SKalesh AP 
1963d9cf962SKalesh AP 	/* Shutdown temperature setting in NVM is optional */
1973d9cf962SKalesh AP 	if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED) ||
1983d9cf962SKalesh AP 	    !bp->shutdown_thresh_temp)
1993d9cf962SKalesh AP 		return 0;
2003d9cf962SKalesh AP 
2013d9cf962SKalesh AP 	return attr->mode;
2023d9cf962SKalesh AP }
2033d9cf962SKalesh AP 
2043d9cf962SKalesh AP static const struct attribute_group bnxt_temp_extra_group = {
2053d9cf962SKalesh AP 	.attrs		= bnxt_temp_extra_attrs,
2063d9cf962SKalesh AP 	.is_visible	= bnxt_temp_extra_attrs_visible,
2073d9cf962SKalesh AP };
2083d9cf962SKalesh AP __ATTRIBUTE_GROUPS(bnxt_temp_extra);
2093d9cf962SKalesh AP 
bnxt_hwmon_uninit(struct bnxt * bp)210a47f3b39SKalesh AP void bnxt_hwmon_uninit(struct bnxt *bp)
211a47f3b39SKalesh AP {
212a47f3b39SKalesh AP 	if (bp->hwmon_dev) {
213a47f3b39SKalesh AP 		hwmon_device_unregister(bp->hwmon_dev);
214a47f3b39SKalesh AP 		bp->hwmon_dev = NULL;
215a47f3b39SKalesh AP 	}
216a47f3b39SKalesh AP }
217a47f3b39SKalesh AP 
bnxt_hwmon_init(struct bnxt * bp)218a47f3b39SKalesh AP void bnxt_hwmon_init(struct bnxt *bp)
219a47f3b39SKalesh AP {
220a47f3b39SKalesh AP 	struct pci_dev *pdev = bp->pdev;
221a47f3b39SKalesh AP 	int rc;
222a47f3b39SKalesh AP 
223cd13244fSKalesh AP 	/* temp1_xxx is only sensor, ensure not registered if it will fail */
224cd13244fSKalesh AP 	rc = bnxt_hwrm_temp_query(bp, NULL);
225a47f3b39SKalesh AP 	if (rc == -EACCES || rc == -EOPNOTSUPP) {
226a47f3b39SKalesh AP 		bnxt_hwmon_uninit(bp);
227a47f3b39SKalesh AP 		return;
228a47f3b39SKalesh AP 	}
229a47f3b39SKalesh AP 
230a47f3b39SKalesh AP 	if (bp->hwmon_dev)
231a47f3b39SKalesh AP 		return;
232a47f3b39SKalesh AP 
233847da8b1SKalesh AP 	bp->hwmon_dev = hwmon_device_register_with_info(&pdev->dev,
234a47f3b39SKalesh AP 							DRV_MODULE_NAME, bp,
2353d9cf962SKalesh AP 							&bnxt_hwmon_chip_info,
2363d9cf962SKalesh AP 							bnxt_temp_extra_groups);
237a47f3b39SKalesh AP 	if (IS_ERR(bp->hwmon_dev)) {
238a47f3b39SKalesh AP 		bp->hwmon_dev = NULL;
239a47f3b39SKalesh AP 		dev_warn(&pdev->dev, "Cannot register hwmon device\n");
240a47f3b39SKalesh AP 	}
241a47f3b39SKalesh AP }
242