Skip to content

Commit

Permalink
net: dsa: move HWMON support to its own file
Browse files Browse the repository at this point in the history
Isolate the HWMON support in DSA in its own file. Currently only the
legacy DSA code is concerned.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vivien Didelot authored and David S. Miller committed Jan 8, 2017
1 parent 82e4869 commit 111427f
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 129 deletions.
1 change: 1 addition & 0 deletions net/dsa/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# the core
obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o slave.o dsa2.o
dsa_core-$(CONFIG_NET_DSA_HWMON) += hwmon.o

# tagging formats
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
Expand Down
131 changes: 2 additions & 129 deletions net/dsa/dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
* (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 Down Expand Up @@ -108,105 +106,6 @@ dsa_switch_probe(struct device *parent, struct device *host_dev, int sw_addr,
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->ops->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->ops->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->ops->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
if (ret < 0)
return ret;

return count;
}
static DEVICE_ATTR_RW(temp1_max);

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->ops->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_ops *ops = ds->ops;
umode_t mode = attr->mode;

if (index == 1) {
if (!ops->get_temp_limit)
mode = 0;
else if (!ops->set_temp_limit)
mode &= ~S_IWUSR;
} else if (index == 2 && !ops->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 **************************************************/
int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
struct device_node *port_dn, int port)
Expand Down Expand Up @@ -415,30 +314,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
if (ret)
return ret;

#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 (ops->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 */
dsa_hwmon_register(ds);

return 0;
}
Expand Down Expand Up @@ -498,10 +374,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
{
int port;

#ifdef CONFIG_NET_DSA_HWMON
if (ds->hwmon_dev)
hwmon_device_unregister(ds->hwmon_dev);
#endif
dsa_hwmon_unregister(ds);

/* Destroy network devices for physical switch ports. */
for (port = 0; port < DSA_MAX_PORTS; port++) {
Expand Down
9 changes: 9 additions & 0 deletions net/dsa/dsa_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds);
void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds);

/* hwmon.c */
#ifdef CONFIG_NET_DSA_HWMON
void dsa_hwmon_register(struct dsa_switch *ds);
void dsa_hwmon_unregister(struct dsa_switch *ds);
#else
static inline void dsa_hwmon_register(struct dsa_switch *ds) { }
static inline void dsa_hwmon_unregister(struct dsa_switch *ds) { }
#endif

/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;
void dsa_slave_mii_bus_init(struct dsa_switch *ds);
Expand Down
147 changes: 147 additions & 0 deletions net/dsa/hwmon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* net/dsa/hwmon.c - HWMON subsystem support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <linux/ctype.h>
#include <linux/hwmon.h>
#include <net/dsa.h>

#include "dsa_priv.h"

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->ops->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->ops->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->ops->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
if (ret < 0)
return ret;

return count;
}
static DEVICE_ATTR_RW(temp1_max);

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->ops->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_ops *ops = ds->ops;
umode_t mode = attr->mode;

if (index == 1) {
if (!ops->get_temp_limit)
mode = 0;
else if (!ops->set_temp_limit)
mode &= ~S_IWUSR;
} else if (index == 2 && !ops->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);

void dsa_hwmon_register(struct dsa_switch *ds)
{
const char *netname = netdev_name(ds->dst->master_netdev);
char hname[IFNAMSIZ + 1];
int i, j;

/* If the switch provides temperature accessors, register with hardware
* monitoring subsystem. Treat registration error as non-fatal.
*/
if (!ds->ops->get_temp)
return;

/* 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,
ds->index);
ds->hwmon_dev = hwmon_device_register_with_groups(NULL, ds->hwmon_name,
ds, dsa_hwmon_groups);
if (IS_ERR(ds->hwmon_dev)) {
pr_warn("DSA: failed to register HWMON subsystem for switch %d\n",
ds->index);
ds->hwmon_dev = NULL;
} else {
pr_info("DSA: registered HWMON subsystem for switch %d\n",
ds->index);
}
}

void dsa_hwmon_unregister(struct dsa_switch *ds)
{
if (ds->hwmon_dev) {
hwmon_device_unregister(ds->hwmon_dev);
ds->hwmon_dev = NULL;
}
}

0 comments on commit 111427f

Please sign in to comment.