Skip to content

Commit

Permalink
net: dsa: Add support for reporting switch chip temperatures
Browse files Browse the repository at this point in the history
Some switches provide chip temperature data.
Add support for reporting it through the hwmon subsystem.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Guenter Roeck authored and David S. Miller committed Oct 30, 2014
1 parent 2716777 commit 51579c3
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 0 deletions.
16 changes: 16 additions & 0 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ struct dsa_switch {
*/
struct device *master_dev;

#ifdef CONFIG_NET_DSA_HWMON
/*
* Hardware monitoring information
*/
char hwmon_name[IFNAMSIZ + 8];
struct device *hwmon_dev;
#endif

/*
* Slave mii_bus and devices for the individual ports.
*/
Expand Down Expand Up @@ -242,6 +250,14 @@ struct dsa_switch_driver {
struct ethtool_eee *e);
int (*get_eee)(struct dsa_switch *ds, int port,
struct ethtool_eee *e);

#ifdef CONFIG_NET_DSA_HWMON
/* Hardware monitoring */
int (*get_temp)(struct dsa_switch *ds, int *temp);
int (*get_temp_limit)(struct dsa_switch *ds, int *temp);
int (*set_temp_limit)(struct dsa_switch *ds, int temp);
int (*get_temp_alarm)(struct dsa_switch *ds, bool *alarm);
#endif
};

void register_switch_driver(struct dsa_switch_driver *type);
Expand Down
11 changes: 11 additions & 0 deletions net/dsa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ config NET_DSA

if NET_DSA

config NET_DSA_HWMON
bool "Distributed Switch Architecture HWMON support"
default y
depends on HWMON && !(NET_DSA=y && HWMON=m)
---help---
Say Y if you want to expose thermal sensor data on switches supported
by the Distributed Switch Architecture.

Some of those switches contain thermal sensors. This data is available
via the hwmon sysfs interface and exposes the onboard sensors.

# tagging formats
config NET_DSA_TAG_BRCM
bool
Expand Down
131 changes: 131 additions & 0 deletions net/dsa/dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
* (at your option) any later version.
*/

#include <linux/ctype.h>
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
Expand All @@ -17,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/sysfs.h>
#include "dsa_priv.h"

char dsa_driver_version[] = "0.1";
Expand Down Expand Up @@ -71,6 +75,104 @@ dsa_switch_probe(struct device *host_dev, int sw_addr, char **_name)
return ret;
}

/* hwmon support ************************************************************/

#ifdef CONFIG_NET_DSA_HWMON

static ssize_t temp1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dsa_switch *ds = dev_get_drvdata(dev);
int temp, ret;

ret = ds->drv->get_temp(ds, &temp);
if (ret < 0)
return ret;

return sprintf(buf, "%d\n", temp * 1000);
}
static DEVICE_ATTR_RO(temp1_input);

static ssize_t temp1_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dsa_switch *ds = dev_get_drvdata(dev);
int temp, ret;

ret = ds->drv->get_temp_limit(ds, &temp);
if (ret < 0)
return ret;

return sprintf(buf, "%d\n", temp * 1000);
}

static ssize_t temp1_max_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
struct dsa_switch *ds = dev_get_drvdata(dev);
int temp, ret;

ret = kstrtoint(buf, 0, &temp);
if (ret < 0)
return ret;

ret = ds->drv->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
if (ret < 0)
return ret;

return count;
}
static DEVICE_ATTR(temp1_max, S_IRUGO, temp1_max_show, temp1_max_store);

static ssize_t temp1_max_alarm_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dsa_switch *ds = dev_get_drvdata(dev);
bool alarm;
int ret;

ret = ds->drv->get_temp_alarm(ds, &alarm);
if (ret < 0)
return ret;

return sprintf(buf, "%d\n", alarm);
}
static DEVICE_ATTR_RO(temp1_max_alarm);

static struct attribute *dsa_hwmon_attrs[] = {
&dev_attr_temp1_input.attr, /* 0 */
&dev_attr_temp1_max.attr, /* 1 */
&dev_attr_temp1_max_alarm.attr, /* 2 */
NULL
};

static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct dsa_switch *ds = dev_get_drvdata(dev);
struct dsa_switch_driver *drv = ds->drv;
umode_t mode = attr->mode;

if (index == 1) {
if (!drv->get_temp_limit)
mode = 0;
else if (drv->set_temp_limit)
mode |= S_IWUSR;
} else if (index == 2 && !drv->get_temp_alarm) {
mode = 0;
}
return mode;
}

static const struct attribute_group dsa_hwmon_group = {
.attrs = dsa_hwmon_attrs,
.is_visible = dsa_hwmon_attrs_visible,
};
__ATTRIBUTE_GROUPS(dsa_hwmon);

#endif /* CONFIG_NET_DSA_HWMON */

/* basic switch operations **************************************************/
static struct dsa_switch *
Expand Down Expand Up @@ -225,6 +327,31 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
ds->ports[i] = slave_dev;
}

#ifdef CONFIG_NET_DSA_HWMON
/* If the switch provides a temperature sensor,
* register with hardware monitoring subsystem.
* Treat registration error as non-fatal and ignore it.
*/
if (drv->get_temp) {
const char *netname = netdev_name(dst->master_netdev);
char hname[IFNAMSIZ + 1];
int i, j;

/* Create valid hwmon 'name' attribute */
for (i = j = 0; i < IFNAMSIZ && netname[i]; i++) {
if (isalnum(netname[i]))
hname[j++] = netname[i];
}
hname[j] = '\0';
scnprintf(ds->hwmon_name, sizeof(ds->hwmon_name), "%s_dsa%d",
hname, index);
ds->hwmon_dev = hwmon_device_register_with_groups(NULL,
ds->hwmon_name, ds, dsa_hwmon_groups);
if (IS_ERR(ds->hwmon_dev))
ds->hwmon_dev = NULL;
}
#endif /* CONFIG_NET_DSA_HWMON */

return ds;

out_free:
Expand All @@ -236,6 +363,10 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,

static void dsa_switch_destroy(struct dsa_switch *ds)
{
#ifdef CONFIG_NET_DSA_HWMON
if (ds->hwmon_dev)
hwmon_device_unregister(ds->hwmon_dev);
#endif
}

#ifdef CONFIG_PM_SLEEP
Expand Down

0 comments on commit 51579c3

Please sign in to comment.