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, 114*b980ac18SJeff Kirsher unsigned int offset, int type) 115*b980ac18SJeff Kirsher { 116e428893bSCarolyn Wyborny int rc; 117e428893bSCarolyn Wyborny unsigned int n_attr; 118e428893bSCarolyn Wyborny struct hwmon_attr *igb_attr; 119e428893bSCarolyn Wyborny 120e428893bSCarolyn Wyborny n_attr = adapter->igb_hwmon_buff.n_hwmon; 121e428893bSCarolyn Wyborny 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 rc = device_create_file(&adapter->pdev->dev, 158e428893bSCarolyn Wyborny &igb_attr->dev_attr); 159e428893bSCarolyn Wyborny if (rc == 0) 160e428893bSCarolyn Wyborny ++adapter->igb_hwmon_buff.n_hwmon; 161e428893bSCarolyn Wyborny 162e428893bSCarolyn Wyborny return rc; 163e428893bSCarolyn Wyborny } 164e428893bSCarolyn Wyborny 165e428893bSCarolyn Wyborny static void igb_sysfs_del_adapter(struct igb_adapter *adapter) 166e428893bSCarolyn Wyborny { 167e428893bSCarolyn Wyborny int i; 168e428893bSCarolyn Wyborny 169e428893bSCarolyn Wyborny if (adapter == NULL) 170e428893bSCarolyn Wyborny return; 171e428893bSCarolyn Wyborny 172e428893bSCarolyn Wyborny for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) { 173e428893bSCarolyn Wyborny device_remove_file(&adapter->pdev->dev, 174e428893bSCarolyn Wyborny &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr); 175e428893bSCarolyn Wyborny } 176e428893bSCarolyn Wyborny 177e428893bSCarolyn Wyborny kfree(adapter->igb_hwmon_buff.hwmon_list); 178e428893bSCarolyn Wyborny 179e428893bSCarolyn Wyborny if (adapter->igb_hwmon_buff.device) 180e428893bSCarolyn Wyborny hwmon_device_unregister(adapter->igb_hwmon_buff.device); 181e428893bSCarolyn Wyborny } 182e428893bSCarolyn Wyborny 183e428893bSCarolyn Wyborny /* called from igb_main.c */ 184e428893bSCarolyn Wyborny void igb_sysfs_exit(struct igb_adapter *adapter) 185e428893bSCarolyn Wyborny { 186e428893bSCarolyn Wyborny igb_sysfs_del_adapter(adapter); 187e428893bSCarolyn Wyborny } 188e428893bSCarolyn Wyborny 189e428893bSCarolyn Wyborny /* called from igb_main.c */ 190e428893bSCarolyn Wyborny int igb_sysfs_init(struct igb_adapter *adapter) 191e428893bSCarolyn Wyborny { 192e428893bSCarolyn Wyborny struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff; 193e428893bSCarolyn Wyborny unsigned int i; 194e428893bSCarolyn Wyborny int n_attrs; 195e428893bSCarolyn Wyborny int rc = 0; 196603e86faSCarolyn Wyborny struct i2c_client *client = NULL; 197e428893bSCarolyn Wyborny 198e428893bSCarolyn Wyborny /* If this method isn't defined we don't support thermals */ 199e428893bSCarolyn Wyborny if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) 200e428893bSCarolyn Wyborny goto exit; 201e428893bSCarolyn Wyborny 202e428893bSCarolyn Wyborny /* Don't create thermal hwmon interface if no sensors present */ 203e428893bSCarolyn Wyborny rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw)); 204e428893bSCarolyn Wyborny if (rc) 205e428893bSCarolyn Wyborny goto exit; 206e428893bSCarolyn Wyborny 207603e86faSCarolyn Wyborny /* init i2c_client */ 208603e86faSCarolyn Wyborny client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info); 209603e86faSCarolyn Wyborny if (client == NULL) { 210603e86faSCarolyn Wyborny dev_info(&adapter->pdev->dev, 211603e86faSCarolyn Wyborny "Failed to create new i2c device..\n"); 212603e86faSCarolyn Wyborny goto exit; 213603e86faSCarolyn Wyborny } 214603e86faSCarolyn Wyborny adapter->i2c_client = client; 215603e86faSCarolyn Wyborny 216e428893bSCarolyn Wyborny /* Allocation space for max attributes 217e428893bSCarolyn Wyborny * max num sensors * values (loc, temp, max, caution) 218e428893bSCarolyn Wyborny */ 219e428893bSCarolyn Wyborny n_attrs = E1000_MAX_SENSORS * 4; 220e428893bSCarolyn Wyborny igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr), 221e428893bSCarolyn Wyborny GFP_KERNEL); 222e428893bSCarolyn Wyborny if (!igb_hwmon->hwmon_list) { 223e428893bSCarolyn Wyborny rc = -ENOMEM; 224e428893bSCarolyn Wyborny goto err; 225e428893bSCarolyn Wyborny } 226e428893bSCarolyn Wyborny 227e428893bSCarolyn Wyborny igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev); 228e428893bSCarolyn Wyborny if (IS_ERR(igb_hwmon->device)) { 229e428893bSCarolyn Wyborny rc = PTR_ERR(igb_hwmon->device); 230e428893bSCarolyn Wyborny goto err; 231e428893bSCarolyn Wyborny } 232e428893bSCarolyn Wyborny 233e428893bSCarolyn Wyborny for (i = 0; i < E1000_MAX_SENSORS; i++) { 234e428893bSCarolyn Wyborny 235e428893bSCarolyn Wyborny /* Only create hwmon sysfs entries for sensors that have 236e428893bSCarolyn Wyborny * meaningful data. 237e428893bSCarolyn Wyborny */ 238e428893bSCarolyn Wyborny if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0) 239e428893bSCarolyn Wyborny continue; 240e428893bSCarolyn Wyborny 241e428893bSCarolyn Wyborny /* Bail if any hwmon attr struct fails to initialize */ 242e428893bSCarolyn Wyborny rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION); 243e428893bSCarolyn Wyborny rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); 244e428893bSCarolyn Wyborny rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); 245e428893bSCarolyn Wyborny rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); 246e428893bSCarolyn Wyborny if (rc) 247e428893bSCarolyn Wyborny goto err; 248e428893bSCarolyn Wyborny } 249e428893bSCarolyn Wyborny 250e428893bSCarolyn Wyborny goto exit; 251e428893bSCarolyn Wyborny 252e428893bSCarolyn Wyborny err: 253e428893bSCarolyn Wyborny igb_sysfs_del_adapter(adapter); 254e428893bSCarolyn Wyborny exit: 255e428893bSCarolyn Wyborny return rc; 256e428893bSCarolyn Wyborny } 257e428893bSCarolyn Wyborny #endif 258