aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/Kconfig11
-rw-r--r--net/dsa/dsa.c131
2 files changed, 142 insertions, 0 deletions
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index a585fd6352eb..5f8ac404535b 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -11,6 +11,17 @@ config NET_DSA
11 11
12if NET_DSA 12if NET_DSA
13 13
14config NET_DSA_HWMON
15 bool "Distributed Switch Architecture HWMON support"
16 default y
17 depends on HWMON && !(NET_DSA=y && HWMON=m)
18 ---help---
19 Say Y if you want to expose thermal sensor data on switches supported
20 by the Distributed Switch Architecture.
21
22 Some of those switches contain thermal sensors. This data is available
23 via the hwmon sysfs interface and exposes the onboard sensors.
24
14# tagging formats 25# tagging formats
15config NET_DSA_TAG_BRCM 26config NET_DSA_TAG_BRCM
16 bool 27 bool
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 22f34cf4cb27..5edbbca89f1f 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -9,6 +9,9 @@
9 * (at your option) any later version. 9 * (at your option) any later version.
10 */ 10 */
11 11
12#include <linux/ctype.h>
13#include <linux/device.h>
14#include <linux/hwmon.h>
12#include <linux/list.h> 15#include <linux/list.h>
13#include <linux/platform_device.h> 16#include <linux/platform_device.h>
14#include <linux/slab.h> 17#include <linux/slab.h>
@@ -17,6 +20,7 @@
17#include <linux/of.h> 20#include <linux/of.h>
18#include <linux/of_mdio.h> 21#include <linux/of_mdio.h>
19#include <linux/of_platform.h> 22#include <linux/of_platform.h>
23#include <linux/sysfs.h>
20#include "dsa_priv.h" 24#include "dsa_priv.h"
21 25
22char dsa_driver_version[] = "0.1"; 26char dsa_driver_version[] = "0.1";
@@ -71,6 +75,104 @@ dsa_switch_probe(struct device *host_dev, int sw_addr, char **_name)
71 return ret; 75 return ret;
72} 76}
73 77
78/* hwmon support ************************************************************/
79
80#ifdef CONFIG_NET_DSA_HWMON
81
82static ssize_t temp1_input_show(struct device *dev,
83 struct device_attribute *attr, char *buf)
84{
85 struct dsa_switch *ds = dev_get_drvdata(dev);
86 int temp, ret;
87
88 ret = ds->drv->get_temp(ds, &temp);
89 if (ret < 0)
90 return ret;
91
92 return sprintf(buf, "%d\n", temp * 1000);
93}
94static DEVICE_ATTR_RO(temp1_input);
95
96static ssize_t temp1_max_show(struct device *dev,
97 struct device_attribute *attr, char *buf)
98{
99 struct dsa_switch *ds = dev_get_drvdata(dev);
100 int temp, ret;
101
102 ret = ds->drv->get_temp_limit(ds, &temp);
103 if (ret < 0)
104 return ret;
105
106 return sprintf(buf, "%d\n", temp * 1000);
107}
108
109static ssize_t temp1_max_store(struct device *dev,
110 struct device_attribute *attr, const char *buf,
111 size_t count)
112{
113 struct dsa_switch *ds = dev_get_drvdata(dev);
114 int temp, ret;
115
116 ret = kstrtoint(buf, 0, &temp);
117 if (ret < 0)
118 return ret;
119
120 ret = ds->drv->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
121 if (ret < 0)
122 return ret;
123
124 return count;
125}
126static DEVICE_ATTR(temp1_max, S_IRUGO, temp1_max_show, temp1_max_store);
127
128static ssize_t temp1_max_alarm_show(struct device *dev,
129 struct device_attribute *attr, char *buf)
130{
131 struct dsa_switch *ds = dev_get_drvdata(dev);
132 bool alarm;
133 int ret;
134
135 ret = ds->drv->get_temp_alarm(ds, &alarm);
136 if (ret < 0)
137 return ret;
138
139 return sprintf(buf, "%d\n", alarm);
140}
141static DEVICE_ATTR_RO(temp1_max_alarm);
142
143static struct attribute *dsa_hwmon_attrs[] = {
144 &dev_attr_temp1_input.attr, /* 0 */
145 &dev_attr_temp1_max.attr, /* 1 */
146 &dev_attr_temp1_max_alarm.attr, /* 2 */
147 NULL
148};
149
150static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj,
151 struct attribute *attr, int index)
152{
153 struct device *dev = container_of(kobj, struct device, kobj);
154 struct dsa_switch *ds = dev_get_drvdata(dev);
155 struct dsa_switch_driver *drv = ds->drv;
156 umode_t mode = attr->mode;
157
158 if (index == 1) {
159 if (!drv->get_temp_limit)
160 mode = 0;
161 else if (drv->set_temp_limit)
162 mode |= S_IWUSR;
163 } else if (index == 2 && !drv->get_temp_alarm) {
164 mode = 0;
165 }
166 return mode;
167}
168
169static const struct attribute_group dsa_hwmon_group = {
170 .attrs = dsa_hwmon_attrs,
171 .is_visible = dsa_hwmon_attrs_visible,
172};
173__ATTRIBUTE_GROUPS(dsa_hwmon);
174
175#endif /* CONFIG_NET_DSA_HWMON */
74 176
75/* basic switch operations **************************************************/ 177/* basic switch operations **************************************************/
76static struct dsa_switch * 178static struct dsa_switch *
@@ -225,6 +327,31 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
225 ds->ports[i] = slave_dev; 327 ds->ports[i] = slave_dev;
226 } 328 }
227 329
330#ifdef CONFIG_NET_DSA_HWMON
331 /* If the switch provides a temperature sensor,
332 * register with hardware monitoring subsystem.
333 * Treat registration error as non-fatal and ignore it.
334 */
335 if (drv->get_temp) {
336 const char *netname = netdev_name(dst->master_netdev);
337 char hname[IFNAMSIZ + 1];
338 int i, j;
339
340 /* Create valid hwmon 'name' attribute */
341 for (i = j = 0; i < IFNAMSIZ && netname[i]; i++) {
342 if (isalnum(netname[i]))
343 hname[j++] = netname[i];
344 }
345 hname[j] = '\0';
346 scnprintf(ds->hwmon_name, sizeof(ds->hwmon_name), "%s_dsa%d",
347 hname, index);
348 ds->hwmon_dev = hwmon_device_register_with_groups(NULL,
349 ds->hwmon_name, ds, dsa_hwmon_groups);
350 if (IS_ERR(ds->hwmon_dev))
351 ds->hwmon_dev = NULL;
352 }
353#endif /* CONFIG_NET_DSA_HWMON */
354
228 return ds; 355 return ds;
229 356
230out_free: 357out_free:
@@ -236,6 +363,10 @@ out:
236 363
237static void dsa_switch_destroy(struct dsa_switch *ds) 364static void dsa_switch_destroy(struct dsa_switch *ds)
238{ 365{
366#ifdef CONFIG_NET_DSA_HWMON
367 if (ds->hwmon_dev)
368 hwmon_device_unregister(ds->hwmon_dev);
369#endif
239} 370}
240 371
241#ifdef CONFIG_PM_SLEEP 372#ifdef CONFIG_PM_SLEEP