xref: /linux/drivers/net/ethernet/intel/igb/igb_hwmon.c (revision 4b9ea4626b52c113c367c4776c9bb11b7231393d)
1e428893bSCarolyn Wyborny /*******************************************************************************
2e428893bSCarolyn Wyborny 
3e428893bSCarolyn Wyborny   Intel(R) Gigabit Ethernet Linux driver
4*4b9ea462SAkeem G. Abodunrin   Copyright(c) 2007-2013 Intel Corporation.
5e428893bSCarolyn Wyborny 
6e428893bSCarolyn Wyborny   This program is free software; you can redistribute it and/or modify it
7e428893bSCarolyn Wyborny   under the terms and conditions of the GNU General Public License,
8e428893bSCarolyn Wyborny   version 2, as published by the Free Software Foundation.
9e428893bSCarolyn Wyborny 
10e428893bSCarolyn Wyborny   This program is distributed in the hope it will be useful, but WITHOUT
11e428893bSCarolyn Wyborny   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12e428893bSCarolyn Wyborny   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13e428893bSCarolyn Wyborny   more details.
14e428893bSCarolyn Wyborny 
15e428893bSCarolyn Wyborny   You should have received a copy of the GNU General Public License along with
16e428893bSCarolyn Wyborny   this program; if not, write to the Free Software Foundation, Inc.,
17e428893bSCarolyn Wyborny   51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18e428893bSCarolyn Wyborny 
19e428893bSCarolyn Wyborny   The full GNU General Public License is included in this distribution in
20e428893bSCarolyn Wyborny   the file called "COPYING".
21e428893bSCarolyn Wyborny 
22e428893bSCarolyn Wyborny   Contact Information:
23e428893bSCarolyn Wyborny   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
24e428893bSCarolyn Wyborny   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
25e428893bSCarolyn Wyborny 
26e428893bSCarolyn Wyborny *******************************************************************************/
27e428893bSCarolyn Wyborny 
28e428893bSCarolyn Wyborny #include "igb.h"
29e428893bSCarolyn Wyborny #include "e1000_82575.h"
30e428893bSCarolyn Wyborny #include "e1000_hw.h"
31e428893bSCarolyn Wyborny 
32e428893bSCarolyn Wyborny #include <linux/module.h>
33e428893bSCarolyn Wyborny #include <linux/types.h>
34e428893bSCarolyn Wyborny #include <linux/sysfs.h>
35e428893bSCarolyn Wyborny #include <linux/kobject.h>
36e428893bSCarolyn Wyborny #include <linux/device.h>
37e428893bSCarolyn Wyborny #include <linux/netdevice.h>
38e428893bSCarolyn Wyborny #include <linux/hwmon.h>
39e428893bSCarolyn Wyborny #include <linux/pci.h>
40e428893bSCarolyn Wyborny 
41e428893bSCarolyn Wyborny #ifdef CONFIG_IGB_HWMON
42e428893bSCarolyn Wyborny /* hwmon callback functions */
43e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_location(struct device *dev,
44e428893bSCarolyn Wyborny 					 struct device_attribute *attr,
45e428893bSCarolyn Wyborny 					 char *buf)
46e428893bSCarolyn Wyborny {
47e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
48e428893bSCarolyn Wyborny 						     dev_attr);
49e428893bSCarolyn Wyborny 	return sprintf(buf, "loc%u\n",
50e428893bSCarolyn Wyborny 		       igb_attr->sensor->location);
51e428893bSCarolyn Wyborny }
52e428893bSCarolyn Wyborny 
53e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_temp(struct device *dev,
54e428893bSCarolyn Wyborny 				     struct device_attribute *attr,
55e428893bSCarolyn Wyborny 				     char *buf)
56e428893bSCarolyn Wyborny {
57e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
58e428893bSCarolyn Wyborny 						     dev_attr);
59e428893bSCarolyn Wyborny 	unsigned int value;
60e428893bSCarolyn Wyborny 
61e428893bSCarolyn Wyborny 	/* reset the temp field */
62e428893bSCarolyn Wyborny 	igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
63e428893bSCarolyn Wyborny 
64e428893bSCarolyn Wyborny 	value = igb_attr->sensor->temp;
65e428893bSCarolyn Wyborny 
66e428893bSCarolyn Wyborny 	/* display millidegree */
67e428893bSCarolyn Wyborny 	value *= 1000;
68e428893bSCarolyn Wyborny 
69e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
70e428893bSCarolyn Wyborny }
71e428893bSCarolyn Wyborny 
72e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
73e428893bSCarolyn Wyborny 				     struct device_attribute *attr,
74e428893bSCarolyn Wyborny 				     char *buf)
75e428893bSCarolyn Wyborny {
76e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
77e428893bSCarolyn Wyborny 						     dev_attr);
78e428893bSCarolyn Wyborny 	unsigned int value = igb_attr->sensor->caution_thresh;
79e428893bSCarolyn Wyborny 
80e428893bSCarolyn Wyborny 	/* display millidegree */
81e428893bSCarolyn Wyborny 	value *= 1000;
82e428893bSCarolyn Wyborny 
83e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
84e428893bSCarolyn Wyborny }
85e428893bSCarolyn Wyborny 
86e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
87e428893bSCarolyn Wyborny 				     struct device_attribute *attr,
88e428893bSCarolyn Wyborny 				     char *buf)
89e428893bSCarolyn Wyborny {
90e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
91e428893bSCarolyn Wyborny 						     dev_attr);
92e428893bSCarolyn Wyborny 	unsigned int value = igb_attr->sensor->max_op_thresh;
93e428893bSCarolyn Wyborny 
94e428893bSCarolyn Wyborny 	/* display millidegree */
95e428893bSCarolyn Wyborny 	value *= 1000;
96e428893bSCarolyn Wyborny 
97e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
98e428893bSCarolyn Wyborny }
99e428893bSCarolyn Wyborny 
100e428893bSCarolyn Wyborny /* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
101e428893bSCarolyn Wyborny  * @ adapter: pointer to the adapter structure
102e428893bSCarolyn Wyborny  * @ offset: offset in the eeprom sensor data table
103e428893bSCarolyn Wyborny  * @ type: type of sensor data to display
104e428893bSCarolyn Wyborny  *
105e428893bSCarolyn Wyborny  * For each file we want in hwmon's sysfs interface we need a device_attribute
106e428893bSCarolyn Wyborny  * This is included in our hwmon_attr struct that contains the references to
107e428893bSCarolyn Wyborny  * the data structures we need to get the data to display.
108e428893bSCarolyn Wyborny  */
109e428893bSCarolyn Wyborny static int igb_add_hwmon_attr(struct igb_adapter *adapter,
110e428893bSCarolyn Wyborny 				unsigned int offset, int type) {
111e428893bSCarolyn Wyborny 	int rc;
112e428893bSCarolyn Wyborny 	unsigned int n_attr;
113e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr;
114e428893bSCarolyn Wyborny 
115e428893bSCarolyn Wyborny 	n_attr = adapter->igb_hwmon_buff.n_hwmon;
116e428893bSCarolyn Wyborny 	igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr];
117e428893bSCarolyn Wyborny 
118e428893bSCarolyn Wyborny 	switch (type) {
119e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_LOC:
120e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_location;
121e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
122e428893bSCarolyn Wyborny 			 "temp%u_label", offset);
123e428893bSCarolyn Wyborny 		break;
124e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_TEMP:
125e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_temp;
126e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
127e428893bSCarolyn Wyborny 			 "temp%u_input", offset);
128e428893bSCarolyn Wyborny 		break;
129e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_CAUTION:
130e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
131e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
132e428893bSCarolyn Wyborny 			 "temp%u_max", offset);
133e428893bSCarolyn Wyborny 		break;
134e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_MAX:
135e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
136e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
137e428893bSCarolyn Wyborny 			 "temp%u_crit", offset);
138e428893bSCarolyn Wyborny 		break;
139e428893bSCarolyn Wyborny 	default:
140e428893bSCarolyn Wyborny 		rc = -EPERM;
141e428893bSCarolyn Wyborny 		return rc;
142e428893bSCarolyn Wyborny 	}
143e428893bSCarolyn Wyborny 
144e428893bSCarolyn Wyborny 	/* These always the same regardless of type */
145e428893bSCarolyn Wyborny 	igb_attr->sensor =
146e428893bSCarolyn Wyborny 		&adapter->hw.mac.thermal_sensor_data.sensor[offset];
147e428893bSCarolyn Wyborny 	igb_attr->hw = &adapter->hw;
148e428893bSCarolyn Wyborny 	igb_attr->dev_attr.store = NULL;
149e428893bSCarolyn Wyborny 	igb_attr->dev_attr.attr.mode = S_IRUGO;
150e428893bSCarolyn Wyborny 	igb_attr->dev_attr.attr.name = igb_attr->name;
151e428893bSCarolyn Wyborny 	sysfs_attr_init(&igb_attr->dev_attr.attr);
152e428893bSCarolyn Wyborny 	rc = device_create_file(&adapter->pdev->dev,
153e428893bSCarolyn Wyborny 				&igb_attr->dev_attr);
154e428893bSCarolyn Wyborny 	if (rc == 0)
155e428893bSCarolyn Wyborny 		++adapter->igb_hwmon_buff.n_hwmon;
156e428893bSCarolyn Wyborny 
157e428893bSCarolyn Wyborny 	return rc;
158e428893bSCarolyn Wyborny }
159e428893bSCarolyn Wyborny 
160e428893bSCarolyn Wyborny static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
161e428893bSCarolyn Wyborny {
162e428893bSCarolyn Wyborny 	int i;
163e428893bSCarolyn Wyborny 
164e428893bSCarolyn Wyborny 	if (adapter == NULL)
165e428893bSCarolyn Wyborny 		return;
166e428893bSCarolyn Wyborny 
167e428893bSCarolyn Wyborny 	for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) {
168e428893bSCarolyn Wyborny 		device_remove_file(&adapter->pdev->dev,
169e428893bSCarolyn Wyborny 			   &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr);
170e428893bSCarolyn Wyborny 	}
171e428893bSCarolyn Wyborny 
172e428893bSCarolyn Wyborny 	kfree(adapter->igb_hwmon_buff.hwmon_list);
173e428893bSCarolyn Wyborny 
174e428893bSCarolyn Wyborny 	if (adapter->igb_hwmon_buff.device)
175e428893bSCarolyn Wyborny 		hwmon_device_unregister(adapter->igb_hwmon_buff.device);
176e428893bSCarolyn Wyborny }
177e428893bSCarolyn Wyborny 
178e428893bSCarolyn Wyborny /* called from igb_main.c */
179e428893bSCarolyn Wyborny void igb_sysfs_exit(struct igb_adapter *adapter)
180e428893bSCarolyn Wyborny {
181e428893bSCarolyn Wyborny 	igb_sysfs_del_adapter(adapter);
182e428893bSCarolyn Wyborny }
183e428893bSCarolyn Wyborny 
184e428893bSCarolyn Wyborny /* called from igb_main.c */
185e428893bSCarolyn Wyborny int igb_sysfs_init(struct igb_adapter *adapter)
186e428893bSCarolyn Wyborny {
187e428893bSCarolyn Wyborny 	struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff;
188e428893bSCarolyn Wyborny 	unsigned int i;
189e428893bSCarolyn Wyborny 	int n_attrs;
190e428893bSCarolyn Wyborny 	int rc = 0;
191e428893bSCarolyn Wyborny 
192e428893bSCarolyn Wyborny 	/* If this method isn't defined we don't support thermals */
193e428893bSCarolyn Wyborny 	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
194e428893bSCarolyn Wyborny 		goto exit;
195e428893bSCarolyn Wyborny 
196e428893bSCarolyn Wyborny 	/* Don't create thermal hwmon interface if no sensors present */
197e428893bSCarolyn Wyborny 	rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
198e428893bSCarolyn Wyborny 		if (rc)
199e428893bSCarolyn Wyborny 			goto exit;
200e428893bSCarolyn Wyborny 
201e428893bSCarolyn Wyborny 	/* Allocation space for max attributes
202e428893bSCarolyn Wyborny 	 * max num sensors * values (loc, temp, max, caution)
203e428893bSCarolyn Wyborny 	 */
204e428893bSCarolyn Wyborny 	n_attrs = E1000_MAX_SENSORS * 4;
205e428893bSCarolyn Wyborny 	igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
206e428893bSCarolyn Wyborny 					  GFP_KERNEL);
207e428893bSCarolyn Wyborny 	if (!igb_hwmon->hwmon_list) {
208e428893bSCarolyn Wyborny 		rc = -ENOMEM;
209e428893bSCarolyn Wyborny 		goto err;
210e428893bSCarolyn Wyborny 	}
211e428893bSCarolyn Wyborny 
212e428893bSCarolyn Wyborny 	igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev);
213e428893bSCarolyn Wyborny 	if (IS_ERR(igb_hwmon->device)) {
214e428893bSCarolyn Wyborny 		rc = PTR_ERR(igb_hwmon->device);
215e428893bSCarolyn Wyborny 		goto err;
216e428893bSCarolyn Wyborny 	}
217e428893bSCarolyn Wyborny 
218e428893bSCarolyn Wyborny 	for (i = 0; i < E1000_MAX_SENSORS; i++) {
219e428893bSCarolyn Wyborny 
220e428893bSCarolyn Wyborny 		/* Only create hwmon sysfs entries for sensors that have
221e428893bSCarolyn Wyborny 		 * meaningful data.
222e428893bSCarolyn Wyborny 		 */
223e428893bSCarolyn Wyborny 		if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
224e428893bSCarolyn Wyborny 			continue;
225e428893bSCarolyn Wyborny 
226e428893bSCarolyn Wyborny 		/* Bail if any hwmon attr struct fails to initialize */
227e428893bSCarolyn Wyborny 		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
228e428893bSCarolyn Wyborny 		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
229e428893bSCarolyn Wyborny 		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
230e428893bSCarolyn Wyborny 		rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
231e428893bSCarolyn Wyborny 		if (rc)
232e428893bSCarolyn Wyborny 			goto err;
233e428893bSCarolyn Wyborny 	}
234e428893bSCarolyn Wyborny 
235e428893bSCarolyn Wyborny 	goto exit;
236e428893bSCarolyn Wyborny 
237e428893bSCarolyn Wyborny err:
238e428893bSCarolyn Wyborny 	igb_sysfs_del_adapter(adapter);
239e428893bSCarolyn Wyborny exit:
240e428893bSCarolyn Wyborny 	return rc;
241e428893bSCarolyn Wyborny }
242e428893bSCarolyn Wyborny #endif
243