xref: /linux/drivers/net/ethernet/intel/igb/igb_hwmon.c (revision e3670b81954ab1247341a08514aa4df09f0b495e)
1e428893bSCarolyn Wyborny /*******************************************************************************
2e428893bSCarolyn Wyborny 
3e428893bSCarolyn Wyborny   Intel(R) Gigabit Ethernet Linux driver
44b9ea462SAkeem 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
4205ec29e8SStephen Hemminger static struct i2c_board_info i350_sensor_info = {
43603e86faSCarolyn Wyborny 	I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)),
44603e86faSCarolyn Wyborny };
45603e86faSCarolyn Wyborny 
46e428893bSCarolyn Wyborny /* hwmon callback functions */
47e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_location(struct device *dev,
48e428893bSCarolyn Wyborny 				       struct device_attribute *attr,
49e428893bSCarolyn Wyborny 				       char *buf)
50e428893bSCarolyn Wyborny {
51e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
52e428893bSCarolyn Wyborny 						   dev_attr);
53e428893bSCarolyn Wyborny 	return sprintf(buf, "loc%u\n",
54e428893bSCarolyn Wyborny 		       igb_attr->sensor->location);
55e428893bSCarolyn Wyborny }
56e428893bSCarolyn Wyborny 
57e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_temp(struct device *dev,
58e428893bSCarolyn Wyborny 				   struct device_attribute *attr,
59e428893bSCarolyn Wyborny 				   char *buf)
60e428893bSCarolyn Wyborny {
61e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
62e428893bSCarolyn Wyborny 						   dev_attr);
63e428893bSCarolyn Wyborny 	unsigned int value;
64e428893bSCarolyn Wyborny 
65e428893bSCarolyn Wyborny 	/* reset the temp field */
66e428893bSCarolyn Wyborny 	igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
67e428893bSCarolyn Wyborny 
68e428893bSCarolyn Wyborny 	value = igb_attr->sensor->temp;
69e428893bSCarolyn Wyborny 
70e428893bSCarolyn Wyborny 	/* display millidegree */
71e428893bSCarolyn Wyborny 	value *= 1000;
72e428893bSCarolyn Wyborny 
73e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
74e428893bSCarolyn Wyborny }
75e428893bSCarolyn Wyborny 
76e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
77e428893bSCarolyn Wyborny 					    struct device_attribute *attr,
78e428893bSCarolyn Wyborny 					    char *buf)
79e428893bSCarolyn Wyborny {
80e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
81e428893bSCarolyn Wyborny 						   dev_attr);
82e428893bSCarolyn Wyborny 	unsigned int value = igb_attr->sensor->caution_thresh;
83e428893bSCarolyn Wyborny 
84e428893bSCarolyn Wyborny 	/* display millidegree */
85e428893bSCarolyn Wyborny 	value *= 1000;
86e428893bSCarolyn Wyborny 
87e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
88e428893bSCarolyn Wyborny }
89e428893bSCarolyn Wyborny 
90e428893bSCarolyn Wyborny static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
91e428893bSCarolyn Wyborny 					  struct device_attribute *attr,
92e428893bSCarolyn Wyborny 					  char *buf)
93e428893bSCarolyn Wyborny {
94e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
95e428893bSCarolyn Wyborny 						   dev_attr);
96e428893bSCarolyn Wyborny 	unsigned int value = igb_attr->sensor->max_op_thresh;
97e428893bSCarolyn Wyborny 
98e428893bSCarolyn Wyborny 	/* display millidegree */
99e428893bSCarolyn Wyborny 	value *= 1000;
100e428893bSCarolyn Wyborny 
101e428893bSCarolyn Wyborny 	return sprintf(buf, "%u\n", value);
102e428893bSCarolyn Wyborny }
103e428893bSCarolyn Wyborny 
104e428893bSCarolyn Wyborny /* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
105e428893bSCarolyn Wyborny  * @ adapter: pointer to the adapter structure
106e428893bSCarolyn Wyborny  * @ offset: offset in the eeprom sensor data table
107e428893bSCarolyn Wyborny  * @ type: type of sensor data to display
108e428893bSCarolyn Wyborny  *
109e428893bSCarolyn Wyborny  * For each file we want in hwmon's sysfs interface we need a device_attribute
110e428893bSCarolyn Wyborny  * This is included in our hwmon_attr struct that contains the references to
111e428893bSCarolyn Wyborny  * the data structures we need to get the data to display.
112e428893bSCarolyn Wyborny  */
113e428893bSCarolyn Wyborny static int igb_add_hwmon_attr(struct igb_adapter *adapter,
114b980ac18SJeff Kirsher 			      unsigned int offset, int type)
115b980ac18SJeff Kirsher {
116e428893bSCarolyn Wyborny 	int rc;
117e428893bSCarolyn Wyborny 	unsigned int n_attr;
118e428893bSCarolyn Wyborny 	struct hwmon_attr *igb_attr;
119e428893bSCarolyn Wyborny 
120*e3670b81SGuenter Roeck 	n_attr = adapter->igb_hwmon_buff->n_hwmon;
121*e3670b81SGuenter Roeck 	igb_attr = &adapter->igb_hwmon_buff->hwmon_list[n_attr];
122e428893bSCarolyn Wyborny 
123e428893bSCarolyn Wyborny 	switch (type) {
124e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_LOC:
125e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_location;
126e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
127e428893bSCarolyn Wyborny 			 "temp%u_label", offset);
128e428893bSCarolyn Wyborny 		break;
129e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_TEMP:
130e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_temp;
131e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
132e428893bSCarolyn Wyborny 			 "temp%u_input", offset);
133e428893bSCarolyn Wyborny 		break;
134e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_CAUTION:
135e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
136e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
137e428893bSCarolyn Wyborny 			 "temp%u_max", offset);
138e428893bSCarolyn Wyborny 		break;
139e428893bSCarolyn Wyborny 	case IGB_HWMON_TYPE_MAX:
140e428893bSCarolyn Wyborny 		igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
141e428893bSCarolyn Wyborny 		snprintf(igb_attr->name, sizeof(igb_attr->name),
142e428893bSCarolyn Wyborny 			 "temp%u_crit", offset);
143e428893bSCarolyn Wyborny 		break;
144e428893bSCarolyn Wyborny 	default:
145e428893bSCarolyn Wyborny 		rc = -EPERM;
146e428893bSCarolyn Wyborny 		return rc;
147e428893bSCarolyn Wyborny 	}
148e428893bSCarolyn Wyborny 
149e428893bSCarolyn Wyborny 	/* These always the same regardless of type */
150e428893bSCarolyn Wyborny 	igb_attr->sensor =
151e428893bSCarolyn Wyborny 		&adapter->hw.mac.thermal_sensor_data.sensor[offset];
152e428893bSCarolyn Wyborny 	igb_attr->hw = &adapter->hw;
153e428893bSCarolyn Wyborny 	igb_attr->dev_attr.store = NULL;
154e428893bSCarolyn Wyborny 	igb_attr->dev_attr.attr.mode = S_IRUGO;
155e428893bSCarolyn Wyborny 	igb_attr->dev_attr.attr.name = igb_attr->name;
156e428893bSCarolyn Wyborny 	sysfs_attr_init(&igb_attr->dev_attr.attr);
157e428893bSCarolyn Wyborny 
158*e3670b81SGuenter Roeck 	adapter->igb_hwmon_buff->attrs[n_attr] = &igb_attr->dev_attr.attr;
159*e3670b81SGuenter Roeck 
160*e3670b81SGuenter Roeck 	++adapter->igb_hwmon_buff->n_hwmon;
161*e3670b81SGuenter Roeck 
162*e3670b81SGuenter Roeck 	return 0;
163e428893bSCarolyn Wyborny }
164e428893bSCarolyn Wyborny 
165e428893bSCarolyn Wyborny static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
166e428893bSCarolyn Wyborny {
167e428893bSCarolyn Wyborny }
168e428893bSCarolyn Wyborny 
169e428893bSCarolyn Wyborny /* called from igb_main.c */
170e428893bSCarolyn Wyborny void igb_sysfs_exit(struct igb_adapter *adapter)
171e428893bSCarolyn Wyborny {
172e428893bSCarolyn Wyborny 	igb_sysfs_del_adapter(adapter);
173e428893bSCarolyn Wyborny }
174e428893bSCarolyn Wyborny 
175e428893bSCarolyn Wyborny /* called from igb_main.c */
176e428893bSCarolyn Wyborny int igb_sysfs_init(struct igb_adapter *adapter)
177e428893bSCarolyn Wyborny {
178*e3670b81SGuenter Roeck 	struct hwmon_buff *igb_hwmon;
179*e3670b81SGuenter Roeck 	struct i2c_client *client;
180*e3670b81SGuenter Roeck 	struct device *hwmon_dev;
181e428893bSCarolyn Wyborny 	unsigned int i;
182e428893bSCarolyn Wyborny 	int rc = 0;
183e428893bSCarolyn Wyborny 
184e428893bSCarolyn Wyborny 	/* If this method isn't defined we don't support thermals */
185e428893bSCarolyn Wyborny 	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
186e428893bSCarolyn Wyborny 		goto exit;
187e428893bSCarolyn Wyborny 
188e428893bSCarolyn Wyborny 	/* Don't create thermal hwmon interface if no sensors present */
189e428893bSCarolyn Wyborny 	rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
190e428893bSCarolyn Wyborny 	if (rc)
191e428893bSCarolyn Wyborny 		goto exit;
192e428893bSCarolyn Wyborny 
193*e3670b81SGuenter Roeck 	igb_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*igb_hwmon),
194*e3670b81SGuenter Roeck 				 GFP_KERNEL);
195*e3670b81SGuenter Roeck 	if (!igb_hwmon) {
196*e3670b81SGuenter Roeck 		rc = -ENOMEM;
197603e86faSCarolyn Wyborny 		goto exit;
198603e86faSCarolyn Wyborny 	}
199*e3670b81SGuenter Roeck 	adapter->igb_hwmon_buff = igb_hwmon;
200e428893bSCarolyn Wyborny 
201e428893bSCarolyn Wyborny 	for (i = 0; i < E1000_MAX_SENSORS; i++) {
202e428893bSCarolyn Wyborny 
203e428893bSCarolyn Wyborny 		/* Only create hwmon sysfs entries for sensors that have
204e428893bSCarolyn Wyborny 		 * meaningful data.
205e428893bSCarolyn Wyborny 		 */
206e428893bSCarolyn Wyborny 		if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
207e428893bSCarolyn Wyborny 			continue;
208e428893bSCarolyn Wyborny 
209e428893bSCarolyn Wyborny 		/* Bail if any hwmon attr struct fails to initialize */
210e428893bSCarolyn Wyborny 		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
211e428893bSCarolyn Wyborny 		if (rc)
212*e3670b81SGuenter Roeck 			goto exit;
213*e3670b81SGuenter Roeck 		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
214*e3670b81SGuenter Roeck 		if (rc)
215*e3670b81SGuenter Roeck 			goto exit;
216*e3670b81SGuenter Roeck 		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
217*e3670b81SGuenter Roeck 		if (rc)
218*e3670b81SGuenter Roeck 			goto exit;
219*e3670b81SGuenter Roeck 		rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
220*e3670b81SGuenter Roeck 		if (rc)
221*e3670b81SGuenter Roeck 			goto exit;
222*e3670b81SGuenter Roeck 	}
223*e3670b81SGuenter Roeck 
224*e3670b81SGuenter Roeck 	/* init i2c_client */
225*e3670b81SGuenter Roeck 	client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info);
226*e3670b81SGuenter Roeck 	if (client == NULL) {
227*e3670b81SGuenter Roeck 		dev_info(&adapter->pdev->dev,
228*e3670b81SGuenter Roeck 			 "Failed to create new i2c device.\n");
229*e3670b81SGuenter Roeck 		rc = -ENODEV;
230*e3670b81SGuenter Roeck 		goto exit;
231*e3670b81SGuenter Roeck 	}
232*e3670b81SGuenter Roeck 	adapter->i2c_client = client;
233*e3670b81SGuenter Roeck 
234*e3670b81SGuenter Roeck 	igb_hwmon->groups[0] = &igb_hwmon->group;
235*e3670b81SGuenter Roeck 	igb_hwmon->group.attrs = igb_hwmon->attrs;
236*e3670b81SGuenter Roeck 
237*e3670b81SGuenter Roeck 	hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev,
238*e3670b81SGuenter Roeck 							   client->name,
239*e3670b81SGuenter Roeck 							   igb_hwmon,
240*e3670b81SGuenter Roeck 							   igb_hwmon->groups);
241*e3670b81SGuenter Roeck 	if (IS_ERR(hwmon_dev)) {
242*e3670b81SGuenter Roeck 		rc = PTR_ERR(hwmon_dev);
243e428893bSCarolyn Wyborny 		goto err;
244e428893bSCarolyn Wyborny 	}
245e428893bSCarolyn Wyborny 
246e428893bSCarolyn Wyborny 	goto exit;
247e428893bSCarolyn Wyborny 
248e428893bSCarolyn Wyborny err:
249e428893bSCarolyn Wyborny 	igb_sysfs_del_adapter(adapter);
250e428893bSCarolyn Wyborny exit:
251e428893bSCarolyn Wyborny 	return rc;
252e428893bSCarolyn Wyborny }
253e428893bSCarolyn Wyborny #endif
254