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