From 838c19f89454cab177ed6f74ab61ad32db1764c5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:27 +0100 Subject: [PATCH 1/6] net: dsa: microchip: move max mtu to one location There are no HW specific registers, so we can process all of them in one location. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Tested-by: Arun Ramadoss <arun.ramadoss@microchip.com> (KSZ9893 and LAN937x) Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz9477.c | 5 ----- drivers/net/dsa/microchip/ksz9477.h | 1 - drivers/net/dsa/microchip/ksz9477_reg.h | 2 -- drivers/net/dsa/microchip/ksz_common.c | 22 +++++++++++++++++----- drivers/net/dsa/microchip/ksz_common.h | 3 ++- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 0d6b409686573..602d00671bef6 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -60,11 +60,6 @@ int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) REG_SW_MTU_MASK, max_frame); } -int ksz9477_max_mtu(struct ksz_device *dev, int port) -{ - return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; -} - static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) { unsigned int val; diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h index 00862c4cfb7f1..7c5bb30327728 100644 --- a/drivers/net/dsa/microchip/ksz9477.h +++ b/drivers/net/dsa/microchip/ksz9477.h @@ -50,7 +50,6 @@ int ksz9477_mdb_add(struct ksz_device *dev, int port, int ksz9477_mdb_del(struct ksz_device *dev, int port, const struct switchdev_obj_port_mdb *mdb, struct dsa_db db); int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu); -int ksz9477_max_mtu(struct ksz_device *dev, int port); void ksz9477_config_cpu_port(struct dsa_switch *ds); int ksz9477_enable_stp_addr(struct ksz_device *dev); int ksz9477_reset_switch(struct ksz_device *dev); diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h b/drivers/net/dsa/microchip/ksz9477_reg.h index 53c68d286dd3a..cc457fa649392 100644 --- a/drivers/net/dsa/microchip/ksz9477_reg.h +++ b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -1615,6 +1615,4 @@ #define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) #define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) -#define KSZ9477_MAX_FRAME_SIZE 9000 - #endif /* KSZ9477_REGS_H */ diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 8c8db315317d3..49a5a236d9588 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -14,6 +14,7 @@ #include <linux/phy.h> #include <linux/etherdevice.h> #include <linux/if_bridge.h> +#include <linux/if_vlan.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/of_mdio.h> @@ -206,7 +207,6 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { .mdb_add = ksz9477_mdb_add, .mdb_del = ksz9477_mdb_del, .change_mtu = ksz9477_change_mtu, - .max_mtu = ksz9477_max_mtu, .phylink_mac_link_up = ksz9477_phylink_mac_link_up, .config_cpu_port = ksz9477_config_cpu_port, .enable_stp_addr = ksz9477_enable_stp_addr, @@ -243,7 +243,6 @@ static const struct ksz_dev_ops lan937x_dev_ops = { .mdb_add = ksz9477_mdb_add, .mdb_del = ksz9477_mdb_del, .change_mtu = lan937x_change_mtu, - .max_mtu = ksz9477_max_mtu, .phylink_mac_link_up = ksz9477_phylink_mac_link_up, .config_cpu_port = lan937x_config_cpu_port, .enable_stp_addr = ksz9477_enable_stp_addr, @@ -2500,10 +2499,23 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) { struct ksz_device *dev = ds->priv; - if (!dev->dev_ops->max_mtu) - return -EOPNOTSUPP; + switch (dev->chip_id) { + case KSZ8563_CHIP_ID: + case KSZ9477_CHIP_ID: + case KSZ9563_CHIP_ID: + case KSZ9567_CHIP_ID: + case KSZ9893_CHIP_ID: + case KSZ9896_CHIP_ID: + case KSZ9897_CHIP_ID: + case LAN9370_CHIP_ID: + case LAN9371_CHIP_ID: + case LAN9372_CHIP_ID: + case LAN9373_CHIP_ID: + case LAN9374_CHIP_ID: + return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; + } - return dev->dev_ops->max_mtu(dev, port); + return -EOPNOTSUPP; } static void ksz_set_xmii(struct ksz_device *dev, int port, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c6726cbd5465c..27c26ee15af4f 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -322,7 +322,6 @@ struct ksz_dev_ops { void (*get_caps)(struct ksz_device *dev, int port, struct phylink_config *config); int (*change_mtu)(struct ksz_device *dev, int port, int mtu); - int (*max_mtu)(struct ksz_device *dev, int port); void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze); void (*port_init_cnt)(struct ksz_device *dev, int port); void (*phylink_mac_config)(struct ksz_device *dev, int port, @@ -588,6 +587,8 @@ static inline int is_lan937x(struct ksz_device *dev) #define PORT_SRC_PHY_INT 1 +#define KSZ9477_MAX_FRAME_SIZE 9000 + /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 From 1d0a1a6d0d63db5bba73abe862180c947861f4d4 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:28 +0100 Subject: [PATCH 2/6] net: dsa: microchip: do not store max MTU for all ports If we have global MTU configuration, it is enough to configure it on CPU port only. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz9477.c | 14 +++++--------- drivers/net/dsa/microchip/ksz_common.h | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 602d00671bef6..f6e7968ab1055 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -45,19 +45,15 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) { - u16 frame_size, max_frame = 0; - int i; - - frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + u16 frame_size; - /* Cache the per-port MTU setting */ - dev->ports[port].max_frame = frame_size; + if (!dsa_is_cpu_port(dev->ds, port)) + return 0; - for (i = 0; i < dev->info->port_cnt; i++) - max_frame = max(max_frame, dev->ports[i].max_frame); + frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, - REG_SW_MTU_MASK, max_frame); + REG_SW_MTU_MASK, frame_size); } static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 27c26ee15af4f..61228be299f9c 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -95,7 +95,6 @@ struct ksz_port { struct ksz_port_mib mib; phy_interface_t interface; - u16 max_frame; u32 rgmii_tx_val; u32 rgmii_rx_val; struct ksz_device *ksz_dev; From 6f1b986a43ce9aa67b11a7e54ac75530705d04e7 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:29 +0100 Subject: [PATCH 3/6] net: dsa: microchip: add ksz_rmw8() function Add ksz_rmw8(), it will be used in the next patch. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz_common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 61228be299f9c..5f404a444ce11 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -454,6 +454,11 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) return regmap_bulk_write(dev->regmap[2], reg, val, 2); } +static inline int ksz_rmw8(struct ksz_device *dev, int offset, u8 mask, u8 val) +{ + return regmap_update_bits(dev->regmap[0], offset, mask, val); +} + static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, u8 *data) { From 29d1e85f45e03c9fd1b8985f983f33c021e130c8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:30 +0100 Subject: [PATCH 4/6] net: dsa: microchip: ksz8: add MTU configuration support Make MTU configurable on KSZ87xx and KSZ88xx series of switches. Before this patch, pre-configured behavior was different on different switch series, due to opposite meaning of the same bit: - KSZ87xx: Reg 4, Bit 1 - if 1, max frame size is 1532; if 0 - 1514 - KSZ88xx: Reg 4, Bit 1 - if 1, max frame size is 1514; if 0 - 1532 Since the code was telling "... SW_LEGAL_PACKET_DISABLE, true)", I assume, the idea was to set max frame size to 1532. With this patch, by setting MTU size 1500, both switch series will be configured to the 1532 frame limit. This patch was tested on KSZ8873. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz8.h | 1 + drivers/net/dsa/microchip/ksz8795.c | 53 ++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz8795_reg.h | 3 ++ drivers/net/dsa/microchip/ksz_common.c | 7 ++++ drivers/net/dsa/microchip/ksz_common.h | 4 ++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h index 8582b4b67d989..ea05abfbd51d6 100644 --- a/drivers/net/dsa/microchip/ksz8.h +++ b/drivers/net/dsa/microchip/ksz8.h @@ -57,5 +57,6 @@ int ksz8_reset_switch(struct ksz_device *dev); int ksz8_switch_detect(struct ksz_device *dev); int ksz8_switch_init(struct ksz_device *dev); void ksz8_switch_exit(struct ksz_device *dev); +int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu); #endif diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index bd3b133e7085b..d01bfd6091305 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -76,6 +76,57 @@ int ksz8_reset_switch(struct ksz_device *dev) return 0; } +static int ksz8863_change_mtu(struct ksz_device *dev, int frame_size) +{ + u8 ctrl2 = 0; + + if (frame_size <= KSZ8_LEGAL_PACKET_SIZE) + ctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE; + else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) + ctrl2 |= KSZ8863_HUGE_PACKET_ENABLE; + + return ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE | + KSZ8863_HUGE_PACKET_ENABLE, ctrl2); +} + +static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size) +{ + u8 ctrl1 = 0, ctrl2 = 0; + int ret; + + if (frame_size > KSZ8_LEGAL_PACKET_SIZE) + ctrl2 |= SW_LEGAL_PACKET_DISABLE; + else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) + ctrl1 |= SW_HUGE_PACKET; + + ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1); + if (ret) + return ret; + + return ksz_rmw8(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, ctrl2); +} + +int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu) +{ + u16 frame_size; + + if (!dsa_is_cpu_port(dev->ds, port)) + return 0; + + frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + + switch (dev->chip_id) { + case KSZ8795_CHIP_ID: + case KSZ8794_CHIP_ID: + case KSZ8765_CHIP_ID: + return ksz8795_change_mtu(dev, frame_size); + case KSZ8830_CHIP_ID: + return ksz8863_change_mtu(dev, frame_size); + } + + return -EOPNOTSUPP; +} + static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) { u8 hi, lo; @@ -1233,8 +1284,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) masks = dev->info->masks; regs = dev->info->regs; - /* Switch marks the maximum frame with extra byte as oversize. */ - ksz_cfg(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, true); ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true); p = &dev->ports[dev->cpu_port]; diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index 77487d6118242..7a57c6088f809 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -48,6 +48,9 @@ #define NO_EXC_COLLISION_DROP BIT(3) #define SW_LEGAL_PACKET_DISABLE BIT(1) +#define KSZ8863_HUGE_PACKET_ENABLE BIT(2) +#define KSZ8863_LEGAL_PACKET_ENABLE BIT(1) + #define REG_SW_CTRL_3 0x05 #define WEIGHTED_FAIR_QUEUE_ENABLE BIT(3) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 49a5a236d9588..f39b041765fb2 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -172,6 +172,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = { .reset = ksz8_reset_switch, .init = ksz8_switch_init, .exit = ksz8_switch_exit, + .change_mtu = ksz8_change_mtu, }; static void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, @@ -2500,6 +2501,12 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) struct ksz_device *dev = ds->priv; switch (dev->chip_id) { + case KSZ8795_CHIP_ID: + case KSZ8794_CHIP_ID: + case KSZ8765_CHIP_ID: + return KSZ8795_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; + case KSZ8830_CHIP_ID: + return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; case KSZ8563_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 5f404a444ce11..cb27f5a180c77 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -591,6 +591,10 @@ static inline int is_lan937x(struct ksz_device *dev) #define PORT_SRC_PHY_INT 1 +#define KSZ8795_HUGE_PACKET_SIZE 2000 +#define KSZ8863_HUGE_PACKET_SIZE 1916 +#define KSZ8863_NORMAL_PACKET_SIZE 1536 +#define KSZ8_LEGAL_PACKET_SIZE 1518 #define KSZ9477_MAX_FRAME_SIZE 9000 /* Regmap tables generation */ From 6b30cfa86ee703dc75743d56b078661753a18da3 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:31 +0100 Subject: [PATCH 5/6] net: dsa: microchip: enable MTU normalization for KSZ8795 and KSZ9477 compatible switches KSZ8795 and KSZ9477 compatible series of switches use global max frame size configuration register. So, enable MTU normalization for this reason. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz8795.c | 2 ++ drivers/net/dsa/microchip/ksz9477.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index d01bfd6091305..060e41b9b6ef5 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1357,6 +1357,8 @@ int ksz8_setup(struct dsa_switch *ds) struct ksz_device *dev = ds->priv; int i; + ds->mtu_enforcement_ingress = true; + ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); /* Enable automatic fast aging when link changed detected. */ diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index f6e7968ab1055..47b54ecf2c6f6 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1134,6 +1134,8 @@ int ksz9477_setup(struct dsa_switch *ds) struct ksz_device *dev = ds->priv; int ret = 0; + ds->mtu_enforcement_ingress = true; + /* Required for port partitioning. */ ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, true); From 55a952eef70a51340afdf080ecf81dd2b7bbf952 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel <o.rempel@pengutronix.de> Date: Mon, 5 Dec 2022 06:22:32 +0100 Subject: [PATCH 6/6] net: dsa: microchip: ksz8: move all DSA configurations to one location To make the code more comparable to KSZ9477 code, move DSA configurations to the same location. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- drivers/net/dsa/microchip/ksz8795.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 060e41b9b6ef5..003b0ac2854c9 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1359,6 +1359,16 @@ int ksz8_setup(struct dsa_switch *ds) ds->mtu_enforcement_ingress = true; + /* We rely on software untagging on the CPU port, so that we + * can support both tagged and untagged VLANs + */ + ds->untag_bridge_pvid = true; + + /* VLAN filtering is partly controlled by the global VLAN + * Enable flag + */ + ds->vlan_filtering_is_global = true; + ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); /* Enable automatic fast aging when link changed detected. */ @@ -1418,16 +1428,6 @@ int ksz8_switch_init(struct ksz_device *dev) dev->phy_port_cnt = dev->info->port_cnt - 1; dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports; - /* We rely on software untagging on the CPU port, so that we - * can support both tagged and untagged VLANs - */ - dev->ds->untag_bridge_pvid = true; - - /* VLAN filtering is partly controlled by the global VLAN - * Enable flag - */ - dev->ds->vlan_filtering_is_global = true; - return 0; }