From ab3d408d3f40f939d46a32b1c24aa2833a13b846 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 8 Jan 2017 14:52:07 -0800 Subject: net: dsa: Encapsulate legacy switch drivers into dsa_switch_driver In preparation for making struct dsa_switch_ops const, encapsulate it within a dsa_switch_driver which has a list pointer and a pointer to dsa_switch_ops. This allows us to take the list_head pointer out of dsa_switch_ops, which is written to by {un,}register_switch_driver. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index b122196d5a1f..edfa9b130953 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -240,8 +240,6 @@ struct switchdev_obj_port_mdb; struct switchdev_obj_port_vlan; struct dsa_switch_ops { - struct list_head list; - /* * Probing and setup. */ @@ -390,8 +388,13 @@ struct dsa_switch_ops { int (*cb)(struct switchdev_obj *obj)); }; -void register_switch_driver(struct dsa_switch_ops *type); -void unregister_switch_driver(struct dsa_switch_ops *type); +struct dsa_switch_driver { + struct list_head list; + struct dsa_switch_ops *ops; +}; + +void register_switch_driver(struct dsa_switch_driver *type); +void unregister_switch_driver(struct dsa_switch_driver *type); struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev); static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) -- cgit v1.2.3-59-g8ed1b From a82f67afe8e297834bedafa529941d9d0808caf8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 8 Jan 2017 14:52:08 -0800 Subject: net: dsa: Make dsa_switch_ops const Now that we have properly encapsulated and made drivers utilize exported functions, we can switch dsa_switch_ops to be a annotated with const. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 2 +- drivers/net/dsa/bcm_sf2.c | 2 +- drivers/net/dsa/mv88e6060.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/qca8k.c | 2 +- include/net/dsa.h | 4 ++-- net/dsa/dsa.c | 10 +++++----- net/dsa/hwmon.c | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index a448661b55c6..5102a3701a1a 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1453,7 +1453,7 @@ static enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds) return DSA_TAG_PROTO_NONE; } -static struct dsa_switch_ops b53_switch_ops = { +static const struct dsa_switch_ops b53_switch_ops = { .get_tag_protocol = b53_get_tag_protocol, .setup = b53_setup, .get_strings = b53_get_strings, diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 52027718d06f..31d017086f8b 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -977,7 +977,7 @@ static struct b53_io_ops bcm_sf2_io_ops = { .write64 = bcm_sf2_core_write64, }; -static struct dsa_switch_ops bcm_sf2_ops = { +static const struct dsa_switch_ops bcm_sf2_ops = { .get_tag_protocol = bcm_sf2_sw_get_tag_protocol, .setup = bcm_sf2_sw_setup, .get_strings = b53_get_strings, diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index bcbd6dcbd8e8..5934b7a4c448 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -252,7 +252,7 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) return reg_write(ds, addr, regnum, val); } -static struct dsa_switch_ops mv88e6060_switch_ops = { +static const struct dsa_switch_ops mv88e6060_switch_ops = { .get_tag_protocol = mv88e6060_get_tag_protocol, .probe = mv88e6060_drv_probe, .setup = mv88e6060_setup, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d43d12c281b3..eea8e0176e33 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4361,7 +4361,7 @@ static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port, return err; } -static struct dsa_switch_ops mv88e6xxx_switch_ops = { +static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .probe = mv88e6xxx_drv_probe, .get_tag_protocol = mv88e6xxx_get_tag_protocol, .setup = mv88e6xxx_setup, diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index b3df70d07ff6..54d270d59eb0 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -911,7 +911,7 @@ qca8k_get_tag_protocol(struct dsa_switch *ds) return DSA_TAG_PROTO_QCA; } -static struct dsa_switch_ops qca8k_switch_ops = { +static const struct dsa_switch_ops qca8k_switch_ops = { .get_tag_protocol = qca8k_get_tag_protocol, .setup = qca8k_setup, .get_strings = qca8k_get_strings, diff --git a/include/net/dsa.h b/include/net/dsa.h index edfa9b130953..b94d1f2ef912 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -169,7 +169,7 @@ struct dsa_switch { /* * The switch operations. */ - struct dsa_switch_ops *ops; + const struct dsa_switch_ops *ops; /* * An array of which element [a] indicates which port on this @@ -390,7 +390,7 @@ struct dsa_switch_ops { struct dsa_switch_driver { struct list_head list; - struct dsa_switch_ops *ops; + const struct dsa_switch_ops *ops; }; void register_switch_driver(struct dsa_switch_driver *type); diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 4e7bc57cdae5..fd532487dfdf 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -76,11 +76,11 @@ void unregister_switch_driver(struct dsa_switch_driver *drv) } EXPORT_SYMBOL_GPL(unregister_switch_driver); -static struct dsa_switch_ops * +static const struct dsa_switch_ops * dsa_switch_probe(struct device *parent, struct device *host_dev, int sw_addr, const char **_name, void **priv) { - struct dsa_switch_ops *ret; + const struct dsa_switch_ops *ret; struct list_head *list; const char *name; @@ -89,7 +89,7 @@ dsa_switch_probe(struct device *parent, struct device *host_dev, int sw_addr, mutex_lock(&dsa_switch_drivers_mutex); list_for_each(list, &dsa_switch_drivers) { - struct dsa_switch_ops *ops; + const struct dsa_switch_ops *ops; struct dsa_switch_driver *drv; drv = list_entry(list, struct dsa_switch_driver, list); @@ -207,7 +207,7 @@ void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds) static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { - struct dsa_switch_ops *ops = ds->ops; + const struct dsa_switch_ops *ops = ds->ops; struct dsa_switch_tree *dst = ds->dst; struct dsa_chip_data *cd = ds->cd; bool valid_name_found = false; @@ -326,7 +326,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, struct device *parent, struct device *host_dev) { struct dsa_chip_data *cd = dst->pd->chip + index; - struct dsa_switch_ops *ops; + const struct dsa_switch_ops *ops; struct dsa_switch *ds; int ret; const char *name; diff --git a/net/dsa/hwmon.c b/net/dsa/hwmon.c index 3a9cdf0b22b8..08831a811278 100644 --- a/net/dsa/hwmon.c +++ b/net/dsa/hwmon.c @@ -86,7 +86,7 @@ static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct dsa_switch *ds = dev_get_drvdata(dev); - struct dsa_switch_ops *ops = ds->ops; + const struct dsa_switch_ops *ops = ds->ops; umode_t mode = attr->mode; if (index == 1) { -- cgit v1.2.3-59-g8ed1b From b22de490869da354116ea4cbbaa09dcbc260b2b4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 17 Jan 2017 20:41:38 -0500 Subject: net: dsa: store CPU switch structure in the tree Store a dsa_switch pointer to the CPU switch in the tree instead of only its index. This avoids the need to initialize it to -1. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 8 ++++---- net/dsa/dsa.c | 7 +++---- net/dsa/dsa2.c | 5 ++--- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index b94d1f2ef912..c72ed7af2a2a 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -124,7 +124,7 @@ struct dsa_switch_tree { /* * The switch and port to which the CPU is attached. */ - s8 cpu_switch; + struct dsa_switch *cpu_switch; s8 cpu_port; /* @@ -204,7 +204,7 @@ struct dsa_switch { static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) { - return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); + return !!(ds == ds->dst->cpu_switch && p == ds->dst->cpu_port); } static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p) @@ -227,10 +227,10 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds) * Else return the (DSA) port number that connects to the * switch that is one hop closer to the cpu. */ - if (dst->cpu_switch == ds->index) + if (dst->cpu_switch == ds) return dst->cpu_port; else - return ds->rtable[dst->cpu_switch]; + return ds->rtable[dst->cpu_switch->index]; } struct switchdev_trans; diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index fd532487dfdf..b220609cfe6f 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -225,12 +225,12 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) continue; if (!strcmp(name, "cpu")) { - if (dst->cpu_switch != -1) { + if (!dst->cpu_switch) { netdev_err(dst->master_netdev, "multiple cpu ports?!\n"); return -EINVAL; } - dst->cpu_switch = index; + dst->cpu_switch = ds; dst->cpu_port = i; ds->cpu_port_mask |= 1 << i; } else if (!strcmp(name, "dsa")) { @@ -254,7 +254,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) * tagging protocol to the preferred tagging format of this * switch. */ - if (dst->cpu_switch == index) { + if (dst->cpu_switch == ds) { enum dsa_tag_protocol tag_protocol; tag_protocol = ops->get_tag_protocol(ds); @@ -757,7 +757,6 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, dst->pd = pd; dst->master_netdev = dev; - dst->cpu_switch = -1; dst->cpu_port = -1; for (i = 0; i < pd->nr_chips; i++) { diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 42a41d84053c..020e072b4299 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -57,7 +57,6 @@ static struct dsa_switch_tree *dsa_add_dst(u32 tree) if (!dst) return NULL; dst->tree = tree; - dst->cpu_switch = -1; INIT_LIST_HEAD(&dst->list); list_add_tail(&dsa_switch_trees, &dst->list); kref_init(&dst->refcount); @@ -448,8 +447,8 @@ static int dsa_cpu_parse(struct device_node *port, u32 index, if (!dst->master_netdev) dst->master_netdev = ethernet_dev; - if (dst->cpu_switch == -1) { - dst->cpu_switch = ds->index; + if (!dst->cpu_switch) { + dst->cpu_switch = ds; dst->cpu_port = index; } -- cgit v1.2.3-59-g8ed1b From cf1a56a4cf196a2922e66e9a8e0bf80d324c5548 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 20 Jan 2017 01:37:50 +0100 Subject: net: dsa: Remove hwmon support Only the Marvell mv88e6xxx DSA driver made use of the HWMON support in DSA. The temperature sensor registers are actually in the embedded PHYs, and the PHY driver now supports it. So remove all HWMON support from DSA and drivers. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 154 ---------------------------------- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 16 ---- include/net/dsa.h | 8 -- net/dsa/Kconfig | 11 --- net/dsa/Makefile | 1 - net/dsa/dsa.c | 4 - net/dsa/dsa_priv.h | 9 -- net/dsa/hwmon.c | 147 -------------------------------- 8 files changed, 350 deletions(-) delete mode 100644 net/dsa/hwmon.c (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 987b2dbbd35a..c7e08e13bb54 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2964,154 +2964,6 @@ static void mv88e6xxx_mdio_unregister(struct mv88e6xxx_chip *chip) of_node_put(chip->mdio_np); } -#ifdef CONFIG_NET_DSA_HWMON - -static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_chip *chip = ds->priv; - u16 val; - int ret; - - *temp = 0; - - mutex_lock(&chip->reg_lock); - - ret = mv88e6xxx_phy_write(chip, 0x0, 0x16, 0x6); - if (ret < 0) - goto error; - - /* Enable temperature sensor */ - ret = mv88e6xxx_phy_read(chip, 0x0, 0x1a, &val); - if (ret < 0) - goto error; - - ret = mv88e6xxx_phy_write(chip, 0x0, 0x1a, val | (1 << 5)); - if (ret < 0) - goto error; - - /* Wait for temperature to stabilize */ - usleep_range(10000, 12000); - - ret = mv88e6xxx_phy_read(chip, 0x0, 0x1a, &val); - if (ret < 0) - goto error; - - /* Disable temperature sensor */ - ret = mv88e6xxx_phy_write(chip, 0x0, 0x1a, val & ~(1 << 5)); - if (ret < 0) - goto error; - - *temp = ((val & 0x1f) - 5) * 5; - -error: - mv88e6xxx_phy_write(chip, 0x0, 0x16, 0x0); - mutex_unlock(&chip->reg_lock); - return ret; -} - -static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int phy = mv88e6xxx_6320_family(chip) ? 3 : 0; - u16 val; - int ret; - - *temp = 0; - - mutex_lock(&chip->reg_lock); - ret = mv88e6xxx_phy_page_read(chip, phy, 6, 27, &val); - mutex_unlock(&chip->reg_lock); - if (ret < 0) - return ret; - - *temp = (val & 0xff) - 25; - - return 0; -} - -static int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_chip *chip = ds->priv; - - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP)) - return -EOPNOTSUPP; - - if (mv88e6xxx_6320_family(chip) || mv88e6xxx_6352_family(chip)) - return mv88e63xx_get_temp(ds, temp); - - return mv88e61xx_get_temp(ds, temp); -} - -static int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int phy = mv88e6xxx_6320_family(chip) ? 3 : 0; - u16 val; - int ret; - - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT)) - return -EOPNOTSUPP; - - *temp = 0; - - mutex_lock(&chip->reg_lock); - ret = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val); - mutex_unlock(&chip->reg_lock); - if (ret < 0) - return ret; - - *temp = (((val >> 8) & 0x1f) * 5) - 25; - - return 0; -} - -static int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int phy = mv88e6xxx_6320_family(chip) ? 3 : 0; - u16 val; - int err; - - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT)) - return -EOPNOTSUPP; - - mutex_lock(&chip->reg_lock); - err = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val); - if (err) - goto unlock; - temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - err = mv88e6xxx_phy_page_write(chip, phy, 6, 26, - (val & 0xe0ff) | (temp << 8)); -unlock: - mutex_unlock(&chip->reg_lock); - - return err; -} - -static int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int phy = mv88e6xxx_6320_family(chip) ? 3 : 0; - u16 val; - int ret; - - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_TEMP_LIMIT)) - return -EOPNOTSUPP; - - *alarm = false; - - mutex_lock(&chip->reg_lock); - ret = mv88e6xxx_phy_page_read(chip, phy, 6, 26, &val); - mutex_unlock(&chip->reg_lock); - if (ret < 0) - return ret; - - *alarm = !!(val & 0x40); - - return 0; -} -#endif /* CONFIG_NET_DSA_HWMON */ - static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) { struct mv88e6xxx_chip *chip = ds->priv; @@ -4386,12 +4238,6 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_sset_count = mv88e6xxx_get_sset_count, .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, -#ifdef CONFIG_NET_DSA_HWMON - .get_temp = mv88e6xxx_get_temp, - .get_temp_limit = mv88e6xxx_get_temp_limit, - .set_temp_limit = mv88e6xxx_set_temp_limit, - .get_temp_alarm = mv88e6xxx_get_temp_alarm, -#endif .get_eeprom_len = mv88e6xxx_get_eeprom_len, .get_eeprom = mv88e6xxx_get_eeprom, .set_eeprom = mv88e6xxx_set_eeprom, diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 466cfdadb7bd..ce8b43b14e96 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -497,12 +497,6 @@ enum mv88e6xxx_cap { */ MV88E6XXX_CAP_STU, - /* Internal temperature sensor. - * Available from any enabled port's PHY register 26, page 6. - */ - MV88E6XXX_CAP_TEMP, - MV88E6XXX_CAP_TEMP_LIMIT, - /* VLAN Table Unit. * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. */ @@ -533,8 +527,6 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) #define MV88E6XXX_FLAG_STU BIT_ULL(MV88E6XXX_CAP_STU) -#define MV88E6XXX_FLAG_TEMP BIT_ULL(MV88E6XXX_CAP_TEMP) -#define MV88E6XXX_FLAG_TEMP_LIMIT BIT_ULL(MV88E6XXX_CAP_TEMP_LIMIT) #define MV88E6XXX_FLAG_VTU BIT_ULL(MV88E6XXX_CAP_VTU) /* Ingress Rate Limit unit */ @@ -586,7 +578,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ @@ -605,8 +596,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ @@ -621,7 +610,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ @@ -637,8 +625,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ @@ -651,8 +637,6 @@ struct mv88e6xxx_ops; (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_STU | \ - MV88E6XXX_FLAG_TEMP | \ - MV88E6XXX_FLAG_TEMP_LIMIT | \ MV88E6XXX_FLAG_VTU | \ MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP | \ diff --git a/include/net/dsa.h b/include/net/dsa.h index c72ed7af2a2a..9d6cd923c48c 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -307,14 +307,6 @@ struct dsa_switch_ops { 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 - /* EEPROM access */ int (*get_eeprom_len)(struct dsa_switch *ds); int (*get_eeprom)(struct dsa_switch *ds, diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 39bb5b3a82f2..9649238eef40 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -15,17 +15,6 @@ 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 diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 560b6747c276..a3380ed0e0be 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -1,7 +1,6 @@ # 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 diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 91f96e1bd2ec..77cb78767f1d 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -316,8 +316,6 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) if (ret) return ret; - dsa_hwmon_register(ds); - return 0; } @@ -376,8 +374,6 @@ static void dsa_switch_destroy(struct dsa_switch *ds) { int port; - dsa_hwmon_unregister(ds); - /* Destroy network devices for physical switch ports. */ for (port = 0; port < DSA_MAX_PORTS; port++) { if (!(ds->enabled_port_mask & (1 << port))) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 7e3385ec73f4..63ae1484abae 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -56,15 +56,6 @@ 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); diff --git a/net/dsa/hwmon.c b/net/dsa/hwmon.c deleted file mode 100644 index 08831a811278..000000000000 --- a/net/dsa/hwmon.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 -#include -#include - -#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); - const 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; - } -} -- cgit v1.2.3-59-g8ed1b From 434502930f59995f37fcc2c02cab79e059fb5043 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 25 Jan 2017 15:04:17 +0100 Subject: net: dsa: Mop up remaining NET_DSA_HWMON references Previous patches have moved the temperature sensor code into the Marvell PHYs. A few now dead references to NET_DSA_HWMON were left behind. Go reap them. Reported-by: Valentin Rothberg Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- Documentation/networking/dsa/dsa.txt | 24 ------------------------ include/net/dsa.h | 8 -------- 2 files changed, 32 deletions(-) (limited to 'include/net/dsa.h') diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt index 63912ef34606..b8b40753133e 100644 --- a/Documentation/networking/dsa/dsa.txt +++ b/Documentation/networking/dsa/dsa.txt @@ -295,7 +295,6 @@ DSA currently leverages the following subsystems: - MDIO/PHY library: drivers/net/phy/phy.c, mdio_bus.c - Switchdev: net/switchdev/* - Device Tree for various of_* functions -- HWMON: drivers/hwmon/* MDIO/PHY library ---------------- @@ -349,12 +348,6 @@ Documentation/devicetree/bindings/net/dsa/dsa.txt. PHY/MDIO library helper functions such as of_get_phy_mode(), of_phy_connect() are also used to query per-port PHY specific details: interface connection, MDIO bus location etc.. -HWMON ------ - -Some switch drivers feature internal temperature sensors which are exposed as -regular HWMON devices in /sys/class/hwmon/. - Driver development ================== @@ -495,23 +488,6 @@ Power management BR_STATE_DISABLED and propagating changes to the hardware if this port is disabled while being a bridge member -Hardware monitoring -------------------- - -These callbacks are only available if CONFIG_NET_DSA_HWMON is enabled: - -- get_temp: this function queries the given switch for its temperature - -- get_temp_limit: this function returns the switch current maximum temperature - limit - -- set_temp_limit: this function configures the maximum temperature limit allowed - -- get_temp_alarm: this function returns the critical temperature threshold - returning an alarm notification - -See Documentation/hwmon/sysfs-interface for details. - Bridge layer ------------ diff --git a/include/net/dsa.h b/include/net/dsa.h index 9d6cd923c48c..08b340403927 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -178,14 +178,6 @@ struct dsa_switch { */ s8 rtable[DSA_MAX_SWITCHES]; -#ifdef CONFIG_NET_DSA_HWMON - /* - * Hardware monitoring information - */ - char hwmon_name[IFNAMSIZ + 8]; - struct device *hwmon_dev; -#endif - /* * The lower device this switch uses to talk to the host */ -- cgit v1.2.3-59-g8ed1b From 55ed0ce0898e15fec30d2ca2a563d7934b082375 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 26 Jan 2017 10:45:51 -0800 Subject: net: dsa: Pass device pointer to dsa_register_switch In preparation for allowing dsa_register_switch() to be supplied with device/platform data, pass down a struct device pointer instead of a struct device_node. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 7 +++---- drivers/net/dsa/qca8k.c | 2 +- include/net/dsa.h | 2 +- net/dsa/dsa2.c | 7 ++++--- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 5cbb14f6a03b..bb210b12ad1b 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1894,7 +1894,7 @@ int b53_switch_register(struct b53_device *dev) pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); - return dsa_register_switch(dev->ds, dev->ds->dev->of_node); + return dsa_register_switch(dev->ds, dev->ds->dev); } EXPORT_SYMBOL(b53_switch_register); diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5668e778ed1d..921e53351786 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4356,8 +4356,7 @@ static struct dsa_switch_driver mv88e6xxx_switch_drv = { .ops = &mv88e6xxx_switch_ops, }; -static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip, - struct device_node *np) +static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) { struct device *dev = chip->dev; struct dsa_switch *ds; @@ -4372,7 +4371,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip, dev_set_drvdata(dev, ds); - return dsa_register_switch(ds, np); + return dsa_register_switch(ds, dev); } static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) @@ -4456,7 +4455,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (err) goto out_g2_irq; - err = mv88e6xxx_register_switch(chip, np); + err = mv88e6xxx_register_switch(chip); if (err) goto out_mdio; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 54d270d59eb0..c084aa484d2b 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -964,7 +964,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); - return dsa_register_switch(priv->ds, priv->ds->dev->of_node); + return dsa_register_switch(priv->ds, &mdiodev->dev); } static void diff --git a/include/net/dsa.h b/include/net/dsa.h index 08b340403927..92fd795e9573 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -387,7 +387,7 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) } void dsa_unregister_switch(struct dsa_switch *ds); -int dsa_register_switch(struct dsa_switch *ds, struct device_node *np); +int dsa_register_switch(struct dsa_switch *ds, struct device *dev); #ifdef CONFIG_PM_SLEEP int dsa_switch_suspend(struct dsa_switch *ds); int dsa_switch_resume(struct dsa_switch *ds); diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 866222a8f9bf..2cf489c5e90f 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -578,8 +578,9 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds, return ports; } -static int _dsa_register_switch(struct dsa_switch *ds, struct device_node *np) +static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev) { + struct device_node *np = dev->of_node; struct device_node *ports = dsa_get_ports(ds, np); struct dsa_switch_tree *dst; u32 tree, index; @@ -659,12 +660,12 @@ out: return err; } -int dsa_register_switch(struct dsa_switch *ds, struct device_node *np) +int dsa_register_switch(struct dsa_switch *ds, struct device *dev) { int err; mutex_lock(&dsa2_mutex); - err = _dsa_register_switch(ds, np); + err = _dsa_register_switch(ds, dev); mutex_unlock(&dsa2_mutex); return err; -- cgit v1.2.3-59-g8ed1b From a0c02161ecfc2f40a0837926efac5376bc6fd6d3 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 27 Jan 2017 15:29:36 -0500 Subject: net: dsa: variable number of ports Change the ports[DSA_MAX_PORTS] array of the dsa_switch structure for a zero-length array, allocated at the same time as the dsa_switch structure itself. A dsa_switch_alloc() helper is provided for that. This commit brings no functional change yet since we pass DSA_MAX_PORTS as the number of ports for the moment. Future patches can update the DSA drivers separately to support dynamic number of ports. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 7 ++++--- drivers/net/dsa/mv88e6xxx/chip.c | 3 +-- drivers/net/dsa/qca8k.c | 3 +-- include/net/dsa.h | 6 +++++- net/dsa/dsa.c | 5 ++--- net/dsa/dsa2.c | 16 ++++++++++++++++ 6 files changed, 29 insertions(+), 11 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index bb210b12ad1b..31afc4d4b68b 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1790,14 +1790,15 @@ struct b53_device *b53_switch_alloc(struct device *base, struct dsa_switch *ds; struct b53_device *dev; - ds = devm_kzalloc(base, sizeof(*ds) + sizeof(*dev), GFP_KERNEL); + ds = dsa_switch_alloc(base, DSA_MAX_PORTS); if (!ds) return NULL; - dev = (struct b53_device *)(ds + 1); + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; ds->priv = dev; - ds->dev = base; dev->dev = base; dev->ds = ds; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 921e53351786..cb7b24748336 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4361,11 +4361,10 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) struct device *dev = chip->dev; struct dsa_switch *ds; - ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); + ds = dsa_switch_alloc(dev, DSA_MAX_PORTS); if (!ds) return -ENOMEM; - ds->dev = dev; ds->priv = chip; ds->ops = &mv88e6xxx_switch_ops; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index c084aa484d2b..f67c6a3cebff 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -954,12 +954,11 @@ qca8k_sw_probe(struct mdio_device *mdiodev) if (id != QCA8K_ID_QCA8337) return -ENODEV; - priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); + priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); if (!priv->ds) return -ENOMEM; priv->ds->priv = priv; - priv->ds->dev = &mdiodev->dev; priv->ds->ops = &qca8k_switch_ops; mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); diff --git a/include/net/dsa.h b/include/net/dsa.h index 92fd795e9573..24e1d935ae68 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -190,8 +190,11 @@ struct dsa_switch { u32 cpu_port_mask; u32 enabled_port_mask; u32 phys_mii_mask; - struct dsa_port ports[DSA_MAX_PORTS]; struct mii_bus *slave_mii_bus; + + /* Dynamically allocated ports, keep last */ + size_t num_ports; + struct dsa_port ports[]; }; static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) @@ -386,6 +389,7 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) return dst->rcv != NULL; } +struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n); void dsa_unregister_switch(struct dsa_switch *ds); int dsa_register_switch(struct dsa_switch *ds, struct device *dev); #ifdef CONFIG_PM_SLEEP diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 07e863369e04..de3ffb421ee4 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -347,8 +347,8 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, /* * Allocate and initialise switch state. */ - ds = devm_kzalloc(parent, sizeof(*ds), GFP_KERNEL); - if (ds == NULL) + ds = dsa_switch_alloc(parent, DSA_MAX_PORTS); + if (!ds) return ERR_PTR(-ENOMEM); ds->dst = dst; @@ -356,7 +356,6 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, ds->cd = cd; ds->ops = ops; ds->priv = priv; - ds->dev = parent; ret = dsa_switch_setup_one(ds, parent); if (ret) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 75f5d1f8554b..4b3a44bec5c8 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -666,6 +666,22 @@ out: return err; } +struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n) +{ + size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port); + struct dsa_switch *ds; + + ds = devm_kzalloc(dev, size, GFP_KERNEL); + if (!ds) + return NULL; + + ds->dev = dev; + ds->num_ports = n; + + return ds; +} +EXPORT_SYMBOL_GPL(dsa_switch_alloc); + int dsa_register_switch(struct dsa_switch *ds, struct device *dev) { int err; -- cgit v1.2.3-59-g8ed1b From 818be8489d6fc8f4cc2c7699bbfd8e1983080f10 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 27 Jan 2017 15:29:38 -0500 Subject: net: dsa: add ds and index to dsa_port Add the physical switch instance and port index a DSA port belongs to to the dsa_port structure. That can be used later to retrieve information about a physical port when configuring a switch fabric, or lighten up struct dsa_slave_priv. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 2 ++ net/dsa/dsa2.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 24e1d935ae68..6bd1f8b05dbd 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -140,6 +140,8 @@ struct dsa_switch_tree { }; struct dsa_port { + struct dsa_switch *ds; + unsigned int index; struct net_device *netdev; struct device_node *dn; unsigned int ageing_time; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 6e7b3e88b778..9f8cc26be9ea 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -670,6 +670,7 @@ struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n) { size_t size = sizeof(struct dsa_switch) + n * sizeof(struct dsa_port); struct dsa_switch *ds; + int i; ds = devm_kzalloc(dev, size, GFP_KERNEL); if (!ds) @@ -678,6 +679,11 @@ struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n) ds->dev = dev; ds->num_ports = n; + for (i = 0; i < ds->num_ports; ++i) { + ds->ports[i].index = i; + ds->ports[i].ds = ds; + } + return ds; } EXPORT_SYMBOL_GPL(dsa_switch_alloc); -- cgit v1.2.3-59-g8ed1b From a5e9a02e1f182237ef44eb3919cf4dd45ed4db9b Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 27 Jan 2017 15:29:40 -0500 Subject: net: dsa: move bridge device in dsa_port Move the bridge_dev pointer from dsa_slave_priv to dsa_port so that DSA drivers can access this information and remove the need to cache it. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 1 + net/dsa/dsa_priv.h | 1 - net/dsa/slave.c | 10 +++++----- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 6bd1f8b05dbd..924533fd4425 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -146,6 +146,7 @@ struct dsa_port { struct device_node *dn; unsigned int ageing_time; u8 stp_state; + struct net_device *bridge_dev; }; struct dsa_switch { diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c519bd0e9206..3022f2e42cdc 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -38,7 +38,6 @@ struct dsa_slave_priv { int old_pause; int old_duplex; - struct net_device *bridge_dev; #ifdef CONFIG_NET_POLL_CONTROLLER struct netpoll *netpoll; #endif diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a2f0267c4a3c..cdb1df87e111 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -64,9 +64,9 @@ static int dsa_slave_get_iflink(const struct net_device *dev) return p->dp->ds->dst->master_netdev->ifindex; } -static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) +static inline bool dsa_port_is_bridged(struct dsa_port *dp) { - return !!p->bridge_dev; + return !!dp->bridge_dev; } static void dsa_port_set_stp_state(struct dsa_switch *ds, int port, u8 state) @@ -98,7 +98,7 @@ static int dsa_slave_open(struct net_device *dev) struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->dp->ds->dst->master_netdev; struct dsa_switch *ds = p->dp->ds; - u8 stp_state = dsa_port_is_bridged(p) ? + u8 stp_state = dsa_port_is_bridged(p->dp) ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; int err; @@ -557,7 +557,7 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, struct dsa_switch *ds = p->dp->ds; int ret = -EOPNOTSUPP; - p->bridge_dev = br; + p->dp->bridge_dev = br; if (ds->ops->port_bridge_join) ret = ds->ops->port_bridge_join(ds, p->dp->index, br); @@ -574,7 +574,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev) if (ds->ops->port_bridge_leave) ds->ops->port_bridge_leave(ds, p->dp->index); - p->bridge_dev = NULL; + p->dp->bridge_dev = NULL; /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional -- cgit v1.2.3-59-g8ed1b From f123f2fbedc7c2723ceb050cd88c2ea1d6a8be32 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 27 Jan 2017 15:29:41 -0500 Subject: net: dsa: pass bridge device when a port leaves Upon reception of the NETDEV_CHANGEUPPER, a leaving port is already unbridged, so reflect this by assigning the port's bridge_dev pointer to NULL before calling the port_bridge_leave DSA driver operation. Now that the bridge_dev pointer is exposed to the drivers, reflecting the current state of the DSA switch fabric is necessary for the drivers to adjust their port based VLANs correctly. Pass the bridge device pointer to the port_bridge_leave operation so that drivers have all information to re-program their chips properly, and do not need to cache it anymore. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 2 +- drivers/net/dsa/b53/b53_priv.h | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 3 ++- drivers/net/dsa/qca8k.c | 2 +- include/net/dsa.h | 3 ++- net/dsa/slave.c | 10 +++++----- 6 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 31afc4d4b68b..32fdcf5570c8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1354,7 +1354,7 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge) } EXPORT_SYMBOL(b53_br_join); -void b53_br_leave(struct dsa_switch *ds, int port) +void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; struct net_device *bridge = dev->ports[port].bridge_dev; diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index a8031b382c55..5dafb70e75fc 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -382,7 +382,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data); void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); int b53_get_sset_count(struct dsa_switch *ds); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge); -void b53_br_leave(struct dsa_switch *ds, int port); +void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state); void b53_br_fast_age(struct dsa_switch *ds, int port); int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering); diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index cb7b24748336..8eb0dc063f4e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2343,7 +2343,8 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, return err; } -static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port) +static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *br) { struct mv88e6xxx_chip *chip = ds->priv; struct net_device *bridge = chip->ports[port].bridge_dev; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index f67c6a3cebff..c85b187aa3d9 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -775,7 +775,7 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, } static void -qca8k_port_bridge_leave(struct dsa_switch *ds, int port) +qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; int i; diff --git a/include/net/dsa.h b/include/net/dsa.h index 924533fd4425..b951e2ebda75 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -325,7 +325,8 @@ struct dsa_switch_ops { int (*set_ageing_time)(struct dsa_switch *ds, unsigned int msecs); int (*port_bridge_join)(struct dsa_switch *ds, int port, struct net_device *bridge); - void (*port_bridge_leave)(struct dsa_switch *ds, int port); + void (*port_bridge_leave)(struct dsa_switch *ds, int port, + struct net_device *bridge); void (*port_stp_state_set)(struct dsa_switch *ds, int port, u8 state); void (*port_fast_age)(struct dsa_switch *ds, int port); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index cdb1df87e111..08725286f79d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -565,16 +565,16 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, return ret == -EOPNOTSUPP ? 0 : ret; } -static void dsa_slave_bridge_port_leave(struct net_device *dev) +static void dsa_slave_bridge_port_leave(struct net_device *dev, + struct net_device *br) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; + p->dp->bridge_dev = NULL; if (ds->ops->port_bridge_leave) - ds->ops->port_bridge_leave(ds, p->dp->index); - - p->dp->bridge_dev = NULL; + ds->ops->port_bridge_leave(ds, p->dp->index, br); /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional @@ -1343,7 +1343,7 @@ static int dsa_slave_port_upper_event(struct net_device *dev, if (info->linking) err = dsa_slave_bridge_port_join(dev, upper); else - dsa_slave_bridge_port_leave(dev); + dsa_slave_bridge_port_leave(dev, upper); } break; -- cgit v1.2.3-59-g8ed1b From bf9f26485d232916cdc2257e42831781e1f075e8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Jan 2017 09:48:40 -0800 Subject: net: dsa: Hook {get,set}_rxnfc ethtool operations In preparation for adding support for CFP/TCAMP in the bcm_sf2 driver add the plumbing to call into driver specific {get,set}_rxnfc operations. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 8 ++++++++ net/dsa/slave.c | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index b951e2ebda75..d5d618c3de64 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -377,6 +377,14 @@ struct dsa_switch_ops { int (*port_mdb_dump)(struct dsa_switch *ds, int port, struct switchdev_obj_port_mdb *mdb, int (*cb)(struct switchdev_obj *obj)); + + /* + * RXNFC + */ + int (*get_rxnfc)(struct dsa_switch *ds, int port, + struct ethtool_rxnfc *nfc, u32 *rule_locs); + int (*set_rxnfc)(struct dsa_switch *ds, int port, + struct ethtool_rxnfc *nfc); }; struct dsa_switch_driver { diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 08725286f79d..6881889e1a9b 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1002,6 +1002,30 @@ void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) ops->get_strings = dsa_cpu_port_get_strings; } +static int dsa_slave_get_rxnfc(struct net_device *dev, + struct ethtool_rxnfc *nfc, u32 *rule_locs) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->dp->ds; + + if (!ds->ops->get_rxnfc) + return -EOPNOTSUPP; + + return ds->ops->get_rxnfc(ds, p->dp->index, nfc, rule_locs); +} + +static int dsa_slave_set_rxnfc(struct net_device *dev, + struct ethtool_rxnfc *nfc) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->dp->ds; + + if (!ds->ops->set_rxnfc) + return -EOPNOTSUPP; + + return ds->ops->set_rxnfc(ds, p->dp->index, nfc); +} + static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_drvinfo = dsa_slave_get_drvinfo, .get_regs_len = dsa_slave_get_regs_len, @@ -1020,6 +1044,8 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_eee = dsa_slave_get_eee, .get_link_ksettings = dsa_slave_get_link_ksettings, .set_link_ksettings = dsa_slave_set_link_ksettings, + .get_rxnfc = dsa_slave_get_rxnfc, + .set_rxnfc = dsa_slave_set_rxnfc, }; static const struct net_device_ops dsa_slave_netdev_ops = { -- cgit v1.2.3-59-g8ed1b From f50f212749e8a28803af3628acbeb85ee0458ed5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 30 Jan 2017 12:41:40 -0800 Subject: net: dsa: Add plumbing for port mirroring Add necessary plumbing at the slave network device level to have switch drivers implement ndo_setup_tc() and most particularly the cls_matchall classifier. We add support for two switch operations: port_add_mirror and port_del_mirror() which configure, on a per-port basis the mirror parameters requested from the cls_matchall classifier. Code is largely borrowed from the Mellanox Spectrum switch driver. Reviewed-by: Jiri Pirko Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 33 +++++++++++++ net/dsa/dsa_priv.h | 3 ++ net/dsa/slave.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 1 deletion(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index d5d618c3de64..2cb77e64d648 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -20,6 +20,8 @@ #include #include +struct tc_action; + enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = 0, DSA_TAG_PROTO_DSA, @@ -139,6 +141,28 @@ struct dsa_switch_tree { const struct dsa_device_ops *tag_ops; }; +/* TC matchall action types, only mirroring for now */ +enum dsa_port_mall_action_type { + DSA_PORT_MALL_MIRROR, +}; + +/* TC mirroring entry */ +struct dsa_mall_mirror_tc_entry { + u8 to_local_port; + bool ingress; +}; + +/* TC matchall entry */ +struct dsa_mall_tc_entry { + struct list_head list; + unsigned long cookie; + enum dsa_port_mall_action_type type; + union { + struct dsa_mall_mirror_tc_entry mirror; + }; +}; + + struct dsa_port { struct dsa_switch *ds; unsigned int index; @@ -385,6 +409,15 @@ struct dsa_switch_ops { struct ethtool_rxnfc *nfc, u32 *rule_locs); int (*set_rxnfc)(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc); + + /* + * TC integration + */ + int (*port_mirror_add)(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress); + void (*port_mirror_del)(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror); }; struct dsa_switch_driver { diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 3022f2e42cdc..a5509b765fc0 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -41,6 +41,9 @@ struct dsa_slave_priv { #ifdef CONFIG_NET_POLL_CONTROLLER struct netpoll *netpoll; #endif + + /* TC context */ + struct list_head mall_tc_list; }; /* dsa.c */ diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 6881889e1a9b..09fc3e9462c1 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -16,12 +16,17 @@ #include #include #include +#include #include #include +#include +#include #include #include #include "dsa_priv.h" +static bool dsa_slave_dev_check(struct net_device *dev); + /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -995,6 +1000,133 @@ static int dsa_slave_get_phys_port_name(struct net_device *dev, return 0; } +static struct dsa_mall_tc_entry * +dsa_slave_mall_tc_entry_find(struct dsa_slave_priv *p, + unsigned long cookie) +{ + struct dsa_mall_tc_entry *mall_tc_entry; + + list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) + if (mall_tc_entry->cookie == cookie) + return mall_tc_entry; + + return NULL; +} + +static int dsa_slave_add_cls_matchall(struct net_device *dev, + __be16 protocol, + struct tc_cls_matchall_offload *cls, + bool ingress) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_mall_tc_entry *mall_tc_entry; + struct dsa_switch *ds = p->dp->ds; + struct net *net = dev_net(dev); + struct dsa_slave_priv *to_p; + struct net_device *to_dev; + const struct tc_action *a; + int err = -EOPNOTSUPP; + LIST_HEAD(actions); + int ifindex; + + if (!ds->ops->port_mirror_add) + return err; + + if (!tc_single_action(cls->exts)) + return err; + + tcf_exts_to_list(cls->exts, &actions); + a = list_first_entry(&actions, struct tc_action, list); + + if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) { + struct dsa_mall_mirror_tc_entry *mirror; + + ifindex = tcf_mirred_ifindex(a); + to_dev = __dev_get_by_index(net, ifindex); + if (!to_dev) + return -EINVAL; + + if (!dsa_slave_dev_check(to_dev)) + return -EOPNOTSUPP; + + mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); + if (!mall_tc_entry) + return -ENOMEM; + + mall_tc_entry->cookie = cls->cookie; + mall_tc_entry->type = DSA_PORT_MALL_MIRROR; + mirror = &mall_tc_entry->mirror; + + to_p = netdev_priv(to_dev); + + mirror->to_local_port = to_p->dp->index; + mirror->ingress = ingress; + + err = ds->ops->port_mirror_add(ds, p->dp->index, mirror, + ingress); + if (err) { + kfree(mall_tc_entry); + return err; + } + + list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); + } + + return 0; +} + +static void dsa_slave_del_cls_matchall(struct net_device *dev, + struct tc_cls_matchall_offload *cls) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_mall_tc_entry *mall_tc_entry; + struct dsa_switch *ds = p->dp->ds; + + if (!ds->ops->port_mirror_del) + return; + + mall_tc_entry = dsa_slave_mall_tc_entry_find(p, cls->cookie); + if (!mall_tc_entry) + return; + + list_del(&mall_tc_entry->list); + + switch (mall_tc_entry->type) { + case DSA_PORT_MALL_MIRROR: + ds->ops->port_mirror_del(ds, p->dp->index, + &mall_tc_entry->mirror); + break; + default: + WARN_ON(1); + } + + kfree(mall_tc_entry); +} + +static int dsa_slave_setup_tc(struct net_device *dev, u32 handle, + __be16 protocol, struct tc_to_netdev *tc) +{ + bool ingress = TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS); + int ret = -EOPNOTSUPP; + + switch (tc->type) { + case TC_SETUP_MATCHALL: + switch (tc->cls_mall->command) { + case TC_CLSMATCHALL_REPLACE: + return dsa_slave_add_cls_matchall(dev, protocol, + tc->cls_mall, + ingress); + case TC_CLSMATCHALL_DESTROY: + dsa_slave_del_cls_matchall(dev, tc->cls_mall); + return 0; + } + default: + break; + } + + return ret; +} + void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) { ops->get_sset_count = dsa_cpu_port_get_sset_count; @@ -1069,6 +1201,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, .ndo_get_phys_port_name = dsa_slave_get_phys_port_name, + .ndo_setup_tc = dsa_slave_setup_tc, }; static const struct switchdev_ops dsa_slave_switchdev_ops = { @@ -1285,7 +1418,8 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, if (slave_dev == NULL) return -ENOMEM; - slave_dev->features = master->vlan_features; + slave_dev->features = master->vlan_features | NETIF_F_HW_TC; + slave_dev->hw_features |= NETIF_F_HW_TC; slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; eth_hw_addr_inherit(slave_dev, master); slave_dev->priv_flags |= IFF_NO_QUEUE; @@ -1304,6 +1438,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, p = netdev_priv(slave_dev); p->dp = &ds->ports[port]; + INIT_LIST_HEAD(&p->mall_tc_list); p->xmit = dst->tag_ops->xmit; p->old_pause = -1; -- cgit v1.2.3-59-g8ed1b From f515f192ab4f45bb695146b82432d63d98775787 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 3 Feb 2017 13:20:20 -0500 Subject: net: dsa: add switch notifier Add a notifier block per DSA switch, registered against a notifier head in the switch fabric they belong to. This infrastructure will allow to propagate fabric-wide events such as port bridging, VLAN configuration, etc. If a DSA switch driver cares about cross-chip configuration, such events can be caught. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 7 +++++++ net/dsa/Makefile | 1 + net/dsa/dsa.c | 6 ++++++ net/dsa/dsa2.c | 6 ++++++ net/dsa/dsa_priv.h | 4 ++++ net/dsa/switch.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 net/dsa/switch.c (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 2cb77e64d648..ac4ea7c3a102 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,9 @@ struct packet_type; struct dsa_switch_tree { struct list_head list; + /* Notifier chain for switch-wide events */ + struct raw_notifier_head nh; + /* Tree identifier */ u32 tree; @@ -182,6 +186,9 @@ struct dsa_switch { struct dsa_switch_tree *dst; int index; + /* Listener for switch fabric events */ + struct notifier_block nb; + /* * Give the switch driver somewhere to hang its private data * structure. diff --git a/net/dsa/Makefile b/net/dsa/Makefile index a3380ed0e0be..72912982de3d 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -1,6 +1,7 @@ # the core obj-$(CONFIG_NET_DSA) += dsa_core.o dsa_core-y += dsa.o slave.o dsa2.o +dsa_core-y += dsa.o slave.o dsa2.o switch.o # tagging formats dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index beb79ccf0f59..22e44f691ab9 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -275,6 +275,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) if (ret < 0) return ret; + ret = dsa_switch_register_notifier(ds); + if (ret) + return ret; + if (ops->set_addr) { ret = ops->set_addr(ds, dst->master_netdev->dev_addr); if (ret < 0) @@ -400,6 +404,8 @@ static void dsa_switch_destroy(struct dsa_switch *ds) if (ds->slave_mii_bus && ds->ops->phy_read) mdiobus_unregister(ds->slave_mii_bus); + + dsa_switch_unregister_notifier(ds); } #ifdef CONFIG_PM_SLEEP diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 9f8cc26be9ea..1c546b6621ee 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -294,6 +294,10 @@ static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (err < 0) return err; + err = dsa_switch_register_notifier(ds); + if (err) + return err; + if (ds->ops->set_addr) { err = ds->ops->set_addr(ds, dst->master_netdev->dev_addr); if (err < 0) @@ -364,6 +368,8 @@ static void dsa_ds_unapply(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (ds->slave_mii_bus && ds->ops->phy_read) mdiobus_unregister(ds->slave_mii_bus); + + dsa_switch_unregister_notifier(ds); } static int dsa_dst_apply(struct dsa_switch_tree *dst) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 591a40aea9ca..0706a511244e 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -66,6 +66,10 @@ int dsa_slave_resume(struct net_device *slave_dev); int dsa_slave_register_notifier(void); void dsa_slave_unregister_notifier(void); +/* switch.c */ +int dsa_switch_register_notifier(struct dsa_switch *ds); +void dsa_switch_unregister_notifier(struct dsa_switch *ds); + /* tag_dsa.c */ extern const struct dsa_device_ops dsa_netdev_ops; diff --git a/net/dsa/switch.c b/net/dsa/switch.c new file mode 100644 index 000000000000..e22fa7633d03 --- /dev/null +++ b/net/dsa/switch.c @@ -0,0 +1,53 @@ +/* + * Handling of a single switch chip, part of a switch fabric + * + * Copyright (c) 2017 Vivien Didelot + * + * 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 +#include +#include + +static int dsa_switch_event(struct notifier_block *nb, + unsigned long event, void *info) +{ + struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb); + int err; + + switch (event) { + default: + err = -EOPNOTSUPP; + break; + } + + /* Non-switchdev operations cannot be rolled back. If a DSA driver + * returns an error during the chained call, switch chips may be in an + * inconsistent state. + */ + if (err) + dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n", + event, err); + + return notifier_from_errno(err); +} + +int dsa_switch_register_notifier(struct dsa_switch *ds) +{ + ds->nb.notifier_call = dsa_switch_event; + + return raw_notifier_chain_register(&ds->dst->nh, &ds->nb); +} + +void dsa_switch_unregister_notifier(struct dsa_switch *ds) +{ + int err; + + err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb); + if (err) + dev_err(ds->dev, "failed to unregister notifier (%d)\n", err); +} -- cgit v1.2.3-59-g8ed1b From 04d3a4c6af52a58370795bc9f70dc15f51f8bb84 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 3 Feb 2017 13:20:21 -0500 Subject: net: dsa: introduce bridge notifier A slave device will now notify the switch fabric once its port is bridged or unbridged, instead of calling directly its switch operations. This code allows propagating cross-chip bridging events in the fabric. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 10 ++++++++++ net/dsa/slave.c | 40 +++++++++++++++++++++++++++++----------- net/dsa/switch.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 11 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index ac4ea7c3a102..e9c940c8936f 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -268,6 +268,16 @@ struct switchdev_obj_port_fdb; struct switchdev_obj_port_mdb; struct switchdev_obj_port_vlan; +#define DSA_NOTIFIER_BRIDGE_JOIN 1 +#define DSA_NOTIFIER_BRIDGE_LEAVE 2 + +/* DSA_NOTIFIER_BRIDGE_* */ +struct dsa_notifier_bridge_info { + struct net_device *br; + int sw_index; + int port; +}; + struct dsa_switch_ops { /* * Probing and setup. diff --git a/net/dsa/slave.c b/net/dsa/slave.c index d8c3c0f00cf3..061a49c29cef 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -27,6 +27,17 @@ static bool dsa_slave_dev_check(struct net_device *dev); +static int dsa_slave_notify(struct net_device *dev, unsigned long e, void *v) +{ + struct dsa_slave_priv *p = netdev_priv(dev); + struct raw_notifier_head *nh = &p->dp->ds->dst->nh; + int err; + + err = raw_notifier_call_chain(nh, e, v); + + return notifier_to_errno(err); +} + /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -562,39 +573,46 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, struct net_device *br) { struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; - int ret = -EOPNOTSUPP; + struct dsa_notifier_bridge_info info = { + .sw_index = p->dp->ds->index, + .port = p->dp->index, + .br = br, + }; + int err; /* Here the port is already bridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ p->dp->bridge_dev = br; - if (ds->ops->port_bridge_join) - ret = ds->ops->port_bridge_join(ds, p->dp->index, br); + err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_JOIN, &info); /* The bridging is rolled back on error */ - if (ret && ret != -EOPNOTSUPP) { + if (err) p->dp->bridge_dev = NULL; - return ret; - } - return 0; + return err; } static void dsa_slave_bridge_port_leave(struct net_device *dev, struct net_device *br) { struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_notifier_bridge_info info = { + .sw_index = p->dp->ds->index, + .port = p->dp->index, + .br = br, + }; + int err; /* Here the port is already unbridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ p->dp->bridge_dev = NULL; - if (ds->ops->port_bridge_leave) - ds->ops->port_bridge_leave(ds, p->dp->index, br); + err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_LEAVE, &info); + if (err) + netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional diff --git a/net/dsa/switch.c b/net/dsa/switch.c index e22fa7633d03..6456dacf9ae9 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -13,6 +13,32 @@ #include #include +static int dsa_switch_bridge_join(struct dsa_switch *ds, + struct dsa_notifier_bridge_info *info) +{ + if (ds->index == info->sw_index && ds->ops->port_bridge_join) + return ds->ops->port_bridge_join(ds, info->port, info->br); + + if (ds->index != info->sw_index) + dev_dbg(ds->dev, "crosschip DSA port %d.%d bridged to %s\n", + info->sw_index, info->port, netdev_name(info->br)); + + return 0; +} + +static int dsa_switch_bridge_leave(struct dsa_switch *ds, + struct dsa_notifier_bridge_info *info) +{ + if (ds->index == info->sw_index && ds->ops->port_bridge_leave) + ds->ops->port_bridge_leave(ds, info->port, info->br); + + if (ds->index != info->sw_index) + dev_dbg(ds->dev, "crosschip DSA port %d.%d unbridged from %s\n", + info->sw_index, info->port, netdev_name(info->br)); + + return 0; +} + static int dsa_switch_event(struct notifier_block *nb, unsigned long event, void *info) { @@ -20,6 +46,12 @@ static int dsa_switch_event(struct notifier_block *nb, int err; switch (event) { + case DSA_NOTIFIER_BRIDGE_JOIN: + err = dsa_switch_bridge_join(ds, info); + break; + case DSA_NOTIFIER_BRIDGE_LEAVE: + err = dsa_switch_bridge_leave(ds, info); + break; default: err = -EOPNOTSUPP; break; -- cgit v1.2.3-59-g8ed1b From 14b89f36eed2993670906a3991bca496a5ebf1a6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 4 Feb 2017 13:02:42 -0800 Subject: net: dsa: Rename and export dev_to_net_device() In preparation for using this function in net/dsa/dsa2.c, rename the function to make its scope DSA specific, and export it. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 1 + net/dsa/dsa.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index e9c940c8936f..2a21fa80f898 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -445,6 +445,7 @@ struct dsa_switch_driver { void register_switch_driver(struct dsa_switch_driver *type); void unregister_switch_driver(struct dsa_switch_driver *type); struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev); +struct net_device *dsa_dev_to_net_device(struct device *dev); static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) { diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 22e44f691ab9..b6d4f6a23f06 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -492,7 +492,7 @@ struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev) } EXPORT_SYMBOL_GPL(dsa_host_dev_to_mii_bus); -static struct net_device *dev_to_net_device(struct device *dev) +struct net_device *dsa_dev_to_net_device(struct device *dev) { struct device *d; @@ -509,6 +509,7 @@ static struct net_device *dev_to_net_device(struct device *dev) return NULL; } +EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); #ifdef CONFIG_OF static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, @@ -817,7 +818,7 @@ static int dsa_probe(struct platform_device *pdev) dev = pd->of_netdev; dev_hold(dev); } else { - dev = dev_to_net_device(pd->netdev); + dev = dsa_dev_to_net_device(pd->netdev); } if (dev == NULL) { ret = -EPROBE_DEFER; -- cgit v1.2.3-59-g8ed1b From 71e0bbde0d88047f66b25721f69a441d46083748 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 4 Feb 2017 13:02:43 -0800 Subject: net: dsa: Add support for platform data Allow drivers to use the new DSA API with platform data. Most of the code in net/dsa/dsa2.c does not rely so much on device_nodes and can get the same information from platform_data instead. We purposely do not support distributed configurations with platform data, so drivers should be providing a pointer to a 'struct dsa_chip_data' structure if they wish to communicate per-port layout. Multiple CPUs port could potentially be supported and dsa_chip_data is extended to receive up to one reference to an upstream network device per port described by a dsa_chip_data structure. dsa_dev_to_net_device() increments the network device's reference count, so we intentionally call dev_put() to be consistent with the DT-enabled path, until we have a generic notifier based solution. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 6 ++++ net/dsa/dsa2.c | 102 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 90 insertions(+), 18 deletions(-) (limited to 'include/net/dsa.h') diff --git a/include/net/dsa.h b/include/net/dsa.h index 2a21fa80f898..b49b2004891e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -45,6 +45,11 @@ struct dsa_chip_data { struct device *host_dev; int sw_addr; + /* + * Reference to network devices + */ + struct device *netdev[DSA_MAX_PORTS]; + /* set to size of eeprom if supported by the switch */ int eeprom_len; @@ -170,6 +175,7 @@ struct dsa_mall_tc_entry { struct dsa_port { struct dsa_switch *ds; unsigned int index; + const char *name; struct net_device *netdev; struct device_node *dn; unsigned int ageing_time; diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 1c546b6621ee..6f5f0a2ad256 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -78,19 +78,28 @@ static void dsa_dst_del_ds(struct dsa_switch_tree *dst, kref_put(&dst->refcount, dsa_free_dst); } +/* For platform data configurations, we need to have a valid name argument to + * differentiate a disabled port from an enabled one + */ static bool dsa_port_is_valid(struct dsa_port *port) { - return !!port->dn; + return !!(port->dn || port->name); } static bool dsa_port_is_dsa(struct dsa_port *port) { - return !!of_parse_phandle(port->dn, "link", 0); + if (port->name && !strcmp(port->name, "dsa")) + return true; + else + return !!of_parse_phandle(port->dn, "link", 0); } static bool dsa_port_is_cpu(struct dsa_port *port) { - return !!of_parse_phandle(port->dn, "ethernet", 0); + if (port->name && !strcmp(port->name, "cpu")) + return true; + else + return !!of_parse_phandle(port->dn, "ethernet", 0); } static bool dsa_ds_find_port_dn(struct dsa_switch *ds, @@ -250,10 +259,11 @@ static void dsa_cpu_port_unapply(struct dsa_port *port, u32 index, static int dsa_user_port_apply(struct dsa_port *port, u32 index, struct dsa_switch *ds) { - const char *name; + const char *name = port->name; int err; - name = of_get_property(port->dn, "label", NULL); + if (port->dn) + name = of_get_property(port->dn, "label", NULL); if (!name) name = "eth%d"; @@ -444,11 +454,16 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index, struct net_device *ethernet_dev; struct device_node *ethernet; - ethernet = of_parse_phandle(port->dn, "ethernet", 0); - if (!ethernet) - return -EINVAL; + if (port->dn) { + ethernet = of_parse_phandle(port->dn, "ethernet", 0); + if (!ethernet) + return -EINVAL; + ethernet_dev = of_find_net_device_by_node(ethernet); + } else { + ethernet_dev = dsa_dev_to_net_device(ds->cd->netdev[index]); + dev_put(ethernet_dev); + } - ethernet_dev = of_find_net_device_by_node(ethernet); if (!ethernet_dev) return -EPROBE_DEFER; @@ -551,6 +566,33 @@ static int dsa_parse_ports_dn(struct device_node *ports, struct dsa_switch *ds) return 0; } +static int dsa_parse_ports(struct dsa_chip_data *cd, struct dsa_switch *ds) +{ + bool valid_name_found = false; + unsigned int i; + + for (i = 0; i < DSA_MAX_PORTS; i++) { + if (!cd->port_names[i]) + continue; + + ds->ports[i].name = cd->port_names[i]; + + /* Initialize enabled_port_mask now for drv->setup() + * to have access to a correct value, just like what + * net/dsa/dsa.c::dsa_switch_setup_one does. + */ + if (!dsa_port_is_cpu(&ds->ports[i])) + ds->enabled_port_mask |= 1 << i; + + valid_name_found = true; + } + + if (!valid_name_found && i == DSA_MAX_PORTS) + return -EINVAL; + + return 0; +} + static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index) { int err; @@ -575,6 +617,18 @@ static int dsa_parse_member_dn(struct device_node *np, u32 *tree, u32 *index) return 0; } +static int dsa_parse_member(struct dsa_chip_data *pd, u32 *tree, u32 *index) +{ + if (!pd) + return -ENODEV; + + /* We do not support complex trees with dsa_chip_data */ + *tree = 0; + *index = 0; + + return 0; +} + static struct device_node *dsa_get_ports(struct dsa_switch *ds, struct device_node *np) { @@ -591,23 +645,34 @@ static struct device_node *dsa_get_ports(struct dsa_switch *ds, static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev) { + struct dsa_chip_data *pdata = dev->platform_data; struct device_node *np = dev->of_node; struct dsa_switch_tree *dst; struct device_node *ports; u32 tree, index; int i, err; - err = dsa_parse_member_dn(np, &tree, &index); - if (err) - return err; + if (np) { + err = dsa_parse_member_dn(np, &tree, &index); + if (err) + return err; - ports = dsa_get_ports(ds, np); - if (IS_ERR(ports)) - return PTR_ERR(ports); + ports = dsa_get_ports(ds, np); + if (IS_ERR(ports)) + return PTR_ERR(ports); - err = dsa_parse_ports_dn(ports, ds); - if (err) - return err; + err = dsa_parse_ports_dn(ports, ds); + if (err) + return err; + } else { + err = dsa_parse_member(pdata, &tree, &index); + if (err) + return err; + + err = dsa_parse_ports(pdata, ds); + if (err) + return err; + } dst = dsa_get_dst(tree); if (!dst) { @@ -623,6 +688,7 @@ static int _dsa_register_switch(struct dsa_switch *ds, struct device *dev) ds->dst = dst; ds->index = index; + ds->cd = pdata; /* Initialize the routing table */ for (i = 0; i < DSA_MAX_SWITCHES; ++i) -- cgit v1.2.3-59-g8ed1b From 4d56a29f17508b2eb8bee66b8f0e3679201fa807 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 7 Feb 2017 15:03:05 -0800 Subject: net: dsa: remove unnecessary phy*.h includes Including phy.h and phy_fixed.h into net/dsa.h causes phy*.h to be an unnecessary dependency for quite a large amount of the kernel. There's very little which actually requires definitions from phy.h in net/dsa.h - the include itself only wants the declaration of a couple of structures and IFNAMSIZ. Add linux/if.h for IFNAMSIZ, declarations for the structures, phy.h to mv88e6xxx.h as it needs it for phy_interface_t, and remove both phy.h and phy_fixed.h from net/dsa.h. This patch reduces from around 800 files rebuilt to around 40 - even with ccache, the time difference is noticable. Tested-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 1 + include/net/dsa.h | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/net/dsa.h') diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index d6b335cd8c09..ac54f40813f7 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifndef UINT64_MAX #define UINT64_MAX (u64)(~((u64)0)) diff --git a/include/net/dsa.h b/include/net/dsa.h index b49b2004891e..4e13e695f025 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -11,17 +11,18 @@ #ifndef __LINUX_NET_DSA_H #define __LINUX_NET_DSA_H +#include #include #include #include #include #include #include -#include -#include #include struct tc_action; +struct phy_device; +struct fixed_phy_status; enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = 0, -- cgit v1.2.3-59-g8ed1b