From f0c24ccf491b09de53cee32114c924551218f2bc Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 17 May 2017 15:46:04 -0400 Subject: net: dsa: include switchdev.h only once DSA drivers and core use switchdev. Include switchdev.h only once, in the dsa.h public header, so that inclusion in DSA drivers or forward declarations of switchdev structures in not necessary anymore. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/dsa/dsa_loop.c') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index a19e1781e9bb..6afab16d13dd 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "dsa_loop.h" -- cgit v1.2.1 From 438ff53739ee523de3755a98ae3a290e69752620 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 17 May 2017 15:46:05 -0400 Subject: net: dsa: use switchdev_obj_dump_cb_t everywhere Now that the DSA public header includes switchdev.h, use the provided switchdev_obj_dump_cb_t typedef for the object dump callback. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/dsa/dsa_loop.c') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 6afab16d13dd..5edf07beb9d2 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -187,7 +187,7 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port, static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; -- cgit v1.2.1 From 23c9ee4934e7a79b49151d0f05c24117d69c73fe Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:12:51 -0400 Subject: net: dsa: remove dev arg of dsa_register_switch The current dsa_register_switch function takes a useless struct device pointer argument, which always equals ds->dev. Drivers either call it with ds->dev, or with the same device pointer passed to dsa_switch_alloc, which ends up being assigned to ds->dev. This patch removes the second argument of the dsa_register_switch and _dsa_register_switch functions. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/dsa/dsa_loop.c') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 5edf07beb9d2..79e62593ff4e 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -271,7 +271,7 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) dev_set_drvdata(&mdiodev->dev, ds); - return dsa_register_switch(ds, ds->dev); + return dsa_register_switch(ds); } static void dsa_loop_drv_remove(struct mdio_device *mdiodev) -- cgit v1.2.1 From 3407dc8ed1a7528e8792c86d9ebc124aa5fa629f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 15 Jun 2017 10:15:52 -0700 Subject: net: dsa: loop: Inline unregister_fixed_phys() This is a simple function that only gets used in the driver's remove function, inline it there. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/net/dsa/dsa_loop.c') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 79e62593ff4e..fb888593c2e9 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -293,15 +293,6 @@ static struct mdio_driver dsa_loop_drv = { #define NUM_FIXED_PHYS (DSA_LOOP_NUM_PORTS - 2) -static void unregister_fixed_phys(void) -{ - unsigned int i; - - for (i = 0; i < NUM_FIXED_PHYS; i++) - if (phydevs[i]) - fixed_phy_unregister(phydevs[i]); -} - static int __init dsa_loop_init(void) { struct fixed_phy_status status = { @@ -320,8 +311,12 @@ module_init(dsa_loop_init); static void __exit dsa_loop_exit(void) { + unsigned int i; + mdio_driver_unregister(&dsa_loop_drv); - unregister_fixed_phys(); + for (i = 0; i < NUM_FIXED_PHYS; i++) + if (phydevs[i]) + fixed_phy_unregister(phydevs[i]); } module_exit(dsa_loop_exit); -- cgit v1.2.1 From 484c01720d84c65e996a6adc4ba8ce6a811879df Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 15 Jun 2017 10:15:53 -0700 Subject: net: dsa: loop: Implement ethtool statistics When a DSA driver implements ethtool statistics, we also override the master network device's ethtool statistics with the CPU port's statistics and this has proven to be a possible source of bugs in the past. Enhance the dsa_loop.c driver to provide statistics under the forme of ok/error reads and writes from the per-port PHY read/writes. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa/dsa_loop.c') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index fb888593c2e9..fdd8f3872102 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,30 @@ struct dsa_loop_vlan { u16 untagged; }; +struct dsa_loop_mib_entry { + char name[ETH_GSTRING_LEN]; + unsigned long val; +}; + +enum dsa_loop_mib_counters { + DSA_LOOP_PHY_READ_OK, + DSA_LOOP_PHY_READ_ERR, + DSA_LOOP_PHY_WRITE_OK, + DSA_LOOP_PHY_WRITE_ERR, + __DSA_LOOP_CNT_MAX, +}; + +static struct dsa_loop_mib_entry dsa_loop_mibs[] = { + [DSA_LOOP_PHY_READ_OK] = { "phy_read_ok", }, + [DSA_LOOP_PHY_READ_ERR] = { "phy_read_err", }, + [DSA_LOOP_PHY_WRITE_OK] = { "phy_write_ok", }, + [DSA_LOOP_PHY_WRITE_ERR] = { "phy_write_err", }, +}; + +struct dsa_loop_port { + struct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX]; +}; + #define DSA_LOOP_VLANS 5 struct dsa_loop_priv { @@ -33,6 +58,7 @@ struct dsa_loop_priv { unsigned int port_base; struct dsa_loop_vlan vlans[DSA_LOOP_VLANS]; struct net_device *netdev; + struct dsa_loop_port ports[DSA_MAX_PORTS]; u16 pvid; }; @@ -47,11 +73,43 @@ static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds) static int dsa_loop_setup(struct dsa_switch *ds) { + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < ds->num_ports; i++) + memcpy(ps->ports[i].mib, dsa_loop_mibs, + sizeof(dsa_loop_mibs)); + dev_dbg(ds->dev, "%s\n", __func__); return 0; } +static int dsa_loop_get_sset_count(struct dsa_switch *ds) +{ + return __DSA_LOOP_CNT_MAX; +} + +static void dsa_loop_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +{ + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) + memcpy(data + i * ETH_GSTRING_LEN, + ps->ports[port].mib[i].name, ETH_GSTRING_LEN); +} + +static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +{ + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) + data[i] = ps->ports[port].mib[i].val; +} + static int dsa_loop_set_addr(struct dsa_switch *ds, u8 *addr) { dev_dbg(ds->dev, "%s\n", __func__); @@ -63,10 +121,17 @@ static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum) { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; + int ret; dev_dbg(ds->dev, "%s\n", __func__); - return mdiobus_read_nested(bus, ps->port_base + port, regnum); + ret = mdiobus_read_nested(bus, ps->port_base + port, regnum); + if (ret < 0) + ps->ports[port].mib[DSA_LOOP_PHY_READ_ERR].val++; + else + ps->ports[port].mib[DSA_LOOP_PHY_READ_OK].val++; + + return ret; } static int dsa_loop_phy_write(struct dsa_switch *ds, int port, @@ -74,10 +139,17 @@ static int dsa_loop_phy_write(struct dsa_switch *ds, int port, { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; + int ret; dev_dbg(ds->dev, "%s\n", __func__); - return mdiobus_write_nested(bus, ps->port_base + port, regnum, value); + ret = mdiobus_write_nested(bus, ps->port_base + port, regnum, value); + if (ret < 0) + ps->ports[port].mib[DSA_LOOP_PHY_WRITE_ERR].val++; + else + ps->ports[port].mib[DSA_LOOP_PHY_WRITE_OK].val++; + + return ret; } static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port, @@ -225,6 +297,9 @@ static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port, static struct dsa_switch_ops dsa_loop_driver = { .get_tag_protocol = dsa_loop_get_protocol, .setup = dsa_loop_setup, + .get_strings = dsa_loop_get_strings, + .get_ethtool_stats = dsa_loop_get_ethtool_stats, + .get_sset_count = dsa_loop_get_sset_count, .set_addr = dsa_loop_set_addr, .phy_read = dsa_loop_phy_read, .phy_write = dsa_loop_phy_write, -- cgit v1.2.1