Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2007 - 2018 Intel Corporation. */
0003 
0004 #include "igb.h"
0005 #include "e1000_82575.h"
0006 #include "e1000_hw.h"
0007 
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/sysfs.h>
0011 #include <linux/kobject.h>
0012 #include <linux/device.h>
0013 #include <linux/netdevice.h>
0014 #include <linux/hwmon.h>
0015 #include <linux/pci.h>
0016 
0017 #ifdef CONFIG_IGB_HWMON
0018 static struct i2c_board_info i350_sensor_info = {
0019     I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)),
0020 };
0021 
0022 /* hwmon callback functions */
0023 static ssize_t igb_hwmon_show_location(struct device *dev,
0024                        struct device_attribute *attr,
0025                        char *buf)
0026 {
0027     struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
0028                            dev_attr);
0029     return sprintf(buf, "loc%u\n",
0030                igb_attr->sensor->location);
0031 }
0032 
0033 static ssize_t igb_hwmon_show_temp(struct device *dev,
0034                    struct device_attribute *attr,
0035                    char *buf)
0036 {
0037     struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
0038                            dev_attr);
0039     unsigned int value;
0040 
0041     /* reset the temp field */
0042     igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
0043 
0044     value = igb_attr->sensor->temp;
0045 
0046     /* display millidegree */
0047     value *= 1000;
0048 
0049     return sprintf(buf, "%u\n", value);
0050 }
0051 
0052 static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
0053                         struct device_attribute *attr,
0054                         char *buf)
0055 {
0056     struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
0057                            dev_attr);
0058     unsigned int value = igb_attr->sensor->caution_thresh;
0059 
0060     /* display millidegree */
0061     value *= 1000;
0062 
0063     return sprintf(buf, "%u\n", value);
0064 }
0065 
0066 static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
0067                       struct device_attribute *attr,
0068                       char *buf)
0069 {
0070     struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
0071                            dev_attr);
0072     unsigned int value = igb_attr->sensor->max_op_thresh;
0073 
0074     /* display millidegree */
0075     value *= 1000;
0076 
0077     return sprintf(buf, "%u\n", value);
0078 }
0079 
0080 /* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
0081  * @ adapter: pointer to the adapter structure
0082  * @ offset: offset in the eeprom sensor data table
0083  * @ type: type of sensor data to display
0084  *
0085  * For each file we want in hwmon's sysfs interface we need a device_attribute
0086  * This is included in our hwmon_attr struct that contains the references to
0087  * the data structures we need to get the data to display.
0088  */
0089 static int igb_add_hwmon_attr(struct igb_adapter *adapter,
0090                   unsigned int offset, int type)
0091 {
0092     int rc;
0093     unsigned int n_attr;
0094     struct hwmon_attr *igb_attr;
0095 
0096     n_attr = adapter->igb_hwmon_buff->n_hwmon;
0097     igb_attr = &adapter->igb_hwmon_buff->hwmon_list[n_attr];
0098 
0099     switch (type) {
0100     case IGB_HWMON_TYPE_LOC:
0101         igb_attr->dev_attr.show = igb_hwmon_show_location;
0102         snprintf(igb_attr->name, sizeof(igb_attr->name),
0103              "temp%u_label", offset + 1);
0104         break;
0105     case IGB_HWMON_TYPE_TEMP:
0106         igb_attr->dev_attr.show = igb_hwmon_show_temp;
0107         snprintf(igb_attr->name, sizeof(igb_attr->name),
0108              "temp%u_input", offset + 1);
0109         break;
0110     case IGB_HWMON_TYPE_CAUTION:
0111         igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
0112         snprintf(igb_attr->name, sizeof(igb_attr->name),
0113              "temp%u_max", offset + 1);
0114         break;
0115     case IGB_HWMON_TYPE_MAX:
0116         igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
0117         snprintf(igb_attr->name, sizeof(igb_attr->name),
0118              "temp%u_crit", offset + 1);
0119         break;
0120     default:
0121         rc = -EPERM;
0122         return rc;
0123     }
0124 
0125     /* These always the same regardless of type */
0126     igb_attr->sensor =
0127         &adapter->hw.mac.thermal_sensor_data.sensor[offset];
0128     igb_attr->hw = &adapter->hw;
0129     igb_attr->dev_attr.store = NULL;
0130     igb_attr->dev_attr.attr.mode = 0444;
0131     igb_attr->dev_attr.attr.name = igb_attr->name;
0132     sysfs_attr_init(&igb_attr->dev_attr.attr);
0133 
0134     adapter->igb_hwmon_buff->attrs[n_attr] = &igb_attr->dev_attr.attr;
0135 
0136     ++adapter->igb_hwmon_buff->n_hwmon;
0137 
0138     return 0;
0139 }
0140 
0141 static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
0142 {
0143 }
0144 
0145 /* called from igb_main.c */
0146 void igb_sysfs_exit(struct igb_adapter *adapter)
0147 {
0148     igb_sysfs_del_adapter(adapter);
0149 }
0150 
0151 /* called from igb_main.c */
0152 int igb_sysfs_init(struct igb_adapter *adapter)
0153 {
0154     struct hwmon_buff *igb_hwmon;
0155     struct i2c_client *client;
0156     struct device *hwmon_dev;
0157     unsigned int i;
0158     int rc = 0;
0159 
0160     /* If this method isn't defined we don't support thermals */
0161     if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
0162         goto exit;
0163 
0164     /* Don't create thermal hwmon interface if no sensors present */
0165     rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
0166     if (rc)
0167         goto exit;
0168 
0169     igb_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*igb_hwmon),
0170                  GFP_KERNEL);
0171     if (!igb_hwmon) {
0172         rc = -ENOMEM;
0173         goto exit;
0174     }
0175     adapter->igb_hwmon_buff = igb_hwmon;
0176 
0177     for (i = 0; i < E1000_MAX_SENSORS; i++) {
0178 
0179         /* Only create hwmon sysfs entries for sensors that have
0180          * meaningful data.
0181          */
0182         if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
0183             continue;
0184 
0185         /* Bail if any hwmon attr struct fails to initialize */
0186         rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
0187         if (rc)
0188             goto exit;
0189         rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
0190         if (rc)
0191             goto exit;
0192         rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
0193         if (rc)
0194             goto exit;
0195         rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
0196         if (rc)
0197             goto exit;
0198     }
0199 
0200     /* init i2c_client */
0201     client = i2c_new_client_device(&adapter->i2c_adap, &i350_sensor_info);
0202     if (IS_ERR(client)) {
0203         dev_info(&adapter->pdev->dev,
0204              "Failed to create new i2c device.\n");
0205         rc = PTR_ERR(client);
0206         goto exit;
0207     }
0208     adapter->i2c_client = client;
0209 
0210     igb_hwmon->groups[0] = &igb_hwmon->group;
0211     igb_hwmon->group.attrs = igb_hwmon->attrs;
0212 
0213     hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev,
0214                                client->name,
0215                                igb_hwmon,
0216                                igb_hwmon->groups);
0217     if (IS_ERR(hwmon_dev)) {
0218         rc = PTR_ERR(hwmon_dev);
0219         goto err;
0220     }
0221 
0222     goto exit;
0223 
0224 err:
0225     igb_sysfs_del_adapter(adapter);
0226 exit:
0227     return rc;
0228 }
0229 #endif