From 1ed26ce4850accf88aedd1b1c7974a94396305d0 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 15 Aug 2022 10:50:08 -0700 Subject: net: dsa: bcm_sf2: Introduce helper for port override offset Depending upon the generation of switches, we have different offsets for configuring a given port's status override where link parameters are applied. Introduce a helper function that we re-use throughout the code in order to let phylink callbacks configure the IMP/CPU port(s) in subsequent changes. Signed-off-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/bcm_sf2.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index be0edfa093d0..10de0cffa047 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -94,6 +94,24 @@ static u16 bcm_sf2_reg_led_base(struct bcm_sf2_priv *priv, int port) return REG_SWITCH_STATUS; } +static u32 bcm_sf2_port_override_offset(struct bcm_sf2_priv *priv, int port) +{ + switch (priv->type) { + case BCM4908_DEVICE_ID: + case BCM7445_DEVICE_ID: + return port == 8 ? CORE_STS_OVERRIDE_IMP : + CORE_STS_OVERRIDE_GMIIP_PORT(port); + case BCM7278_DEVICE_ID: + return port == 8 ? CORE_STS_OVERRIDE_IMP2 : + CORE_STS_OVERRIDE_GMIIP2_PORT(port); + default: + WARN_ONCE(1, "Unsupported device: %d\n", priv->type); + } + + /* RO fallback register */ + return REG_SWITCH_STATUS; +} + /* Return the number of active ports, not counting the IMP (CPU) port */ static unsigned int bcm_sf2_num_active_ports(struct dsa_switch *ds) { @@ -167,11 +185,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) b53_brcm_hdr_setup(ds, port); if (port == 8) { - if (priv->type == BCM4908_DEVICE_ID || - priv->type == BCM7445_DEVICE_ID) - offset = CORE_STS_OVERRIDE_IMP; - else - offset = CORE_STS_OVERRIDE_IMP2; + offset = bcm_sf2_port_override_offset(priv, port); /* Force link status for IMP port */ reg = core_readl(priv, offset); @@ -813,12 +827,7 @@ static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port, return; if (port != core_readl(priv, CORE_IMP0_PRT_ID)) { - if (priv->type == BCM4908_DEVICE_ID || - priv->type == BCM7445_DEVICE_ID) - offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); - else - offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); - + offset = bcm_sf2_port_override_offset(priv, port); reg = core_readl(priv, offset); reg &= ~LINK_STS; core_writel(priv, reg, offset); @@ -843,11 +852,7 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, u32 reg_rgmii_ctrl = 0; u32 reg, offset; - if (priv->type == BCM4908_DEVICE_ID || - priv->type == BCM7445_DEVICE_ID) - offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); - else - offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); + offset = bcm_sf2_port_override_offset(priv, port); if (interface == PHY_INTERFACE_MODE_RGMII || interface == PHY_INTERFACE_MODE_RGMII_TXID || -- cgit From 4d2f6dde4daa12315254485566968fe7c7432cfd Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 15 Aug 2022 10:50:09 -0700 Subject: net: dsa: bcm_sf2: Have PHYLINK configure CPU/IMP port(s) Remove the artificial limitations imposed upon bcm_sf2_sw_mac_link_{up,down} and allow us to override the link parameters for IMP port(s) as well as regular ports by accounting for the special differences that exist there. Remove the code that did override the link parameters in bcm_sf2_imp_setup(). Signed-off-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/bcm_sf2.c | 95 +++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 52 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 10de0cffa047..572f7450b527 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -159,7 +159,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); unsigned int i; - u32 reg, offset; + u32 reg; /* Enable the port memories */ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); @@ -185,17 +185,6 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) b53_brcm_hdr_setup(ds, port); if (port == 8) { - offset = bcm_sf2_port_override_offset(priv, port); - - /* Force link status for IMP port */ - reg = core_readl(priv, offset); - reg |= (MII_SW_OR | LINK_STS); - if (priv->type == BCM4908_DEVICE_ID) - reg |= GMII_SPEED_UP_2G; - else - reg &= ~GMII_SPEED_UP_2G; - core_writel(priv, reg, offset); - /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */ reg = core_readl(priv, CORE_IMP_CTL); reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN); @@ -826,12 +815,10 @@ static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port, if (priv->wol_ports_mask & BIT(port)) return; - if (port != core_readl(priv, CORE_IMP0_PRT_ID)) { - offset = bcm_sf2_port_override_offset(priv, port); - reg = core_readl(priv, offset); - reg &= ~LINK_STS; - core_writel(priv, reg, offset); - } + offset = bcm_sf2_port_override_offset(priv, port); + reg = core_readl(priv, offset); + reg &= ~LINK_STS; + core_writel(priv, reg, offset); bcm_sf2_sw_mac_link_set(ds, port, interface, false); } @@ -845,51 +832,55 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_eee *p = &priv->dev->ports[port].eee; + u32 reg_rgmii_ctrl = 0; + u32 reg, offset; bcm_sf2_sw_mac_link_set(ds, port, interface, true); - if (port != core_readl(priv, CORE_IMP0_PRT_ID)) { - u32 reg_rgmii_ctrl = 0; - u32 reg, offset; + offset = bcm_sf2_port_override_offset(priv, port); - offset = bcm_sf2_port_override_offset(priv, port); + if (phy_interface_mode_is_rgmii(interface) || + interface == PHY_INTERFACE_MODE_MII || + interface == PHY_INTERFACE_MODE_REVMII) { + reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port); + reg = reg_readl(priv, reg_rgmii_ctrl); + reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); - if (interface == PHY_INTERFACE_MODE_RGMII || - interface == PHY_INTERFACE_MODE_RGMII_TXID || - interface == PHY_INTERFACE_MODE_MII || - interface == PHY_INTERFACE_MODE_REVMII) { - reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port); - reg = reg_readl(priv, reg_rgmii_ctrl); - reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); + if (tx_pause) + reg |= TX_PAUSE_EN; + if (rx_pause) + reg |= RX_PAUSE_EN; - if (tx_pause) - reg |= TX_PAUSE_EN; - if (rx_pause) - reg |= RX_PAUSE_EN; + reg_writel(priv, reg, reg_rgmii_ctrl); + } - reg_writel(priv, reg, reg_rgmii_ctrl); - } + reg = LINK_STS; + if (port == 8) { + if (priv->type == BCM4908_DEVICE_ID) + reg |= GMII_SPEED_UP_2G; + reg |= MII_SW_OR; + } else { + reg |= SW_OVERRIDE; + } - reg = SW_OVERRIDE | LINK_STS; - switch (speed) { - case SPEED_1000: - reg |= SPDSTS_1000 << SPEED_SHIFT; - break; - case SPEED_100: - reg |= SPDSTS_100 << SPEED_SHIFT; - break; - } + switch (speed) { + case SPEED_1000: + reg |= SPDSTS_1000 << SPEED_SHIFT; + break; + case SPEED_100: + reg |= SPDSTS_100 << SPEED_SHIFT; + break; + } - if (duplex == DUPLEX_FULL) - reg |= DUPLX_MODE; + if (duplex == DUPLEX_FULL) + reg |= DUPLX_MODE; - if (tx_pause) - reg |= TXFLOW_CNTL; - if (rx_pause) - reg |= RXFLOW_CNTL; + if (tx_pause) + reg |= TXFLOW_CNTL; + if (rx_pause) + reg |= RXFLOW_CNTL; - core_writel(priv, reg, offset); - } + core_writel(priv, reg, offset); if (mode == MLO_AN_PHY && phydev) p->eee_enabled = b53_eee_init(ds, port, phydev); -- cgit From 36a0bf44358597dee6947938e8643c61442cab87 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 19 Aug 2022 20:48:19 +0300 Subject: net: mscc: ocelot: set up tag_8021q CPU ports independent of user port affinity This is a partial revert of commit c295f9831f1d ("net: mscc: ocelot: switch from {,un}set to {,un}assign for tag_8021q CPU ports"), because as it turns out, this isn't how tag_8021q CPU ports under a LAG are supposed to work. Under that scenario, all user ports are "assigned" to the single tag_8021q CPU port represented by the logical port corresponding to the bonding interface. So one CPU port in a LAG would have is_dsa_8021q_cpu set to true (the one whose physical port ID is equal to the logical port ID), and the other one to false. In turn, this makes 2 undesirable things happen: (1) PGID_CPU contains only the first physical CPU port, rather than both (2) only the first CPU port will be added to the private VLANs used by ocelot for VLAN-unaware bridging To make the driver behave in the same way for both bonded CPU ports, we need to bring back the old concept of setting up a port as a tag_8021q CPU port, and this is what deals with VLAN membership and PGID_CPU updating. But we also need the CPU port "assignment" (the user to CPU port affinity), and this is what updates the PGID_SRC forwarding rules. All DSA CPU ports are statically configured for tag_8021q mode when the tagging protocol is changed to ocelot-8021q. User ports are "assigned" to one CPU port or the other dynamically (this will be handled by a future change). Signed-off-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/ocelot/felix.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index aadb0bd7c24f..ee19ed96f284 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -445,6 +445,9 @@ static int felix_tag_8021q_setup(struct dsa_switch *ds) if (err) return err; + dsa_switch_for_each_cpu_port(dp, ds) + ocelot_port_setup_dsa_8021q_cpu(ocelot, dp->index); + dsa_switch_for_each_user_port(dp, ds) ocelot_port_assign_dsa_8021q_cpu(ocelot, dp->index, dp->cpu_dp->index); @@ -493,6 +496,9 @@ static void felix_tag_8021q_teardown(struct dsa_switch *ds) dsa_switch_for_each_user_port(dp, ds) ocelot_port_unassign_dsa_8021q_cpu(ocelot, dp->index); + dsa_switch_for_each_cpu_port(dp, ds) + ocelot_port_teardown_dsa_8021q_cpu(ocelot, dp->index); + dsa_tag_8021q_unregister(ds); } -- cgit From 1d2577ab0f052375379fa112d1aa34dbb4ef1463 Mon Sep 17 00:00:00 2001 From: Marcus Carlberg Date: Mon, 22 Aug 2022 16:41:36 +0200 Subject: net: dsa: mv88e6xxx: support RGMII cmode Since the probe defaults all interfaces to the highest speed possible (10GBASE-X in mv88e6393x) before the phy mode configuration from the devicetree is considered it is currently impossible to use port 0 in RGMII mode. This change will allow RGMII modes to be configurable for port 0 enabling port 0 to be configured as RGMII as well as serial depending on configuration. Signed-off-by: Marcus Carlberg Link: https://lore.kernel.org/r/20220822144136.16627-1-marcus.carlberg@axis.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++++++ drivers/net/dsa/mv88e6xxx/port.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 07e9a4da924c..6403f1f8bdbb 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -816,6 +816,14 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, MAC_10000FD; } } + + if (port == 0) { + __set_bit(PHY_INTERFACE_MODE_RMII, supported); + __set_bit(PHY_INTERFACE_MODE_RGMII, supported); + __set_bit(PHY_INTERFACE_MODE_RGMII_ID, supported); + __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, supported); + __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, supported); + } } static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 90c55f23b7c9..5c4195c635b0 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -517,6 +517,12 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_RMII: cmode = MV88E6XXX_PORT_STS_CMODE_RMII; break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + cmode = MV88E6XXX_PORT_STS_CMODE_RGMII; + break; case PHY_INTERFACE_MODE_1000BASEX: cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX; break; @@ -634,6 +640,19 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, if (port != 0 && port != 9 && port != 10) return -EOPNOTSUPP; + if (port == 9 || port == 10) { + switch (mode) { + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + return -EINVAL; + default: + break; + } + } + /* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) -- cgit From 8532c60efcc5b7b382006129b77aee2c19c43f15 Mon Sep 17 00:00:00 2001 From: Marcus Carlberg Date: Wed, 24 Aug 2022 11:37:06 +0200 Subject: net: dsa: mv88e6xxx: Allow external SMI if serial p0_mode set to one of the supported serial mode should not prevent configuring the external SMI interface in mv88e6xxx_g2_scratch_gpio_set_smi. The current masking of the p0_mode only checks the first 2 bits. This results in switches supporting serial mode cannot setup external SMI on certain serial modes (Ex: 1000BASE-X and SGMII). Extend the mask of the p0_mode to include the reduced modes and serial modes as allowed modes for the external SMI interface. Signed-off-by: Marcus Carlberg Link: https://lore.kernel.org/r/20220824093706.19049-1-marcus.carlberg@axis.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/global2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 807aeaad9830..7536b8b0ad01 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -298,7 +298,7 @@ #define MV88E6352_G2_SCRATCH_CONFIG_DATA1 0x71 #define MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU BIT(2) #define MV88E6352_G2_SCRATCH_CONFIG_DATA2 0x72 -#define MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK 0x3 +#define MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK 0xf #define MV88E6352_G2_SCRATCH_CONFIG_DATA3 0x73 #define MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL BIT(1) -- cgit From b449080956127410dbc94ba7497de066d68c7573 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:18 +0200 Subject: net: dsa: microchip: add separate struct ksz_chip_data for KSZ8563 chip Add separate entry for the KSZ8563 chip. According to the documentation it can support Gbit only on RGMII port. So, we will need to be able to describe in the followup patch. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 39 ++++++++++++++++++++++++++++++++-- drivers/net/dsa/microchip/ksz_common.h | 6 ++++++ drivers/net/dsa/microchip/ksz_spi.c | 2 +- 3 files changed, 44 insertions(+), 3 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 6bd69a7e6809..5cadc831c75d 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -413,6 +413,29 @@ static const u8 lan937x_shifts[] = { }; const struct ksz_chip_data ksz_switch_chips[] = { + [KSZ8563] = { + .chip_id = KSZ8563_CHIP_ID, + .dev_name = "KSZ8563", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x07, /* can be configured as cpu port */ + .port_cnt = 3, /* total port count */ + .ops = &ksz9477_dev_ops, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ + .supports_mii = {false, false, true}, + .supports_rmii = {false, false, true}, + .supports_rgmii = {false, false, true}, + .internal_phy = {true, true, false}, + }, + [KSZ8795] = { .chip_id = KSZ8795_CHIP_ID, .dev_name = "KSZ8795", @@ -1366,6 +1389,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, proto = DSA_TAG_PROTO_KSZ8795; if (dev->chip_id == KSZ8830_CHIP_ID || + dev->chip_id == KSZ8563_CHIP_ID || dev->chip_id == KSZ9893_CHIP_ID) proto = DSA_TAG_PROTO_KSZ9893; @@ -1685,7 +1709,7 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, static int ksz_switch_detect(struct ksz_device *dev) { - u8 id1, id2; + u8 id1, id2, id4; u16 id16; u32 id32; int ret; @@ -1731,7 +1755,6 @@ static int ksz_switch_detect(struct ksz_device *dev) switch (id32) { case KSZ9477_CHIP_ID: case KSZ9897_CHIP_ID: - case KSZ9893_CHIP_ID: case KSZ9567_CHIP_ID: case LAN9370_CHIP_ID: case LAN9371_CHIP_ID: @@ -1739,6 +1762,18 @@ static int ksz_switch_detect(struct ksz_device *dev) case LAN9373_CHIP_ID: case LAN9374_CHIP_ID: dev->chip_id = id32; + break; + case KSZ9893_CHIP_ID: + ret = ksz_read8(dev, REG_CHIP_ID4, + &id4); + if (ret) + return ret; + + if (id4 == SKU_ID_KSZ8563) + dev->chip_id = KSZ8563_CHIP_ID; + else + dev->chip_id = KSZ9893_CHIP_ID; + break; default: dev_err(dev->dev, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 0d9520dc6d2d..eedcbcddd000 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -124,6 +124,7 @@ struct ksz_device { /* List of supported models */ enum ksz_model { + KSZ8563, KSZ8795, KSZ8794, KSZ8765, @@ -140,6 +141,7 @@ enum ksz_model { }; enum ksz_chip_id { + KSZ8563_CHIP_ID = 0x8563, KSZ8795_CHIP_ID = 0x8795, KSZ8794_CHIP_ID = 0x8794, KSZ8765_CHIP_ID = 0x8765, @@ -483,6 +485,10 @@ static inline int is_lan937x(struct ksz_device *dev) #define SW_REV_ID_M GENMASK(7, 4) +/* KSZ9893, KSZ9563, KSZ8563 specific register */ +#define REG_CHIP_ID4 0x0f +#define SKU_ID_KSZ8563 0x3c + /* Driver set switch broadcast storm protection at 10% rate. */ #define BROADCAST_STORM_PROT_RATE 10 diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 05bd089795f8..746b725b09ec 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -160,7 +160,7 @@ static const struct of_device_id ksz_dt_ids[] = { }, { .compatible = "microchip,ksz8563", - .data = &ksz_switch_chips[KSZ9893] + .data = &ksz_switch_chips[KSZ8563] }, { .compatible = "microchip,ksz9567", -- cgit From 505bf3205aaa3d736aa432ff62bd532882cec32e Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:19 +0200 Subject: net: dsa: microchip: do per-port Gbit detection instead of per-chip KSZ8563 has two 100Mbit PHYs and CPU port with RGMII support. Since 1000Mbit configuration for the RGMII capable MAC is present, we should use per port validation. As main part of migration to per-port validation we need to rework ksz9477_switch_init() function. Which is using undocumented REG_GLOBAL_OPTIONS register to detect per-chip Gbit support. So, it is related to some sort of risk for regressions. To reduce this risk I compared the code with publicly available documentations. This function will executed on following currently supported chips: struct ksz_chip_data OF compatible KSZ9477 KSZ9477 KSZ9897 KSZ9897 KSZ9893 KSZ9893, KSZ9563 KSZ8563 KSZ8563 KSZ9567 KSZ9567 Only KSZ9893, KSZ9563, KSZ8563 document existence of 0xf == REG_GLOBAL_OPTIONS register with bit field description "SKU ID": KSZ9893 0x0C KSZ9563 0x1C KSZ8563 0x3C The existence of hidden flags is not documented. KSZ9477, KSZ9897, KSZ9567 do not document this register at all. Only KSZ8563 is documented as non Gbit chip: 100Mbit PHYs and RGMII CPU port. So, this change should not introduce a regression for configurations with properly used OF compatibles. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 20 +++----------------- drivers/net/dsa/microchip/ksz_common.c | 5 +++++ drivers/net/dsa/microchip/ksz_common.h | 2 +- 3 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index e4f446db0ca1..0f7f44358d7b 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -320,7 +320,7 @@ void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) return; /* No gigabit support. Do not write to this register. */ - if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000) + if (!dev->info->gbit_capable[addr] && reg == MII_CTRL1000) return; ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); @@ -914,7 +914,7 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) /* Energy Efficient Ethernet (EEE) feature select must * be manually disabled (except on KSZ8565 which is 100Mbit) */ - if (dev->features & GBIT_SUPPORT) + if (dev->info->gbit_capable[port]) ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000); /* Register settings are required to meet data sheet @@ -941,7 +941,7 @@ void ksz9477_get_caps(struct ksz_device *dev, int port, config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE | MAC_SYM_PAUSE; - if (dev->features & GBIT_SUPPORT) + if (dev->info->gbit_capable[port]) config->mac_capabilities |= MAC_1000FD; } @@ -1158,27 +1158,13 @@ int ksz9477_switch_init(struct ksz_device *dev) if (ret) return ret; - ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8); - if (ret) - return ret; - /* Number of ports can be reduced depending on chip. */ dev->phy_port_cnt = 5; - /* Default capability is gigabit capable. */ - dev->features = GBIT_SUPPORT; - if (dev->chip_id == KSZ9893_CHIP_ID) { dev->features |= IS_9893; - /* Chip does not support gigabit. */ - if (data8 & SW_QW_ABLE) - dev->features &= ~GBIT_SUPPORT; dev->phy_port_cnt = 2; - } else { - /* Chip does not support gigabit. */ - if (!(data8 & SW_GIGABIT_ABLE)) - dev->features &= ~GBIT_SUPPORT; } return 0; diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 5cadc831c75d..7b6d7efc0a00 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -434,6 +434,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_rmii = {false, false, true}, .supports_rgmii = {false, false, true}, .internal_phy = {true, true, false}, + .gbit_capable = {false, false, true}, }, [KSZ8795] = { @@ -568,6 +569,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { false, true, false}, .internal_phy = {true, true, true, true, true, false, false}, + .gbit_capable = {true, true, true, true, true, true, true}, }, [KSZ9897] = { @@ -596,6 +598,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { false, true, true}, .internal_phy = {true, true, true, true, true, false, false}, + .gbit_capable = {true, true, true, true, true, true, true}, }, [KSZ9893] = { @@ -619,6 +622,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_rmii = {false, false, true}, .supports_rgmii = {false, false, true}, .internal_phy = {true, true, false}, + .gbit_capable = {true, true, true}, }, [KSZ9567] = { @@ -647,6 +651,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { false, true, true}, .internal_phy = {true, true, true, true, true, false, false}, + .gbit_capable = {true, true, true, true, true, true, true}, }, [LAN9370] = { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index eedcbcddd000..e3e120d65941 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -61,6 +61,7 @@ struct ksz_chip_data { bool supports_rmii[KSZ_MAX_NUM_PORTS]; bool supports_rgmii[KSZ_MAX_NUM_PORTS]; bool internal_phy[KSZ_MAX_NUM_PORTS]; + bool gbit_capable[KSZ_MAX_NUM_PORTS]; }; struct ksz_port { @@ -504,7 +505,6 @@ static inline int is_lan937x(struct ksz_device *dev) #define SW_START 0x01 /* Used with variable features to indicate capabilities. */ -#define GBIT_SUPPORT BIT(0) #define IS_9893 BIT(2) /* xMII configuration */ -- cgit From d7539fc2b41a126d596d1e5777e0697a4acc692c Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:20 +0200 Subject: net: dsa: microchip: don't announce extended register support on non Gbit chips This issue was detected after adding support of regmap_ranges for KSZ8563R chip. This chip is reporting extended registers support without having actual extended registers. This made PHYlib request not existing registers. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 0f7f44358d7b..2b3bf1d3950c 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -264,6 +264,16 @@ void ksz9477_port_init_cnt(struct ksz_device *dev, int port) mutex_unlock(&mib->cnt_mutex); } +static void ksz9477_r_phy_quirks(struct ksz_device *dev, u16 addr, u16 reg, + u16 *data) +{ + /* KSZ8563R do not have extended registers but BMSR_ESTATEN and + * BMSR_ERCAP bits are set. + */ + if (dev->chip_id == KSZ8563_CHIP_ID && reg == MII_BMSR) + *data &= ~(BMSR_ESTATEN | BMSR_ERCAP); +} + void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) { u16 val = 0xffff; @@ -308,6 +318,7 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) } } else { ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); + ksz9477_r_phy_quirks(dev, addr, reg, &val); } *data = val; -- cgit From 8f420456792308639fcbc15462050c521fbd127d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:21 +0200 Subject: net: dsa: microchip: allow to pass return values for PHY read/write accesses PHY access may end with errors on different levels. So, allow to forward return values where possible. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz8.h | 4 ++-- drivers/net/dsa/microchip/ksz8795.c | 8 ++++++-- drivers/net/dsa/microchip/ksz9477.c | 12 ++++++++---- drivers/net/dsa/microchip/ksz9477.h | 4 ++-- drivers/net/dsa/microchip/ksz_common.c | 10 ++++++++-- drivers/net/dsa/microchip/ksz_common.h | 4 ++-- drivers/net/dsa/microchip/lan937x.h | 4 ++-- drivers/net/dsa/microchip/lan937x_main.c | 8 ++++---- 8 files changed, 34 insertions(+), 20 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h index 42c50cc4d853..8582b4b67d98 100644 --- a/drivers/net/dsa/microchip/ksz8.h +++ b/drivers/net/dsa/microchip/ksz8.h @@ -17,8 +17,8 @@ u32 ksz8_get_port_addr(int port, int offset); void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member); void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port); void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port); -void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); -void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val); +int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); +int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val); int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr, u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries); int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr, diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index c79a5128235f..f2dd75ee0e07 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -552,7 +552,7 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) ksz8_w_table(dev, TABLE_VLAN, addr, buf); } -void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) +int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) { u8 restart, speed, ctrl, link; int processed = true; @@ -674,9 +674,11 @@ void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) } if (processed) *val = data; + + return 0; } -void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) +int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) { u8 restart, speed, ctrl, data; const u16 *regs; @@ -787,6 +789,8 @@ void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) default: break; } + + return 0; } void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 2b3bf1d3950c..a4f682d3e1fe 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -274,7 +274,7 @@ static void ksz9477_r_phy_quirks(struct ksz_device *dev, u16 addr, u16 reg, *data &= ~(BMSR_ESTATEN | BMSR_ERCAP); } -void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) +int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) { u16 val = 0xffff; @@ -322,19 +322,23 @@ void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) } *data = val; + + return 0; } -void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) +int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { /* No real PHY after this. */ if (addr >= dev->phy_port_cnt) - return; + return 0; /* No gigabit support. Do not write to this register. */ if (!dev->info->gbit_capable[addr] && reg == MII_CTRL1000) - return; + return 0; ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + + return 0; } void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h index cd278b307b3c..ce87e4e09ada 100644 --- a/drivers/net/dsa/microchip/ksz9477.h +++ b/drivers/net/dsa/microchip/ksz9477.h @@ -16,8 +16,8 @@ u32 ksz9477_get_port_addr(int port, int offset); void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member); void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port); void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port); -void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); -void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); +int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); +int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, u64 *dropped, u64 *cnt); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7b6d7efc0a00..099c7bf69940 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1132,8 +1132,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) { struct ksz_device *dev = ds->priv; u16 val = 0xffff; + int ret; - dev->dev_ops->r_phy(dev, addr, reg, &val); + ret = dev->dev_ops->r_phy(dev, addr, reg, &val); + if (ret) + return ret; return val; } @@ -1141,8 +1144,11 @@ static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) { struct ksz_device *dev = ds->priv; + int ret; - dev->dev_ops->w_phy(dev, addr, reg, val); + ret = dev->dev_ops->w_phy(dev, addr, reg, val); + if (ret) + return ret; return 0; } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index e3e120d65941..584850672b9a 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -262,8 +262,8 @@ struct ksz_dev_ops { void (*flush_dyn_mac_table)(struct ksz_device *dev, int port); void (*port_cleanup)(struct ksz_device *dev, int port); void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); - void (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); - void (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); + int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); + int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, u64 *cnt); void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr, diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h index 4e0b1dccec27..5d78d034a62f 100644 --- a/drivers/net/dsa/microchip/lan937x.h +++ b/drivers/net/dsa/microchip/lan937x.h @@ -12,8 +12,8 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); void lan937x_config_cpu_port(struct dsa_switch *ds); int lan937x_switch_init(struct ksz_device *dev); void lan937x_switch_exit(struct ksz_device *dev); -void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); -void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); +int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); +int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu); void lan937x_phylink_get_caps(struct ksz_device *dev, int port, struct phylink_config *config); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index daedd2bf20c1..7b464f1fb5d8 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -128,14 +128,14 @@ static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); } -void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) +int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) { - lan937x_internal_phy_read(dev, addr, reg, data); + return lan937x_internal_phy_read(dev, addr, reg, data); } -void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) +int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { - lan937x_internal_phy_write(dev, addr, reg, val); + return lan937x_internal_phy_write(dev, addr, reg, val); } static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) -- cgit From d38bc3b4b8a6a01170d7f79f2c48ca678d135bbb Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:22 +0200 Subject: net: dsa: microchip: forward error value on all ksz_pread/ksz_pwrite functions ksz_read*/ksz_write* are able to return errors, so forward it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.h | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 584850672b9a..62b9499afca5 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -394,40 +394,42 @@ 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 void ksz_pread8(struct ksz_device *dev, int port, int offset, - u8 *data) +static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, + u8 *data) { - ksz_read8(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_read8(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static inline void ksz_pread16(struct ksz_device *dev, int port, int offset, - u16 *data) +static inline int ksz_pread16(struct ksz_device *dev, int port, int offset, + u16 *data) { - ksz_read16(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_read16(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static inline void ksz_pread32(struct ksz_device *dev, int port, int offset, - u32 *data) +static inline int ksz_pread32(struct ksz_device *dev, int port, int offset, + u32 *data) { - ksz_read32(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_read32(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static inline void ksz_pwrite8(struct ksz_device *dev, int port, int offset, - u8 data) +static inline int ksz_pwrite8(struct ksz_device *dev, int port, int offset, + u8 data) { - ksz_write8(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_write8(dev, dev->dev_ops->get_port_addr(port, offset), data); } -static inline void ksz_pwrite16(struct ksz_device *dev, int port, int offset, - u16 data) +static inline int ksz_pwrite16(struct ksz_device *dev, int port, int offset, + u16 data) { - ksz_write16(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_write16(dev, dev->dev_ops->get_port_addr(port, offset), + data); } -static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, - u32 data) +static inline int ksz_pwrite32(struct ksz_device *dev, int port, int offset, + u32 data) { - ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), data); + return ksz_write32(dev, dev->dev_ops->get_port_addr(port, offset), + data); } static inline void ksz_prmw8(struct ksz_device *dev, int port, int offset, -- cgit From 9da975e1bbef6804145743a6ec0cae0f2f3f4c09 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:23 +0200 Subject: net: dsa: microchip: ksz9477: add error handling to ksz9477_r/w_phy Now ksz_pread/ksz_pwrite can return error value. So, make use of it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index a4f682d3e1fe..f60ceaf25a66 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -277,6 +277,7 @@ static void ksz9477_r_phy_quirks(struct ksz_device *dev, u16 addr, u16 reg, int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) { u16 val = 0xffff; + int ret; /* No real PHY after this. Simulate the PHY. * A fixed PHY can be setup in the device tree, but this function is @@ -317,7 +318,10 @@ int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) break; } } else { - ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); + ret = ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); + if (ret) + return ret; + ksz9477_r_phy_quirks(dev, addr, reg, &val); } @@ -334,11 +338,9 @@ int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) /* No gigabit support. Do not write to this register. */ if (!dev->info->gbit_capable[addr] && reg == MII_CTRL1000) - return 0; + return -ENXIO; - ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); - - return 0; + return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); } void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) -- cgit From 9590fc4a2af55f92142ecbb724d999adf77a07c0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:24 +0200 Subject: net: dsa: microchip: ksz8795: add error handling to ksz8_r/w_phy Now ksz_pread/ksz_pwrite can return error value. So, make use of it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz8795.c | 102 ++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 21 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index f2dd75ee0e07..f020d9f40284 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -560,14 +560,24 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) u8 val1, val2; u16 data = 0; u8 p = phy; + int ret; regs = dev->info->regs; switch (reg) { case MII_BMCR: - ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); - ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); - ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); + ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); + if (ret) + return ret; + + ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); + if (ret) + return ret; + + ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); + if (ret) + return ret; + if (restart & PORT_PHY_LOOPBACK) data |= BMCR_LOOPBACK; if (ctrl & PORT_FORCE_100_MBIT) @@ -597,7 +607,10 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) data |= KSZ886X_BMCR_DISABLE_LED; break; case MII_BMSR: - ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); + ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); + if (ret) + return ret; + data = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | @@ -618,7 +631,10 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) data = KSZ8795_ID_LO; break; case MII_ADVERTISE: - ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); + ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); + if (ret) + return ret; + data = ADVERTISE_CSMA; if (ctrl & PORT_AUTO_NEG_SYM_PAUSE) data |= ADVERTISE_PAUSE_CAP; @@ -632,7 +648,10 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) data |= ADVERTISE_10HALF; break; case MII_LPA: - ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link); + ret = ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link); + if (ret) + return ret; + data = LPA_SLCT; if (link & PORT_REMOTE_SYM_PAUSE) data |= LPA_PAUSE_CAP; @@ -648,8 +667,14 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) data |= LPA_LPACK; break; case PHY_REG_LINK_MD: - ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1); - ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2); + ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1); + if (ret) + return ret; + + ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2); + if (ret) + return ret; + if (val1 & PORT_START_CABLE_DIAG) data |= PHY_START_CABLE_DIAG; @@ -664,7 +689,10 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2)); break; case PHY_REG_PHY_CTRL: - ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); + ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); + if (ret) + return ret; + if (link & PORT_MDIX_STATUS) data |= KSZ886X_CTRL_MDIX_STAT; break; @@ -683,6 +711,7 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) u8 restart, speed, ctrl, data; const u16 *regs; u8 p = phy; + int ret; regs = dev->info->regs; @@ -692,15 +721,26 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) /* Do not support PHY reset function. */ if (val & BMCR_RESET) break; - ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); + ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); + if (ret) + return ret; + data = speed; if (val & KSZ886X_BMCR_HP_MDIX) data |= PORT_HP_MDIX; else data &= ~PORT_HP_MDIX; - if (data != speed) - ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); - ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); + + if (data != speed) { + ret = ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); + if (ret) + return ret; + } + + ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); + if (ret) + return ret; + data = ctrl; if (ksz_is_ksz88x3(dev)) { if ((val & BMCR_ANENABLE)) @@ -726,9 +766,17 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) data |= PORT_FORCE_FULL_DUPLEX; else data &= ~PORT_FORCE_FULL_DUPLEX; - if (data != ctrl) - ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); - ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); + + if (data != ctrl) { + ret = ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); + if (ret) + return ret; + } + + ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); + if (ret) + return ret; + data = restart; if (val & KSZ886X_BMCR_DISABLE_LED) data |= PORT_LED_OFF; @@ -758,11 +806,19 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) data |= PORT_PHY_LOOPBACK; else data &= ~PORT_PHY_LOOPBACK; - if (data != restart) - ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], data); + + if (data != restart) { + ret = ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], + data); + if (ret) + return ret; + } break; case MII_ADVERTISE: - ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); + ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); + if (ret) + return ret; + data = ctrl; data &= ~(PORT_AUTO_NEG_SYM_PAUSE | PORT_AUTO_NEG_100BTX_FD | @@ -779,8 +835,12 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) data |= PORT_AUTO_NEG_10BT_FD; if (val & ADVERTISE_10HALF) data |= PORT_AUTO_NEG_10BT; - if (data != ctrl) - ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data); + + if (data != ctrl) { + ret = ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data); + if (ret) + return ret; + } break; case PHY_REG_LINK_MD: if (val & PHY_START_CABLE_DIAG) -- cgit From b5708dc6539d7630b4ddbd9f72a74280630770b8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:25 +0200 Subject: net: dsa: microchip: KSZ9893: do not write to not supported Output Clock Control Register This issue was detected after adding regmap register access validation. KSZ9893 compatible chips do not have "Output Clock Control Register 0x0103". So, avoid writing to it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index f60ceaf25a66..fb9de6b447b1 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -193,6 +193,11 @@ int ksz9477_reset_switch(struct ksz_device *dev) ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); + /* KSZ9893 compatible chips do not support refclk configuration */ + if (dev->chip_id == KSZ9893_CHIP_ID || + dev->chip_id == KSZ8563_CHIP_ID) + return 0; + data8 = SW_ENABLE_REFCLKO; if (dev->synclko_disable) data8 = 0; -- cgit From ec6ba50c65c1e30218f69055a556bdd133af6da5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:26 +0200 Subject: net: dsa: microchip: add support for regmap_access_tables This is complex driver with support for different chips with different layouts. To detect at least some bugs earlier, we should validate register accesses by using regmap_access_table support. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.h | 46 +++++++++++++++++++++++++++++++--- drivers/net/dsa/microchip/ksz_spi.c | 3 +++ 2 files changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 62b9499afca5..4491cedd32c3 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -62,6 +62,8 @@ struct ksz_chip_data { bool supports_rgmii[KSZ_MAX_NUM_PORTS]; bool internal_phy[KSZ_MAX_NUM_PORTS]; bool gbit_capable[KSZ_MAX_NUM_PORTS]; + const struct regmap_access_table *wr_table; + const struct regmap_access_table *rd_table; }; struct ksz_port { @@ -333,6 +335,10 @@ static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) unsigned int value; int ret = regmap_read(dev->regmap[0], reg, &value); + if (ret) + dev_err(dev->dev, "can't read 8bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + *val = value; return ret; } @@ -342,6 +348,10 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) unsigned int value; int ret = regmap_read(dev->regmap[1], reg, &value); + if (ret) + dev_err(dev->dev, "can't read 16bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + *val = value; return ret; } @@ -351,6 +361,10 @@ static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) unsigned int value; int ret = regmap_read(dev->regmap[2], reg, &value); + if (ret) + dev_err(dev->dev, "can't read 32bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + *val = value; return ret; } @@ -361,7 +375,10 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val) int ret; ret = regmap_bulk_read(dev->regmap[2], reg, value, 2); - if (!ret) + if (ret) + dev_err(dev->dev, "can't read 64bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + else *val = (u64)value[0] << 32 | value[1]; return ret; @@ -369,17 +386,38 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val) static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value) { - return regmap_write(dev->regmap[0], reg, value); + int ret; + + ret = regmap_write(dev->regmap[0], reg, value); + if (ret) + dev_err(dev->dev, "can't write 8bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + + return ret; } static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) { - return regmap_write(dev->regmap[1], reg, value); + int ret; + + ret = regmap_write(dev->regmap[1], reg, value); + if (ret) + dev_err(dev->dev, "can't write 16bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + + return ret; } static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) { - return regmap_write(dev->regmap[2], reg, value); + int ret; + + ret = regmap_write(dev->regmap[2], reg, value); + if (ret) + dev_err(dev->dev, "can't write 32bit reg: 0x%x %pe\n", reg, + ERR_PTR(ret)); + + return ret; } static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 746b725b09ec..44c2d9912406 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -66,7 +66,10 @@ static int ksz_spi_probe(struct spi_device *spi) for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { rc = regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; + rc.wr_table = chip->wr_table; + rc.rd_table = chip->rd_table; dev->regmap[i] = devm_regmap_init_spi(spi, &rc); + if (IS_ERR(dev->regmap[i])) { ret = PTR_ERR(dev->regmap[i]); dev_err(&spi->dev, -- cgit From 41131bac9a9adf98024d129d676c09cdf72b7de7 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:27 +0200 Subject: net: dsa: microchip: add regmap_range for KSZ8563 chip Add register validation for KSZ8563. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 121 +++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 099c7bf69940..b63d4ca60855 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -412,6 +412,125 @@ static const u8 lan937x_shifts[] = { [ALU_STAT_INDEX] = 8, }; +static const struct regmap_range ksz8563_valid_regs[] = { + regmap_reg_range(0x0000, 0x0003), + regmap_reg_range(0x0006, 0x0006), + regmap_reg_range(0x000f, 0x001f), + regmap_reg_range(0x0100, 0x0100), + regmap_reg_range(0x0104, 0x0107), + regmap_reg_range(0x010d, 0x010d), + regmap_reg_range(0x0110, 0x0113), + regmap_reg_range(0x0120, 0x012b), + regmap_reg_range(0x0201, 0x0201), + regmap_reg_range(0x0210, 0x0213), + regmap_reg_range(0x0300, 0x0300), + regmap_reg_range(0x0302, 0x031b), + regmap_reg_range(0x0320, 0x032b), + regmap_reg_range(0x0330, 0x0336), + regmap_reg_range(0x0338, 0x033e), + regmap_reg_range(0x0340, 0x035f), + regmap_reg_range(0x0370, 0x0370), + regmap_reg_range(0x0378, 0x0378), + regmap_reg_range(0x037c, 0x037d), + regmap_reg_range(0x0390, 0x0393), + regmap_reg_range(0x0400, 0x040e), + regmap_reg_range(0x0410, 0x042f), + regmap_reg_range(0x0500, 0x0519), + regmap_reg_range(0x0520, 0x054b), + regmap_reg_range(0x0550, 0x05b3), + + /* port 1 */ + regmap_reg_range(0x1000, 0x1001), + regmap_reg_range(0x1004, 0x100b), + regmap_reg_range(0x1013, 0x1013), + regmap_reg_range(0x1017, 0x1017), + regmap_reg_range(0x101b, 0x101b), + regmap_reg_range(0x101f, 0x1021), + regmap_reg_range(0x1030, 0x1030), + regmap_reg_range(0x1100, 0x1111), + regmap_reg_range(0x111a, 0x111d), + regmap_reg_range(0x1122, 0x1127), + regmap_reg_range(0x112a, 0x112b), + regmap_reg_range(0x1136, 0x1139), + regmap_reg_range(0x113e, 0x113f), + regmap_reg_range(0x1400, 0x1401), + regmap_reg_range(0x1403, 0x1403), + regmap_reg_range(0x1410, 0x1417), + regmap_reg_range(0x1420, 0x1423), + regmap_reg_range(0x1500, 0x1507), + regmap_reg_range(0x1600, 0x1612), + regmap_reg_range(0x1800, 0x180f), + regmap_reg_range(0x1900, 0x1907), + regmap_reg_range(0x1914, 0x191b), + regmap_reg_range(0x1a00, 0x1a03), + regmap_reg_range(0x1a04, 0x1a08), + regmap_reg_range(0x1b00, 0x1b01), + regmap_reg_range(0x1b04, 0x1b04), + regmap_reg_range(0x1c00, 0x1c05), + regmap_reg_range(0x1c08, 0x1c1b), + + /* port 2 */ + regmap_reg_range(0x2000, 0x2001), + regmap_reg_range(0x2004, 0x200b), + regmap_reg_range(0x2013, 0x2013), + regmap_reg_range(0x2017, 0x2017), + regmap_reg_range(0x201b, 0x201b), + regmap_reg_range(0x201f, 0x2021), + regmap_reg_range(0x2030, 0x2030), + regmap_reg_range(0x2100, 0x2111), + regmap_reg_range(0x211a, 0x211d), + regmap_reg_range(0x2122, 0x2127), + regmap_reg_range(0x212a, 0x212b), + regmap_reg_range(0x2136, 0x2139), + regmap_reg_range(0x213e, 0x213f), + regmap_reg_range(0x2400, 0x2401), + regmap_reg_range(0x2403, 0x2403), + regmap_reg_range(0x2410, 0x2417), + regmap_reg_range(0x2420, 0x2423), + regmap_reg_range(0x2500, 0x2507), + regmap_reg_range(0x2600, 0x2612), + regmap_reg_range(0x2800, 0x280f), + regmap_reg_range(0x2900, 0x2907), + regmap_reg_range(0x2914, 0x291b), + regmap_reg_range(0x2a00, 0x2a03), + regmap_reg_range(0x2a04, 0x2a08), + regmap_reg_range(0x2b00, 0x2b01), + regmap_reg_range(0x2b04, 0x2b04), + regmap_reg_range(0x2c00, 0x2c05), + regmap_reg_range(0x2c08, 0x2c1b), + + /* port 3 */ + regmap_reg_range(0x3000, 0x3001), + regmap_reg_range(0x3004, 0x300b), + regmap_reg_range(0x3013, 0x3013), + regmap_reg_range(0x3017, 0x3017), + regmap_reg_range(0x301b, 0x301b), + regmap_reg_range(0x301f, 0x3021), + regmap_reg_range(0x3030, 0x3030), + regmap_reg_range(0x3300, 0x3301), + regmap_reg_range(0x3303, 0x3303), + regmap_reg_range(0x3400, 0x3401), + regmap_reg_range(0x3403, 0x3403), + regmap_reg_range(0x3410, 0x3417), + regmap_reg_range(0x3420, 0x3423), + regmap_reg_range(0x3500, 0x3507), + regmap_reg_range(0x3600, 0x3612), + regmap_reg_range(0x3800, 0x380f), + regmap_reg_range(0x3900, 0x3907), + regmap_reg_range(0x3914, 0x391b), + regmap_reg_range(0x3a00, 0x3a03), + regmap_reg_range(0x3a04, 0x3a08), + regmap_reg_range(0x3b00, 0x3b01), + regmap_reg_range(0x3b04, 0x3b04), + regmap_reg_range(0x3c00, 0x3c05), + regmap_reg_range(0x3c08, 0x3c1b), +}; + +static const struct regmap_access_table ksz8563_register_set = { + .yes_ranges = ksz8563_valid_regs, + .n_yes_ranges = ARRAY_SIZE(ksz8563_valid_regs), +}; + const struct ksz_chip_data ksz_switch_chips[] = { [KSZ8563] = { .chip_id = KSZ8563_CHIP_ID, @@ -435,6 +554,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_rgmii = {false, false, true}, .internal_phy = {true, true, false}, .gbit_capable = {false, false, true}, + .wr_table = &ksz8563_register_set, + .rd_table = &ksz8563_register_set, }, [KSZ8795] = { -- cgit From 5bd3ecd121e34370b4d5a02de925335655bbaa9a Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:28 +0200 Subject: net: dsa: microchip: ksz9477: remove MII_CTRL1000 check from ksz9477_w_phy() The reason why PHYlib may access MII_CTRL1000 on the chip without GBit support is only if chip provides wrong information about extended caps register. This issue is now handled by ksz9477_r_phy_quirks() With proper regmap_ranges provided for all chips we will be able to catch this kind of bugs any way. So, remove this sanity check. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index fb9de6b447b1..f0c81d90c99f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -341,10 +341,6 @@ int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) if (addr >= dev->phy_port_cnt) return 0; - /* No gigabit support. Do not write to this register. */ - if (!dev->info->gbit_capable[addr] && reg == MII_CTRL1000) - return -ENXIO; - return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); } -- cgit From 74e792b5f2dd518983f401aa130094f1dbd0d74f Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:29 +0200 Subject: net: dsa: microchip: add regmap_range for KSZ9477 chip Add register validation for KSZ9477 Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 272 +++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b63d4ca60855..7eb74ab04933 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -531,6 +531,276 @@ static const struct regmap_access_table ksz8563_register_set = { .n_yes_ranges = ARRAY_SIZE(ksz8563_valid_regs), }; +static const struct regmap_range ksz9477_valid_regs[] = { + regmap_reg_range(0x0000, 0x0003), + regmap_reg_range(0x0006, 0x0006), + regmap_reg_range(0x0010, 0x001f), + regmap_reg_range(0x0100, 0x0100), + regmap_reg_range(0x0103, 0x0107), + regmap_reg_range(0x010d, 0x010d), + regmap_reg_range(0x0110, 0x0113), + regmap_reg_range(0x0120, 0x012b), + regmap_reg_range(0x0201, 0x0201), + regmap_reg_range(0x0210, 0x0213), + regmap_reg_range(0x0300, 0x0300), + regmap_reg_range(0x0302, 0x031b), + regmap_reg_range(0x0320, 0x032b), + regmap_reg_range(0x0330, 0x0336), + regmap_reg_range(0x0338, 0x033e), + regmap_reg_range(0x0340, 0x035f), + regmap_reg_range(0x0370, 0x0370), + regmap_reg_range(0x0378, 0x0378), + regmap_reg_range(0x037c, 0x037d), + regmap_reg_range(0x0390, 0x0393), + regmap_reg_range(0x0400, 0x040e), + regmap_reg_range(0x0410, 0x042f), + regmap_reg_range(0x0444, 0x044b), + regmap_reg_range(0x0450, 0x046f), + regmap_reg_range(0x0500, 0x0519), + regmap_reg_range(0x0520, 0x054b), + regmap_reg_range(0x0550, 0x05b3), + regmap_reg_range(0x0604, 0x060b), + regmap_reg_range(0x0610, 0x0612), + regmap_reg_range(0x0614, 0x062c), + regmap_reg_range(0x0640, 0x0645), + regmap_reg_range(0x0648, 0x064d), + + /* port 1 */ + regmap_reg_range(0x1000, 0x1001), + regmap_reg_range(0x1013, 0x1013), + regmap_reg_range(0x1017, 0x1017), + regmap_reg_range(0x101b, 0x101b), + regmap_reg_range(0x101f, 0x1020), + regmap_reg_range(0x1030, 0x1030), + regmap_reg_range(0x1100, 0x1115), + regmap_reg_range(0x111a, 0x111f), + regmap_reg_range(0x1122, 0x1127), + regmap_reg_range(0x112a, 0x112b), + regmap_reg_range(0x1136, 0x1139), + regmap_reg_range(0x113e, 0x113f), + regmap_reg_range(0x1400, 0x1401), + regmap_reg_range(0x1403, 0x1403), + regmap_reg_range(0x1410, 0x1417), + regmap_reg_range(0x1420, 0x1423), + regmap_reg_range(0x1500, 0x1507), + regmap_reg_range(0x1600, 0x1613), + regmap_reg_range(0x1800, 0x180f), + regmap_reg_range(0x1820, 0x1827), + regmap_reg_range(0x1830, 0x1837), + regmap_reg_range(0x1840, 0x184b), + regmap_reg_range(0x1900, 0x1907), + regmap_reg_range(0x1914, 0x191b), + regmap_reg_range(0x1920, 0x1920), + regmap_reg_range(0x1923, 0x1927), + regmap_reg_range(0x1a00, 0x1a03), + regmap_reg_range(0x1a04, 0x1a07), + regmap_reg_range(0x1b00, 0x1b01), + regmap_reg_range(0x1b04, 0x1b04), + regmap_reg_range(0x1c00, 0x1c05), + regmap_reg_range(0x1c08, 0x1c1b), + + /* port 2 */ + regmap_reg_range(0x2000, 0x2001), + regmap_reg_range(0x2013, 0x2013), + regmap_reg_range(0x2017, 0x2017), + regmap_reg_range(0x201b, 0x201b), + regmap_reg_range(0x201f, 0x2020), + regmap_reg_range(0x2030, 0x2030), + regmap_reg_range(0x2100, 0x2115), + regmap_reg_range(0x211a, 0x211f), + regmap_reg_range(0x2122, 0x2127), + regmap_reg_range(0x212a, 0x212b), + regmap_reg_range(0x2136, 0x2139), + regmap_reg_range(0x213e, 0x213f), + regmap_reg_range(0x2400, 0x2401), + regmap_reg_range(0x2403, 0x2403), + regmap_reg_range(0x2410, 0x2417), + regmap_reg_range(0x2420, 0x2423), + regmap_reg_range(0x2500, 0x2507), + regmap_reg_range(0x2600, 0x2613), + regmap_reg_range(0x2800, 0x280f), + regmap_reg_range(0x2820, 0x2827), + regmap_reg_range(0x2830, 0x2837), + regmap_reg_range(0x2840, 0x284b), + regmap_reg_range(0x2900, 0x2907), + regmap_reg_range(0x2914, 0x291b), + regmap_reg_range(0x2920, 0x2920), + regmap_reg_range(0x2923, 0x2927), + regmap_reg_range(0x2a00, 0x2a03), + regmap_reg_range(0x2a04, 0x2a07), + regmap_reg_range(0x2b00, 0x2b01), + regmap_reg_range(0x2b04, 0x2b04), + regmap_reg_range(0x2c00, 0x2c05), + regmap_reg_range(0x2c08, 0x2c1b), + + /* port 3 */ + regmap_reg_range(0x3000, 0x3001), + regmap_reg_range(0x3013, 0x3013), + regmap_reg_range(0x3017, 0x3017), + regmap_reg_range(0x301b, 0x301b), + regmap_reg_range(0x301f, 0x3020), + regmap_reg_range(0x3030, 0x3030), + regmap_reg_range(0x3100, 0x3115), + regmap_reg_range(0x311a, 0x311f), + regmap_reg_range(0x3122, 0x3127), + regmap_reg_range(0x312a, 0x312b), + regmap_reg_range(0x3136, 0x3139), + regmap_reg_range(0x313e, 0x313f), + regmap_reg_range(0x3400, 0x3401), + regmap_reg_range(0x3403, 0x3403), + regmap_reg_range(0x3410, 0x3417), + regmap_reg_range(0x3420, 0x3423), + regmap_reg_range(0x3500, 0x3507), + regmap_reg_range(0x3600, 0x3613), + regmap_reg_range(0x3800, 0x380f), + regmap_reg_range(0x3820, 0x3827), + regmap_reg_range(0x3830, 0x3837), + regmap_reg_range(0x3840, 0x384b), + regmap_reg_range(0x3900, 0x3907), + regmap_reg_range(0x3914, 0x391b), + regmap_reg_range(0x3920, 0x3920), + regmap_reg_range(0x3923, 0x3927), + regmap_reg_range(0x3a00, 0x3a03), + regmap_reg_range(0x3a04, 0x3a07), + regmap_reg_range(0x3b00, 0x3b01), + regmap_reg_range(0x3b04, 0x3b04), + regmap_reg_range(0x3c00, 0x3c05), + regmap_reg_range(0x3c08, 0x3c1b), + + /* port 4 */ + regmap_reg_range(0x4000, 0x4001), + regmap_reg_range(0x4013, 0x4013), + regmap_reg_range(0x4017, 0x4017), + regmap_reg_range(0x401b, 0x401b), + regmap_reg_range(0x401f, 0x4020), + regmap_reg_range(0x4030, 0x4030), + regmap_reg_range(0x4100, 0x4115), + regmap_reg_range(0x411a, 0x411f), + regmap_reg_range(0x4122, 0x4127), + regmap_reg_range(0x412a, 0x412b), + regmap_reg_range(0x4136, 0x4139), + regmap_reg_range(0x413e, 0x413f), + regmap_reg_range(0x4400, 0x4401), + regmap_reg_range(0x4403, 0x4403), + regmap_reg_range(0x4410, 0x4417), + regmap_reg_range(0x4420, 0x4423), + regmap_reg_range(0x4500, 0x4507), + regmap_reg_range(0x4600, 0x4613), + regmap_reg_range(0x4800, 0x480f), + regmap_reg_range(0x4820, 0x4827), + regmap_reg_range(0x4830, 0x4837), + regmap_reg_range(0x4840, 0x484b), + regmap_reg_range(0x4900, 0x4907), + regmap_reg_range(0x4914, 0x491b), + regmap_reg_range(0x4920, 0x4920), + regmap_reg_range(0x4923, 0x4927), + regmap_reg_range(0x4a00, 0x4a03), + regmap_reg_range(0x4a04, 0x4a07), + regmap_reg_range(0x4b00, 0x4b01), + regmap_reg_range(0x4b04, 0x4b04), + regmap_reg_range(0x4c00, 0x4c05), + regmap_reg_range(0x4c08, 0x4c1b), + + /* port 5 */ + regmap_reg_range(0x5000, 0x5001), + regmap_reg_range(0x5013, 0x5013), + regmap_reg_range(0x5017, 0x5017), + regmap_reg_range(0x501b, 0x501b), + regmap_reg_range(0x501f, 0x5020), + regmap_reg_range(0x5030, 0x5030), + regmap_reg_range(0x5100, 0x5115), + regmap_reg_range(0x511a, 0x511f), + regmap_reg_range(0x5122, 0x5127), + regmap_reg_range(0x512a, 0x512b), + regmap_reg_range(0x5136, 0x5139), + regmap_reg_range(0x513e, 0x513f), + regmap_reg_range(0x5400, 0x5401), + regmap_reg_range(0x5403, 0x5403), + regmap_reg_range(0x5410, 0x5417), + regmap_reg_range(0x5420, 0x5423), + regmap_reg_range(0x5500, 0x5507), + regmap_reg_range(0x5600, 0x5613), + regmap_reg_range(0x5800, 0x580f), + regmap_reg_range(0x5820, 0x5827), + regmap_reg_range(0x5830, 0x5837), + regmap_reg_range(0x5840, 0x584b), + regmap_reg_range(0x5900, 0x5907), + regmap_reg_range(0x5914, 0x591b), + regmap_reg_range(0x5920, 0x5920), + regmap_reg_range(0x5923, 0x5927), + regmap_reg_range(0x5a00, 0x5a03), + regmap_reg_range(0x5a04, 0x5a07), + regmap_reg_range(0x5b00, 0x5b01), + regmap_reg_range(0x5b04, 0x5b04), + regmap_reg_range(0x5c00, 0x5c05), + regmap_reg_range(0x5c08, 0x5c1b), + + /* port 6 */ + regmap_reg_range(0x6000, 0x6001), + regmap_reg_range(0x6013, 0x6013), + regmap_reg_range(0x6017, 0x6017), + regmap_reg_range(0x601b, 0x601b), + regmap_reg_range(0x601f, 0x6020), + regmap_reg_range(0x6030, 0x6030), + regmap_reg_range(0x6300, 0x6301), + regmap_reg_range(0x6400, 0x6401), + regmap_reg_range(0x6403, 0x6403), + regmap_reg_range(0x6410, 0x6417), + regmap_reg_range(0x6420, 0x6423), + regmap_reg_range(0x6500, 0x6507), + regmap_reg_range(0x6600, 0x6613), + regmap_reg_range(0x6800, 0x680f), + regmap_reg_range(0x6820, 0x6827), + regmap_reg_range(0x6830, 0x6837), + regmap_reg_range(0x6840, 0x684b), + regmap_reg_range(0x6900, 0x6907), + regmap_reg_range(0x6914, 0x691b), + regmap_reg_range(0x6920, 0x6920), + regmap_reg_range(0x6923, 0x6927), + regmap_reg_range(0x6a00, 0x6a03), + regmap_reg_range(0x6a04, 0x6a07), + regmap_reg_range(0x6b00, 0x6b01), + regmap_reg_range(0x6b04, 0x6b04), + regmap_reg_range(0x6c00, 0x6c05), + regmap_reg_range(0x6c08, 0x6c1b), + + /* port 7 */ + regmap_reg_range(0x7000, 0x7001), + regmap_reg_range(0x7013, 0x7013), + regmap_reg_range(0x7017, 0x7017), + regmap_reg_range(0x701b, 0x701b), + regmap_reg_range(0x701f, 0x7020), + regmap_reg_range(0x7030, 0x7030), + regmap_reg_range(0x7200, 0x7203), + regmap_reg_range(0x7206, 0x7207), + regmap_reg_range(0x7300, 0x7301), + regmap_reg_range(0x7400, 0x7401), + regmap_reg_range(0x7403, 0x7403), + regmap_reg_range(0x7410, 0x7417), + regmap_reg_range(0x7420, 0x7423), + regmap_reg_range(0x7500, 0x7507), + regmap_reg_range(0x7600, 0x7613), + regmap_reg_range(0x7800, 0x780f), + regmap_reg_range(0x7820, 0x7827), + regmap_reg_range(0x7830, 0x7837), + regmap_reg_range(0x7840, 0x784b), + regmap_reg_range(0x7900, 0x7907), + regmap_reg_range(0x7914, 0x791b), + regmap_reg_range(0x7920, 0x7920), + regmap_reg_range(0x7923, 0x7927), + regmap_reg_range(0x7a00, 0x7a03), + regmap_reg_range(0x7a04, 0x7a07), + regmap_reg_range(0x7b00, 0x7b01), + regmap_reg_range(0x7b04, 0x7b04), + regmap_reg_range(0x7c00, 0x7c05), + regmap_reg_range(0x7c08, 0x7c1b), +}; + +static const struct regmap_access_table ksz9477_register_set = { + .yes_ranges = ksz9477_valid_regs, + .n_yes_ranges = ARRAY_SIZE(ksz9477_valid_regs), +}; + const struct ksz_chip_data ksz_switch_chips[] = { [KSZ8563] = { .chip_id = KSZ8563_CHIP_ID, @@ -691,6 +961,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, true, true, false, false}, .gbit_capable = {true, true, true, true, true, true, true}, + .wr_table = &ksz9477_register_set, + .rd_table = &ksz9477_register_set, }, [KSZ9897] = { -- cgit From 0a7fbd514edfcf1e67f9737f35c0a12b3ff1b438 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:30 +0200 Subject: net: dsa: microchip: ksz9477: use internal_phy instead of phy_port_cnt With code refactoring was introduced new variable internal_phy. Let's use it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index f0c81d90c99f..d1ee6b4b4954 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -290,7 +290,7 @@ int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) * For RGMII PHY there is no way to access it so the fixed PHY should * be used. For SGMII PHY the supporting code will be added later. */ - if (addr >= dev->phy_port_cnt) { + if (!dev->info->internal_phy[addr]) { struct ksz_port *p = &dev->ports[addr]; switch (reg) { @@ -338,7 +338,7 @@ int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { /* No real PHY after this. */ - if (addr >= dev->phy_port_cnt) + if (!dev->info->internal_phy[addr]) return 0; return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); @@ -887,7 +887,7 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) phy_interface_t interface; bool gbit; - if (port < dev->phy_port_cnt) + if (dev->info->internal_phy[port]) return PHY_INTERFACE_MODE_NA; gbit = ksz_get_gbit(dev, port); @@ -994,7 +994,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) /* enable 802.1p priority */ ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); - if (port < dev->phy_port_cnt) { + if (dev->info->internal_phy[port]) { /* do not force flow control */ ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, @@ -1017,7 +1017,7 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) ksz9477_cfg_port_member(dev, port, member); /* clear pending interrupts */ - if (port < dev->phy_port_cnt) + if (dev->info->internal_phy[port]) ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); } @@ -1080,7 +1080,7 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); p->on = 1; - if (i < dev->phy_port_cnt) + if (dev->info->internal_phy[i]) p->phy = 1; if (dev->chip_id == 0x00947700 && i == 6) { p->sgmii = 1; @@ -1176,15 +1176,9 @@ int ksz9477_switch_init(struct ksz_device *dev) if (ret) return ret; - /* Number of ports can be reduced depending on chip. */ - dev->phy_port_cnt = 5; - - if (dev->chip_id == KSZ9893_CHIP_ID) { + if (dev->chip_id == KSZ9893_CHIP_ID) dev->features |= IS_9893; - dev->phy_port_cnt = 2; - } - return 0; } -- cgit From 6aaa8e7d20026652ede69ce3ff4772859752da15 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:31 +0200 Subject: net: dsa: microchip: remove unused port phy variable This variable is unused. So, drop it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz8795.c | 1 - drivers/net/dsa/microchip/ksz9477.c | 5 ----- drivers/net/dsa/microchip/ksz_common.h | 1 - 3 files changed, 7 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index f020d9f40284..bd3b133e7085 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -1251,7 +1251,6 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) if (i == dev->phy_port_cnt) break; p->on = 1; - p->phy = 1; } for (i = 0; i < dev->phy_port_cnt; i++) { p = &dev->ports[i]; diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index d1ee6b4b4954..4a2074a12b3f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1080,13 +1080,8 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); p->on = 1; - if (dev->info->internal_phy[i]) - p->phy = 1; if (dev->chip_id == 0x00947700 && i == 6) { p->sgmii = 1; - - /* SGMII PHY detection code is not implemented yet. */ - p->phy = 0; } } } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 4491cedd32c3..99da2092d0d7 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -73,7 +73,6 @@ struct ksz_port { struct phy_device phydev; u32 on:1; /* port is not disabled by hardware */ - u32 phy:1; /* port has a PHY */ u32 fiber:1; /* port is fiber */ u32 sgmii:1; /* port is SGMII */ u32 force:1; -- cgit From 7d39143449ea3308ed116a7cc71bc870a2d25151 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:32 +0200 Subject: net: dsa: microchip: ksz9477: remove unused "on" variable This variable is not used on ksz9477 side. Remove it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 4a2074a12b3f..18375309233a 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1069,7 +1069,6 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) /* enable cpu port */ ksz9477_port_setup(dev, i, true); - p->on = 1; } } @@ -1079,7 +1078,6 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) p = &dev->ports[i]; ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); - p->on = 1; if (dev->chip_id == 0x00947700 && i == 6) { p->sgmii = 1; } -- cgit From e7f695210140ea67dd81f7c9d95c3a685966e1de Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:33 +0200 Subject: net: dsa: microchip: remove unused sgmii variable This variable is not used. So, remove it. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 5 ----- drivers/net/dsa/microchip/ksz_common.h | 1 - 2 files changed, 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 18375309233a..077b4e5c29c7 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1075,12 +1075,7 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) for (i = 0; i < dev->info->port_cnt; i++) { if (i == dev->cpu_port) continue; - p = &dev->ports[i]; - ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); - if (dev->chip_id == 0x00947700 && i == 6) { - p->sgmii = 1; - } } } diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 99da2092d0d7..4914cc1c803a 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -74,7 +74,6 @@ struct ksz_port { u32 on:1; /* port is not disabled by hardware */ u32 fiber:1; /* port is fiber */ - u32 sgmii:1; /* port is SGMII */ u32 force:1; u32 read:1; /* read MIB counters in background */ u32 freeze:1; /* MIB counter freeze is enabled */ -- cgit From 32cbac21b9f47c00b72d40a46d87039270daff7a Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 Aug 2022 12:56:34 +0200 Subject: net: dsa: microchip: remove IS_9893 flag Use chip_id as other places of this code do it Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 3 --- drivers/net/dsa/microchip/ksz_common.c | 3 ++- drivers/net/dsa/microchip/ksz_common.h | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 077b4e5c29c7..42d7e4c12459 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1164,9 +1164,6 @@ int ksz9477_switch_init(struct ksz_device *dev) if (ret) return ret; - if (dev->chip_id == KSZ9893_CHIP_ID) - dev->features |= IS_9893; - return 0; } diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7eb74ab04933..37fb5ba2cd7a 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1912,7 +1912,8 @@ static void ksz_set_xmii(struct ksz_device *dev, int port, case PHY_INTERFACE_MODE_RGMII_RXID: data8 |= bitval[P_RGMII_SEL]; /* On KSZ9893, disable RGMII in-band status support */ - if (dev->features & IS_9893) + if (dev->chip_id == KSZ9893_CHIP_ID || + dev->chip_id == KSZ8563_CHIP_ID) data8 &= ~P_MII_MAC_MODE; break; default: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 4914cc1c803a..c01989c04d4e 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -119,7 +119,6 @@ struct ksz_device { unsigned long mib_read_interval; u16 mirror_rx; u16 mirror_tx; - u32 features; /* chip specific features */ u16 port_mask; }; @@ -542,9 +541,6 @@ static inline int is_lan937x(struct ksz_device *dev) #define SW_START 0x01 -/* Used with variable features to indicate capabilities. */ -#define IS_9893 BIT(2) - /* xMII configuration */ #define P_MII_DUPLEX_M BIT(6) #define P_MII_100MBIT_M BIT(4) -- cgit From fb3ceec187e8bca474340e361a18163a2e79c0a2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 30 Aug 2022 22:14:52 +0200 Subject: net: move from strlcpy with unused retval to strscpy Follow the advice of the below link and prefer 'strscpy' in this subsystem. Conversion is 1:1 because the return value is not used. Generated by a coccinelle script. Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ Signed-off-by: Wolfram Sang Acked-by: Marc Kleine-Budde # for CAN Link: https://lore.kernel.org/r/20220830201457.7984-1-wsa+renesas@sang-engineering.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 2 +- drivers/net/dsa/bcm_sf2_cfp.c | 2 +- drivers/net/dsa/hirschmann/hellcreek.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 48cf344750ff..59cdfc51ce06 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -972,7 +972,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, if (stringset == ETH_SS_STATS) { for (i = 0; i < mib_size; i++) - strlcpy(data + i * ETH_GSTRING_LEN, + strscpy(data + i * ETH_GSTRING_LEN, mibs[i].name, ETH_GSTRING_LEN); } else if (stringset == ETH_SS_PHY_STATS) { phydev = b53_get_phy_device(ds, port); diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index edbe5e7f1cb6..22bc295bebdb 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -1296,7 +1296,7 @@ void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, "CFP%03d_%sCntr", i, bcm_sf2_cfp_stats[j].name); iter = (i - 1) * s + j; - strlcpy(data + iter * ETH_GSTRING_LEN, + strscpy(data + iter * ETH_GSTRING_LEN, buf, ETH_GSTRING_LEN); } } diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index 01f90994dedd..ea8bbfce0f1f 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -288,7 +288,7 @@ static void hellcreek_get_strings(struct dsa_switch *ds, int port, for (i = 0; i < ARRAY_SIZE(hellcreek_counter); ++i) { const struct hellcreek_counter *counter = &hellcreek_counter[i]; - strlcpy(data + i * ETH_GSTRING_LEN, + strscpy(data + i * ETH_GSTRING_LEN, counter->name, ETH_GSTRING_LEN); } } diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6403f1f8bdbb..6f4ea39ab466 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1136,7 +1136,7 @@ static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) unsigned int i; for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) - strlcpy(data + i * ETH_GSTRING_LEN, + strscpy(data + i * ETH_GSTRING_LEN, mv88e6xxx_atu_vtu_stats_strings[i], ETH_GSTRING_LEN); } -- cgit From f3c165459c5189b7b469e3b86107ee8819c93774 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Fri, 2 Sep 2022 16:02:08 +0530 Subject: net: dsa: microchip: add reference to ksz_device inside the ksz_port struct ksz_port doesn't have reference to ksz_device as of now. In order to find out from which port interrupt has triggered, we need to pass the struct ksz_port as a host data. When the interrupt is triggered, we can get the port from which interrupt triggered, but to identify it is phy interrupt we have to read status register. The regmap structure for accessing the device register is present in the ksz_device struct. To access the ksz_device from the ksz_port, the reference is added to it with port number as well. Signed-off-by: Arun Ramadoss Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 3 +++ drivers/net/dsa/microchip/ksz_common.h | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 37fb5ba2cd7a..63b9faa89393 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2357,6 +2357,9 @@ int ksz_switch_register(struct ksz_device *dev) GFP_KERNEL); if (!dev->ports[i].mib.counters) return -ENOMEM; + + dev->ports[i].ksz_dev = dev; + dev->ports[i].num = i; } /* set the real number of ports */ diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index c01989c04d4e..3fa3e4731d58 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -16,6 +16,8 @@ #define KSZ_MAX_NUM_PORTS 8 +struct ksz_device; + struct vlan_table { u32 table[3]; }; @@ -83,6 +85,8 @@ struct ksz_port { u16 max_frame; u32 rgmii_tx_val; u32 rgmii_rx_val; + struct ksz_device *ksz_dev; + u8 num; }; struct ksz_device { -- cgit From f313936261ac18a2527fc0752cf988950587d0ce Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Fri, 2 Sep 2022 16:02:09 +0530 Subject: net: dsa: microchip: lan937x: clear the POR_READY_INT status bit In the lan937x_reset_switch(), it masks all the switch and port registers. In the Global_Int_status register, POR ready bit is write 1 to clear bit and all other bits are read only. So, this patch clear the por_ready_int status bit by writing 1. Signed-off-by: Arun Ramadoss Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/lan937x_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 7b464f1fb5d8..0466c4d0b10c 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -225,6 +225,10 @@ int lan937x_reset_switch(struct ksz_device *dev) if (ret < 0) return ret; + ret = ksz_write32(dev, REG_SW_INT_STATUS__4, POR_READY_INT); + if (ret < 0) + return ret; + ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF); if (ret < 0) return ret; -- cgit From c9cd961c0d43a22eb704aa92e1f8fb33e3d286e8 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Fri, 2 Sep 2022 16:02:10 +0530 Subject: net: dsa: microchip: lan937x: add interrupt support for port phy link This patch enables the interrupts for internal phy link detection for LAN937x. The interrupt enable bits are active low. There is global interrupt mask for each port. And each port has the individual interrupt mask for TAS. QCI, SGMII, PTP, PHY and ACL. The first level of interrupt domain is registered for global port interrupt and second level of interrupt domain for the individual port interrupts. The phy interrupt is enabled in the lan937x_mdio_register function. Interrupt from which port is raised will be detected based on the interrupt host data. Signed-off-by: Arun Ramadoss Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 10 + drivers/net/dsa/microchip/ksz_common.h | 14 ++ drivers/net/dsa/microchip/ksz_spi.c | 2 + drivers/net/dsa/microchip/lan937x.h | 1 + drivers/net/dsa/microchip/lan937x_main.c | 364 ++++++++++++++++++++++++++++++- drivers/net/dsa/microchip/lan937x_reg.h | 12 + 6 files changed, 399 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 63b9faa89393..ec2896a23834 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -205,6 +205,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { static const struct ksz_dev_ops lan937x_dev_ops = { .setup = lan937x_setup, + .teardown = lan937x_teardown, .get_port_addr = ksz9477_get_port_addr, .cfg_port_member = ksz9477_cfg_port_member, .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, @@ -1444,6 +1445,14 @@ static int ksz_setup(struct dsa_switch *ds) return 0; } +static void ksz_teardown(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + + if (dev->dev_ops->teardown) + dev->dev_ops->teardown(ds); +} + static void port_r_cnt(struct ksz_device *dev, int port) { struct ksz_port_mib *mib = &dev->ports[port].mib; @@ -2193,6 +2202,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .get_tag_protocol = ksz_get_tag_protocol, .get_phy_flags = ksz_get_phy_flags, .setup = ksz_setup, + .teardown = ksz_teardown, .phy_read = ksz_phy_read16, .phy_write = ksz_phy_write16, .phylink_get_caps = ksz_phylink_get_caps, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 3fa3e4731d58..35346b39ce54 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -13,6 +13,7 @@ #include #include #include +#include #define KSZ_MAX_NUM_PORTS 8 @@ -68,6 +69,14 @@ struct ksz_chip_data { const struct regmap_access_table *rd_table; }; +struct ksz_irq { + u16 masked; + struct irq_chip chip; + struct irq_domain *domain; + int nirqs; + char name[16]; +}; + struct ksz_port { bool remove_tag; /* Remove Tag flag set, for ksz8795 only */ bool learning; @@ -86,6 +95,7 @@ struct ksz_port { u32 rgmii_tx_val; u32 rgmii_rx_val; struct ksz_device *ksz_dev; + struct ksz_irq pirq; u8 num; }; @@ -104,6 +114,7 @@ struct ksz_device { struct regmap *regmap[3]; void *priv; + int irq; struct gpio_desc *reset_gpio; /* Optional reset GPIO */ @@ -124,6 +135,8 @@ struct ksz_device { u16 mirror_rx; u16 mirror_tx; u16 port_mask; + struct mutex lock_irq; /* IRQ Access */ + struct ksz_irq girq; }; /* List of supported models */ @@ -260,6 +273,7 @@ struct alu_struct { struct ksz_dev_ops { int (*setup)(struct dsa_switch *ds); + void (*teardown)(struct dsa_switch *ds); u32 (*get_port_addr)(int port, int offset); void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member); void (*flush_dyn_mac_table)(struct ksz_device *dev, int port); diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 44c2d9912406..126ed1c986a9 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -88,6 +88,8 @@ static int ksz_spi_probe(struct spi_device *spi) if (ret) return ret; + dev->irq = spi->irq; + ret = ksz_switch_register(dev); /* Main DSA driver may not be started yet. */ diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h index 5d78d034a62f..1b7f077946f3 100644 --- a/drivers/net/dsa/microchip/lan937x.h +++ b/drivers/net/dsa/microchip/lan937x.h @@ -8,6 +8,7 @@ int lan937x_reset_switch(struct ksz_device *dev); int lan937x_setup(struct dsa_switch *ds); +void lan937x_teardown(struct dsa_switch *ds); void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); void lan937x_config_cpu_port(struct dsa_switch *ds); int lan937x_switch_init(struct ksz_device *dev); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 0466c4d0b10c..4867aa62dd4c 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,6 +20,8 @@ #include "ksz_common.h" #include "lan937x.h" +#define LAN937x_PNIRQS 6 + static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); @@ -165,6 +169,45 @@ static int lan937x_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, return lan937x_internal_phy_write(dev, addr, regnum, val); } +static int lan937x_irq_phy_setup(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + int phy, err_phy; + int irq; + int ret; + + for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) { + if (BIT(phy) & ds->phys_mii_mask) { + irq = irq_find_mapping(dev->ports[phy].pirq.domain, + PORT_SRC_PHY_INT); + if (irq < 0) { + ret = irq; + goto out; + } + ds->slave_mii_bus->irq[phy] = irq; + } + } + return 0; +out: + err_phy = phy; + + for (phy = 0; phy < err_phy; phy++) + if (BIT(phy) & ds->phys_mii_mask) + irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); + + return ret; +} + +static void lan937x_irq_phy_free(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + int phy; + + for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) + if (BIT(phy) & ds->phys_mii_mask) + irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); +} + static int lan937x_mdio_register(struct ksz_device *dev) { struct dsa_switch *ds = dev->ds; @@ -194,10 +237,15 @@ static int lan937x_mdio_register(struct ksz_device *dev) ds->slave_mii_bus = bus; + ret = lan937x_irq_phy_setup(dev); + if (ret) + return ret; + ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); if (ret) { dev_err(ds->dev, "unable to register MDIO bus %s\n", bus->id); + lan937x_irq_phy_free(dev); } of_node_put(mdio_np); @@ -387,9 +435,289 @@ void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port) } } +int lan937x_switch_init(struct ksz_device *dev) +{ + dev->port_mask = (1 << dev->info->port_cnt) - 1; + + return 0; +} + +static void lan937x_girq_mask(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + dev->girq.masked |= (1 << n); +} + +static void lan937x_girq_unmask(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + dev->girq.masked &= ~(1 << n); +} + +static void lan937x_girq_bus_lock(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + + mutex_lock(&dev->lock_irq); +} + +static void lan937x_girq_bus_sync_unlock(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + int ret; + + ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, dev->girq.masked); + if (ret) + dev_err(dev->dev, "failed to change IRQ mask\n"); + + mutex_unlock(&dev->lock_irq); +} + +static const struct irq_chip lan937x_girq_chip = { + .name = "lan937x-global", + .irq_mask = lan937x_girq_mask, + .irq_unmask = lan937x_girq_unmask, + .irq_bus_lock = lan937x_girq_bus_lock, + .irq_bus_sync_unlock = lan937x_girq_bus_sync_unlock, +}; + +static int lan937x_girq_domain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct ksz_device *dev = d->host_data; + + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &dev->girq.chip, handle_level_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops lan937x_girq_domain_ops = { + .map = lan937x_girq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void lan937x_girq_free(struct ksz_device *dev) +{ + int irq, virq; + + free_irq(dev->irq, dev); + + for (irq = 0; irq < dev->girq.nirqs; irq++) { + virq = irq_find_mapping(dev->girq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(dev->girq.domain); +} + +static irqreturn_t lan937x_girq_thread_fn(int irq, void *dev_id) +{ + struct ksz_device *dev = dev_id; + unsigned int nhandled = 0; + unsigned int sub_irq; + unsigned int n; + u32 data; + int ret; + + /* Read global interrupt status register */ + ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data); + if (ret) + goto out; + + for (n = 0; n < dev->girq.nirqs; ++n) { + if (data & (1 << n)) { + sub_irq = irq_find_mapping(dev->girq.domain, n); + handle_nested_irq(sub_irq); + ++nhandled; + } + } +out: + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static int lan937x_girq_setup(struct ksz_device *dev) +{ + int ret, irq; + + dev->girq.nirqs = dev->info->port_cnt; + dev->girq.domain = irq_domain_add_simple(NULL, dev->girq.nirqs, 0, + &lan937x_girq_domain_ops, dev); + if (!dev->girq.domain) + return -ENOMEM; + + for (irq = 0; irq < dev->girq.nirqs; irq++) + irq_create_mapping(dev->girq.domain, irq); + + dev->girq.chip = lan937x_girq_chip; + dev->girq.masked = ~0; + + ret = request_threaded_irq(dev->irq, NULL, lan937x_girq_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + dev_name(dev->dev), dev); + if (ret) + goto out; + + return 0; + +out: + lan937x_girq_free(dev); + + return ret; +} + +static void lan937x_pirq_mask(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + port->pirq.masked |= (1 << n); +} + +static void lan937x_pirq_unmask(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + port->pirq.masked &= ~(1 << n); +} + +static void lan937x_pirq_bus_lock(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = port->ksz_dev; + + mutex_lock(&dev->lock_irq); +} + +static void lan937x_pirq_bus_sync_unlock(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = port->ksz_dev; + + ksz_pwrite8(dev, port->num, REG_PORT_INT_MASK, port->pirq.masked); + mutex_unlock(&dev->lock_irq); +} + +static const struct irq_chip lan937x_pirq_chip = { + .name = "lan937x-port", + .irq_mask = lan937x_pirq_mask, + .irq_unmask = lan937x_pirq_unmask, + .irq_bus_lock = lan937x_pirq_bus_lock, + .irq_bus_sync_unlock = lan937x_pirq_bus_sync_unlock, +}; + +static int lan937x_pirq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct ksz_port *port = d->host_data; + + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &port->pirq.chip, handle_level_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops lan937x_pirq_domain_ops = { + .map = lan937x_pirq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void lan937x_pirq_free(struct ksz_device *dev, u8 p) +{ + struct ksz_port *port = &dev->ports[p]; + int irq, virq; + int irq_num; + + irq_num = irq_find_mapping(dev->girq.domain, p); + if (irq_num < 0) + return; + + free_irq(irq_num, port); + + for (irq = 0; irq < port->pirq.nirqs; irq++) { + virq = irq_find_mapping(port->pirq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(port->pirq.domain); +} + +static irqreturn_t lan937x_pirq_thread_fn(int irq, void *dev_id) +{ + struct ksz_port *port = dev_id; + unsigned int nhandled = 0; + struct ksz_device *dev; + unsigned int sub_irq; + unsigned int n; + u8 data; + + dev = port->ksz_dev; + + /* Read port interrupt status register */ + ksz_pread8(dev, port->num, REG_PORT_INT_STATUS, &data); + + for (n = 0; n < port->pirq.nirqs; ++n) { + if (data & (1 << n)) { + sub_irq = irq_find_mapping(port->pirq.domain, n); + handle_nested_irq(sub_irq); + ++nhandled; + } + } + + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static int lan937x_pirq_setup(struct ksz_device *dev, u8 p) +{ + struct ksz_port *port = &dev->ports[p]; + int ret, irq; + int irq_num; + + port->pirq.nirqs = LAN937x_PNIRQS; + port->pirq.domain = irq_domain_add_simple(dev->dev->of_node, + port->pirq.nirqs, 0, + &lan937x_pirq_domain_ops, + port); + if (!port->pirq.domain) + return -ENOMEM; + + for (irq = 0; irq < port->pirq.nirqs; irq++) + irq_create_mapping(port->pirq.domain, irq); + + port->pirq.chip = lan937x_pirq_chip; + port->pirq.masked = ~0; + + irq_num = irq_find_mapping(dev->girq.domain, p); + if (irq_num < 0) + return irq_num; + + snprintf(port->pirq.name, sizeof(port->pirq.name), "port_irq-%d", p); + + ret = request_threaded_irq(irq_num, NULL, lan937x_pirq_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + port->pirq.name, port); + if (ret) + goto out; + + return 0; + +out: + lan937x_pirq_free(dev, p); + + return ret; +} + int lan937x_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; + struct dsa_port *dp; int ret; /* enable Indirect Access from SPI to the VPHY registers */ @@ -399,10 +727,22 @@ int lan937x_setup(struct dsa_switch *ds) return ret; } + if (dev->irq > 0) { + ret = lan937x_girq_setup(dev); + if (ret) + return ret; + + dsa_switch_for_each_user_port(dp, dev->ds) { + ret = lan937x_pirq_setup(dev, dp->index); + if (ret) + goto out_girq; + } + } + ret = lan937x_mdio_register(dev); if (ret < 0) { dev_err(dev->dev, "failed to register the mdio"); - return ret; + goto out_pirq; } /* The VLAN aware is a global setting. Mixed vlan @@ -428,13 +768,29 @@ int lan937x_setup(struct dsa_switch *ds) (SW_CLK125_ENB | SW_CLK25_ENB), true); return 0; + +out_pirq: + if (dev->irq > 0) + dsa_switch_for_each_user_port(dp, dev->ds) + lan937x_pirq_free(dev, dp->index); +out_girq: + if (dev->irq > 0) + lan937x_girq_free(dev); + + return ret; } -int lan937x_switch_init(struct ksz_device *dev) +void lan937x_teardown(struct dsa_switch *ds) { - dev->port_mask = (1 << dev->info->port_cnt) - 1; + struct ksz_device *dev = ds->priv; + struct dsa_port *dp; - return 0; + if (dev->irq > 0) { + dsa_switch_for_each_user_port(dp, dev->ds) + lan937x_pirq_free(dev, dp->index); + + lan937x_girq_free(dev); + } } void lan937x_switch_exit(struct ksz_device *dev) diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h index ba4adaddb3ec..a3c669d86e51 100644 --- a/drivers/net/dsa/microchip/lan937x_reg.h +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -118,6 +118,18 @@ /* Port Registers */ /* 0 - Operation */ +#define REG_PORT_INT_STATUS 0x001B +#define REG_PORT_INT_MASK 0x001F + +#define PORT_TAS_INT BIT(5) +#define PORT_QCI_INT BIT(4) +#define PORT_SGMII_INT BIT(3) +#define PORT_PTP_INT BIT(2) +#define PORT_PHY_INT BIT(1) +#define PORT_ACL_INT BIT(0) + +#define PORT_SRC_PHY_INT 1 + #define REG_PORT_CTRL_0 0x0020 #define PORT_MAC_LOOPBACK BIT(7) -- cgit From 2eb3ff3c09082bb4792f2149cf6582e2626a5e30 Mon Sep 17 00:00:00 2001 From: Romain Naour Date: Fri, 2 Sep 2022 12:16:07 +0200 Subject: net: dsa: microchip: add KSZ9896 switch support Add support for the KSZ9896 6-port Gigabit Ethernet Switch to the ksz9477 driver. Although the KSZ9896 is already listed in the device tree binding documentation since a1c0ed24fe9b (dt-bindings: net: dsa: document additional Microchip KSZ9477 family switches) the chip id (0x00989600) is not recognized by ksz_switch_detect() and rejected by the driver. The KSZ9896 is similar to KSZ9897 but has only one configurable MII/RMII/RGMII/GMII cpu port. Signed-off-by: Romain Naour Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 31 +++++++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_common.h | 2 ++ drivers/net/dsa/microchip/ksz_spi.c | 6 ++++++ 3 files changed, 39 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index ec2896a23834..b19631d47058 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -966,6 +966,35 @@ const struct ksz_chip_data ksz_switch_chips[] = { .rd_table = &ksz9477_register_set, }, + [KSZ9896] = { + .chip_id = KSZ9896_CHIP_ID, + .dev_name = "KSZ9896", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x3F, /* can be configured as cpu port */ + .port_cnt = 6, /* total physical port count */ + .ops = &ksz9477_dev_ops, + .phy_errata_9477 = true, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, + .supports_mii = {false, false, false, false, + false, true}, + .supports_rmii = {false, false, false, false, + false, true}, + .supports_rgmii = {false, false, false, false, + false, true}, + .internal_phy = {true, true, true, true, + true, false}, + .gbit_capable = {true, true, true, true, true, true}, + }, + [KSZ9897] = { .chip_id = KSZ9897_CHIP_ID, .dev_name = "KSZ9897", @@ -1807,6 +1836,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, proto = DSA_TAG_PROTO_KSZ9893; if (dev->chip_id == KSZ9477_CHIP_ID || + dev->chip_id == KSZ9896_CHIP_ID || dev->chip_id == KSZ9897_CHIP_ID || dev->chip_id == KSZ9567_CHIP_ID) proto = DSA_TAG_PROTO_KSZ9477; @@ -2168,6 +2198,7 @@ static int ksz_switch_detect(struct ksz_device *dev) switch (id32) { case KSZ9477_CHIP_ID: + case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: case KSZ9567_CHIP_ID: case LAN9370_CHIP_ID: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 35346b39ce54..7c63f900dfce 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -147,6 +147,7 @@ enum ksz_model { KSZ8765, KSZ8830, KSZ9477, + KSZ9896, KSZ9897, KSZ9893, KSZ9567, @@ -164,6 +165,7 @@ enum ksz_chip_id { KSZ8765_CHIP_ID = 0x8765, KSZ8830_CHIP_ID = 0x8830, KSZ9477_CHIP_ID = 0x00947700, + KSZ9896_CHIP_ID = 0x00989600, KSZ9897_CHIP_ID = 0x00989700, KSZ9893_CHIP_ID = 0x00989300, KSZ9567_CHIP_ID = 0x00956700, diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 126ed1c986a9..82e2352f55fa 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -151,6 +151,10 @@ static const struct of_device_id ksz_dt_ids[] = { .compatible = "microchip,ksz9477", .data = &ksz_switch_chips[KSZ9477] }, + { + .compatible = "microchip,ksz9896", + .data = &ksz_switch_chips[KSZ9896] + }, { .compatible = "microchip,ksz9897", .data = &ksz_switch_chips[KSZ9897] @@ -202,6 +206,7 @@ static const struct spi_device_id ksz_spi_ids[] = { { "ksz8863" }, { "ksz8873" }, { "ksz9477" }, + { "ksz9896" }, { "ksz9897" }, { "ksz9893" }, { "ksz9563" }, @@ -231,6 +236,7 @@ static struct spi_driver ksz_spi_driver = { module_spi_driver(ksz_spi_driver); MODULE_ALIAS("spi:ksz9477"); +MODULE_ALIAS("spi:ksz9896"); MODULE_ALIAS("spi:ksz9897"); MODULE_ALIAS("spi:ksz9893"); MODULE_ALIAS("spi:ksz9563"); -- cgit From 13767525929db1693b24555c07878d8cb3a274be Mon Sep 17 00:00:00 2001 From: Romain Naour Date: Fri, 2 Sep 2022 12:16:08 +0200 Subject: net: dsa: microchip: add KSZ9896 to KSZ9477 I2C driver Add support for the KSZ9896 6-port Gigabit Ethernet Switch to the ksz9477 driver. The KSZ9896 supports both SPI (already in) and I2C. Signed-off-by: Romain Naour Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477_i2c.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 99966514d444..8fbc122e3384 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -91,6 +91,10 @@ static const struct of_device_id ksz9477_dt_ids[] = { .compatible = "microchip,ksz9477", .data = &ksz_switch_chips[KSZ9477] }, + { + .compatible = "microchip,ksz9896", + .data = &ksz_switch_chips[KSZ9896] + }, { .compatible = "microchip,ksz9897", .data = &ksz_switch_chips[KSZ9897] -- cgit From 3a8b8ea6c7c298482e54c6abee006c400b7aa568 Mon Sep 17 00:00:00 2001 From: Romain Naour Date: Fri, 2 Sep 2022 12:16:09 +0200 Subject: net: dsa: microchip: ksz9477: remove 0x033C and 0x033D addresses from regmap_access_tables According to the KSZ9477S datasheet, there is no global register at 0x033C and 0x033D addresses. Signed-off-by: Romain Naour Cc: Oleksij Rempel Tested-by: Oleksij Rempel Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b19631d47058..e615a2252fc1 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -547,7 +547,8 @@ static const struct regmap_range ksz9477_valid_regs[] = { regmap_reg_range(0x0302, 0x031b), regmap_reg_range(0x0320, 0x032b), regmap_reg_range(0x0330, 0x0336), - regmap_reg_range(0x0338, 0x033e), + regmap_reg_range(0x0338, 0x033b), + regmap_reg_range(0x033e, 0x033e), regmap_reg_range(0x0340, 0x035f), regmap_reg_range(0x0370, 0x0370), regmap_reg_range(0x0378, 0x0378), -- cgit From 6674e7fd3beaf745b2e9d281a66f925a13de8ea7 Mon Sep 17 00:00:00 2001 From: Romain Naour Date: Fri, 2 Sep 2022 12:16:10 +0200 Subject: net: dsa: microchip: add regmap_range for KSZ9896 chip Add register validation for KSZ9896. Signed-off-by: Romain Naour Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 215 +++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index e615a2252fc1..986b7c8f5269 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -803,6 +803,219 @@ static const struct regmap_access_table ksz9477_register_set = { .n_yes_ranges = ARRAY_SIZE(ksz9477_valid_regs), }; +static const struct regmap_range ksz9896_valid_regs[] = { + regmap_reg_range(0x0000, 0x0003), + regmap_reg_range(0x0006, 0x0006), + regmap_reg_range(0x0010, 0x001f), + regmap_reg_range(0x0100, 0x0100), + regmap_reg_range(0x0103, 0x0107), + regmap_reg_range(0x010d, 0x010d), + regmap_reg_range(0x0110, 0x0113), + regmap_reg_range(0x0120, 0x0127), + regmap_reg_range(0x0201, 0x0201), + regmap_reg_range(0x0210, 0x0213), + regmap_reg_range(0x0300, 0x0300), + regmap_reg_range(0x0302, 0x030b), + regmap_reg_range(0x0310, 0x031b), + regmap_reg_range(0x0320, 0x032b), + regmap_reg_range(0x0330, 0x0336), + regmap_reg_range(0x0338, 0x033b), + regmap_reg_range(0x033e, 0x033e), + regmap_reg_range(0x0340, 0x035f), + regmap_reg_range(0x0370, 0x0370), + regmap_reg_range(0x0378, 0x0378), + regmap_reg_range(0x037c, 0x037d), + regmap_reg_range(0x0390, 0x0393), + regmap_reg_range(0x0400, 0x040e), + regmap_reg_range(0x0410, 0x042f), + + /* port 1 */ + regmap_reg_range(0x1000, 0x1001), + regmap_reg_range(0x1013, 0x1013), + regmap_reg_range(0x1017, 0x1017), + regmap_reg_range(0x101b, 0x101b), + regmap_reg_range(0x101f, 0x1020), + regmap_reg_range(0x1030, 0x1030), + regmap_reg_range(0x1100, 0x1115), + regmap_reg_range(0x111a, 0x111f), + regmap_reg_range(0x1122, 0x1127), + regmap_reg_range(0x112a, 0x112b), + regmap_reg_range(0x1136, 0x1139), + regmap_reg_range(0x113e, 0x113f), + regmap_reg_range(0x1400, 0x1401), + regmap_reg_range(0x1403, 0x1403), + regmap_reg_range(0x1410, 0x1417), + regmap_reg_range(0x1420, 0x1423), + regmap_reg_range(0x1500, 0x1507), + regmap_reg_range(0x1600, 0x1612), + regmap_reg_range(0x1800, 0x180f), + regmap_reg_range(0x1820, 0x1827), + regmap_reg_range(0x1830, 0x1837), + regmap_reg_range(0x1840, 0x184b), + regmap_reg_range(0x1900, 0x1907), + regmap_reg_range(0x1914, 0x1915), + regmap_reg_range(0x1a00, 0x1a03), + regmap_reg_range(0x1a04, 0x1a07), + regmap_reg_range(0x1b00, 0x1b01), + regmap_reg_range(0x1b04, 0x1b04), + + /* port 2 */ + regmap_reg_range(0x2000, 0x2001), + regmap_reg_range(0x2013, 0x2013), + regmap_reg_range(0x2017, 0x2017), + regmap_reg_range(0x201b, 0x201b), + regmap_reg_range(0x201f, 0x2020), + regmap_reg_range(0x2030, 0x2030), + regmap_reg_range(0x2100, 0x2115), + regmap_reg_range(0x211a, 0x211f), + regmap_reg_range(0x2122, 0x2127), + regmap_reg_range(0x212a, 0x212b), + regmap_reg_range(0x2136, 0x2139), + regmap_reg_range(0x213e, 0x213f), + regmap_reg_range(0x2400, 0x2401), + regmap_reg_range(0x2403, 0x2403), + regmap_reg_range(0x2410, 0x2417), + regmap_reg_range(0x2420, 0x2423), + regmap_reg_range(0x2500, 0x2507), + regmap_reg_range(0x2600, 0x2612), + regmap_reg_range(0x2800, 0x280f), + regmap_reg_range(0x2820, 0x2827), + regmap_reg_range(0x2830, 0x2837), + regmap_reg_range(0x2840, 0x284b), + regmap_reg_range(0x2900, 0x2907), + regmap_reg_range(0x2914, 0x2915), + regmap_reg_range(0x2a00, 0x2a03), + regmap_reg_range(0x2a04, 0x2a07), + regmap_reg_range(0x2b00, 0x2b01), + regmap_reg_range(0x2b04, 0x2b04), + + /* port 3 */ + regmap_reg_range(0x3000, 0x3001), + regmap_reg_range(0x3013, 0x3013), + regmap_reg_range(0x3017, 0x3017), + regmap_reg_range(0x301b, 0x301b), + regmap_reg_range(0x301f, 0x3020), + regmap_reg_range(0x3030, 0x3030), + regmap_reg_range(0x3100, 0x3115), + regmap_reg_range(0x311a, 0x311f), + regmap_reg_range(0x3122, 0x3127), + regmap_reg_range(0x312a, 0x312b), + regmap_reg_range(0x3136, 0x3139), + regmap_reg_range(0x313e, 0x313f), + regmap_reg_range(0x3400, 0x3401), + regmap_reg_range(0x3403, 0x3403), + regmap_reg_range(0x3410, 0x3417), + regmap_reg_range(0x3420, 0x3423), + regmap_reg_range(0x3500, 0x3507), + regmap_reg_range(0x3600, 0x3612), + regmap_reg_range(0x3800, 0x380f), + regmap_reg_range(0x3820, 0x3827), + regmap_reg_range(0x3830, 0x3837), + regmap_reg_range(0x3840, 0x384b), + regmap_reg_range(0x3900, 0x3907), + regmap_reg_range(0x3914, 0x3915), + regmap_reg_range(0x3a00, 0x3a03), + regmap_reg_range(0x3a04, 0x3a07), + regmap_reg_range(0x3b00, 0x3b01), + regmap_reg_range(0x3b04, 0x3b04), + + /* port 4 */ + regmap_reg_range(0x4000, 0x4001), + regmap_reg_range(0x4013, 0x4013), + regmap_reg_range(0x4017, 0x4017), + regmap_reg_range(0x401b, 0x401b), + regmap_reg_range(0x401f, 0x4020), + regmap_reg_range(0x4030, 0x4030), + regmap_reg_range(0x4100, 0x4115), + regmap_reg_range(0x411a, 0x411f), + regmap_reg_range(0x4122, 0x4127), + regmap_reg_range(0x412a, 0x412b), + regmap_reg_range(0x4136, 0x4139), + regmap_reg_range(0x413e, 0x413f), + regmap_reg_range(0x4400, 0x4401), + regmap_reg_range(0x4403, 0x4403), + regmap_reg_range(0x4410, 0x4417), + regmap_reg_range(0x4420, 0x4423), + regmap_reg_range(0x4500, 0x4507), + regmap_reg_range(0x4600, 0x4612), + regmap_reg_range(0x4800, 0x480f), + regmap_reg_range(0x4820, 0x4827), + regmap_reg_range(0x4830, 0x4837), + regmap_reg_range(0x4840, 0x484b), + regmap_reg_range(0x4900, 0x4907), + regmap_reg_range(0x4914, 0x4915), + regmap_reg_range(0x4a00, 0x4a03), + regmap_reg_range(0x4a04, 0x4a07), + regmap_reg_range(0x4b00, 0x4b01), + regmap_reg_range(0x4b04, 0x4b04), + + /* port 5 */ + regmap_reg_range(0x5000, 0x5001), + regmap_reg_range(0x5013, 0x5013), + regmap_reg_range(0x5017, 0x5017), + regmap_reg_range(0x501b, 0x501b), + regmap_reg_range(0x501f, 0x5020), + regmap_reg_range(0x5030, 0x5030), + regmap_reg_range(0x5100, 0x5115), + regmap_reg_range(0x511a, 0x511f), + regmap_reg_range(0x5122, 0x5127), + regmap_reg_range(0x512a, 0x512b), + regmap_reg_range(0x5136, 0x5139), + regmap_reg_range(0x513e, 0x513f), + regmap_reg_range(0x5400, 0x5401), + regmap_reg_range(0x5403, 0x5403), + regmap_reg_range(0x5410, 0x5417), + regmap_reg_range(0x5420, 0x5423), + regmap_reg_range(0x5500, 0x5507), + regmap_reg_range(0x5600, 0x5612), + regmap_reg_range(0x5800, 0x580f), + regmap_reg_range(0x5820, 0x5827), + regmap_reg_range(0x5830, 0x5837), + regmap_reg_range(0x5840, 0x584b), + regmap_reg_range(0x5900, 0x5907), + regmap_reg_range(0x5914, 0x5915), + regmap_reg_range(0x5a00, 0x5a03), + regmap_reg_range(0x5a04, 0x5a07), + regmap_reg_range(0x5b00, 0x5b01), + regmap_reg_range(0x5b04, 0x5b04), + + /* port 6 */ + regmap_reg_range(0x6000, 0x6001), + regmap_reg_range(0x6013, 0x6013), + regmap_reg_range(0x6017, 0x6017), + regmap_reg_range(0x601b, 0x601b), + regmap_reg_range(0x601f, 0x6020), + regmap_reg_range(0x6030, 0x6030), + regmap_reg_range(0x6100, 0x6115), + regmap_reg_range(0x611a, 0x611f), + regmap_reg_range(0x6122, 0x6127), + regmap_reg_range(0x612a, 0x612b), + regmap_reg_range(0x6136, 0x6139), + regmap_reg_range(0x613e, 0x613f), + regmap_reg_range(0x6300, 0x6301), + regmap_reg_range(0x6400, 0x6401), + regmap_reg_range(0x6403, 0x6403), + regmap_reg_range(0x6410, 0x6417), + regmap_reg_range(0x6420, 0x6423), + regmap_reg_range(0x6500, 0x6507), + regmap_reg_range(0x6600, 0x6612), + regmap_reg_range(0x6800, 0x680f), + regmap_reg_range(0x6820, 0x6827), + regmap_reg_range(0x6830, 0x6837), + regmap_reg_range(0x6840, 0x684b), + regmap_reg_range(0x6900, 0x6907), + regmap_reg_range(0x6914, 0x6915), + regmap_reg_range(0x6a00, 0x6a03), + regmap_reg_range(0x6a04, 0x6a07), + regmap_reg_range(0x6b00, 0x6b01), + regmap_reg_range(0x6b04, 0x6b04), +}; + +static const struct regmap_access_table ksz9896_register_set = { + .yes_ranges = ksz9896_valid_regs, + .n_yes_ranges = ARRAY_SIZE(ksz9896_valid_regs), +}; + const struct ksz_chip_data ksz_switch_chips[] = { [KSZ8563] = { .chip_id = KSZ8563_CHIP_ID, @@ -994,6 +1207,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, true, true, false}, .gbit_capable = {true, true, true, true, true, true}, + .wr_table = &ksz9896_register_set, + .rd_table = &ksz9896_register_set, }, [KSZ9897] = { -- cgit From 732f374e23a9ae05dbc13825e4b02b3abce9f9aa Mon Sep 17 00:00:00 2001 From: Jerry Ray Date: Fri, 2 Sep 2022 16:30:20 -0500 Subject: net: dsa: LAN9303: Add early read to sync Add initial BYTE_ORDER read to sync the 32-bit accesses over the 16-bit mdio bus to improve driver robustness. The lan9303 expects two mdio read transactions back-to-back to read a 32-bit register. The first read transaction causes the other half of the 32-bit register to get latched. The subsequent read returns the latched second half of the 32-bit read. The BYTE_ORDER register is an exception to this rule. As it is a constant value, there is no need to latch the second half. We read this register first in case there were reads during the boot loader process that might have occurred prior to this driver taking over ownership of accessing this device. This patch has been tested on the SAMA5D3-EDS with a LAN9303 RMII daughter card. Signed-off-by: Jerry Ray Signed-off-by: David S. Miller --- drivers/net/dsa/lan9303-core.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index e03ff1f267bb..9d5302001abf 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -32,6 +32,7 @@ #define LAN9303_INT_EN 0x17 # define LAN9303_INT_EN_PHY_INT2_EN BIT(27) # define LAN9303_INT_EN_PHY_INT1_EN BIT(26) +#define LAN9303_BYTE_ORDER 0x19 #define LAN9303_HW_CFG 0x1D # define LAN9303_HW_CFG_READY BIT(27) # define LAN9303_HW_CFG_AMDX_EN_PORT2 BIT(26) @@ -851,10 +852,6 @@ static int lan9303_check_device(struct lan9303 *chip) if (ret) { dev_err(chip->dev, "failed to read chip revision register: %d\n", ret); - if (!chip->reset_gpio) { - dev_dbg(chip->dev, - "hint: maybe failed due to missing reset GPIO\n"); - } return ret; } @@ -1349,6 +1346,7 @@ static int lan9303_probe_reset_gpio(struct lan9303 *chip, int lan9303_probe(struct lan9303 *chip, struct device_node *np) { int ret; + u32 reg; mutex_init(&chip->indirect_mutex); mutex_init(&chip->alr_mutex); @@ -1359,6 +1357,19 @@ int lan9303_probe(struct lan9303 *chip, struct device_node *np) lan9303_handle_reset(chip); + /* First read to the device. This is a Dummy read to ensure MDIO */ + /* access is in 32-bit sync. */ + ret = lan9303_read(chip->regmap, LAN9303_BYTE_ORDER, ®); + if (ret) { + dev_err(chip->dev, "failed to access the device: %d\n", + ret); + if (!chip->reset_gpio) { + dev_dbg(chip->dev, + "hint: maybe failed due to missing reset GPIO\n"); + } + return ret; + } + ret = lan9303_check_device(chip); if (ret) return ret; -- cgit From 13248b975038241be329388a9a707dd12fdd5466 Mon Sep 17 00:00:00 2001 From: Jerry Ray Date: Fri, 2 Sep 2022 16:30:21 -0500 Subject: net: dsa: LAN9303: Add basic support for LAN9354 Adding support for the LAN9354 device by allowing it to use the LAN9303 DSA driver. These devices have the same underlying access and control methods and from a feature set point of view the LAN9354 is a superset of the LAN9303. The MDIO access method has been tested on a SAMA5D3-EDS board with a LAN9354 RMII daughter card. While the SPI access method should also be the same, it has not been tested and as such is not included at this time. Signed-off-by: Jerry Ray Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 6 +++--- drivers/net/dsa/lan9303-core.c | 11 ++++++++--- drivers/net/dsa/lan9303_mdio.c | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index d8ae0e8af2a0..07507b4820d7 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -76,7 +76,7 @@ config NET_DSA_SMSC_LAN9303 select NET_DSA_TAG_LAN9303 select REGMAP help - This enables support for the SMSC/Microchip LAN9303 3 port ethernet + This enables support for the Microchip LAN9303/LAN9354 3 port ethernet switch chips. config NET_DSA_SMSC_LAN9303_I2C @@ -90,11 +90,11 @@ config NET_DSA_SMSC_LAN9303_I2C for I2C managed mode. config NET_DSA_SMSC_LAN9303_MDIO - tristate "SMSC/Microchip LAN9303 3-ports 10/100 ethernet switch in MDIO managed mode" + tristate "Microchip LAN9303/LAN9354 3-ports 10/100 ethernet switch in MDIO managed mode" select NET_DSA_SMSC_LAN9303 depends on VLAN_8021Q || VLAN_8021Q=n help - Enable access functions if the SMSC/Microchip LAN9303 is configured + Enable access functions if the Microchip LAN9303/LAN9354 is configured for MDIO managed mode. config NET_DSA_VITESSE_VSC73XX diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index 9d5302001abf..9e04541c3144 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -22,6 +22,10 @@ */ #define LAN9303_CHIP_REV 0x14 # define LAN9303_CHIP_ID 0x9303 +# define LAN9352_CHIP_ID 0x9352 +# define LAN9353_CHIP_ID 0x9353 +# define LAN9354_CHIP_ID 0x9354 +# define LAN9355_CHIP_ID 0x9355 #define LAN9303_IRQ_CFG 0x15 # define LAN9303_IRQ_CFG_IRQ_ENABLE BIT(8) # define LAN9303_IRQ_CFG_IRQ_POL BIT(4) @@ -855,8 +859,9 @@ static int lan9303_check_device(struct lan9303 *chip) return ret; } - if ((reg >> 16) != LAN9303_CHIP_ID) { - dev_err(chip->dev, "expecting LAN9303 chip, but found: %X\n", + if (((reg >> 16) != LAN9303_CHIP_ID) && + ((reg >> 16) != LAN9354_CHIP_ID)) { + dev_err(chip->dev, "unexpected device found: LAN%4.4X\n", reg >> 16); return -ENODEV; } @@ -872,7 +877,7 @@ static int lan9303_check_device(struct lan9303 *chip) if (ret) dev_warn(chip->dev, "failed to disable switching %d\n", ret); - dev_info(chip->dev, "Found LAN9303 rev. %u\n", reg & 0xffff); + dev_info(chip->dev, "Found LAN%4.4X rev. %u\n", (reg >> 16), reg & 0xffff); ret = lan9303_detect_phy_setup(chip); if (ret) { diff --git a/drivers/net/dsa/lan9303_mdio.c b/drivers/net/dsa/lan9303_mdio.c index bbb7032409ba..d12c55fdc811 100644 --- a/drivers/net/dsa/lan9303_mdio.c +++ b/drivers/net/dsa/lan9303_mdio.c @@ -158,6 +158,7 @@ static void lan9303_mdio_shutdown(struct mdio_device *mdiodev) static const struct of_device_id lan9303_mdio_of_match[] = { { .compatible = "smsc,lan9303-mdio" }, + { .compatible = "microchip,lan9354-mdio" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, lan9303_mdio_of_match); -- cgit From 0a2360c59687e4caec363565c166e8a2b3e30677 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:03 +0300 Subject: net: dsa: felix: add definitions for the stream filter counters TSN stream (802.1Qci, 802.1CB) filters are also accessed through STAT_VIEW, just like the port registers, but these counters are per stream, rather than per port. So we don't keep them in ocelot_port_update_stats(). What we can do, however, is we can create register definitions for them just like we have for the port counters, and delete the last remaining user of the SYS_CNT register + a group index (read_gix). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 15 ++++++++++----- drivers/net/dsa/ocelot/seville_vsc9953.c | 1 - 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index f8f19a85744c..3c80df4253b2 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -367,6 +367,10 @@ static const u32 vsc9959_sys_regmap[] = { REG(SYS_COUNT_DROP_GREEN_PRIO_5, 0x00043c), REG(SYS_COUNT_DROP_GREEN_PRIO_6, 0x000440), REG(SYS_COUNT_DROP_GREEN_PRIO_7, 0x000444), + REG(SYS_COUNT_SF_MATCHING_FRAMES, 0x000800), + REG(SYS_COUNT_SF_NOT_PASSING_FRAMES, 0x000804), + REG(SYS_COUNT_SF_NOT_PASSING_SDU, 0x000808), + REG(SYS_COUNT_SF_RED_FRAMES, 0x00080c), REG(SYS_RESET_CFG, 0x000e00), REG(SYS_SR_ETYPE_CFG, 0x000e04), REG(SYS_VLAN_ETYPE_CFG, 0x000e08), @@ -388,7 +392,6 @@ static const u32 vsc9959_sys_regmap[] = { REG_RESERVED(SYS_MMGT_FAST), REG_RESERVED(SYS_EVENTS_DIF), REG_RESERVED(SYS_EVENTS_CORE), - REG(SYS_CNT, 0x000000), REG(SYS_PTP_STATUS, 0x000f14), REG(SYS_PTP_TXSTAMP, 0x000f18), REG(SYS_PTP_NXT, 0x000f1c), @@ -2577,10 +2580,12 @@ static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index, SYS_STAT_CFG_STAT_VIEW_M, SYS_STAT_CFG); - counters->match = ocelot_read_gix(ocelot, SYS_CNT, 0x200); - counters->not_pass_gate = ocelot_read_gix(ocelot, SYS_CNT, 0x201); - counters->not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202); - counters->red = ocelot_read_gix(ocelot, SYS_CNT, 0x203); + counters->match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES); + counters->not_pass_gate = ocelot_read(ocelot, + SYS_COUNT_SF_NOT_PASSING_FRAMES); + counters->not_pass_sdu = ocelot_read(ocelot, + SYS_COUNT_SF_NOT_PASSING_SDU); + counters->red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES); /* Clear the PSFP counter. */ ocelot_write(ocelot, diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index b34f4cdfe814..26fdd0d90724 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -383,7 +383,6 @@ static const u32 vsc9953_sys_regmap[] = { REG_RESERVED(SYS_MMGT_FAST), REG_RESERVED(SYS_EVENTS_DIF), REG_RESERVED(SYS_EVENTS_CORE), - REG_RESERVED(SYS_CNT), REG_RESERVED(SYS_PTP_STATUS), REG_RESERVED(SYS_PTP_TXSTAMP), REG_RESERVED(SYS_PTP_NXT), -- cgit From 96980ff7c2caa5baef0c684e719547a53762e82c Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:04 +0300 Subject: net: mscc: ocelot: make access to STAT_VIEW sleepable again To support SPI-controlled switches in the future, access to SYS_STAT_CFG_STAT_VIEW needs to be done outside of any spinlock protected region, but it still needs to be serialized (by a mutex). Split the ocelot->stats_lock spinlock into a mutex that serializes indirect access to hardware registers (ocelot->stat_view_lock) and a spinlock that serializes access to the u64 ocelot->stats array. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 3c80df4253b2..858ccf1e67f0 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2574,7 +2574,7 @@ static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot, static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index, struct felix_stream_filter_counters *counters) { - spin_lock(&ocelot->stats_lock); + mutex_lock(&ocelot->stat_view_lock); ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index), SYS_STAT_CFG_STAT_VIEW_M, @@ -2593,7 +2593,7 @@ static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index, SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), SYS_STAT_CFG); - spin_unlock(&ocelot->stats_lock); + mutex_unlock(&ocelot->stat_view_lock); } static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, -- cgit From 25027c8409b4541611d0060077607d8ca70740df Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:05 +0300 Subject: net: dsa: felix: check the 32-bit PSFP stats against overflow The Felix PSFP counters suffer from the same problem as the ocelot ndo_get_stats64 ones - they are 32-bit, so they can easily overflow and this can easily go undetected. Add a custom hook in ocelot_check_stats_work() through which driver specific actions can be taken, and update the stats for the existing PSFP filters from that hook. Previously, vsc9959_psfp_filter_add() and vsc9959_psfp_filter_del() were serialized with respect to each other via rtnl_lock(). However, with the new entry point into &psfp->sfi_list coming from the periodic worker, we now need an explicit mutex to serialize access to these lists. We used to keep a struct felix_stream_filter_counters on stack, through which vsc9959_psfp_stats_get() - a FLOW_CLS_STATS callback - would retrieve data from vsc9959_psfp_counters_get(). We need to become smarter about that in 3 ways: - we need to keep a persistent set of counters for each stream instead of keeping them on stack - we need to promote those counters from u32 to u64, and create a procedure that properly keeps 64-bit counters. Since we clear the hardware counters anyway, and we poll every 2 seconds, a simple increment of a u64 counter with a u32 value will perfectly do the job. - FLOW_CLS_STATS also expect incremental counters, so we also need to zeroize our u64 counters every time sch_flower calls us Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 131 ++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 43 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 858ccf1e67f0..b815bc4278d9 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2046,7 +2046,15 @@ struct felix_stream { u32 ssid; }; +struct felix_stream_filter_counters { + u64 match; + u64 not_pass_gate; + u64 not_pass_sdu; + u64 red; +}; + struct felix_stream_filter { + struct felix_stream_filter_counters stats; struct list_head list; refcount_t refcount; u32 index; @@ -2061,13 +2069,6 @@ struct felix_stream_filter { u32 maxsdu; }; -struct felix_stream_filter_counters { - u32 match; - u32 not_pass_gate; - u32 not_pass_sdu; - u32 red; -}; - struct felix_stream_gate { u32 index; u8 enable; @@ -2571,31 +2572,6 @@ static void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot, } } -static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index, - struct felix_stream_filter_counters *counters) -{ - mutex_lock(&ocelot->stat_view_lock); - - ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index), - SYS_STAT_CFG_STAT_VIEW_M, - SYS_STAT_CFG); - - counters->match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES); - counters->not_pass_gate = ocelot_read(ocelot, - SYS_COUNT_SF_NOT_PASSING_FRAMES); - counters->not_pass_sdu = ocelot_read(ocelot, - SYS_COUNT_SF_NOT_PASSING_SDU); - counters->red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES); - - /* Clear the PSFP counter. */ - ocelot_write(ocelot, - SYS_STAT_CFG_STAT_VIEW(index) | - SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), - SYS_STAT_CFG); - - mutex_unlock(&ocelot->stat_view_lock); -} - static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, struct flow_cls_offload *f) { @@ -2620,6 +2596,8 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, return ret; } + mutex_lock(&psfp->lock); + flow_action_for_each(i, a, &f->rule->action) { switch (a->id) { case FLOW_ACTION_GATE: @@ -2661,6 +2639,7 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, sfi.maxsdu = a->police.mtu; break; default: + mutex_unlock(&psfp->lock); return -EOPNOTSUPP; } } @@ -2730,6 +2709,8 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port, goto err; } + mutex_unlock(&psfp->lock); + return 0; err: @@ -2739,6 +2720,8 @@ err: if (sfi.fm_valid) ocelot_vcap_policer_del(ocelot, sfi.fmid); + mutex_unlock(&psfp->lock); + return ret; } @@ -2746,18 +2729,22 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot, struct flow_cls_offload *f) { struct felix_stream *stream, tmp, *stream_entry; + struct ocelot_psfp_list *psfp = &ocelot->psfp; static struct felix_stream_filter *sfi; - struct ocelot_psfp_list *psfp; - psfp = &ocelot->psfp; + mutex_lock(&psfp->lock); stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); - if (!stream) + if (!stream) { + mutex_unlock(&psfp->lock); return -ENOMEM; + } sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); - if (!sfi) + if (!sfi) { + mutex_unlock(&psfp->lock); return -ENOMEM; + } if (sfi->sg_valid) vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid); @@ -2783,27 +2770,83 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot, stream_entry->ports); } + mutex_unlock(&psfp->lock); + return 0; } +static void vsc9959_update_sfid_stats(struct ocelot *ocelot, + struct felix_stream_filter *sfi) +{ + struct felix_stream_filter_counters *s = &sfi->stats; + u32 match, not_pass_gate, not_pass_sdu, red; + u32 sfid = sfi->index; + + lockdep_assert_held(&ocelot->stat_view_lock); + + ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(sfid), + SYS_STAT_CFG_STAT_VIEW_M, + SYS_STAT_CFG); + + match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES); + not_pass_gate = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_FRAMES); + not_pass_sdu = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_SDU); + red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES); + + /* Clear the PSFP counter. */ + ocelot_write(ocelot, + SYS_STAT_CFG_STAT_VIEW(sfid) | + SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10), + SYS_STAT_CFG); + + s->match += match; + s->not_pass_gate += not_pass_gate; + s->not_pass_sdu += not_pass_sdu; + s->red += red; +} + +/* Caller must hold &ocelot->stat_view_lock */ +static void vsc9959_update_stats(struct ocelot *ocelot) +{ + struct ocelot_psfp_list *psfp = &ocelot->psfp; + struct felix_stream_filter *sfi; + + mutex_lock(&psfp->lock); + + list_for_each_entry(sfi, &psfp->sfi_list, list) + vsc9959_update_sfid_stats(ocelot, sfi); + + mutex_unlock(&psfp->lock); +} + static int vsc9959_psfp_stats_get(struct ocelot *ocelot, struct flow_cls_offload *f, struct flow_stats *stats) { - struct felix_stream_filter_counters counters; - struct ocelot_psfp_list *psfp; + struct ocelot_psfp_list *psfp = &ocelot->psfp; + struct felix_stream_filter_counters *s; + static struct felix_stream_filter *sfi; struct felix_stream *stream; - psfp = &ocelot->psfp; stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie); if (!stream) return -ENOMEM; - vsc9959_psfp_counters_get(ocelot, stream->sfid, &counters); + sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid); + if (!sfi) + return -EINVAL; + + mutex_lock(&ocelot->stat_view_lock); + + vsc9959_update_sfid_stats(ocelot, sfi); + + s = &sfi->stats; + stats->pkts = s->match; + stats->drops = s->not_pass_gate + s->not_pass_sdu + s->red; - stats->pkts = counters.match; - stats->drops = counters.not_pass_gate + counters.not_pass_sdu + - counters.red; + memset(s, 0, sizeof(*s)); + + mutex_unlock(&ocelot->stat_view_lock); return 0; } @@ -2815,6 +2858,7 @@ static void vsc9959_psfp_init(struct ocelot *ocelot) INIT_LIST_HEAD(&psfp->stream_list); INIT_LIST_HEAD(&psfp->sfi_list); INIT_LIST_HEAD(&psfp->sgi_list); + mutex_init(&psfp->lock); } /* When using cut-through forwarding and the egress port runs at a higher data @@ -2913,6 +2957,7 @@ static const struct ocelot_ops vsc9959_ops = { .psfp_stats_get = vsc9959_psfp_stats_get, .cut_through_fwd = vsc9959_cut_through_fwd, .tas_clock_adjust = vsc9959_tas_clock_adjust, + .update_stats = vsc9959_update_stats, }; static const struct felix_info felix_info_vsc9959 = { -- cgit From 776b71e553841f9cde87c21078ce2d9772e6da7a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:11 +0300 Subject: net: dsa: felix: use ocelot's ndo_get_stats64 method Move the logic from the ocelot switchdev driver's ocelot_get_stats64() method to the common switch lib and reuse it for the DSA driver. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index ee19ed96f284..71e22990aa67 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1034,6 +1034,14 @@ static void felix_port_qos_map_init(struct ocelot *ocelot, int port) } } +static void felix_get_stats64(struct dsa_switch *ds, int port, + struct rtnl_link_stats64 *stats) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_stats64(ocelot, port, stats); +} + static void felix_get_strings(struct dsa_switch *ds, int port, u32 stringset, u8 *data) { @@ -1848,6 +1856,7 @@ const struct dsa_switch_ops felix_switch_ops = { .setup = felix_setup, .teardown = felix_teardown, .set_ageing_time = felix_set_ageing_time, + .get_stats64 = felix_get_stats64, .get_strings = felix_get_strings, .get_ethtool_stats = felix_get_ethtool_stats, .get_sset_count = felix_get_sset_count, -- cgit From e32036e1ae7bb71b64559313f9ea8790a0acaa51 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:13 +0300 Subject: net: mscc: ocelot: add support for all sorts of standardized counters present in DSA DSA is integrated with the new standardized ethtool -S --groups option, but the felix driver only exports unstructured statistics. Reuse the array of 64-bit statistics collected by ocelot_check_stats_work(), but just export select values from it. Since ocelot_check_stats_work() runs periodically to avoid 32-bit overflow, and the ethtool calling context is sleepable, we update the 64-bit stats one more time, to provide up-to-date values. The locking scheme with a mutex followed by a spinlock is a bit hard to digest, so we create and use a ocelot_port_stats_run() helper with a callback that populates the ethool stats group the caller is interested in. The exported stats are: ethtool -S swp0 --groups eth-phy ethtool -S swp0 --groups eth-mac ethtool -S swp0 --groups eth-ctrl ethtool -S swp0 --groups rmon ethtool --include-statistics --show-pause swp0 Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 71e22990aa67..c73ef5f7aa64 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1042,6 +1042,47 @@ static void felix_get_stats64(struct dsa_switch *ds, int port, ocelot_port_get_stats64(ocelot, port, stats); } +static void felix_get_pause_stats(struct dsa_switch *ds, int port, + struct ethtool_pause_stats *pause_stats) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_pause_stats(ocelot, port, pause_stats); +} + +static void felix_get_rmon_stats(struct dsa_switch *ds, int port, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_rmon_stats(ocelot, port, rmon_stats, ranges); +} + +static void felix_get_eth_ctrl_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_eth_ctrl_stats(ocelot, port, ctrl_stats); +} + +static void felix_get_eth_mac_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_eth_mac_stats(ocelot, port, mac_stats); +} + +static void felix_get_eth_phy_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_get_eth_phy_stats(ocelot, port, phy_stats); +} + static void felix_get_strings(struct dsa_switch *ds, int port, u32 stringset, u8 *data) { @@ -1857,6 +1898,11 @@ const struct dsa_switch_ops felix_switch_ops = { .teardown = felix_teardown, .set_ageing_time = felix_set_ageing_time, .get_stats64 = felix_get_stats64, + .get_pause_stats = felix_get_pause_stats, + .get_rmon_stats = felix_get_rmon_stats, + .get_eth_ctrl_stats = felix_get_eth_ctrl_stats, + .get_eth_mac_stats = felix_get_eth_mac_stats, + .get_eth_phy_stats = felix_get_eth_phy_stats, .get_strings = felix_get_strings, .get_ethtool_stats = felix_get_ethtool_stats, .get_sset_count = felix_get_sset_count, -- cgit From be5c13f262050f90b56a4290645bf7a14055d3cd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:14 +0300 Subject: net: mscc: ocelot: harmonize names of SYS_COUNT_TX_AGING and OCELOT_STAT_TX_AGED The hardware counter is called C_TX_AGED, so rename SYS_COUNT_TX_AGING to SYS_COUNT_TX_AGED. This will become important since we want to minimize the way in which we declare struct ocelot_stat_layout elements, using the C preprocessor. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 4 ++-- drivers/net/dsa/ocelot/seville_vsc9953.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index b815bc4278d9..e1c5bcb5432d 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -348,7 +348,7 @@ static const u32 vsc9959_sys_regmap[] = { REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00026c), REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000270), REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000274), - REG(SYS_COUNT_TX_AGING, 0x000278), + REG(SYS_COUNT_TX_AGED, 0x000278), REG(SYS_COUNT_DROP_LOCAL, 0x000400), REG(SYS_COUNT_DROP_TAIL, 0x000404), REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000408), @@ -921,7 +921,7 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = }, [OCELOT_STAT_TX_AGED] = { .name = "tx_aged", - .reg = SYS_COUNT_TX_AGING, + .reg = SYS_COUNT_TX_AGED, }, [OCELOT_STAT_DROP_LOCAL] = { .name = "drop_local", diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 26fdd0d90724..5799c4e50e36 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -343,7 +343,7 @@ static const u32 vsc9953_sys_regmap[] = { REG(SYS_COUNT_TX_GREEN_PRIO_5, 0x00016c), REG(SYS_COUNT_TX_GREEN_PRIO_6, 0x000170), REG(SYS_COUNT_TX_GREEN_PRIO_7, 0x000174), - REG(SYS_COUNT_TX_AGING, 0x000178), + REG(SYS_COUNT_TX_AGED, 0x000178), REG(SYS_COUNT_DROP_LOCAL, 0x000200), REG(SYS_COUNT_DROP_TAIL, 0x000204), REG(SYS_COUNT_DROP_YELLOW_PRIO_0, 0x000208), @@ -912,7 +912,7 @@ static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = }, [OCELOT_STAT_TX_AGED] = { .name = "tx_aged", - .reg = SYS_COUNT_TX_AGING, + .reg = SYS_COUNT_TX_AGED, }, [OCELOT_STAT_DROP_LOCAL] = { .name = "drop_local", -- cgit From b69cf1c675723b1417e018971faf2bcb1620ee7a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:15 +0300 Subject: net: mscc: ocelot: minimize definitions for stats The current definition of struct ocelot_stat_layout is long-winded (4 lines per entry, and we have hundreds of entries), so we could make an effort to use the C preprocessor and reduce the line count. Create an implicit correspondence between enum ocelot_reg, which tells us the register address (SYS_COUNT_RX_OCTETS etc) and enum ocelot_stat which allows us to index the ocelot->stats array (OCELOT_STAT_RX_OCTETS etc), and don't require us to specify both when we define what stats each switch family has. Create an OCELOT_STAT() macro that pairs only an enum ocelot_stat to an enum ocelot_reg, and an OCELOT_STAT_ETHTOOL() macro which also contains a name exported to the unstructured ethtool -S stringset API. For now, we define all counters as having the OCELOT_STAT_ETHTOOL() kind, but we will add more counters in the future which are not exported to the unstructured ethtool -S. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 465 +++++++------------------------ drivers/net/dsa/ocelot/seville_vsc9953.c | 465 +++++++------------------------ 2 files changed, 186 insertions(+), 744 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index e1c5bcb5432d..3c90809e023d 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -623,378 +623,99 @@ static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { }; static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = { - [OCELOT_STAT_RX_OCTETS] = { - .name = "rx_octets", - .reg = SYS_COUNT_RX_OCTETS, - }, - [OCELOT_STAT_RX_UNICAST] = { - .name = "rx_unicast", - .reg = SYS_COUNT_RX_UNICAST, - }, - [OCELOT_STAT_RX_MULTICAST] = { - .name = "rx_multicast", - .reg = SYS_COUNT_RX_MULTICAST, - }, - [OCELOT_STAT_RX_BROADCAST] = { - .name = "rx_broadcast", - .reg = SYS_COUNT_RX_BROADCAST, - }, - [OCELOT_STAT_RX_SHORTS] = { - .name = "rx_shorts", - .reg = SYS_COUNT_RX_SHORTS, - }, - [OCELOT_STAT_RX_FRAGMENTS] = { - .name = "rx_fragments", - .reg = SYS_COUNT_RX_FRAGMENTS, - }, - [OCELOT_STAT_RX_JABBERS] = { - .name = "rx_jabbers", - .reg = SYS_COUNT_RX_JABBERS, - }, - [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = { - .name = "rx_crc_align_errs", - .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS, - }, - [OCELOT_STAT_RX_SYM_ERRS] = { - .name = "rx_sym_errs", - .reg = SYS_COUNT_RX_SYM_ERRS, - }, - [OCELOT_STAT_RX_64] = { - .name = "rx_frames_below_65_octets", - .reg = SYS_COUNT_RX_64, - }, - [OCELOT_STAT_RX_65_127] = { - .name = "rx_frames_65_to_127_octets", - .reg = SYS_COUNT_RX_65_127, - }, - [OCELOT_STAT_RX_128_255] = { - .name = "rx_frames_128_to_255_octets", - .reg = SYS_COUNT_RX_128_255, - }, - [OCELOT_STAT_RX_256_511] = { - .name = "rx_frames_256_to_511_octets", - .reg = SYS_COUNT_RX_256_511, - }, - [OCELOT_STAT_RX_512_1023] = { - .name = "rx_frames_512_to_1023_octets", - .reg = SYS_COUNT_RX_512_1023, - }, - [OCELOT_STAT_RX_1024_1526] = { - .name = "rx_frames_1024_to_1526_octets", - .reg = SYS_COUNT_RX_1024_1526, - }, - [OCELOT_STAT_RX_1527_MAX] = { - .name = "rx_frames_over_1526_octets", - .reg = SYS_COUNT_RX_1527_MAX, - }, - [OCELOT_STAT_RX_PAUSE] = { - .name = "rx_pause", - .reg = SYS_COUNT_RX_PAUSE, - }, - [OCELOT_STAT_RX_CONTROL] = { - .name = "rx_control", - .reg = SYS_COUNT_RX_CONTROL, - }, - [OCELOT_STAT_RX_LONGS] = { - .name = "rx_longs", - .reg = SYS_COUNT_RX_LONGS, - }, - [OCELOT_STAT_RX_CLASSIFIED_DROPS] = { - .name = "rx_classified_drops", - .reg = SYS_COUNT_RX_CLASSIFIED_DROPS, - }, - [OCELOT_STAT_RX_RED_PRIO_0] = { - .name = "rx_red_prio_0", - .reg = SYS_COUNT_RX_RED_PRIO_0, - }, - [OCELOT_STAT_RX_RED_PRIO_1] = { - .name = "rx_red_prio_1", - .reg = SYS_COUNT_RX_RED_PRIO_1, - }, - [OCELOT_STAT_RX_RED_PRIO_2] = { - .name = "rx_red_prio_2", - .reg = SYS_COUNT_RX_RED_PRIO_2, - }, - [OCELOT_STAT_RX_RED_PRIO_3] = { - .name = "rx_red_prio_3", - .reg = SYS_COUNT_RX_RED_PRIO_3, - }, - [OCELOT_STAT_RX_RED_PRIO_4] = { - .name = "rx_red_prio_4", - .reg = SYS_COUNT_RX_RED_PRIO_4, - }, - [OCELOT_STAT_RX_RED_PRIO_5] = { - .name = "rx_red_prio_5", - .reg = SYS_COUNT_RX_RED_PRIO_5, - }, - [OCELOT_STAT_RX_RED_PRIO_6] = { - .name = "rx_red_prio_6", - .reg = SYS_COUNT_RX_RED_PRIO_6, - }, - [OCELOT_STAT_RX_RED_PRIO_7] = { - .name = "rx_red_prio_7", - .reg = SYS_COUNT_RX_RED_PRIO_7, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_0] = { - .name = "rx_yellow_prio_0", - .reg = SYS_COUNT_RX_YELLOW_PRIO_0, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_1] = { - .name = "rx_yellow_prio_1", - .reg = SYS_COUNT_RX_YELLOW_PRIO_1, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_2] = { - .name = "rx_yellow_prio_2", - .reg = SYS_COUNT_RX_YELLOW_PRIO_2, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_3] = { - .name = "rx_yellow_prio_3", - .reg = SYS_COUNT_RX_YELLOW_PRIO_3, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_4] = { - .name = "rx_yellow_prio_4", - .reg = SYS_COUNT_RX_YELLOW_PRIO_4, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_5] = { - .name = "rx_yellow_prio_5", - .reg = SYS_COUNT_RX_YELLOW_PRIO_5, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_6] = { - .name = "rx_yellow_prio_6", - .reg = SYS_COUNT_RX_YELLOW_PRIO_6, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_7] = { - .name = "rx_yellow_prio_7", - .reg = SYS_COUNT_RX_YELLOW_PRIO_7, - }, - [OCELOT_STAT_RX_GREEN_PRIO_0] = { - .name = "rx_green_prio_0", - .reg = SYS_COUNT_RX_GREEN_PRIO_0, - }, - [OCELOT_STAT_RX_GREEN_PRIO_1] = { - .name = "rx_green_prio_1", - .reg = SYS_COUNT_RX_GREEN_PRIO_1, - }, - [OCELOT_STAT_RX_GREEN_PRIO_2] = { - .name = "rx_green_prio_2", - .reg = SYS_COUNT_RX_GREEN_PRIO_2, - }, - [OCELOT_STAT_RX_GREEN_PRIO_3] = { - .name = "rx_green_prio_3", - .reg = SYS_COUNT_RX_GREEN_PRIO_3, - }, - [OCELOT_STAT_RX_GREEN_PRIO_4] = { - .name = "rx_green_prio_4", - .reg = SYS_COUNT_RX_GREEN_PRIO_4, - }, - [OCELOT_STAT_RX_GREEN_PRIO_5] = { - .name = "rx_green_prio_5", - .reg = SYS_COUNT_RX_GREEN_PRIO_5, - }, - [OCELOT_STAT_RX_GREEN_PRIO_6] = { - .name = "rx_green_prio_6", - .reg = SYS_COUNT_RX_GREEN_PRIO_6, - }, - [OCELOT_STAT_RX_GREEN_PRIO_7] = { - .name = "rx_green_prio_7", - .reg = SYS_COUNT_RX_GREEN_PRIO_7, - }, - [OCELOT_STAT_TX_OCTETS] = { - .name = "tx_octets", - .reg = SYS_COUNT_TX_OCTETS, - }, - [OCELOT_STAT_TX_UNICAST] = { - .name = "tx_unicast", - .reg = SYS_COUNT_TX_UNICAST, - }, - [OCELOT_STAT_TX_MULTICAST] = { - .name = "tx_multicast", - .reg = SYS_COUNT_TX_MULTICAST, - }, - [OCELOT_STAT_TX_BROADCAST] = { - .name = "tx_broadcast", - .reg = SYS_COUNT_TX_BROADCAST, - }, - [OCELOT_STAT_TX_COLLISION] = { - .name = "tx_collision", - .reg = SYS_COUNT_TX_COLLISION, - }, - [OCELOT_STAT_TX_DROPS] = { - .name = "tx_drops", - .reg = SYS_COUNT_TX_DROPS, - }, - [OCELOT_STAT_TX_PAUSE] = { - .name = "tx_pause", - .reg = SYS_COUNT_TX_PAUSE, - }, - [OCELOT_STAT_TX_64] = { - .name = "tx_frames_below_65_octets", - .reg = SYS_COUNT_TX_64, - }, - [OCELOT_STAT_TX_65_127] = { - .name = "tx_frames_65_to_127_octets", - .reg = SYS_COUNT_TX_65_127, - }, - [OCELOT_STAT_TX_128_255] = { - .name = "tx_frames_128_255_octets", - .reg = SYS_COUNT_TX_128_255, - }, - [OCELOT_STAT_TX_256_511] = { - .name = "tx_frames_256_511_octets", - .reg = SYS_COUNT_TX_256_511, - }, - [OCELOT_STAT_TX_512_1023] = { - .name = "tx_frames_512_1023_octets", - .reg = SYS_COUNT_TX_512_1023, - }, - [OCELOT_STAT_TX_1024_1526] = { - .name = "tx_frames_1024_1526_octets", - .reg = SYS_COUNT_TX_1024_1526, - }, - [OCELOT_STAT_TX_1527_MAX] = { - .name = "tx_frames_over_1526_octets", - .reg = SYS_COUNT_TX_1527_MAX, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_0] = { - .name = "tx_yellow_prio_0", - .reg = SYS_COUNT_TX_YELLOW_PRIO_0, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_1] = { - .name = "tx_yellow_prio_1", - .reg = SYS_COUNT_TX_YELLOW_PRIO_1, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_2] = { - .name = "tx_yellow_prio_2", - .reg = SYS_COUNT_TX_YELLOW_PRIO_2, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_3] = { - .name = "tx_yellow_prio_3", - .reg = SYS_COUNT_TX_YELLOW_PRIO_3, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_4] = { - .name = "tx_yellow_prio_4", - .reg = SYS_COUNT_TX_YELLOW_PRIO_4, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_5] = { - .name = "tx_yellow_prio_5", - .reg = SYS_COUNT_TX_YELLOW_PRIO_5, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_6] = { - .name = "tx_yellow_prio_6", - .reg = SYS_COUNT_TX_YELLOW_PRIO_6, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_7] = { - .name = "tx_yellow_prio_7", - .reg = SYS_COUNT_TX_YELLOW_PRIO_7, - }, - [OCELOT_STAT_TX_GREEN_PRIO_0] = { - .name = "tx_green_prio_0", - .reg = SYS_COUNT_TX_GREEN_PRIO_0, - }, - [OCELOT_STAT_TX_GREEN_PRIO_1] = { - .name = "tx_green_prio_1", - .reg = SYS_COUNT_TX_GREEN_PRIO_1, - }, - [OCELOT_STAT_TX_GREEN_PRIO_2] = { - .name = "tx_green_prio_2", - .reg = SYS_COUNT_TX_GREEN_PRIO_2, - }, - [OCELOT_STAT_TX_GREEN_PRIO_3] = { - .name = "tx_green_prio_3", - .reg = SYS_COUNT_TX_GREEN_PRIO_3, - }, - [OCELOT_STAT_TX_GREEN_PRIO_4] = { - .name = "tx_green_prio_4", - .reg = SYS_COUNT_TX_GREEN_PRIO_4, - }, - [OCELOT_STAT_TX_GREEN_PRIO_5] = { - .name = "tx_green_prio_5", - .reg = SYS_COUNT_TX_GREEN_PRIO_5, - }, - [OCELOT_STAT_TX_GREEN_PRIO_6] = { - .name = "tx_green_prio_6", - .reg = SYS_COUNT_TX_GREEN_PRIO_6, - }, - [OCELOT_STAT_TX_GREEN_PRIO_7] = { - .name = "tx_green_prio_7", - .reg = SYS_COUNT_TX_GREEN_PRIO_7, - }, - [OCELOT_STAT_TX_AGED] = { - .name = "tx_aged", - .reg = SYS_COUNT_TX_AGED, - }, - [OCELOT_STAT_DROP_LOCAL] = { - .name = "drop_local", - .reg = SYS_COUNT_DROP_LOCAL, - }, - [OCELOT_STAT_DROP_TAIL] = { - .name = "drop_tail", - .reg = SYS_COUNT_DROP_TAIL, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_0] = { - .name = "drop_yellow_prio_0", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_0, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_1] = { - .name = "drop_yellow_prio_1", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_1, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_2] = { - .name = "drop_yellow_prio_2", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_2, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_3] = { - .name = "drop_yellow_prio_3", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_3, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_4] = { - .name = "drop_yellow_prio_4", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_4, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_5] = { - .name = "drop_yellow_prio_5", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_5, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_6] = { - .name = "drop_yellow_prio_6", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_6, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_7] = { - .name = "drop_yellow_prio_7", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_7, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_0] = { - .name = "drop_green_prio_0", - .reg = SYS_COUNT_DROP_GREEN_PRIO_0, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_1] = { - .name = "drop_green_prio_1", - .reg = SYS_COUNT_DROP_GREEN_PRIO_1, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_2] = { - .name = "drop_green_prio_2", - .reg = SYS_COUNT_DROP_GREEN_PRIO_2, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_3] = { - .name = "drop_green_prio_3", - .reg = SYS_COUNT_DROP_GREEN_PRIO_3, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_4] = { - .name = "drop_green_prio_4", - .reg = SYS_COUNT_DROP_GREEN_PRIO_4, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_5] = { - .name = "drop_green_prio_5", - .reg = SYS_COUNT_DROP_GREEN_PRIO_5, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_6] = { - .name = "drop_green_prio_6", - .reg = SYS_COUNT_DROP_GREEN_PRIO_6, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_7] = { - .name = "drop_green_prio_7", - .reg = SYS_COUNT_DROP_GREEN_PRIO_7, - }, + OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), + OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), + OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), + OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), + OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), + OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), + OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), + OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), + OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), + OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), + OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), + OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), + OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), + OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), + OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), + OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), + OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), + OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), + OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), + OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), + OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), + OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), + OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), + OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), + OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), + OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), + OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), + OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), + OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), + OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), + OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), + OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), + OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), + OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), + OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), + OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), + OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7"), }; static const struct vcap_field vsc9959_vcap_es0_keys[] = { diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 5799c4e50e36..a8f69d483abf 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -614,378 +614,99 @@ static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = { }; static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = { - [OCELOT_STAT_RX_OCTETS] = { - .name = "rx_octets", - .reg = SYS_COUNT_RX_OCTETS, - }, - [OCELOT_STAT_RX_UNICAST] = { - .name = "rx_unicast", - .reg = SYS_COUNT_RX_UNICAST, - }, - [OCELOT_STAT_RX_MULTICAST] = { - .name = "rx_multicast", - .reg = SYS_COUNT_RX_MULTICAST, - }, - [OCELOT_STAT_RX_BROADCAST] = { - .name = "rx_broadcast", - .reg = SYS_COUNT_RX_BROADCAST, - }, - [OCELOT_STAT_RX_SHORTS] = { - .name = "rx_shorts", - .reg = SYS_COUNT_RX_SHORTS, - }, - [OCELOT_STAT_RX_FRAGMENTS] = { - .name = "rx_fragments", - .reg = SYS_COUNT_RX_FRAGMENTS, - }, - [OCELOT_STAT_RX_JABBERS] = { - .name = "rx_jabbers", - .reg = SYS_COUNT_RX_JABBERS, - }, - [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = { - .name = "rx_crc_align_errs", - .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS, - }, - [OCELOT_STAT_RX_SYM_ERRS] = { - .name = "rx_sym_errs", - .reg = SYS_COUNT_RX_SYM_ERRS, - }, - [OCELOT_STAT_RX_64] = { - .name = "rx_frames_below_65_octets", - .reg = SYS_COUNT_RX_64, - }, - [OCELOT_STAT_RX_65_127] = { - .name = "rx_frames_65_to_127_octets", - .reg = SYS_COUNT_RX_65_127, - }, - [OCELOT_STAT_RX_128_255] = { - .name = "rx_frames_128_to_255_octets", - .reg = SYS_COUNT_RX_128_255, - }, - [OCELOT_STAT_RX_256_511] = { - .name = "rx_frames_256_to_511_octets", - .reg = SYS_COUNT_RX_256_511, - }, - [OCELOT_STAT_RX_512_1023] = { - .name = "rx_frames_512_to_1023_octets", - .reg = SYS_COUNT_RX_512_1023, - }, - [OCELOT_STAT_RX_1024_1526] = { - .name = "rx_frames_1024_to_1526_octets", - .reg = SYS_COUNT_RX_1024_1526, - }, - [OCELOT_STAT_RX_1527_MAX] = { - .name = "rx_frames_over_1526_octets", - .reg = SYS_COUNT_RX_1527_MAX, - }, - [OCELOT_STAT_RX_PAUSE] = { - .name = "rx_pause", - .reg = SYS_COUNT_RX_PAUSE, - }, - [OCELOT_STAT_RX_CONTROL] = { - .name = "rx_control", - .reg = SYS_COUNT_RX_CONTROL, - }, - [OCELOT_STAT_RX_LONGS] = { - .name = "rx_longs", - .reg = SYS_COUNT_RX_LONGS, - }, - [OCELOT_STAT_RX_CLASSIFIED_DROPS] = { - .name = "rx_classified_drops", - .reg = SYS_COUNT_RX_CLASSIFIED_DROPS, - }, - [OCELOT_STAT_RX_RED_PRIO_0] = { - .name = "rx_red_prio_0", - .reg = SYS_COUNT_RX_RED_PRIO_0, - }, - [OCELOT_STAT_RX_RED_PRIO_1] = { - .name = "rx_red_prio_1", - .reg = SYS_COUNT_RX_RED_PRIO_1, - }, - [OCELOT_STAT_RX_RED_PRIO_2] = { - .name = "rx_red_prio_2", - .reg = SYS_COUNT_RX_RED_PRIO_2, - }, - [OCELOT_STAT_RX_RED_PRIO_3] = { - .name = "rx_red_prio_3", - .reg = SYS_COUNT_RX_RED_PRIO_3, - }, - [OCELOT_STAT_RX_RED_PRIO_4] = { - .name = "rx_red_prio_4", - .reg = SYS_COUNT_RX_RED_PRIO_4, - }, - [OCELOT_STAT_RX_RED_PRIO_5] = { - .name = "rx_red_prio_5", - .reg = SYS_COUNT_RX_RED_PRIO_5, - }, - [OCELOT_STAT_RX_RED_PRIO_6] = { - .name = "rx_red_prio_6", - .reg = SYS_COUNT_RX_RED_PRIO_6, - }, - [OCELOT_STAT_RX_RED_PRIO_7] = { - .name = "rx_red_prio_7", - .reg = SYS_COUNT_RX_RED_PRIO_7, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_0] = { - .name = "rx_yellow_prio_0", - .reg = SYS_COUNT_RX_YELLOW_PRIO_0, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_1] = { - .name = "rx_yellow_prio_1", - .reg = SYS_COUNT_RX_YELLOW_PRIO_1, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_2] = { - .name = "rx_yellow_prio_2", - .reg = SYS_COUNT_RX_YELLOW_PRIO_2, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_3] = { - .name = "rx_yellow_prio_3", - .reg = SYS_COUNT_RX_YELLOW_PRIO_3, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_4] = { - .name = "rx_yellow_prio_4", - .reg = SYS_COUNT_RX_YELLOW_PRIO_4, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_5] = { - .name = "rx_yellow_prio_5", - .reg = SYS_COUNT_RX_YELLOW_PRIO_5, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_6] = { - .name = "rx_yellow_prio_6", - .reg = SYS_COUNT_RX_YELLOW_PRIO_6, - }, - [OCELOT_STAT_RX_YELLOW_PRIO_7] = { - .name = "rx_yellow_prio_7", - .reg = SYS_COUNT_RX_YELLOW_PRIO_7, - }, - [OCELOT_STAT_RX_GREEN_PRIO_0] = { - .name = "rx_green_prio_0", - .reg = SYS_COUNT_RX_GREEN_PRIO_0, - }, - [OCELOT_STAT_RX_GREEN_PRIO_1] = { - .name = "rx_green_prio_1", - .reg = SYS_COUNT_RX_GREEN_PRIO_1, - }, - [OCELOT_STAT_RX_GREEN_PRIO_2] = { - .name = "rx_green_prio_2", - .reg = SYS_COUNT_RX_GREEN_PRIO_2, - }, - [OCELOT_STAT_RX_GREEN_PRIO_3] = { - .name = "rx_green_prio_3", - .reg = SYS_COUNT_RX_GREEN_PRIO_3, - }, - [OCELOT_STAT_RX_GREEN_PRIO_4] = { - .name = "rx_green_prio_4", - .reg = SYS_COUNT_RX_GREEN_PRIO_4, - }, - [OCELOT_STAT_RX_GREEN_PRIO_5] = { - .name = "rx_green_prio_5", - .reg = SYS_COUNT_RX_GREEN_PRIO_5, - }, - [OCELOT_STAT_RX_GREEN_PRIO_6] = { - .name = "rx_green_prio_6", - .reg = SYS_COUNT_RX_GREEN_PRIO_6, - }, - [OCELOT_STAT_RX_GREEN_PRIO_7] = { - .name = "rx_green_prio_7", - .reg = SYS_COUNT_RX_GREEN_PRIO_7, - }, - [OCELOT_STAT_TX_OCTETS] = { - .name = "tx_octets", - .reg = SYS_COUNT_TX_OCTETS, - }, - [OCELOT_STAT_TX_UNICAST] = { - .name = "tx_unicast", - .reg = SYS_COUNT_TX_UNICAST, - }, - [OCELOT_STAT_TX_MULTICAST] = { - .name = "tx_multicast", - .reg = SYS_COUNT_TX_MULTICAST, - }, - [OCELOT_STAT_TX_BROADCAST] = { - .name = "tx_broadcast", - .reg = SYS_COUNT_TX_BROADCAST, - }, - [OCELOT_STAT_TX_COLLISION] = { - .name = "tx_collision", - .reg = SYS_COUNT_TX_COLLISION, - }, - [OCELOT_STAT_TX_DROPS] = { - .name = "tx_drops", - .reg = SYS_COUNT_TX_DROPS, - }, - [OCELOT_STAT_TX_PAUSE] = { - .name = "tx_pause", - .reg = SYS_COUNT_TX_PAUSE, - }, - [OCELOT_STAT_TX_64] = { - .name = "tx_frames_below_65_octets", - .reg = SYS_COUNT_TX_64, - }, - [OCELOT_STAT_TX_65_127] = { - .name = "tx_frames_65_to_127_octets", - .reg = SYS_COUNT_TX_65_127, - }, - [OCELOT_STAT_TX_128_255] = { - .name = "tx_frames_128_255_octets", - .reg = SYS_COUNT_TX_128_255, - }, - [OCELOT_STAT_TX_256_511] = { - .name = "tx_frames_256_511_octets", - .reg = SYS_COUNT_TX_256_511, - }, - [OCELOT_STAT_TX_512_1023] = { - .name = "tx_frames_512_1023_octets", - .reg = SYS_COUNT_TX_512_1023, - }, - [OCELOT_STAT_TX_1024_1526] = { - .name = "tx_frames_1024_1526_octets", - .reg = SYS_COUNT_TX_1024_1526, - }, - [OCELOT_STAT_TX_1527_MAX] = { - .name = "tx_frames_over_1526_octets", - .reg = SYS_COUNT_TX_1527_MAX, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_0] = { - .name = "tx_yellow_prio_0", - .reg = SYS_COUNT_TX_YELLOW_PRIO_0, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_1] = { - .name = "tx_yellow_prio_1", - .reg = SYS_COUNT_TX_YELLOW_PRIO_1, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_2] = { - .name = "tx_yellow_prio_2", - .reg = SYS_COUNT_TX_YELLOW_PRIO_2, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_3] = { - .name = "tx_yellow_prio_3", - .reg = SYS_COUNT_TX_YELLOW_PRIO_3, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_4] = { - .name = "tx_yellow_prio_4", - .reg = SYS_COUNT_TX_YELLOW_PRIO_4, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_5] = { - .name = "tx_yellow_prio_5", - .reg = SYS_COUNT_TX_YELLOW_PRIO_5, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_6] = { - .name = "tx_yellow_prio_6", - .reg = SYS_COUNT_TX_YELLOW_PRIO_6, - }, - [OCELOT_STAT_TX_YELLOW_PRIO_7] = { - .name = "tx_yellow_prio_7", - .reg = SYS_COUNT_TX_YELLOW_PRIO_7, - }, - [OCELOT_STAT_TX_GREEN_PRIO_0] = { - .name = "tx_green_prio_0", - .reg = SYS_COUNT_TX_GREEN_PRIO_0, - }, - [OCELOT_STAT_TX_GREEN_PRIO_1] = { - .name = "tx_green_prio_1", - .reg = SYS_COUNT_TX_GREEN_PRIO_1, - }, - [OCELOT_STAT_TX_GREEN_PRIO_2] = { - .name = "tx_green_prio_2", - .reg = SYS_COUNT_TX_GREEN_PRIO_2, - }, - [OCELOT_STAT_TX_GREEN_PRIO_3] = { - .name = "tx_green_prio_3", - .reg = SYS_COUNT_TX_GREEN_PRIO_3, - }, - [OCELOT_STAT_TX_GREEN_PRIO_4] = { - .name = "tx_green_prio_4", - .reg = SYS_COUNT_TX_GREEN_PRIO_4, - }, - [OCELOT_STAT_TX_GREEN_PRIO_5] = { - .name = "tx_green_prio_5", - .reg = SYS_COUNT_TX_GREEN_PRIO_5, - }, - [OCELOT_STAT_TX_GREEN_PRIO_6] = { - .name = "tx_green_prio_6", - .reg = SYS_COUNT_TX_GREEN_PRIO_6, - }, - [OCELOT_STAT_TX_GREEN_PRIO_7] = { - .name = "tx_green_prio_7", - .reg = SYS_COUNT_TX_GREEN_PRIO_7, - }, - [OCELOT_STAT_TX_AGED] = { - .name = "tx_aged", - .reg = SYS_COUNT_TX_AGED, - }, - [OCELOT_STAT_DROP_LOCAL] = { - .name = "drop_local", - .reg = SYS_COUNT_DROP_LOCAL, - }, - [OCELOT_STAT_DROP_TAIL] = { - .name = "drop_tail", - .reg = SYS_COUNT_DROP_TAIL, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_0] = { - .name = "drop_yellow_prio_0", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_0, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_1] = { - .name = "drop_yellow_prio_1", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_1, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_2] = { - .name = "drop_yellow_prio_2", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_2, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_3] = { - .name = "drop_yellow_prio_3", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_3, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_4] = { - .name = "drop_yellow_prio_4", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_4, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_5] = { - .name = "drop_yellow_prio_5", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_5, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_6] = { - .name = "drop_yellow_prio_6", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_6, - }, - [OCELOT_STAT_DROP_YELLOW_PRIO_7] = { - .name = "drop_yellow_prio_7", - .reg = SYS_COUNT_DROP_YELLOW_PRIO_7, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_0] = { - .name = "drop_green_prio_0", - .reg = SYS_COUNT_DROP_GREEN_PRIO_0, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_1] = { - .name = "drop_green_prio_1", - .reg = SYS_COUNT_DROP_GREEN_PRIO_1, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_2] = { - .name = "drop_green_prio_2", - .reg = SYS_COUNT_DROP_GREEN_PRIO_2, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_3] = { - .name = "drop_green_prio_3", - .reg = SYS_COUNT_DROP_GREEN_PRIO_3, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_4] = { - .name = "drop_green_prio_4", - .reg = SYS_COUNT_DROP_GREEN_PRIO_4, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_5] = { - .name = "drop_green_prio_5", - .reg = SYS_COUNT_DROP_GREEN_PRIO_5, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_6] = { - .name = "drop_green_prio_6", - .reg = SYS_COUNT_DROP_GREEN_PRIO_6, - }, - [OCELOT_STAT_DROP_GREEN_PRIO_7] = { - .name = "drop_green_prio_7", - .reg = SYS_COUNT_DROP_GREEN_PRIO_7, - }, + OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), + OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), + OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), + OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), + OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), + OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), + OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), + OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), + OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), + OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), + OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), + OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), + OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), + OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), + OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), + OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), + OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), + OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), + OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), + OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), + OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), + OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), + OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), + OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), + OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), + OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), + OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), + OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), + OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), + OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), + OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), + OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), + OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), + OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), + OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), + OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), + OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), + OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), + OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), + OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), + OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), + OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7"), }; static const struct vcap_field vsc9953_vcap_es0_keys[] = { -- cgit From 4d1d157fb6a49f6720a3fb3135299e475d5bc844 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 8 Sep 2022 19:48:16 +0300 Subject: net: mscc: ocelot: share the common stat definitions between all drivers All switch families supported by the ocelot lib (ocelot, felix, seville) export the same registers so far. But for example felix also has TSN counters, while the others don't. To reduce the bloat even further, create an OCELOT_COMMON_STATS() macro which just lists all stats that are common between switches. The array elements are still replicated among all of vsc9959_stats_layout, vsc9953_stats_layout and ocelot_stats_layout. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 94 +------------------------------- drivers/net/dsa/ocelot/seville_vsc9953.c | 94 +------------------------------- 2 files changed, 2 insertions(+), 186 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 3c90809e023d..459288d6222c 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -623,99 +623,7 @@ static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { }; static const struct ocelot_stat_layout vsc9959_stats_layout[OCELOT_NUM_STATS] = { - OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), - OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), - OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), - OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), - OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), - OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), - OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), - OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), - OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), - OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), - OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), - OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), - OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), - OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), - OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), - OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), - OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), - OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), - OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), - OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), - OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), - OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), - OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), - OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), - OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), - OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), - OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), - OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), - OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), - OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), - OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), - OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), - OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), - OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), - OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), - OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), - OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7"), + OCELOT_COMMON_STATS, }; static const struct vcap_field vsc9959_vcap_es0_keys[] = { diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index a8f69d483abf..3ce1cd1a8d4a 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -614,99 +614,7 @@ static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = { }; static const struct ocelot_stat_layout vsc9953_stats_layout[OCELOT_NUM_STATS] = { - OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), - OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), - OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), - OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), - OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), - OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), - OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), - OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), - OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), - OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), - OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), - OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), - OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), - OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), - OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), - OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), - OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), - OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), - OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), - OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), - OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), - OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), - OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), - OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), - OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), - OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), - OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), - OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), - OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), - OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), - OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), - OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), - OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), - OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), - OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), - OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), - OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), - OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), - OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), - OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), - OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), - OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7"), + OCELOT_COMMON_STATS, }; static const struct vcap_field vsc9953_vcap_es0_keys[] = { -- cgit From 2c119d9982b1aba54a2eca59c2455cd09f3bc749 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Wed, 7 Sep 2022 12:50:39 +0530 Subject: net: dsa: microchip: add the support for set_ageing_time KSZ9477 has the 11 bit ageing count value which is split across the two registers. And LAN937x has the 20 bit ageing count which is also split into two registers. Each count in the registers represents 1 second. This patch add the support for ageing time for KSZ9477 and LAN937x series of switch. Signed-off-by: Arun Ramadoss Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477.c | 25 +++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz9477.h | 1 + drivers/net/dsa/microchip/ksz9477_reg.h | 4 +++- drivers/net/dsa/microchip/ksz_common.c | 13 +++++++++++++ drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/dsa/microchip/lan937x.h | 1 + drivers/net/dsa/microchip/lan937x_main.c | 17 +++++++++++++++++ drivers/net/dsa/microchip/lan937x_reg.h | 6 ++++++ 8 files changed, 67 insertions(+), 1 deletion(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 42d7e4c12459..a6a0321a8931 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -963,6 +963,31 @@ void ksz9477_get_caps(struct ksz_device *dev, int port, config->mac_capabilities |= MAC_1000FD; } +int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs) +{ + u32 secs = msecs / 1000; + u8 value; + u8 data; + int ret; + + value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs); + + ret = ksz_write8(dev, REG_SW_LUE_CTRL_3, value); + if (ret < 0) + return ret; + + data = FIELD_GET(SW_AGE_PERIOD_10_8_M, secs); + + ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value); + if (ret < 0) + return ret; + + value &= ~SW_AGE_CNT_M; + value |= FIELD_PREP(SW_AGE_CNT_M, data); + + return ksz_write8(dev, REG_SW_LUE_CTRL_0, value); +} + void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) { struct dsa_switch *ds = dev->ds; diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h index ce87e4e09ada..00862c4cfb7f 100644 --- a/drivers/net/dsa/microchip/ksz9477.h +++ b/drivers/net/dsa/microchip/ksz9477.h @@ -16,6 +16,7 @@ u32 ksz9477_get_port_addr(int port, int offset); void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member); void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port); void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port); +int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs); int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt); diff --git a/drivers/net/dsa/microchip/ksz9477_reg.h b/drivers/net/dsa/microchip/ksz9477_reg.h index ddf99d1e4bbd..53c68d286dd3 100644 --- a/drivers/net/dsa/microchip/ksz9477_reg.h +++ b/drivers/net/dsa/microchip/ksz9477_reg.h @@ -189,8 +189,9 @@ #define SW_VLAN_ENABLE BIT(7) #define SW_DROP_INVALID_VID BIT(6) -#define SW_AGE_CNT_M 0x7 +#define SW_AGE_CNT_M GENMASK(5, 3) #define SW_AGE_CNT_S 3 +#define SW_AGE_PERIOD_10_8_M GENMASK(10, 8) #define SW_RESV_MCAST_ENABLE BIT(2) #define SW_HASH_OPTION_M 0x03 #define SW_HASH_OPTION_CRC 1 @@ -225,6 +226,7 @@ #define SW_PRIO_LOWEST_DA_SA 3 #define REG_SW_LUE_CTRL_3 0x0313 +#define SW_AGE_PERIOD_7_0_M GENMASK(7, 0) #define REG_SW_LUE_INT_STATUS 0x0314 #define REG_SW_LUE_INT_ENABLE 0x0315 diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 3b3b2046da2e..fcaa71f66322 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -183,6 +183,7 @@ static const struct ksz_dev_ops ksz9477_dev_ops = { .cfg_port_member = ksz9477_cfg_port_member, .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, .port_setup = ksz9477_port_setup, + .set_ageing_time = ksz9477_set_ageing_time, .r_phy = ksz9477_r_phy, .w_phy = ksz9477_w_phy, .r_mib_cnt = ksz9477_r_mib_cnt, @@ -218,6 +219,7 @@ static const struct ksz_dev_ops lan937x_dev_ops = { .cfg_port_member = ksz9477_cfg_port_member, .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, .port_setup = lan937x_port_setup, + .set_ageing_time = lan937x_set_ageing_time, .r_phy = lan937x_r_phy, .w_phy = lan937x_w_phy, .r_mib_cnt = ksz9477_r_mib_cnt, @@ -1893,6 +1895,16 @@ static void ksz_port_fast_age(struct dsa_switch *ds, int port) dev->dev_ops->flush_dyn_mac_table(dev, port); } +static int ksz_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +{ + struct ksz_device *dev = ds->priv; + + if (!dev->dev_ops->set_ageing_time) + return -EOPNOTSUPP; + + return dev->dev_ops->set_ageing_time(dev, msecs); +} + static int ksz_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, struct dsa_db db) @@ -2475,6 +2487,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .phylink_mac_link_up = ksz_phylink_mac_link_up, .phylink_mac_link_down = ksz_mac_link_down, .port_enable = ksz_enable_port, + .set_ageing_time = ksz_set_ageing_time, .get_strings = ksz_get_strings, .get_ethtool_stats = ksz_get_ethtool_stats, .get_sset_count = ksz_sset_count, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 7c63f900dfce..6203dcd8c8f7 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -281,6 +281,7 @@ struct ksz_dev_ops { void (*flush_dyn_mac_table)(struct ksz_device *dev, int port); void (*port_cleanup)(struct ksz_device *dev, int port); void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); + int (*set_ageing_time)(struct ksz_device *dev, unsigned int msecs); int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h index 1b7f077946f3..8e9e66d6728d 100644 --- a/drivers/net/dsa/microchip/lan937x.h +++ b/drivers/net/dsa/microchip/lan937x.h @@ -19,4 +19,5 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu); void lan937x_phylink_get_caps(struct ksz_device *dev, int port, struct phylink_config *config); void lan937x_setup_rgmii_delay(struct ksz_device *dev, int port); +int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs); #endif diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 4867aa62dd4c..9b6760b1e572 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -367,6 +367,23 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu) return 0; } +int lan937x_set_ageing_time(struct ksz_device *dev, unsigned int msecs) +{ + u32 secs = msecs / 1000; + u32 value; + int ret; + + value = FIELD_GET(SW_AGE_PERIOD_7_0_M, secs); + + ret = ksz_write8(dev, REG_SW_AGE_PERIOD__1, value); + if (ret < 0) + return ret; + + value = FIELD_GET(SW_AGE_PERIOD_19_8_M, secs); + + return ksz_write16(dev, REG_SW_AGE_PERIOD__2, value); +} + static void lan937x_set_tune_adj(struct ksz_device *dev, int port, u16 reg, u8 val) { diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h index a3c669d86e51..5bc16a4c4441 100644 --- a/drivers/net/dsa/microchip/lan937x_reg.h +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -62,6 +62,12 @@ #define SW_FAST_AGING BIT(1) #define SW_LINK_AUTO_AGING BIT(0) +#define REG_SW_AGE_PERIOD__1 0x0313 +#define SW_AGE_PERIOD_7_0_M GENMASK(7, 0) + +#define REG_SW_AGE_PERIOD__2 0x0320 +#define SW_AGE_PERIOD_19_8_M GENMASK(19, 8) + #define REG_SW_MAC_CTRL_0 0x0330 #define SW_NEW_BACKOFF BIT(7) #define SW_PAUSE_UNH_MODE BIT(1) -- cgit From 2f8a786f472445d66348859af8795aa6ffd9ff8c Mon Sep 17 00:00:00 2001 From: Sun Ke Date: Thu, 8 Sep 2022 12:02:26 +0800 Subject: net: dsa: microchip: lan937x: fix reference count leak in lan937x_mdio_register() This node pointer is returned by of_find_compatible_node() with refcount incremented in this function. of_node_put() on it before exitting this function. Fixes: c9cd961c0d43 ("net: dsa: microchip: lan937x: add interrupt support for port phy link") Signed-off-by: Sun Ke Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20220908040226.871690-1-sunke32@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/lan937x_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 9b6760b1e572..3e83f8ca0f09 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -238,8 +238,10 @@ static int lan937x_mdio_register(struct ksz_device *dev) ds->slave_mii_bus = bus; ret = lan937x_irq_phy_setup(dev); - if (ret) + if (ret) { + of_node_put(mdio_np); return ret; + } ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); if (ret) { -- cgit From 8f6a19c0316deb48cdfdc5335de9a6d7db5b7b62 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 11 Sep 2022 04:06:58 +0300 Subject: net: dsa: introduce dsa_port_get_master() There is a desire to support for DSA masters in a LAG. That configuration is intended to work by simply enslaving the master to a bonding/team device. But the physical DSA master (the LAG slave) still has a dev->dsa_ptr, and that cpu_dp still corresponds to the physical CPU port. However, we would like to be able to retrieve the LAG that's the upper of the physical DSA master. In preparation for that, introduce a helper called dsa_port_get_master() that replaces all occurrences of the dp->cpu_dp->master pattern. The distinction between LAG and non-LAG will be made later within the helper itself. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: Paolo Abeni --- drivers/net/dsa/bcm_sf2.c | 4 ++-- drivers/net/dsa/bcm_sf2_cfp.c | 4 ++-- drivers/net/dsa/lan9303-core.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 572f7450b527..6507663f35e5 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -983,7 +983,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; + struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_wolinfo pwol = { }; @@ -1007,7 +1007,7 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; + struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; struct ethtool_wolinfo pwol = { }; diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 22bc295bebdb..c4010b7bf089 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -1102,7 +1102,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv, int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc, u32 *rule_locs) { - struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; + struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; @@ -1145,7 +1145,7 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc) { - struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; + struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index 9e04541c3144..438e46af03e9 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1092,7 +1092,7 @@ static int lan9303_port_enable(struct dsa_switch *ds, int port, if (!dsa_port_is_user(dp)) return 0; - vlan_vid_add(dp->cpu_dp->master, htons(ETH_P_8021Q), port); + vlan_vid_add(dsa_port_to_master(dp), htons(ETH_P_8021Q), port); return lan9303_enable_processing_port(chip, port); } @@ -1105,7 +1105,7 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port) if (!dsa_port_is_user(dp)) return; - vlan_vid_del(dp->cpu_dp->master, htons(ETH_P_8021Q), port); + vlan_vid_del(dsa_port_to_master(dp), htons(ETH_P_8021Q), port); lan9303_disable_processing_port(chip, port); lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN); -- cgit From 2e359b00a11715c7a89d7448e6e4cb4d84543520 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 11 Sep 2022 04:07:03 +0300 Subject: net: dsa: propagate extack to port_lag_join Drivers could refuse to offload a LAG configuration for a variety of reasons, mainly having to do with its TX type. Additionally, since DSA masters may now also be LAG interfaces, and this will translate into a call to port_lag_join on the CPU ports, there may be extra restrictions there. Propagate the netlink extack to this DSA method in order for drivers to give a meaningful error message back to the user. Signed-off-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/mv88e6xxx/chip.c | 27 +++++++++++++++++++-------- drivers/net/dsa/ocelot/felix.c | 5 +++-- drivers/net/dsa/qca/qca8k-common.c | 23 +++++++++++++++++------ drivers/net/dsa/qca/qca8k.h | 3 ++- 4 files changed, 41 insertions(+), 17 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6f4ea39ab466..5f178faa110f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -6593,14 +6593,17 @@ out: static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { struct mv88e6xxx_chip *chip = ds->priv; struct dsa_port *dp; int members = 0; - if (!mv88e6xxx_has_lag(chip)) + if (!mv88e6xxx_has_lag(chip)) { + NL_SET_ERR_MSG_MOD(extack, "Chip does not support LAG offload"); return false; + } if (!lag.id) return false; @@ -6609,14 +6612,20 @@ static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, /* Includes the port joining the LAG */ members++; - if (members > 8) + if (members > 8) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot offload more than 8 LAG ports"); return false; + } /* We could potentially relax this to include active * backup in the future. */ - if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { + NL_SET_ERR_MSG_MOD(extack, + "Can only offload LAG using hash TX type"); return false; + } /* Ideally we would also validate that the hash type matches * the hardware. Alas, this is always set to unknown on team @@ -6769,12 +6778,13 @@ static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port) static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { struct mv88e6xxx_chip *chip = ds->priv; int err, id; - if (!mv88e6xxx_lag_can_offload(ds, lag, info)) + if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack)) return -EOPNOTSUPP; /* DSA LAG IDs are one-based */ @@ -6827,12 +6837,13 @@ static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index, static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { struct mv88e6xxx_chip *chip = ds->priv; int err; - if (!mv88e6xxx_lag_can_offload(ds, lag, info)) + if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack)) return -EOPNOTSUPP; mv88e6xxx_reg_lock(chip); diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index c73ef5f7aa64..82dcc21a7172 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -861,11 +861,12 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port, static int felix_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { struct ocelot *ocelot = ds->priv; - return ocelot_port_lag_join(ocelot, port, lag.dev, info); + return ocelot_port_lag_join(ocelot, port, lag.dev, info, extack); } static int felix_lag_leave(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index bba95613e218..fb45b598847b 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -1017,7 +1017,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port, static bool qca8k_lag_can_offload(struct dsa_switch *ds, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { struct dsa_port *dp; int members = 0; @@ -1029,15 +1030,24 @@ static bool qca8k_lag_can_offload(struct dsa_switch *ds, /* Includes the port joining the LAG */ members++; - if (members > QCA8K_NUM_PORTS_FOR_LAG) + if (members > QCA8K_NUM_PORTS_FOR_LAG) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot offload more than 4 LAG ports"); return false; + } - if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { + NL_SET_ERR_MSG_MOD(extack, + "Can only offload LAG using hash TX type"); return false; + } if (info->hash_type != NETDEV_LAG_HASH_L2 && - info->hash_type != NETDEV_LAG_HASH_L23) + info->hash_type != NETDEV_LAG_HASH_L23) { + NL_SET_ERR_MSG_MOD(extack, + "Can only offload L2 or L2+L3 TX hash"); return false; + } return true; } @@ -1160,11 +1170,12 @@ static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, } int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info) + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) { int ret; - if (!qca8k_lag_can_offload(ds, lag, info)) + if (!qca8k_lag_can_offload(ds, lag, info, extack)) return -EOPNOTSUPP; ret = qca8k_lag_setup_hash(ds, lag, info); diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index e36ecc9777f4..0b7a5cb12321 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -512,7 +512,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port, /* Common port LAG function */ int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, - struct netdev_lag_upper_info *info); + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack); int qca8k_port_lag_leave(struct dsa_switch *ds, int port, struct dsa_lag lag); -- cgit From eca70102cfb19d783d30d3e9b13713d58581eb67 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 11 Sep 2022 04:07:06 +0300 Subject: net: dsa: felix: add support for changing DSA master Changing the DSA master means different things depending on the tagging protocol in use. For NPI mode ("ocelot" and "seville"), there is a single port which can be configured as NPI, but DSA only permits changing the CPU port affinity of user ports one by one. So changing a user port to a different NPI port globally changes what the NPI port is, and breaks the user ports still using the old one. To address this while still permitting the change of the NPI port, require that the user ports which are still affine to the old NPI port are down, and cannot be brought up until they are all affine to the same NPI port. The tag_8021q mode ("ocelot-8021q") is more flexible, in that each user port can be freely assigned to one CPU port or to the other. This works by filtering host addresses towards both tag_8021q CPU ports, and then restricting the forwarding from a certain user port only to one of the two tag_8021q CPU ports. Additionally, the 2 tag_8021q CPU ports can be placed in a LAG. This works by enabling forwarding via PGID_SRC from a certain user port towards the logical port ID containing both tag_8021q CPU ports, but then restricting forwarding per packet, via the LAG hash codes in PGID_AGGR, to either one or the other. When we change the DSA master to a LAG device, DSA guarantees us that the LAG has at least one lower interface as a physical DSA master. But DSA masters can come and go as lowers of that LAG, and ds->ops->port_change_master() will not get called, because the DSA master is still the same (the LAG). So we need to hook into the ds->ops->port_lag_{join,leave} calls on the CPU ports and update the logical port ID of the LAG that user ports are assigned to. Signed-off-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/ocelot/felix.c | 118 ++++++++++++++++++++++++++++++++++++++++- drivers/net/dsa/ocelot/felix.h | 3 ++ 2 files changed, 119 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 82dcc21a7172..d2a9d292160c 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -42,6 +42,25 @@ static struct net_device *felix_classify_db(struct dsa_db db) } } +static int felix_cpu_port_for_master(struct dsa_switch *ds, + struct net_device *master) +{ + struct ocelot *ocelot = ds->priv; + struct dsa_port *cpu_dp; + int lag; + + if (netif_is_lag_master(master)) { + mutex_lock(&ocelot->fwd_domain_lock); + lag = ocelot_bond_get_id(ocelot, master); + mutex_unlock(&ocelot->fwd_domain_lock); + + return lag; + } + + cpu_dp = master->dsa_ptr; + return cpu_dp->index; +} + /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that * the tagger can perform RX source port identification. */ @@ -422,6 +441,40 @@ static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds) return BIT(ocelot->num_phys_ports); } +static int felix_tag_npi_change_master(struct dsa_switch *ds, int port, + struct net_device *master, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; + struct ocelot *ocelot = ds->priv; + + if (netif_is_lag_master(master)) { + NL_SET_ERR_MSG_MOD(extack, + "LAG DSA master only supported using ocelot-8021q"); + return -EOPNOTSUPP; + } + + /* Changing the NPI port breaks user ports still assigned to the old + * one, so only allow it while they're down, and don't allow them to + * come back up until they're all changed to the new one. + */ + dsa_switch_for_each_user_port(other_dp, ds) { + struct net_device *slave = other_dp->slave; + + if (other_dp != dp && (slave->flags & IFF_UP) && + dsa_port_to_master(other_dp) != master) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot change while old master still has users"); + return -EOPNOTSUPP; + } + } + + felix_npi_port_deinit(ocelot, ocelot->npi); + felix_npi_port_init(ocelot, felix_cpu_port_for_master(ds, master)); + + return 0; +} + /* Alternatively to using the NPI functionality, that same hardware MAC * connected internally to the enetc or fman DSA master can be configured to * use the software-defined tag_8021q frame format. As far as the hardware is @@ -433,6 +486,7 @@ static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = { .setup = felix_tag_npi_setup, .teardown = felix_tag_npi_teardown, .get_host_fwd_mask = felix_tag_npi_get_host_fwd_mask, + .change_master = felix_tag_npi_change_master, }; static int felix_tag_8021q_setup(struct dsa_switch *ds) @@ -507,10 +561,24 @@ static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds) return dsa_cpu_ports(ds); } +static int felix_tag_8021q_change_master(struct dsa_switch *ds, int port, + struct net_device *master, + struct netlink_ext_ack *extack) +{ + int cpu = felix_cpu_port_for_master(ds, master); + struct ocelot *ocelot = ds->priv; + + ocelot_port_unassign_dsa_8021q_cpu(ocelot, port); + ocelot_port_assign_dsa_8021q_cpu(ocelot, port, cpu); + + return felix_update_trapping_destinations(ds, true); +} + static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = { .setup = felix_tag_8021q_setup, .teardown = felix_tag_8021q_teardown, .get_host_fwd_mask = felix_tag_8021q_get_host_fwd_mask, + .change_master = felix_tag_8021q_change_master, }; static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask, @@ -673,6 +741,16 @@ static void felix_port_set_host_flood(struct dsa_switch *ds, int port, !!felix->host_flood_mc_mask, true); } +static int felix_port_change_master(struct dsa_switch *ds, int port, + struct net_device *master, + struct netlink_ext_ack *extack) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + return felix->tag_proto_ops->change_master(ds, port, master, extack); +} + static int felix_set_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) { @@ -865,8 +943,17 @@ static int felix_lag_join(struct dsa_switch *ds, int port, struct netlink_ext_ack *extack) { struct ocelot *ocelot = ds->priv; + int err; - return ocelot_port_lag_join(ocelot, port, lag.dev, info, extack); + err = ocelot_port_lag_join(ocelot, port, lag.dev, info, extack); + if (err) + return err; + + /* Update the logical LAG port that serves as tag_8021q CPU port */ + if (!dsa_is_cpu_port(ds, port)) + return 0; + + return felix_port_change_master(ds, port, lag.dev, extack); } static int felix_lag_leave(struct dsa_switch *ds, int port, @@ -876,7 +963,11 @@ static int felix_lag_leave(struct dsa_switch *ds, int port, ocelot_port_lag_leave(ocelot, port, lag.dev); - return 0; + /* Update the logical LAG port that serves as tag_8021q CPU port */ + if (!dsa_is_cpu_port(ds, port)) + return 0; + + return felix_port_change_master(ds, port, lag.dev, NULL); } static int felix_lag_change(struct dsa_switch *ds, int port) @@ -1014,6 +1105,27 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, felix->info->port_sched_speed_set(ocelot, port, speed); } +static int felix_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct dsa_port *dp = dsa_to_port(ds, port); + struct ocelot *ocelot = ds->priv; + + if (!dsa_port_is_user(dp)) + return 0; + + if (ocelot->npi >= 0) { + struct net_device *master = dsa_port_to_master(dp); + + if (felix_cpu_port_for_master(ds, master) != ocelot->npi) { + dev_err(ds->dev, "Multiple masters are not allowed\n"); + return -EINVAL; + } + } + + return 0; +} + static void felix_port_qos_map_init(struct ocelot *ocelot, int port) { int i; @@ -1913,6 +2025,7 @@ const struct dsa_switch_ops felix_switch_ops = { .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, .phylink_mac_link_down = felix_phylink_mac_link_down, .phylink_mac_link_up = felix_phylink_mac_link_up, + .port_enable = felix_port_enable, .port_fast_age = felix_port_fast_age, .port_fdb_dump = felix_fdb_dump, .port_fdb_add = felix_fdb_add, @@ -1968,6 +2081,7 @@ const struct dsa_switch_ops felix_switch_ops = { .port_add_dscp_prio = felix_port_add_dscp_prio, .port_del_dscp_prio = felix_port_del_dscp_prio, .port_set_host_flood = felix_port_set_host_flood, + .port_change_master = felix_port_change_master, }; struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index deb8dde1fc19..e4fd5eef57a0 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -71,6 +71,9 @@ struct felix_tag_proto_ops { int (*setup)(struct dsa_switch *ds); void (*teardown)(struct dsa_switch *ds); unsigned long (*get_host_fwd_mask)(struct dsa_switch *ds); + int (*change_master)(struct dsa_switch *ds, int port, + struct net_device *master, + struct netlink_ext_ack *extack); }; extern const struct dsa_switch_ops felix_switch_ops; -- cgit From d02bb8bef4576d4511425270e61617b13ec4c387 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 15 Sep 2022 19:42:11 +0800 Subject: net: dsa: lantiq: Switch to use dev_err_probe() helper dev_err() can be replace with dev_err_probe() which will check if error code is -EPROBE_DEFER. Signed-off-by: Yang Yingliang Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/lantiq_gswip.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index e531b93f3cb2..88f95d6e41c9 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1989,11 +1989,9 @@ static int gswip_gphy_fw_probe(struct gswip_priv *priv, } gphy_fw->reset = of_reset_control_array_get_exclusive(gphy_fw_np); - if (IS_ERR(gphy_fw->reset)) { - if (PTR_ERR(gphy_fw->reset) != -EPROBE_DEFER) - dev_err(dev, "Failed to lookup gphy reset\n"); - return PTR_ERR(gphy_fw->reset); - } + if (IS_ERR(gphy_fw->reset)) + return dev_err_probe(dev, PTR_ERR(gphy_fw->reset), + "Failed to lookup gphy reset\n"); return gswip_gphy_fw_load(priv, gphy_fw); } -- cgit From 764a73b43c360d1c2925baa6bd76160599c76991 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:07 +0800 Subject: net: dsa: b53: remove unnecessary set_drvdata() Remove unnecessary set_drvdata(NULL) function in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_mdio.c | 2 -- drivers/net/dsa/b53/b53_mmap.c | 2 -- drivers/net/dsa/b53/b53_srab.c | 2 -- 3 files changed, 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index a7aeb3c132c9..6ddc03b58b28 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -356,8 +356,6 @@ static void b53_mdio_remove(struct mdio_device *mdiodev) return; b53_switch_remove(dev); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void b53_mdio_shutdown(struct mdio_device *mdiodev) diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index ae4c79d39bc0..e968322dfbf0 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -316,8 +316,6 @@ static int b53_mmap_remove(struct platform_device *pdev) if (dev) b53_switch_remove(dev); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index da0b889880f6..bcb44034404d 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -667,8 +667,6 @@ static int b53_srab_remove(struct platform_device *pdev) b53_srab_intr_set(dev->priv, false); b53_switch_remove(dev); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From 47f6aa145036b57186f1eae35d0eebb2bf3fd6b7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:08 +0800 Subject: net: dsa: bcm_sf2: remove unnecessary platform_set_drvdata() Remove unnecessary platform_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/bcm_sf2.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 6507663f35e5..cde253d27bd0 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -1551,8 +1551,6 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev) if (priv->type == BCM7278_DEVICE_ID) reset_control_assert(priv->rcdev); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From c1816b20141597071c67a69e8fb8d31f1b9adfad Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:09 +0800 Subject: net: dsa: loop: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Acked-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/dsa_loop.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 263e41191c29..b9107fe40023 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -351,8 +351,6 @@ static void dsa_loop_drv_remove(struct mdio_device *mdiodev) dsa_unregister_switch(ds); dev_put(ps->netdev); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev) -- cgit From 8668cfc6db48aafed0cc9cd2f770dea246e02f52 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:10 +0800 Subject: net: dsa: hellcreek: remove unnecessary platform_set_drvdata() Remove unnecessary platform_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Acked-by: Kurt Kanzenbach Signed-off-by: Jakub Kicinski --- drivers/net/dsa/hirschmann/hellcreek.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index ea8bbfce0f1f..eac6ace7c5f9 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -1996,7 +1996,6 @@ static int hellcreek_remove(struct platform_device *pdev) hellcreek_hwtstamp_free(hellcreek); hellcreek_ptp_free(hellcreek); dsa_unregister_switch(hellcreek->ds); - platform_set_drvdata(pdev, NULL); return 0; } -- cgit From 2697085007f0dd2a1c0e31375934d302ff68bca2 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:11 +0800 Subject: net: dsa: lan9303: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/lan9303_mdio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/lan9303_mdio.c b/drivers/net/dsa/lan9303_mdio.c index d12c55fdc811..4f33369a2de5 100644 --- a/drivers/net/dsa/lan9303_mdio.c +++ b/drivers/net/dsa/lan9303_mdio.c @@ -138,8 +138,6 @@ static void lan9303_mdio_remove(struct mdio_device *mdiodev) return; lan9303_remove(&sw_dev->chip); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void lan9303_mdio_shutdown(struct mdio_device *mdiodev) -- cgit From f6ddabca45f684357cfdea7a61b94ddfb22cd583 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:12 +0800 Subject: net: dsa: lantiq_gswip: remove unnecessary platform_set_drvdata() Remove unnecessary platform_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/lantiq_gswip.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 88f95d6e41c9..05ecaa007ab1 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -2229,8 +2229,6 @@ static int gswip_remove(struct platform_device *pdev) for (i = 0; i < priv->num_gphy_fw; i++) gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From 3525ecc127d893f99671df041764aa4185c79e0b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:13 +0800 Subject: net: dsa: microchip: remove unnecessary set_drvdata() Remove unnecessary set_drvdata(NULL) function in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz8863_smi.c | 2 -- drivers/net/dsa/microchip/ksz_spi.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index 5247fdfb964d..ddb40838181e 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -180,8 +180,6 @@ static void ksz8863_smi_remove(struct mdio_device *mdiodev) if (dev) ksz_switch_remove(dev); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void ksz8863_smi_shutdown(struct mdio_device *mdiodev) diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 82e2352f55fa..1b6ab891b986 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -107,8 +107,6 @@ static void ksz_spi_remove(struct spi_device *spi) if (dev) ksz_switch_remove(dev); - - spi_set_drvdata(spi, NULL); } static void ksz_spi_shutdown(struct spi_device *spi) -- cgit From ebe48922c0c45bcedd407d0fe546464694061af7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:14 +0800 Subject: net: dsa: mt7530: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 835807911be0..a6cb5b0406fe 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -3300,8 +3300,6 @@ mt7530_remove(struct mdio_device *mdiodev) dsa_unregister_switch(priv->ds); mutex_destroy(&priv->reg_mutex); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void mt7530_shutdown(struct mdio_device *mdiodev) -- cgit From 92f529b7a3b7ec71960328a58f1a06aad75205e3 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:15 +0800 Subject: net: dsa: mv88e6060: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6060.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 83dca9179aa0..fdda62d6eb16 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -297,8 +297,6 @@ static void mv88e6060_remove(struct mdio_device *mdiodev) return; dsa_unregister_switch(ds); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void mv88e6060_shutdown(struct mdio_device *mdiodev) -- cgit From b25a575c9cd08a08fbe8a9569abd81d362cbfb85 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:16 +0800 Subject: net: dsa: mv88e6xxx: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5f178faa110f..2479be3a1e35 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -7185,8 +7185,6 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev) mv88e6xxx_g1_irq_free(chip); else mv88e6xxx_irq_poll_free(chip); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void mv88e6xxx_shutdown(struct mdio_device *mdiodev) -- cgit From f66d1ecc1ad4f75cce3aa9286d4c7f9a980f5a39 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:17 +0800 Subject: net: dsa: ocelot: remove unnecessary set_drvdata() Remove unnecessary set_drvdata(NULL) function in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix_vsc9959.c | 2 -- drivers/net/dsa/ocelot/seville_vsc9953.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 459288d6222c..2ec49e42b3f4 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2727,8 +2727,6 @@ static void felix_pci_remove(struct pci_dev *pdev) kfree(felix); pci_disable_device(pdev); - - pci_set_drvdata(pdev, NULL); } static void felix_pci_shutdown(struct pci_dev *pdev) diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 3ce1cd1a8d4a..5b29fa930627 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -1153,8 +1153,6 @@ static int seville_remove(struct platform_device *pdev) kfree(felix->ds); kfree(felix); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From 14b29ece30e53f9b380f146d5f4f9062131b0d65 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:18 +0800 Subject: net: dsa: ar9331: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/qca/ar9331.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/qca/ar9331.c b/drivers/net/dsa/qca/ar9331.c index 0796b7cf8cae..e7b98b864fa1 100644 --- a/drivers/net/dsa/qca/ar9331.c +++ b/drivers/net/dsa/qca/ar9331.c @@ -1099,8 +1099,6 @@ static void ar9331_sw_remove(struct mdio_device *mdiodev) dsa_unregister_switch(&priv->ds); reset_control_assert(priv->sw_reset); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void ar9331_sw_shutdown(struct mdio_device *mdiodev) -- cgit From 68c4e297e09c3b3e2012ea54e5329d03d653c977 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:19 +0800 Subject: net: dsa: qca8k: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/qca/qca8k-8xxx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index c181346388a4..5669c92c93f7 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1957,8 +1957,6 @@ qca8k_sw_remove(struct mdio_device *mdiodev) qca8k_port_set_status(priv, i, 0); dsa_unregister_switch(priv->ds); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void qca8k_sw_shutdown(struct mdio_device *mdiodev) -- cgit From 24d64ced1bf8d333dc4697d1cc6d2b4f64cc145d Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:20 +0800 Subject: net: dsa: realtek: remove unnecessary set_drvdata() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary set_drvdata(NULL) function in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Acked-by: Alvin Å ipraga Acked-by: Linus Walleij Signed-off-by: Jakub Kicinski --- drivers/net/dsa/realtek/realtek-mdio.c | 2 -- drivers/net/dsa/realtek/realtek-smi.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index c58f49d558d2..3e54fac5f902 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -245,8 +245,6 @@ static void realtek_mdio_remove(struct mdio_device *mdiodev) /* leave the device reset asserted */ if (priv->reset) gpiod_set_value(priv->reset, 1); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void realtek_mdio_shutdown(struct mdio_device *mdiodev) diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 45992f79ec8d..1b447d96b9c4 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -522,8 +522,6 @@ static int realtek_smi_remove(struct platform_device *pdev) if (priv->reset) gpiod_set_value(priv->reset, 1); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From 4f6ee77aebf19908db8e88491f51dab2ffbe4524 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:21 +0800 Subject: net: dsa: rzn1-a5psw: remove unnecessary platform_set_drvdata() Remove unnecessary platform_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/rzn1_a5psw.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c index 0744e8162e1d..ed413d555bec 100644 --- a/drivers/net/dsa/rzn1_a5psw.c +++ b/drivers/net/dsa/rzn1_a5psw.c @@ -1025,8 +1025,6 @@ static int a5psw_remove(struct platform_device *pdev) clk_disable_unprepare(a5psw->hclk); clk_disable_unprepare(a5psw->clk); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit From ee08bf0d0a3aa8c4f00ae006b8068e8ea16d1cf9 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:22 +0800 Subject: net: dsa: sja1105: remove unnecessary spi_set_drvdata() Remove unnecessary spi_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/sja1105/sja1105_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index b03d0d0c3dbf..412666111b0c 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -3351,8 +3351,6 @@ static void sja1105_remove(struct spi_device *spi) return; dsa_unregister_switch(priv->ds); - - spi_set_drvdata(spi, NULL); } static void sja1105_shutdown(struct spi_device *spi) -- cgit From 774b060debb189cb778fc195395dd24ea67bef5b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:23 +0800 Subject: net: dsa: vitesse-vsc73xx: remove unnecessary set_drvdata() Remove unnecessary set_drvdata(NULL) function in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Acked-by: Linus Walleij Signed-off-by: Jakub Kicinski --- drivers/net/dsa/vitesse-vsc73xx-platform.c | 2 -- drivers/net/dsa/vitesse-vsc73xx-spi.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/vitesse-vsc73xx-platform.c b/drivers/net/dsa/vitesse-vsc73xx-platform.c index fe4b154a0a57..bd4206e8f9af 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-platform.c +++ b/drivers/net/dsa/vitesse-vsc73xx-platform.c @@ -121,8 +121,6 @@ static int vsc73xx_platform_remove(struct platform_device *pdev) vsc73xx_remove(&vsc_platform->vsc); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/net/dsa/vitesse-vsc73xx-spi.c b/drivers/net/dsa/vitesse-vsc73xx-spi.c index 97a92e6da60d..85b9a0f51dd8 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-spi.c +++ b/drivers/net/dsa/vitesse-vsc73xx-spi.c @@ -167,8 +167,6 @@ static void vsc73xx_spi_remove(struct spi_device *spi) return; vsc73xx_remove(&vsc_spi->vsc); - - spi_set_drvdata(spi, NULL); } static void vsc73xx_spi_shutdown(struct spi_device *spi) -- cgit From 24aeeb107f0724fa15e16d5f28b39f3c3ecfc746 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 21 Sep 2022 22:05:24 +0800 Subject: net: dsa: xrs700x: remove unnecessary dev_set_drvdata() Remove unnecessary dev_set_drvdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/xrs700x/xrs700x_mdio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/xrs700x/xrs700x_mdio.c b/drivers/net/dsa/xrs700x/xrs700x_mdio.c index 127a677d1f39..5f7d344b5d73 100644 --- a/drivers/net/dsa/xrs700x/xrs700x_mdio.c +++ b/drivers/net/dsa/xrs700x/xrs700x_mdio.c @@ -140,8 +140,6 @@ static void xrs700x_mdio_remove(struct mdio_device *mdiodev) return; xrs700x_switch_remove(priv); - - dev_set_drvdata(&mdiodev->dev, NULL); } static void xrs700x_mdio_shutdown(struct mdio_device *mdiodev) -- cgit From e19de30d20809af3221ef8a2648b8a8a52e02d90 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 21 Sep 2022 01:23:14 +0100 Subject: net: dsa: mt7530: add support for in-band link status Read link status from SGMII PCS for in-band managed 2500Base-X and 1000Base-X connection on a MAC port of the MT7531. This is needed to get the SFP cage working which is connected to SGMII interface of port 5 of the MT7531 switch IC on the Bananapi BPi-R3 board. While at it also handle an_complete for both the autoneg and the non-autoneg codepath. Signed-off-by: Daniel Golle Signed-off-by: David S. Miller --- drivers/net/dsa/mt7530.c | 50 +++++++++++++++++++++++++++++++++++------------- drivers/net/dsa/mt7530.h | 1 + 2 files changed, 38 insertions(+), 13 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index a6cb5b0406fe..e87f16a5756b 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2699,9 +2699,6 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: - if (phylink_autoneg_inband(mode)) - return -EINVAL; - return mt7531_sgmii_setup_mode_force(priv, port, interface); default: return -EINVAL; @@ -2777,13 +2774,6 @@ unsupported: return; } - if (phylink_autoneg_inband(mode) && - state->interface != PHY_INTERFACE_MODE_SGMII) { - dev_err(ds->dev, "%s: in-band negotiation unsupported\n", - __func__); - return; - } - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; mcr_new &= ~PMCR_LINK_SETTINGS_MASK; @@ -2922,6 +2912,9 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port)) + config->mac_capabilities |= MAC_2500FD; + /* This driver does not make use of the speed, duplex, pause or the * advertisement in its mac_config, so it is safe to mark this driver * as non-legacy. @@ -2987,6 +2980,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); state->link = !!(status & MT7531_SGMII_LINK_STATUS); + state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); if (state->interface == PHY_INTERFACE_MODE_SGMII && (status & MT7531_SGMII_AN_ENABLE)) { val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); @@ -3017,16 +3011,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, return 0; } +static void +mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, + struct phylink_link_state *state) +{ + unsigned int val; + + val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); + state->link = !!(val & MT7531_SGMII_LINK_STATUS); + if (!state->link) + return; + + state->an_complete = state->link; + + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + state->speed = SPEED_2500; + else + state->speed = SPEED_1000; + + state->duplex = DUPLEX_FULL; + state->pause = MLO_PAUSE_NONE; +} + static void mt7531_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; int port = pcs_to_mt753x_pcs(pcs)->port; - if (state->interface == PHY_INTERFACE_MODE_SGMII) + if (state->interface == PHY_INTERFACE_MODE_SGMII) { mt7531_sgmii_pcs_get_state_an(priv, port, state); - else - state->link = false; + return; + } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || + (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { + mt7531_sgmii_pcs_get_state_inband(priv, port, state); + return; + } + + state->link = false; } static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, @@ -3067,6 +3089,8 @@ mt753x_setup(struct dsa_switch *ds) priv->pcs[i].pcs.ops = priv->info->pcs_ops; priv->pcs[i].priv = priv; priv->pcs[i].port = i; + if (mt753x_is_mac_port(i)) + priv->pcs[i].pcs.poll = 1; } ret = priv->info->sw_setup(ds); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index e509af95c354..e8d966435350 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -373,6 +373,7 @@ enum mt7530_vlan_port_acc_frm { #define MT7531_SGMII_LINK_STATUS BIT(18) #define MT7531_SGMII_AN_ENABLE BIT(12) #define MT7531_SGMII_AN_RESTART BIT(9) +#define MT7531_SGMII_AN_COMPLETE BIT(21) /* Register for SGMII PCS_SPPED_ABILITY */ #define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) -- cgit From 978f1f72460cb2dc742a35bae4de50b6b9ac653f Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Thu, 22 Sep 2022 12:40:23 +0530 Subject: net: dsa: microchip: determine number of port irq based on switch type Currently the number of port irqs is hard coded for the lan937x switch as 6. In order to make the generic interrupt handler for ksz switches, number of port irq supported by the switch is added to the ksz_chip_data. It is 4 for ksz9477, 2 for ksz9897 and 3 for ksz9567. Signed-off-by: Arun Ramadoss Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 10 ++++++++++ drivers/net/dsa/microchip/ksz_common.h | 1 + drivers/net/dsa/microchip/lan937x_main.c | 4 +--- 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index fcaa71f66322..07283279c578 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1168,6 +1168,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 16, .cpu_ports = 0x7F, /* can be configured as cpu port */ .port_cnt = 7, /* total physical port count */ + .port_nirqs = 4, .ops = &ksz9477_dev_ops, .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, @@ -1199,6 +1200,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 16, .cpu_ports = 0x3F, /* can be configured as cpu port */ .port_cnt = 6, /* total physical port count */ + .port_nirqs = 2, .ops = &ksz9477_dev_ops, .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, @@ -1230,6 +1232,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 16, .cpu_ports = 0x7F, /* can be configured as cpu port */ .port_cnt = 7, /* total physical port count */ + .port_nirqs = 2, .ops = &ksz9477_dev_ops, .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, @@ -1259,6 +1262,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 16, .cpu_ports = 0x07, /* can be configured as cpu port */ .port_cnt = 3, /* total port count */ + .port_nirqs = 2, .ops = &ksz9477_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1283,6 +1287,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 16, .cpu_ports = 0x7F, /* can be configured as cpu port */ .port_cnt = 7, /* total physical port count */ + .port_nirqs = 3, .ops = &ksz9477_dev_ops, .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, @@ -1312,6 +1317,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 256, .cpu_ports = 0x10, /* can be configured as cpu port */ .port_cnt = 5, /* total physical port count */ + .port_nirqs = 6, .ops = &lan937x_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1335,6 +1341,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 256, .cpu_ports = 0x30, /* can be configured as cpu port */ .port_cnt = 6, /* total physical port count */ + .port_nirqs = 6, .ops = &lan937x_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1358,6 +1365,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 256, .cpu_ports = 0x30, /* can be configured as cpu port */ .port_cnt = 8, /* total physical port count */ + .port_nirqs = 6, .ops = &lan937x_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1385,6 +1393,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 256, .cpu_ports = 0x38, /* can be configured as cpu port */ .port_cnt = 5, /* total physical port count */ + .port_nirqs = 6, .ops = &lan937x_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), @@ -1412,6 +1421,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_statics = 256, .cpu_ports = 0x30, /* can be configured as cpu port */ .port_cnt = 8, /* total physical port count */ + .port_nirqs = 6, .ops = &lan937x_dev_ops, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 6203dcd8c8f7..baa1e1bc1b7c 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -45,6 +45,7 @@ struct ksz_chip_data { int num_statics; int cpu_ports; int port_cnt; + u8 port_nirqs; const struct ksz_dev_ops *ops; bool phy_errata_9477; bool ksz87xx_eee_link_erratum; diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index cefe8517629a..fd5114a09463 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -20,8 +20,6 @@ #include "ksz_common.h" #include "lan937x.h" -#define LAN937x_PNIRQS 6 - static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); @@ -695,7 +693,7 @@ static int lan937x_pirq_setup(struct ksz_device *dev, u8 p) int ret, irq; int irq_num; - port->pirq.nirqs = LAN937x_PNIRQS; + port->pirq.nirqs = dev->info->port_nirqs; port->pirq.domain = irq_domain_add_simple(dev->dev->of_node, port->pirq.nirqs, 0, &lan937x_pirq_domain_ops, -- cgit From abc1cb8cbd7376a2f856e64986ee5ce0849d974b Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Thu, 22 Sep 2022 12:40:24 +0530 Subject: net: dsa: microchip: enable phy interrupts only if interrupt enabled in dts In the lan937x_mdio_register function, phy interrupts are enabled irrespective of irq is enabled in the switch. Now, the check is added to enable the phy interrupt only if the irq is enabled in the switch. Signed-off-by: Arun Ramadoss Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/lan937x_main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index fd5114a09463..c25ac439a927 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -235,17 +235,20 @@ static int lan937x_mdio_register(struct ksz_device *dev) ds->slave_mii_bus = bus; - ret = lan937x_irq_phy_setup(dev); - if (ret) { - of_node_put(mdio_np); - return ret; + if (dev->irq > 0) { + ret = lan937x_irq_phy_setup(dev); + if (ret) { + of_node_put(mdio_np); + return ret; + } } ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); if (ret) { dev_err(ds->dev, "unable to register MDIO bus %s\n", bus->id); - lan937x_irq_phy_free(dev); + if (dev->irq > 0) + lan937x_irq_phy_free(dev); } of_node_put(mdio_np); -- cgit From 68ccceaef0b46935e805f4c1cfd20b6af0e6fc77 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Thu, 22 Sep 2022 12:40:25 +0530 Subject: net: dsa: microchip: lan937x: return zero if mdio node not present Currently, if the mdio node is not present in the dts file then lan937x_mdio_register return -ENODEV and entire probing process fails. To make the mdio_register generic for all ksz series switches and to maintain back-compatibility with existing dts file, return -ENODEV is replaced with return 0. Signed-off-by: Arun Ramadoss Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/lan937x_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index c25ac439a927..06964c8a14a4 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -214,10 +214,8 @@ static int lan937x_mdio_register(struct ksz_device *dev) int ret; mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); - if (!mdio_np) { - dev_err(ds->dev, "no MDIO bus node\n"); - return -ENODEV; - } + if (!mdio_np) + return 0; bus = devm_mdiobus_alloc(ds->dev); if (!bus) { -- cgit From ff319a644829427ebe599185d05db308389f7d72 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Thu, 22 Sep 2022 12:40:26 +0530 Subject: net: dsa: microchip: move interrupt handling logic from lan937x to ksz_common To support the phy link detection through interrupt method for ksz9477 based switch, the interrupt handling routines are moved from lan937x_main.c to ksz_common.c. The only changes made are functions names are prefixed with ksz_ instead of lan937x_. Signed-off-by: Arun Ramadoss Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 424 ++++++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_common.h | 9 + drivers/net/dsa/microchip/lan937x_main.c | 426 ------------------------------- 3 files changed, 433 insertions(+), 426 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 07283279c578..605ce3ffbeff 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -1653,9 +1656,394 @@ static void ksz_update_port_member(struct ksz_device *dev, int port) dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); } +static int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct ksz_device *dev = bus->priv; + u16 val; + int ret; + + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + + ret = dev->dev_ops->r_phy(dev, addr, regnum, &val); + if (ret < 0) + return ret; + + return val; +} + +static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct ksz_device *dev = bus->priv; + + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + + return dev->dev_ops->w_phy(dev, addr, regnum, val); +} + +static int ksz_irq_phy_setup(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + int phy; + int irq; + int ret; + + for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) { + if (BIT(phy) & ds->phys_mii_mask) { + irq = irq_find_mapping(dev->ports[phy].pirq.domain, + PORT_SRC_PHY_INT); + if (irq < 0) { + ret = irq; + goto out; + } + ds->slave_mii_bus->irq[phy] = irq; + } + } + return 0; +out: + while (phy--) + if (BIT(phy) & ds->phys_mii_mask) + irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); + + return ret; +} + +static void ksz_irq_phy_free(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + int phy; + + for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) + if (BIT(phy) & ds->phys_mii_mask) + irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); +} + +static int ksz_mdio_register(struct ksz_device *dev) +{ + struct dsa_switch *ds = dev->ds; + struct device_node *mdio_np; + struct mii_bus *bus; + int ret; + + mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); + if (!mdio_np) + return 0; + + bus = devm_mdiobus_alloc(ds->dev); + if (!bus) { + of_node_put(mdio_np); + return -ENOMEM; + } + + bus->priv = dev; + bus->read = ksz_sw_mdio_read; + bus->write = ksz_sw_mdio_write; + bus->name = "ksz slave smi"; + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + bus->parent = ds->dev; + bus->phy_mask = ~ds->phys_mii_mask; + + ds->slave_mii_bus = bus; + + if (dev->irq > 0) { + ret = ksz_irq_phy_setup(dev); + if (ret) { + of_node_put(mdio_np); + return ret; + } + } + + ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); + if (ret) { + dev_err(ds->dev, "unable to register MDIO bus %s\n", + bus->id); + if (dev->irq > 0) + ksz_irq_phy_free(dev); + } + + of_node_put(mdio_np); + + return ret; +} + +static void ksz_girq_mask(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + dev->girq.masked |= (1 << n); +} + +static void ksz_girq_unmask(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + dev->girq.masked &= ~(1 << n); +} + +static void ksz_girq_bus_lock(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + + mutex_lock(&dev->lock_irq); +} + +static void ksz_girq_bus_sync_unlock(struct irq_data *d) +{ + struct ksz_device *dev = irq_data_get_irq_chip_data(d); + int ret; + + ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, dev->girq.masked); + if (ret) + dev_err(dev->dev, "failed to change IRQ mask\n"); + + mutex_unlock(&dev->lock_irq); +} + +static const struct irq_chip ksz_girq_chip = { + .name = "ksz-global", + .irq_mask = ksz_girq_mask, + .irq_unmask = ksz_girq_unmask, + .irq_bus_lock = ksz_girq_bus_lock, + .irq_bus_sync_unlock = ksz_girq_bus_sync_unlock, +}; + +static int ksz_girq_domain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct ksz_device *dev = d->host_data; + + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &dev->girq.chip, handle_level_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops ksz_girq_domain_ops = { + .map = ksz_girq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void ksz_girq_free(struct ksz_device *dev) +{ + int irq, virq; + + free_irq(dev->irq, dev); + + for (irq = 0; irq < dev->girq.nirqs; irq++) { + virq = irq_find_mapping(dev->girq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(dev->girq.domain); +} + +static irqreturn_t ksz_girq_thread_fn(int irq, void *dev_id) +{ + struct ksz_device *dev = dev_id; + unsigned int nhandled = 0; + unsigned int sub_irq; + unsigned int n; + u32 data; + int ret; + + /* Read global interrupt status register */ + ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data); + if (ret) + goto out; + + for (n = 0; n < dev->girq.nirqs; ++n) { + if (data & (1 << n)) { + sub_irq = irq_find_mapping(dev->girq.domain, n); + handle_nested_irq(sub_irq); + ++nhandled; + } + } +out: + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static int ksz_girq_setup(struct ksz_device *dev) +{ + int ret, irq; + + dev->girq.nirqs = dev->info->port_cnt; + dev->girq.domain = irq_domain_add_simple(NULL, dev->girq.nirqs, 0, + &ksz_girq_domain_ops, dev); + if (!dev->girq.domain) + return -ENOMEM; + + for (irq = 0; irq < dev->girq.nirqs; irq++) + irq_create_mapping(dev->girq.domain, irq); + + dev->girq.chip = ksz_girq_chip; + dev->girq.masked = ~0; + + ret = request_threaded_irq(dev->irq, NULL, ksz_girq_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + dev_name(dev->dev), dev); + if (ret) + goto out; + + return 0; + +out: + ksz_girq_free(dev); + + return ret; +} + +static void ksz_pirq_mask(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + port->pirq.masked |= (1 << n); +} + +static void ksz_pirq_unmask(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + unsigned int n = d->hwirq; + + port->pirq.masked &= ~(1 << n); +} + +static void ksz_pirq_bus_lock(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = port->ksz_dev; + + mutex_lock(&dev->lock_irq); +} + +static void ksz_pirq_bus_sync_unlock(struct irq_data *d) +{ + struct ksz_port *port = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = port->ksz_dev; + + ksz_pwrite8(dev, port->num, REG_PORT_INT_MASK, port->pirq.masked); + mutex_unlock(&dev->lock_irq); +} + +static const struct irq_chip ksz_pirq_chip = { + .name = "ksz-port", + .irq_mask = ksz_pirq_mask, + .irq_unmask = ksz_pirq_unmask, + .irq_bus_lock = ksz_pirq_bus_lock, + .irq_bus_sync_unlock = ksz_pirq_bus_sync_unlock, +}; + +static int ksz_pirq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct ksz_port *port = d->host_data; + + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &port->pirq.chip, handle_level_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops ksz_pirq_domain_ops = { + .map = ksz_pirq_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void ksz_pirq_free(struct ksz_device *dev, u8 p) +{ + struct ksz_port *port = &dev->ports[p]; + int irq, virq; + int irq_num; + + irq_num = irq_find_mapping(dev->girq.domain, p); + if (irq_num < 0) + return; + + free_irq(irq_num, port); + + for (irq = 0; irq < port->pirq.nirqs; irq++) { + virq = irq_find_mapping(port->pirq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(port->pirq.domain); +} + +static irqreturn_t ksz_pirq_thread_fn(int irq, void *dev_id) +{ + struct ksz_port *port = dev_id; + unsigned int nhandled = 0; + struct ksz_device *dev; + unsigned int sub_irq; + unsigned int n; + u8 data; + + dev = port->ksz_dev; + + /* Read port interrupt status register */ + ksz_pread8(dev, port->num, REG_PORT_INT_STATUS, &data); + + for (n = 0; n < port->pirq.nirqs; ++n) { + if (data & (1 << n)) { + sub_irq = irq_find_mapping(port->pirq.domain, n); + handle_nested_irq(sub_irq); + ++nhandled; + } + } + + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static int ksz_pirq_setup(struct ksz_device *dev, u8 p) +{ + struct ksz_port *port = &dev->ports[p]; + int ret, irq; + int irq_num; + + port->pirq.nirqs = dev->info->port_nirqs; + port->pirq.domain = irq_domain_add_simple(dev->dev->of_node, + port->pirq.nirqs, 0, + &ksz_pirq_domain_ops, + port); + if (!port->pirq.domain) + return -ENOMEM; + + for (irq = 0; irq < port->pirq.nirqs; irq++) + irq_create_mapping(port->pirq.domain, irq); + + port->pirq.chip = ksz_pirq_chip; + port->pirq.masked = ~0; + + irq_num = irq_find_mapping(dev->girq.domain, p); + if (irq_num < 0) + return irq_num; + + snprintf(port->pirq.name, sizeof(port->pirq.name), "port_irq-%d", p); + + ret = request_threaded_irq(irq_num, NULL, ksz_pirq_thread_fn, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + port->pirq.name, port); + if (ret) + goto out; + + return 0; + +out: + ksz_pirq_free(dev, p); + + return ret; +} + static int ksz_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; + struct dsa_port *dp; struct ksz_port *p; const u16 *regs; int ret; @@ -1704,16 +2092,52 @@ static int ksz_setup(struct dsa_switch *ds) p = &dev->ports[dev->cpu_port]; p->learning = true; + if (dev->irq > 0) { + ret = ksz_girq_setup(dev); + if (ret) + return ret; + + dsa_switch_for_each_user_port(dp, dev->ds) { + ret = ksz_pirq_setup(dev, dp->index); + if (ret) + goto out_girq; + } + } + + ret = ksz_mdio_register(dev); + if (ret < 0) { + dev_err(dev->dev, "failed to register the mdio"); + goto out_pirq; + } + /* start switch */ regmap_update_bits(dev->regmap[0], regs[S_START_CTRL], SW_START, SW_START); return 0; + +out_pirq: + if (dev->irq > 0) + dsa_switch_for_each_user_port(dp, dev->ds) + ksz_pirq_free(dev, dp->index); +out_girq: + if (dev->irq > 0) + ksz_girq_free(dev); + + return ret; } static void ksz_teardown(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; + struct dsa_port *dp; + + if (dev->irq > 0) { + dsa_switch_for_each_user_port(dp, dev->ds) + ksz_pirq_free(dev, dp->index); + + ksz_girq_free(dev); + } if (dev->dev_ops->teardown) dev->dev_ops->teardown(ds); diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index baa1e1bc1b7c..6edce587bfd2 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -573,6 +573,15 @@ static inline int is_lan937x(struct ksz_device *dev) #define P_MII_MAC_MODE BIT(2) #define P_MII_SEL_M 0x3 +/* Interrupt */ +#define REG_SW_PORT_INT_STATUS__4 0x0018 +#define REG_SW_PORT_INT_MASK__4 0x001C + +#define REG_PORT_INT_STATUS 0x001B +#define REG_PORT_INT_MASK 0x001F + +#define PORT_SRC_PHY_INT 1 + /* Regmap tables generation */ #define KSZ_SPI_OP_RD 3 #define KSZ_SPI_OP_WR 2 diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 06964c8a14a4..7e4f307a0387 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -7,11 +7,8 @@ #include #include #include -#include #include #include -#include -#include #include #include #include @@ -140,120 +137,6 @@ int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) return lan937x_internal_phy_write(dev, addr, reg, val); } -static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) -{ - struct ksz_device *dev = bus->priv; - u16 val; - int ret; - - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - ret = lan937x_internal_phy_read(dev, addr, regnum, &val); - if (ret < 0) - return ret; - - return val; -} - -static int lan937x_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) -{ - struct ksz_device *dev = bus->priv; - - if (regnum & MII_ADDR_C45) - return -EOPNOTSUPP; - - return lan937x_internal_phy_write(dev, addr, regnum, val); -} - -static int lan937x_irq_phy_setup(struct ksz_device *dev) -{ - struct dsa_switch *ds = dev->ds; - int phy, err_phy; - int irq; - int ret; - - for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) { - if (BIT(phy) & ds->phys_mii_mask) { - irq = irq_find_mapping(dev->ports[phy].pirq.domain, - PORT_SRC_PHY_INT); - if (irq < 0) { - ret = irq; - goto out; - } - ds->slave_mii_bus->irq[phy] = irq; - } - } - return 0; -out: - err_phy = phy; - - for (phy = 0; phy < err_phy; phy++) - if (BIT(phy) & ds->phys_mii_mask) - irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); - - return ret; -} - -static void lan937x_irq_phy_free(struct ksz_device *dev) -{ - struct dsa_switch *ds = dev->ds; - int phy; - - for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) - if (BIT(phy) & ds->phys_mii_mask) - irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); -} - -static int lan937x_mdio_register(struct ksz_device *dev) -{ - struct dsa_switch *ds = dev->ds; - struct device_node *mdio_np; - struct mii_bus *bus; - int ret; - - mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); - if (!mdio_np) - return 0; - - bus = devm_mdiobus_alloc(ds->dev); - if (!bus) { - of_node_put(mdio_np); - return -ENOMEM; - } - - bus->priv = dev; - bus->read = lan937x_sw_mdio_read; - bus->write = lan937x_sw_mdio_write; - bus->name = "lan937x slave smi"; - snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); - bus->parent = ds->dev; - bus->phy_mask = ~ds->phys_mii_mask; - - ds->slave_mii_bus = bus; - - if (dev->irq > 0) { - ret = lan937x_irq_phy_setup(dev); - if (ret) { - of_node_put(mdio_np); - return ret; - } - } - - ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); - if (ret) { - dev_err(ds->dev, "unable to register MDIO bus %s\n", - bus->id); - if (dev->irq > 0) - lan937x_irq_phy_free(dev); - } - - of_node_put(mdio_np); - - return ret; -} - int lan937x_reset_switch(struct ksz_device *dev) { u32 data32; @@ -456,282 +339,9 @@ int lan937x_switch_init(struct ksz_device *dev) return 0; } -static void lan937x_girq_mask(struct irq_data *d) -{ - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - dev->girq.masked |= (1 << n); -} - -static void lan937x_girq_unmask(struct irq_data *d) -{ - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - dev->girq.masked &= ~(1 << n); -} - -static void lan937x_girq_bus_lock(struct irq_data *d) -{ - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - - mutex_lock(&dev->lock_irq); -} - -static void lan937x_girq_bus_sync_unlock(struct irq_data *d) -{ - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - int ret; - - ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, dev->girq.masked); - if (ret) - dev_err(dev->dev, "failed to change IRQ mask\n"); - - mutex_unlock(&dev->lock_irq); -} - -static const struct irq_chip lan937x_girq_chip = { - .name = "lan937x-global", - .irq_mask = lan937x_girq_mask, - .irq_unmask = lan937x_girq_unmask, - .irq_bus_lock = lan937x_girq_bus_lock, - .irq_bus_sync_unlock = lan937x_girq_bus_sync_unlock, -}; - -static int lan937x_girq_domain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - struct ksz_device *dev = d->host_data; - - irq_set_chip_data(irq, d->host_data); - irq_set_chip_and_handler(irq, &dev->girq.chip, handle_level_irq); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops lan937x_girq_domain_ops = { - .map = lan937x_girq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void lan937x_girq_free(struct ksz_device *dev) -{ - int irq, virq; - - free_irq(dev->irq, dev); - - for (irq = 0; irq < dev->girq.nirqs; irq++) { - virq = irq_find_mapping(dev->girq.domain, irq); - irq_dispose_mapping(virq); - } - - irq_domain_remove(dev->girq.domain); -} - -static irqreturn_t lan937x_girq_thread_fn(int irq, void *dev_id) -{ - struct ksz_device *dev = dev_id; - unsigned int nhandled = 0; - unsigned int sub_irq; - unsigned int n; - u32 data; - int ret; - - /* Read global interrupt status register */ - ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data); - if (ret) - goto out; - - for (n = 0; n < dev->girq.nirqs; ++n) { - if (data & (1 << n)) { - sub_irq = irq_find_mapping(dev->girq.domain, n); - handle_nested_irq(sub_irq); - ++nhandled; - } - } -out: - return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); -} - -static int lan937x_girq_setup(struct ksz_device *dev) -{ - int ret, irq; - - dev->girq.nirqs = dev->info->port_cnt; - dev->girq.domain = irq_domain_add_simple(NULL, dev->girq.nirqs, 0, - &lan937x_girq_domain_ops, dev); - if (!dev->girq.domain) - return -ENOMEM; - - for (irq = 0; irq < dev->girq.nirqs; irq++) - irq_create_mapping(dev->girq.domain, irq); - - dev->girq.chip = lan937x_girq_chip; - dev->girq.masked = ~0; - - ret = request_threaded_irq(dev->irq, NULL, lan937x_girq_thread_fn, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - dev_name(dev->dev), dev); - if (ret) - goto out; - - return 0; - -out: - lan937x_girq_free(dev); - - return ret; -} - -static void lan937x_pirq_mask(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - port->pirq.masked |= (1 << n); -} - -static void lan937x_pirq_unmask(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - port->pirq.masked &= ~(1 << n); -} - -static void lan937x_pirq_bus_lock(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - struct ksz_device *dev = port->ksz_dev; - - mutex_lock(&dev->lock_irq); -} - -static void lan937x_pirq_bus_sync_unlock(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - struct ksz_device *dev = port->ksz_dev; - - ksz_pwrite8(dev, port->num, REG_PORT_INT_MASK, port->pirq.masked); - mutex_unlock(&dev->lock_irq); -} - -static const struct irq_chip lan937x_pirq_chip = { - .name = "lan937x-port", - .irq_mask = lan937x_pirq_mask, - .irq_unmask = lan937x_pirq_unmask, - .irq_bus_lock = lan937x_pirq_bus_lock, - .irq_bus_sync_unlock = lan937x_pirq_bus_sync_unlock, -}; - -static int lan937x_pirq_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct ksz_port *port = d->host_data; - - irq_set_chip_data(irq, d->host_data); - irq_set_chip_and_handler(irq, &port->pirq.chip, handle_level_irq); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops lan937x_pirq_domain_ops = { - .map = lan937x_pirq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void lan937x_pirq_free(struct ksz_device *dev, u8 p) -{ - struct ksz_port *port = &dev->ports[p]; - int irq, virq; - int irq_num; - - irq_num = irq_find_mapping(dev->girq.domain, p); - if (irq_num < 0) - return; - - free_irq(irq_num, port); - - for (irq = 0; irq < port->pirq.nirqs; irq++) { - virq = irq_find_mapping(port->pirq.domain, irq); - irq_dispose_mapping(virq); - } - - irq_domain_remove(port->pirq.domain); -} - -static irqreturn_t lan937x_pirq_thread_fn(int irq, void *dev_id) -{ - struct ksz_port *port = dev_id; - unsigned int nhandled = 0; - struct ksz_device *dev; - unsigned int sub_irq; - unsigned int n; - u8 data; - - dev = port->ksz_dev; - - /* Read port interrupt status register */ - ksz_pread8(dev, port->num, REG_PORT_INT_STATUS, &data); - - for (n = 0; n < port->pirq.nirqs; ++n) { - if (data & (1 << n)) { - sub_irq = irq_find_mapping(port->pirq.domain, n); - handle_nested_irq(sub_irq); - ++nhandled; - } - } - - return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); -} - -static int lan937x_pirq_setup(struct ksz_device *dev, u8 p) -{ - struct ksz_port *port = &dev->ports[p]; - int ret, irq; - int irq_num; - - port->pirq.nirqs = dev->info->port_nirqs; - port->pirq.domain = irq_domain_add_simple(dev->dev->of_node, - port->pirq.nirqs, 0, - &lan937x_pirq_domain_ops, - port); - if (!port->pirq.domain) - return -ENOMEM; - - for (irq = 0; irq < port->pirq.nirqs; irq++) - irq_create_mapping(port->pirq.domain, irq); - - port->pirq.chip = lan937x_pirq_chip; - port->pirq.masked = ~0; - - irq_num = irq_find_mapping(dev->girq.domain, p); - if (irq_num < 0) - return irq_num; - - snprintf(port->pirq.name, sizeof(port->pirq.name), "port_irq-%d", p); - - ret = request_threaded_irq(irq_num, NULL, lan937x_pirq_thread_fn, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - port->pirq.name, port); - if (ret) - goto out; - - return 0; - -out: - lan937x_pirq_free(dev, p); - - return ret; -} - int lan937x_setup(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; - struct dsa_port *dp; int ret; /* enable Indirect Access from SPI to the VPHY registers */ @@ -741,24 +351,6 @@ int lan937x_setup(struct dsa_switch *ds) return ret; } - if (dev->irq > 0) { - ret = lan937x_girq_setup(dev); - if (ret) - return ret; - - dsa_switch_for_each_user_port(dp, dev->ds) { - ret = lan937x_pirq_setup(dev, dp->index); - if (ret) - goto out_girq; - } - } - - ret = lan937x_mdio_register(dev); - if (ret < 0) { - dev_err(dev->dev, "failed to register the mdio"); - goto out_pirq; - } - /* The VLAN aware is a global setting. Mixed vlan * filterings are not supported. */ @@ -782,29 +374,11 @@ int lan937x_setup(struct dsa_switch *ds) (SW_CLK125_ENB | SW_CLK25_ENB), true); return 0; - -out_pirq: - if (dev->irq > 0) - dsa_switch_for_each_user_port(dp, dev->ds) - lan937x_pirq_free(dev, dp->index); -out_girq: - if (dev->irq > 0) - lan937x_girq_free(dev); - - return ret; } void lan937x_teardown(struct dsa_switch *ds) { - struct ksz_device *dev = ds->priv; - struct dsa_port *dp; - if (dev->irq > 0) { - dsa_switch_for_each_user_port(dp, dev->ds) - lan937x_pirq_free(dev, dp->index); - - lan937x_girq_free(dev); - } } void lan937x_switch_exit(struct ksz_device *dev) -- cgit From e1add7dd6183b9d4184847c310f8dd9f1a2ba7a4 Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Thu, 22 Sep 2022 12:40:27 +0530 Subject: net: dsa: microchip: use common irq routines for girq and pirq The global port interrupt routines and individual ports interrupt routines has similar implementation except the mask & status register and number of nested irqs in them. The mask & status register and pointer to ksz_device is added to ksz_irq and uses the ksz_irq as irq_chip_data. Signed-off-by: Arun Ramadoss Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.c | 264 ++++++++++----------------------- drivers/net/dsa/microchip/ksz_common.h | 9 +- 2 files changed, 81 insertions(+), 192 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 605ce3ffbeff..d612181b3226 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1768,97 +1768,97 @@ static int ksz_mdio_register(struct ksz_device *dev) return ret; } -static void ksz_girq_mask(struct irq_data *d) +static void ksz_irq_mask(struct irq_data *d) { - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); - dev->girq.masked |= (1 << n); + kirq->masked |= BIT(d->hwirq); } -static void ksz_girq_unmask(struct irq_data *d) +static void ksz_irq_unmask(struct irq_data *d) { - struct ksz_device *dev = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); - dev->girq.masked &= ~(1 << n); + kirq->masked &= ~BIT(d->hwirq); } -static void ksz_girq_bus_lock(struct irq_data *d) +static void ksz_irq_bus_lock(struct irq_data *d) { - struct ksz_device *dev = irq_data_get_irq_chip_data(d); + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); - mutex_lock(&dev->lock_irq); + mutex_lock(&kirq->dev->lock_irq); } -static void ksz_girq_bus_sync_unlock(struct irq_data *d) +static void ksz_irq_bus_sync_unlock(struct irq_data *d) { - struct ksz_device *dev = irq_data_get_irq_chip_data(d); + struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); + struct ksz_device *dev = kirq->dev; int ret; - ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, dev->girq.masked); + ret = ksz_write32(dev, kirq->reg_mask, kirq->masked); if (ret) dev_err(dev->dev, "failed to change IRQ mask\n"); mutex_unlock(&dev->lock_irq); } -static const struct irq_chip ksz_girq_chip = { - .name = "ksz-global", - .irq_mask = ksz_girq_mask, - .irq_unmask = ksz_girq_unmask, - .irq_bus_lock = ksz_girq_bus_lock, - .irq_bus_sync_unlock = ksz_girq_bus_sync_unlock, +static const struct irq_chip ksz_irq_chip = { + .name = "ksz-irq", + .irq_mask = ksz_irq_mask, + .irq_unmask = ksz_irq_unmask, + .irq_bus_lock = ksz_irq_bus_lock, + .irq_bus_sync_unlock = ksz_irq_bus_sync_unlock, }; -static int ksz_girq_domain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) +static int ksz_irq_domain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) { - struct ksz_device *dev = d->host_data; - irq_set_chip_data(irq, d->host_data); - irq_set_chip_and_handler(irq, &dev->girq.chip, handle_level_irq); + irq_set_chip_and_handler(irq, &ksz_irq_chip, handle_level_irq); irq_set_noprobe(irq); return 0; } -static const struct irq_domain_ops ksz_girq_domain_ops = { - .map = ksz_girq_domain_map, +static const struct irq_domain_ops ksz_irq_domain_ops = { + .map = ksz_irq_domain_map, .xlate = irq_domain_xlate_twocell, }; -static void ksz_girq_free(struct ksz_device *dev) +static void ksz_irq_free(struct ksz_irq *kirq) { int irq, virq; - free_irq(dev->irq, dev); + free_irq(kirq->irq_num, kirq); - for (irq = 0; irq < dev->girq.nirqs; irq++) { - virq = irq_find_mapping(dev->girq.domain, irq); + for (irq = 0; irq < kirq->nirqs; irq++) { + virq = irq_find_mapping(kirq->domain, irq); irq_dispose_mapping(virq); } - irq_domain_remove(dev->girq.domain); + irq_domain_remove(kirq->domain); } -static irqreturn_t ksz_girq_thread_fn(int irq, void *dev_id) +static irqreturn_t ksz_irq_thread_fn(int irq, void *dev_id) { - struct ksz_device *dev = dev_id; + struct ksz_irq *kirq = dev_id; unsigned int nhandled = 0; + struct ksz_device *dev; unsigned int sub_irq; - unsigned int n; - u32 data; + u8 data; int ret; + u8 n; - /* Read global interrupt status register */ - ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data); + dev = kirq->dev; + + /* Read interrupt status register */ + ret = ksz_read8(dev, kirq->reg_status, &data); if (ret) goto out; - for (n = 0; n < dev->girq.nirqs; ++n) { - if (data & (1 << n)) { - sub_irq = irq_find_mapping(dev->girq.domain, n); + for (n = 0; n < kirq->nirqs; ++n) { + if (data & BIT(n)) { + sub_irq = irq_find_mapping(kirq->domain, n); handle_nested_irq(sub_irq); ++nhandled; } @@ -1867,177 +1867,63 @@ out: return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); } -static int ksz_girq_setup(struct ksz_device *dev) +static int ksz_irq_common_setup(struct ksz_device *dev, struct ksz_irq *kirq) { - int ret, irq; + int ret, n; - dev->girq.nirqs = dev->info->port_cnt; - dev->girq.domain = irq_domain_add_simple(NULL, dev->girq.nirqs, 0, - &ksz_girq_domain_ops, dev); - if (!dev->girq.domain) - return -ENOMEM; + kirq->dev = dev; + kirq->masked = ~0; - for (irq = 0; irq < dev->girq.nirqs; irq++) - irq_create_mapping(dev->girq.domain, irq); + kirq->domain = irq_domain_add_simple(dev->dev->of_node, kirq->nirqs, 0, + &ksz_irq_domain_ops, kirq); + if (!kirq->domain) + return -ENOMEM; - dev->girq.chip = ksz_girq_chip; - dev->girq.masked = ~0; + for (n = 0; n < kirq->nirqs; n++) + irq_create_mapping(kirq->domain, n); - ret = request_threaded_irq(dev->irq, NULL, ksz_girq_thread_fn, + ret = request_threaded_irq(kirq->irq_num, NULL, ksz_irq_thread_fn, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - dev_name(dev->dev), dev); + kirq->name, kirq); if (ret) goto out; return 0; out: - ksz_girq_free(dev); + ksz_irq_free(kirq); return ret; } -static void ksz_pirq_mask(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - port->pirq.masked |= (1 << n); -} - -static void ksz_pirq_unmask(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - unsigned int n = d->hwirq; - - port->pirq.masked &= ~(1 << n); -} - -static void ksz_pirq_bus_lock(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - struct ksz_device *dev = port->ksz_dev; - - mutex_lock(&dev->lock_irq); -} - -static void ksz_pirq_bus_sync_unlock(struct irq_data *d) -{ - struct ksz_port *port = irq_data_get_irq_chip_data(d); - struct ksz_device *dev = port->ksz_dev; - - ksz_pwrite8(dev, port->num, REG_PORT_INT_MASK, port->pirq.masked); - mutex_unlock(&dev->lock_irq); -} - -static const struct irq_chip ksz_pirq_chip = { - .name = "ksz-port", - .irq_mask = ksz_pirq_mask, - .irq_unmask = ksz_pirq_unmask, - .irq_bus_lock = ksz_pirq_bus_lock, - .irq_bus_sync_unlock = ksz_pirq_bus_sync_unlock, -}; - -static int ksz_pirq_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct ksz_port *port = d->host_data; - - irq_set_chip_data(irq, d->host_data); - irq_set_chip_and_handler(irq, &port->pirq.chip, handle_level_irq); - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops ksz_pirq_domain_ops = { - .map = ksz_pirq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void ksz_pirq_free(struct ksz_device *dev, u8 p) -{ - struct ksz_port *port = &dev->ports[p]; - int irq, virq; - int irq_num; - - irq_num = irq_find_mapping(dev->girq.domain, p); - if (irq_num < 0) - return; - - free_irq(irq_num, port); - - for (irq = 0; irq < port->pirq.nirqs; irq++) { - virq = irq_find_mapping(port->pirq.domain, irq); - irq_dispose_mapping(virq); - } - - irq_domain_remove(port->pirq.domain); -} - -static irqreturn_t ksz_pirq_thread_fn(int irq, void *dev_id) +static int ksz_girq_setup(struct ksz_device *dev) { - struct ksz_port *port = dev_id; - unsigned int nhandled = 0; - struct ksz_device *dev; - unsigned int sub_irq; - unsigned int n; - u8 data; - - dev = port->ksz_dev; + struct ksz_irq *girq = &dev->girq; - /* Read port interrupt status register */ - ksz_pread8(dev, port->num, REG_PORT_INT_STATUS, &data); + girq->nirqs = dev->info->port_cnt; + girq->reg_mask = REG_SW_PORT_INT_MASK__1; + girq->reg_status = REG_SW_PORT_INT_STATUS__1; + snprintf(girq->name, sizeof(girq->name), "global_port_irq"); - for (n = 0; n < port->pirq.nirqs; ++n) { - if (data & (1 << n)) { - sub_irq = irq_find_mapping(port->pirq.domain, n); - handle_nested_irq(sub_irq); - ++nhandled; - } - } + girq->irq_num = dev->irq; - return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); + return ksz_irq_common_setup(dev, girq); } static int ksz_pirq_setup(struct ksz_device *dev, u8 p) { - struct ksz_port *port = &dev->ports[p]; - int ret, irq; - int irq_num; - - port->pirq.nirqs = dev->info->port_nirqs; - port->pirq.domain = irq_domain_add_simple(dev->dev->of_node, - port->pirq.nirqs, 0, - &ksz_pirq_domain_ops, - port); - if (!port->pirq.domain) - return -ENOMEM; - - for (irq = 0; irq < port->pirq.nirqs; irq++) - irq_create_mapping(port->pirq.domain, irq); - - port->pirq.chip = ksz_pirq_chip; - port->pirq.masked = ~0; + struct ksz_irq *pirq = &dev->ports[p].pirq; - irq_num = irq_find_mapping(dev->girq.domain, p); - if (irq_num < 0) - return irq_num; + pirq->nirqs = dev->info->port_nirqs; + pirq->reg_mask = dev->dev_ops->get_port_addr(p, REG_PORT_INT_MASK); + pirq->reg_status = dev->dev_ops->get_port_addr(p, REG_PORT_INT_STATUS); + snprintf(pirq->name, sizeof(pirq->name), "port_irq-%d", p); - snprintf(port->pirq.name, sizeof(port->pirq.name), "port_irq-%d", p); + pirq->irq_num = irq_find_mapping(dev->girq.domain, p); + if (pirq->irq_num < 0) + return pirq->irq_num; - ret = request_threaded_irq(irq_num, NULL, ksz_pirq_thread_fn, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - port->pirq.name, port); - if (ret) - goto out; - - return 0; - -out: - ksz_pirq_free(dev, p); - - return ret; + return ksz_irq_common_setup(dev, pirq); } static int ksz_setup(struct dsa_switch *ds) @@ -2119,10 +2005,10 @@ static int ksz_setup(struct dsa_switch *ds) out_pirq: if (dev->irq > 0) dsa_switch_for_each_user_port(dp, dev->ds) - ksz_pirq_free(dev, dp->index); + ksz_irq_free(&dev->ports[dp->index].pirq); out_girq: if (dev->irq > 0) - ksz_girq_free(dev); + ksz_irq_free(&dev->girq); return ret; } @@ -2134,9 +2020,9 @@ static void ksz_teardown(struct dsa_switch *ds) if (dev->irq > 0) { dsa_switch_for_each_user_port(dp, dev->ds) - ksz_pirq_free(dev, dp->index); + ksz_irq_free(&dev->ports[dp->index].pirq); - ksz_girq_free(dev); + ksz_irq_free(&dev->girq); } if (dev->dev_ops->teardown) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 6edce587bfd2..9cfa179575ce 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -72,10 +72,13 @@ struct ksz_chip_data { struct ksz_irq { u16 masked; - struct irq_chip chip; + u16 reg_mask; + u16 reg_status; struct irq_domain *domain; int nirqs; + int irq_num; char name[16]; + struct ksz_device *dev; }; struct ksz_port { @@ -574,8 +577,8 @@ static inline int is_lan937x(struct ksz_device *dev) #define P_MII_SEL_M 0x3 /* Interrupt */ -#define REG_SW_PORT_INT_STATUS__4 0x0018 -#define REG_SW_PORT_INT_MASK__4 0x001C +#define REG_SW_PORT_INT_STATUS__1 0x001B +#define REG_SW_PORT_INT_MASK__1 0x001F #define REG_PORT_INT_STATUS 0x001B #define REG_PORT_INT_MASK 0x001F -- cgit From db5d451c4640a62b0971c7753ab321f089f32571 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 23 Sep 2022 22:37:40 +0800 Subject: net: dsa: lan9303: remove unnecessary i2c_set_clientdata() Remove unnecessary i2c_set_clientdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/lan9303_i2c.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/lan9303_i2c.c b/drivers/net/dsa/lan9303_i2c.c index 8ca4713310fa..79be5fc044bd 100644 --- a/drivers/net/dsa/lan9303_i2c.c +++ b/drivers/net/dsa/lan9303_i2c.c @@ -74,8 +74,6 @@ static int lan9303_i2c_remove(struct i2c_client *client) lan9303_remove(&sw_dev->chip); - i2c_set_clientdata(client, NULL); - return 0; } -- cgit From 008971adb95d332d21b9cc94231d93d7324d859d Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 23 Sep 2022 22:37:41 +0800 Subject: net: dsa: microchip: ksz9477: remove unnecessary i2c_set_clientdata() Remove unnecessary i2c_set_clientdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz9477_i2c.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 8fbc122e3384..e111756f6473 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -59,8 +59,6 @@ static int ksz9477_i2c_remove(struct i2c_client *i2c) if (dev) ksz_switch_remove(dev); - i2c_set_clientdata(i2c, NULL); - return 0; } -- cgit From 6387bf7c390a17a03f05a70099e135f61c7cb437 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 23 Sep 2022 22:37:42 +0800 Subject: net: dsa: xrs700x: remove unnecessary i2c_set_clientdata() Remove unnecessary i2c_set_clientdata() in ->remove(), the driver_data will be set to NULL in device_unbind_cleanup() after calling ->remove(). Signed-off-by: Yang Yingliang Signed-off-by: Jakub Kicinski --- drivers/net/dsa/xrs700x/xrs700x_i2c.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/xrs700x/xrs700x_i2c.c b/drivers/net/dsa/xrs700x/xrs700x_i2c.c index 6deae388a0d6..cd533b9e17ec 100644 --- a/drivers/net/dsa/xrs700x/xrs700x_i2c.c +++ b/drivers/net/dsa/xrs700x/xrs700x_i2c.c @@ -114,8 +114,6 @@ static int xrs700x_i2c_remove(struct i2c_client *i2c) xrs700x_switch_remove(priv); - i2c_set_clientdata(i2c, NULL); - return 0; } -- cgit From 5fc080de89f12b4415338c8d2ab58530c7706f3b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Sep 2022 22:15:16 +0300 Subject: net: dsa: felix: remove felix_info :: imdio_res The imdio_res is used only by vsc9959, which references its own vsc9959_imdio_res through the common felix_info->imdio_res pointer. Since the common code doesn't care about this resource (and it can't be part of the common array of resources, either, because it belongs in a different PCI BAR), just reference it directly. Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.h | 1 - drivers/net/dsa/ocelot/felix_vsc9959.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index e4fd5eef57a0..535a615f2b70 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -18,7 +18,6 @@ struct felix_info { const struct resource *target_io_res; const struct resource *port_io_res; - const struct resource *imdio_res; const struct reg_field *regfields; const u32 *const *map; const struct ocelot_ops *ops; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 2ec49e42b3f4..2234b4eccc1e 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1021,7 +1021,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) return -ENOMEM; } - memcpy(&res, felix->info->imdio_res, sizeof(res)); + memcpy(&res, &vsc9959_imdio_res, sizeof(res)); res.flags = IORESOURCE_MEM; res.start += felix->imdio_base; res.end += felix->imdio_base; @@ -2592,7 +2592,6 @@ static const struct ocelot_ops vsc9959_ops = { static const struct felix_info felix_info_vsc9959 = { .target_io_res = vsc9959_target_io_res, .port_io_res = vsc9959_port_io_res, - .imdio_res = &vsc9959_imdio_res, .regfields = vsc9959_regfields, .map = vsc9959_regmap, .ops = &vsc9959_ops, -- cgit From 1382ba68a0535924f1bd0221dd373d44b6c57609 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Sep 2022 22:15:17 +0300 Subject: net: dsa: felix: remove felix_info :: imdio_base This address is only relevant for the vsc9959, which is a PCIe device that holds its switch registers in a different PCIe BAR compared to the registers for the internal MDIO controller. Hide this aspect from the common felix driver and move the pci_resource_start() call to the only place that needs it, which is in vsc9959_mdio_bus_alloc(). Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.h | 1 - drivers/net/dsa/ocelot/felix_vsc9959.c | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 535a615f2b70..4921f5cc8170 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -85,7 +85,6 @@ struct felix { struct mii_bus *imdio; struct phylink_pcs **pcs; resource_size_t switch_base; - resource_size_t imdio_base; enum dsa_tag_protocol tag_proto; const struct felix_tag_proto_ops *tag_proto_ops; struct kthread_worker *xmit_worker; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 2234b4eccc1e..4ca9fbe197c7 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1003,9 +1003,11 @@ static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse) static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) { + struct pci_dev *pdev = to_pci_dev(ocelot->dev); struct felix *felix = ocelot_to_felix(ocelot); struct enetc_mdio_priv *mdio_priv; struct device *dev = ocelot->dev; + resource_size_t imdio_base; void __iomem *imdio_regs; struct resource res; struct enetc_hw *hw; @@ -1021,10 +1023,12 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) return -ENOMEM; } + imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); + memcpy(&res, &vsc9959_imdio_res, sizeof(res)); res.flags = IORESOURCE_MEM; - res.start += felix->imdio_base; - res.end += felix->imdio_base; + res.start += imdio_base; + res.end += imdio_base; imdio_regs = devm_ioremap_resource(dev, &res); if (IS_ERR(imdio_regs)) @@ -2665,7 +2669,6 @@ static int felix_pci_probe(struct pci_dev *pdev, ocelot->num_flooding_pgids = OCELOT_NUM_TC; felix->info = &felix_info_vsc9959; felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR); - felix->imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); pci_set_master(pdev); -- cgit From 8f66c64bfca33fd863e2bf0f53d7774d0c9c6aba Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Sep 2022 22:15:18 +0300 Subject: net: dsa: felix: remove felix_info :: init_regmap It turns out that the idea of having a customizable implementation of a regmap creation from a resource is not exactly useful. The idea was for the new MFD-based VSC7512 driver to use something that creates a SPI regmap from a resource. But there are problems in actually getting those resources (it involves getting them from MFD). To avoid all that, we'll be getting resources by name, so this custom init_regmap() method won't be needed. Remove it. Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.c | 4 ++-- drivers/net/dsa/ocelot/felix.h | 2 -- drivers/net/dsa/ocelot/felix_vsc9959.c | 1 - drivers/net/dsa/ocelot/seville_vsc9953.c | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index d2a9d292160c..b7a66c151be3 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1360,7 +1360,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) res.start += felix->switch_base; res.end += felix->switch_base; - target = felix->info->init_regmap(ocelot, &res); + target = ocelot_regmap_init(ocelot, &res); if (IS_ERR(target)) { dev_err(ocelot->dev, "Failed to map device memory space\n"); @@ -1397,7 +1397,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) res.start += felix->switch_base; res.end += felix->switch_base; - target = felix->info->init_regmap(ocelot, &res); + target = ocelot_regmap_init(ocelot, &res); if (IS_ERR(target)) { dev_err(ocelot->dev, "Failed to map memory space for port %d\n", diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 4921f5cc8170..54322d0398fd 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -55,8 +55,6 @@ struct felix_info { void (*tas_guard_bands_update)(struct ocelot *ocelot, int port); void (*port_sched_speed_set)(struct ocelot *ocelot, int port, u32 speed); - struct regmap *(*init_regmap)(struct ocelot *ocelot, - struct resource *res); }; /* Methods for initializing the hardware resources specific to a tagging diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 4ca9fbe197c7..e465e3f85467 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2617,7 +2617,6 @@ static const struct felix_info felix_info_vsc9959 = { .port_setup_tc = vsc9959_port_setup_tc, .port_sched_speed_set = vsc9959_sched_speed_set, .tas_guard_bands_update = vsc9959_tas_guard_bands_update, - .init_regmap = ocelot_regmap_init, }; static irqreturn_t felix_irq_handler(int irq, void *data) diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 5b29fa930627..e807db0dea98 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -1078,7 +1078,6 @@ static const struct felix_info seville_info_vsc9953 = { .mdio_bus_free = vsc9953_mdio_bus_free, .phylink_validate = vsc9953_phylink_validate, .port_modes = vsc9953_port_modes, - .init_regmap = ocelot_regmap_init, }; static int seville_probe(struct platform_device *pdev) -- cgit From 044d447a801f2d0c03e153ef41835aebf66ca2d6 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Sep 2022 22:15:19 +0300 Subject: net: dsa: felix: use DEFINE_RES_MEM_NAMED for resources Use less verbose resource definitions in vsc9959 and vsc9953. This also sets IORESOURCE_MEM in the constant array of resources, so we don't have to do this from felix_init_structs() - in fact, in the future, we may even support IORESOURCE_REG resources. Note that this macro takes start and length as argument, and we had start and end before. So transform end into length. While at it, sort the resources according to their offset. Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.c | 2 - drivers/net/dsa/ocelot/felix_vsc9959.c | 104 +++++---------------------- drivers/net/dsa/ocelot/seville_vsc9953.c | 120 ++++++------------------------- 3 files changed, 38 insertions(+), 188 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index b7a66c151be3..6a7643c31c46 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1356,7 +1356,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) continue; memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); - res.flags = IORESOURCE_MEM; res.start += felix->switch_base; res.end += felix->switch_base; @@ -1393,7 +1392,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) } memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); - res.flags = IORESOURCE_MEM; res.start += felix->switch_base; res.end += felix->switch_base; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index e465e3f85467..1872727e80df 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -478,99 +478,32 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = { /* Addresses are relative to the PCI device's base address */ static const struct resource vsc9959_target_io_res[TARGET_MAX] = { - [ANA] = { - .start = 0x0280000, - .end = 0x028ffff, - .name = "ana", - }, - [QS] = { - .start = 0x0080000, - .end = 0x00800ff, - .name = "qs", - }, - [QSYS] = { - .start = 0x0200000, - .end = 0x021ffff, - .name = "qsys", - }, - [REW] = { - .start = 0x0030000, - .end = 0x003ffff, - .name = "rew", - }, - [SYS] = { - .start = 0x0010000, - .end = 0x001ffff, - .name = "sys", - }, - [S0] = { - .start = 0x0040000, - .end = 0x00403ff, - .name = "s0", - }, - [S1] = { - .start = 0x0050000, - .end = 0x00503ff, - .name = "s1", - }, - [S2] = { - .start = 0x0060000, - .end = 0x00603ff, - .name = "s2", - }, - [PTP] = { - .start = 0x0090000, - .end = 0x00900cb, - .name = "ptp", - }, - [GCB] = { - .start = 0x0070000, - .end = 0x00701ff, - .name = "devcpu_gcb", - }, + [SYS] = DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), + [REW] = DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), + [S0] = DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), + [S1] = DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), + [S2] = DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), + [GCB] = DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), + [QS] = DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), + [PTP] = DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), + [QSYS] = DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), + [ANA] = DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), }; static const struct resource vsc9959_port_io_res[] = { - { - .start = 0x0100000, - .end = 0x010ffff, - .name = "port0", - }, - { - .start = 0x0110000, - .end = 0x011ffff, - .name = "port1", - }, - { - .start = 0x0120000, - .end = 0x012ffff, - .name = "port2", - }, - { - .start = 0x0130000, - .end = 0x013ffff, - .name = "port3", - }, - { - .start = 0x0140000, - .end = 0x014ffff, - .name = "port4", - }, - { - .start = 0x0150000, - .end = 0x015ffff, - .name = "port5", - }, + DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), + DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), + DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), + DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"), + DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"), + DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"), }; /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an * SGMII/QSGMII MAC PCS can be found. */ -static const struct resource vsc9959_imdio_res = { - .start = 0x8030, - .end = 0x8040, - .name = "imdio", -}; +static const struct resource vsc9959_imdio_res = + DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio"); static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), @@ -1026,7 +959,6 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR); memcpy(&res, &vsc9959_imdio_res, sizeof(res)); - res.flags = IORESOURCE_MEM; res.start += imdio_base; res.end += imdio_base; diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index e807db0dea98..66237c4385ac 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -459,109 +459,29 @@ static const u32 *vsc9953_regmap[TARGET_MAX] = { /* Addresses are relative to the device's base address */ static const struct resource vsc9953_target_io_res[TARGET_MAX] = { - [ANA] = { - .start = 0x0280000, - .end = 0x028ffff, - .name = "ana", - }, - [QS] = { - .start = 0x0080000, - .end = 0x00800ff, - .name = "qs", - }, - [QSYS] = { - .start = 0x0200000, - .end = 0x021ffff, - .name = "qsys", - }, - [REW] = { - .start = 0x0030000, - .end = 0x003ffff, - .name = "rew", - }, - [SYS] = { - .start = 0x0010000, - .end = 0x001ffff, - .name = "sys", - }, - [S0] = { - .start = 0x0040000, - .end = 0x00403ff, - .name = "s0", - }, - [S1] = { - .start = 0x0050000, - .end = 0x00503ff, - .name = "s1", - }, - [S2] = { - .start = 0x0060000, - .end = 0x00603ff, - .name = "s2", - }, - [PTP] = { - .start = 0x0090000, - .end = 0x00900cb, - .name = "ptp", - }, - [GCB] = { - .start = 0x0070000, - .end = 0x00701ff, - .name = "devcpu_gcb", - }, + [SYS] = DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), + [REW] = DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), + [S0] = DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), + [S1] = DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), + [S2] = DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), + [GCB] = DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), + [QS] = DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), + [PTP] = DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), + [QSYS] = DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), + [ANA] = DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), }; static const struct resource vsc9953_port_io_res[] = { - { - .start = 0x0100000, - .end = 0x010ffff, - .name = "port0", - }, - { - .start = 0x0110000, - .end = 0x011ffff, - .name = "port1", - }, - { - .start = 0x0120000, - .end = 0x012ffff, - .name = "port2", - }, - { - .start = 0x0130000, - .end = 0x013ffff, - .name = "port3", - }, - { - .start = 0x0140000, - .end = 0x014ffff, - .name = "port4", - }, - { - .start = 0x0150000, - .end = 0x015ffff, - .name = "port5", - }, - { - .start = 0x0160000, - .end = 0x016ffff, - .name = "port6", - }, - { - .start = 0x0170000, - .end = 0x017ffff, - .name = "port7", - }, - { - .start = 0x0180000, - .end = 0x018ffff, - .name = "port8", - }, - { - .start = 0x0190000, - .end = 0x019ffff, - .name = "port9", - }, + DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), + DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), + DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), + DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"), + DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"), + DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"), + DEFINE_RES_MEM_NAMED(0x0160000, 0x0010000, "port6"), + DEFINE_RES_MEM_NAMED(0x0170000, 0x0010000, "port7"), + DEFINE_RES_MEM_NAMED(0x0180000, 0x0010000, "port8"), + DEFINE_RES_MEM_NAMED(0x0190000, 0x0010000, "port9"), }; static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = { -- cgit From 1109b97b6161307cdd78e13b2c24cf2f7af4fe5b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Sep 2022 22:15:20 +0300 Subject: net: dsa: felix: update regmap requests to be string-based Existing felix DSA drivers (vsc9959, vsc9953) are all switches that were integrated in NXP SoCs, which makes them a bit unusual compared to the usual Microchip branded Ocelot switches. To be precise, looking at Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml, one can see 21 memory regions for the "switch" node, and these correspond to the "targets" of the switch IP, which are spread throughout the guts of that SoC's memory space. In NXP integrations, those targets still exist, but they were condensed within a single memory region, with no other peripheral in between them, so it made more sense for the driver to ioremap the entire memory space of the switch, and then find the targets within that memory space via some offsets hardcoded in the driver. The effect of this design decision is that now, the felix driver expects hardware instantiations to provide their own resource definitions, which is kind of odd when considering a typical device (those are retrieved from 'reg' properties in the device tree, using platform_get_resource() or similar). Allow other hardware instantiations that share the felix driver to not provide a hardcoded array of resources in the future. Instead, make the common denominator based on which regmaps are created be just the resource "names". Each instantiation comes with its own array of names that are mandatory for it, and with an optional array of resources. So we split the resources in 2 arrays, one is what's requested and the other is what's provided. There is one pool of provided resources, in felix->info->resources (of length felix->info->num_resources). There are 2 different ways of requesting a resource. One is by enum ocelot_target (this handles the global regmaps), and one is by int port (this handles the per-port ones). For the existing vsc9959 and vsc9953, it would be a bit stupid to request something that's not provided, given that the 2 arrays are both defined in the same place. The advantage is that we can now modify felix_request_regmap_by_name() to make felix->info->resources[] optional, and if absent, the implementation can call dev_get_regmap() and this is something that is compatible with MFD. Co-developed-by: Colin Foster Signed-off-by: Colin Foster Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix.c | 71 +++++++++++++++++++++++--------- drivers/net/dsa/ocelot/felix.h | 9 +++- drivers/net/dsa/ocelot/felix_vsc9959.c | 43 ++++++++++++------- drivers/net/dsa/ocelot/seville_vsc9953.c | 43 ++++++++++++------- 4 files changed, 112 insertions(+), 54 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 6a7643c31c46..dd3a18cc89dd 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1312,11 +1312,55 @@ static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) return err; } +static struct regmap *felix_request_regmap_by_name(struct felix *felix, + const char *resource_name) +{ + struct ocelot *ocelot = &felix->ocelot; + struct resource res; + int i; + + for (i = 0; i < felix->info->num_resources; i++) { + if (strcmp(resource_name, felix->info->resources[i].name)) + continue; + + memcpy(&res, &felix->info->resources[i], sizeof(res)); + res.start += felix->switch_base; + res.end += felix->switch_base; + + return ocelot_regmap_init(ocelot, &res); + } + + return ERR_PTR(-ENOENT); +} + +static struct regmap *felix_request_regmap(struct felix *felix, + enum ocelot_target target) +{ + const char *resource_name = felix->info->resource_names[target]; + + /* If the driver didn't provide a resource name for the target, + * the resource is optional. + */ + if (!resource_name) + return NULL; + + return felix_request_regmap_by_name(felix, resource_name); +} + +static struct regmap *felix_request_port_regmap(struct felix *felix, int port) +{ + char resource_name[32]; + + sprintf(resource_name, "port%d", port); + + return felix_request_regmap_by_name(felix, resource_name); +} + static int felix_init_structs(struct felix *felix, int num_phys_ports) { struct ocelot *ocelot = &felix->ocelot; phy_interface_t *port_phy_modes; - struct resource res; + struct regmap *target; int port, i, err; ocelot->num_phys_ports = num_phys_ports; @@ -1350,19 +1394,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) } for (i = 0; i < TARGET_MAX; i++) { - struct regmap *target; - - if (!felix->info->target_io_res[i].name) - continue; - - memcpy(&res, &felix->info->target_io_res[i], sizeof(res)); - res.start += felix->switch_base; - res.end += felix->switch_base; - - target = ocelot_regmap_init(ocelot, &res); + target = felix_request_regmap(felix, i); if (IS_ERR(target)) { dev_err(ocelot->dev, - "Failed to map device memory space\n"); + "Failed to map device memory space: %pe\n", + target); kfree(port_phy_modes); return PTR_ERR(target); } @@ -1379,7 +1415,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) for (port = 0; port < num_phys_ports; port++) { struct ocelot_port *ocelot_port; - struct regmap *target; ocelot_port = devm_kzalloc(ocelot->dev, sizeof(struct ocelot_port), @@ -1391,15 +1426,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) return -ENOMEM; } - memcpy(&res, &felix->info->port_io_res[port], sizeof(res)); - res.start += felix->switch_base; - res.end += felix->switch_base; - - target = ocelot_regmap_init(ocelot, &res); + target = felix_request_port_regmap(felix, port); if (IS_ERR(target)) { dev_err(ocelot->dev, - "Failed to map memory space for port %d\n", - port); + "Failed to map memory space for port %d: %pe\n", + port, target); kfree(port_phy_modes); return PTR_ERR(target); } diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 54322d0398fd..c9c29999c336 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -16,8 +16,13 @@ /* Platform-specific information */ struct felix_info { - const struct resource *target_io_res; - const struct resource *port_io_res; + /* Hardcoded resources provided by the hardware instantiation. */ + const struct resource *resources; + size_t num_resources; + /* Names of the mandatory resources that will be requested during + * probe. Must have TARGET_MAX elements, since it is indexed by target. + */ + const char *const *resource_names; const struct reg_field *regfields; const u32 *const *map; const struct ocelot_ops *ops; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 1872727e80df..12810fea2075 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -477,26 +477,36 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = { }; /* Addresses are relative to the PCI device's base address */ -static const struct resource vsc9959_target_io_res[TARGET_MAX] = { - [SYS] = DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), - [REW] = DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), - [S0] = DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), - [S1] = DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), - [S2] = DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), - [GCB] = DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), - [QS] = DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), - [PTP] = DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), - [QSYS] = DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), - [ANA] = DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), -}; - -static const struct resource vsc9959_port_io_res[] = { +static const struct resource vsc9959_resources[] = { + DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), + DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), + DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), + DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), + DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), + DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), + DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), + DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"), DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"), DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"), + DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), + DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), +}; + +static const char * const vsc9959_resource_names[TARGET_MAX] = { + [SYS] = "sys", + [REW] = "rew", + [S0] = "s0", + [S1] = "s1", + [S2] = "s2", + [GCB] = "devcpu_gcb", + [QS] = "qs", + [PTP] = "ptp", + [QSYS] = "qsys", + [ANA] = "ana", }; /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an @@ -2526,8 +2536,9 @@ static const struct ocelot_ops vsc9959_ops = { }; static const struct felix_info felix_info_vsc9959 = { - .target_io_res = vsc9959_target_io_res, - .port_io_res = vsc9959_port_io_res, + .resources = vsc9959_resources, + .num_resources = ARRAY_SIZE(vsc9959_resources), + .resource_names = vsc9959_resource_names, .regfields = vsc9959_regfields, .map = vsc9959_regmap, .ops = &vsc9959_ops, diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 66237c4385ac..7af33b2c685d 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -458,20 +458,15 @@ static const u32 *vsc9953_regmap[TARGET_MAX] = { }; /* Addresses are relative to the device's base address */ -static const struct resource vsc9953_target_io_res[TARGET_MAX] = { - [SYS] = DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), - [REW] = DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), - [S0] = DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), - [S1] = DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), - [S2] = DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), - [GCB] = DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), - [QS] = DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), - [PTP] = DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), - [QSYS] = DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), - [ANA] = DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), -}; - -static const struct resource vsc9953_port_io_res[] = { +static const struct resource vsc9953_resources[] = { + DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"), + DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"), + DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"), + DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"), + DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"), + DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"), + DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"), + DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"), DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"), DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"), DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"), @@ -482,6 +477,21 @@ static const struct resource vsc9953_port_io_res[] = { DEFINE_RES_MEM_NAMED(0x0170000, 0x0010000, "port7"), DEFINE_RES_MEM_NAMED(0x0180000, 0x0010000, "port8"), DEFINE_RES_MEM_NAMED(0x0190000, 0x0010000, "port9"), + DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"), + DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"), +}; + +static const char * const vsc9953_resource_names[TARGET_MAX] = { + [SYS] = "sys", + [REW] = "rew", + [S0] = "s0", + [S1] = "s1", + [S2] = "s2", + [GCB] = "devcpu_gcb", + [QS] = "qs", + [PTP] = "ptp", + [QSYS] = "qsys", + [ANA] = "ana", }; static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = { @@ -980,8 +990,9 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot) } static const struct felix_info seville_info_vsc9953 = { - .target_io_res = vsc9953_target_io_res, - .port_io_res = vsc9953_port_io_res, + .resources = vsc9953_resources, + .num_resources = ARRAY_SIZE(vsc9953_resources), + .resource_names = vsc9953_resource_names, .regfields = vsc9953_regfields, .map = vsc9953_regmap, .ops = &vsc9953_ops, -- cgit From 1712be05a8a7713d2f564d01cf0bbf25d4310cb2 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 28 Sep 2022 12:51:59 +0300 Subject: net: dsa: felix: offload per-tc max SDU from tc-taprio Our current vsc9959_tas_guard_bands_update() algorithm has a limitation imposed by the hardware design. To avoid packet overruns between one gate interval and the next (which would add jitter for scheduled traffic in the next gate), we configure the switch to use guard bands. These are as large as the largest packet which is possible to be transmitted. The problem is that at tc-taprio intervals of sizes comparable to a guard band, there isn't an obvious place in which to split the interval between the useful portion (for scheduling) and the guard band portion (where scheduling is blocked). For example, a 10 us interval at 1Gbps allows 1225 octets to be transmitted. We currently split the interval between the bare minimum of 33 ns useful time (required to schedule a single packet) and the rest as guard band. But 33 ns of useful scheduling time will only allow a single packet to be sent, be that packet 1200 octets in size, or 60 octets in size. It is impossible to send 2 60 octets frames in the 10 us window. Except that if we reduced the guard band (and therefore the maximum allowable SDU size) to 5 us, the useful time for scheduling is now also 5 us, so more packets could be scheduled. The hardware inflexibility of not scheduling according to individual packet lengths must unfortunately propagate to the user, who needs to tune the queueMaxSDU values if he wants to fit more small packets into a 10 us interval, rather than one large packet. Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix_vsc9959.c | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 12810fea2075..26a35ae322d1 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1194,6 +1194,14 @@ static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc) } } +static u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc) +{ + if (!taprio || !taprio->max_sdu[tc]) + return 0; + + return taprio->max_sdu[tc] + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN; +} + /* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU * values (the default value is 1518). Also, for traffic class windows smaller @@ -1203,6 +1211,7 @@ static u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc) static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct tc_taprio_qopt_offload *taprio; u64 min_gate_len[OCELOT_NUM_TC]; int speed, picos_per_byte; u64 needed_bit_time_ps; @@ -1212,6 +1221,8 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) lockdep_assert_held(&ocelot->tas_lock); + taprio = ocelot_port->taprio; + val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port); tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val); @@ -1248,11 +1259,12 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) "port %d: max frame size %d needs %llu ps at speed %d\n", port, maxlen, needed_bit_time_ps, speed); - vsc9959_tas_min_gate_lengths(ocelot_port->taprio, min_gate_len); + vsc9959_tas_min_gate_lengths(taprio, min_gate_len); mutex_lock(&ocelot->fwd_domain_lock); for (tc = 0; tc < OCELOT_NUM_TC; tc++) { + u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc); u64 remaining_gate_len_ps; u32 max_sdu; @@ -1263,7 +1275,7 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) /* Setting QMAXSDU_CFG to 0 disables oversized frame * dropping. */ - max_sdu = 0; + max_sdu = requested_max_sdu; dev_dbg(ocelot->dev, "port %d tc %d min gate len %llu" ", sending all frames\n", @@ -1294,6 +1306,10 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) */ if (max_sdu > 20) max_sdu -= 20; + + if (requested_max_sdu && requested_max_sdu < max_sdu) + max_sdu = requested_max_sdu; + dev_info(ocelot->dev, "port %d tc %d min gate length %llu" " ns not enough for max frame size %d at %d" @@ -1583,6 +1599,21 @@ static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port, return 0; } +static int vsc9959_qos_query_caps(struct tc_query_caps_base *base) +{ + switch (base->type) { + case TC_SETUP_QDISC_TAPRIO: { + struct tc_taprio_caps *caps = base->caps; + + caps->supports_queue_max_sdu = true; + + return 0; + } + default: + return -EOPNOTSUPP; + } +} + static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type, void *type_data) @@ -1590,6 +1621,8 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, struct ocelot *ocelot = ds->priv; switch (type) { + case TC_QUERY_CAPS: + return vsc9959_qos_query_caps(type_data); case TC_SETUP_QDISC_TAPRIO: return vsc9959_qos_port_tas_set(ocelot, port, type_data); case TC_SETUP_QDISC_CBS: -- cgit From 248376b1b13f7300e94a9f8d97062d43dfa4a847 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 28 Sep 2022 12:52:00 +0300 Subject: net: dsa: hellcreek: refactor hellcreek_port_setup_tc() to use switch/case The following patch will need to make this function also respond to TC_QUERY_BASE, so make the processing more structured around the tc_setup_type. Signed-off-by: Vladimir Oltean Reviewed-by: Kurt Kanzenbach Signed-off-by: Jakub Kicinski --- drivers/net/dsa/hirschmann/hellcreek.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index eac6ace7c5f9..19e61d4112b3 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -1812,19 +1812,23 @@ static bool hellcreek_validate_schedule(struct hellcreek *hellcreek, static int hellcreek_port_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type, void *type_data) { - struct tc_taprio_qopt_offload *taprio = type_data; struct hellcreek *hellcreek = ds->priv; - if (type != TC_SETUP_QDISC_TAPRIO) - return -EOPNOTSUPP; + switch (type) { + case TC_SETUP_QDISC_TAPRIO: { + struct tc_taprio_qopt_offload *taprio = type_data; - if (!hellcreek_validate_schedule(hellcreek, taprio)) - return -EOPNOTSUPP; + if (!hellcreek_validate_schedule(hellcreek, taprio)) + return -EOPNOTSUPP; - if (taprio->enable) - return hellcreek_port_set_schedule(ds, port, taprio); + if (taprio->enable) + return hellcreek_port_set_schedule(ds, port, taprio); - return hellcreek_port_del_schedule(ds, port); + return hellcreek_port_del_schedule(ds, port); + } + default: + return -EOPNOTSUPP; + } } static const struct dsa_switch_ops hellcreek_ds_ops = { -- cgit From a745c697830b74e4787b0c849f763941928aa06d Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Wed, 28 Sep 2022 12:52:01 +0300 Subject: net: dsa: hellcreek: Offload per-tc max SDU from tc-taprio Add support for configuring the max SDU per priority and per port. If not specified, keep the default. Signed-off-by: Kurt Kanzenbach Signed-off-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/hirschmann/hellcreek.c | 76 +++++++++++++++++++++++++++++++++- drivers/net/dsa/hirschmann/hellcreek.h | 7 ++++ 2 files changed, 81 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa') diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index 19e61d4112b3..951f7935c872 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -128,6 +128,16 @@ static void hellcreek_select_prio(struct hellcreek *hellcreek, int prio) hellcreek_write(hellcreek, val, HR_PSEL); } +static void hellcreek_select_port_prio(struct hellcreek *hellcreek, int port, + int prio) +{ + u16 val = port << HR_PSEL_PTWSEL_SHIFT; + + val |= prio << HR_PSEL_PRTCWSEL_SHIFT; + + hellcreek_write(hellcreek, val, HR_PSEL); +} + static void hellcreek_select_counter(struct hellcreek *hellcreek, int counter) { u16 val = counter << HR_CSEL_SHIFT; @@ -1537,6 +1547,45 @@ out: return ret; } +static void hellcreek_setup_maxsdu(struct hellcreek *hellcreek, int port, + const struct tc_taprio_qopt_offload *schedule) +{ + int tc; + + for (tc = 0; tc < 8; ++tc) { + u32 max_sdu = schedule->max_sdu[tc] + VLAN_ETH_HLEN - ETH_FCS_LEN; + u16 val; + + if (!schedule->max_sdu[tc]) + continue; + + dev_dbg(hellcreek->dev, "Configure max-sdu %u for tc %d on port %d\n", + max_sdu, tc, port); + + hellcreek_select_port_prio(hellcreek, port, tc); + + val = (max_sdu & HR_PTPRTCCFG_MAXSDU_MASK) << HR_PTPRTCCFG_MAXSDU_SHIFT; + + hellcreek_write(hellcreek, val, HR_PTPRTCCFG); + } +} + +static void hellcreek_reset_maxsdu(struct hellcreek *hellcreek, int port) +{ + int tc; + + for (tc = 0; tc < 8; ++tc) { + u16 val; + + hellcreek_select_port_prio(hellcreek, port, tc); + + val = (HELLCREEK_DEFAULT_MAX_SDU & HR_PTPRTCCFG_MAXSDU_MASK) + << HR_PTPRTCCFG_MAXSDU_SHIFT; + + hellcreek_write(hellcreek, val, HR_PTPRTCCFG); + } +} + static void hellcreek_setup_gcl(struct hellcreek *hellcreek, int port, const struct tc_taprio_qopt_offload *schedule) { @@ -1720,7 +1769,10 @@ static int hellcreek_port_set_schedule(struct dsa_switch *ds, int port, } hellcreek_port->current_schedule = taprio_offload_get(taprio); - /* Then select port */ + /* Configure max sdu */ + hellcreek_setup_maxsdu(hellcreek, port, hellcreek_port->current_schedule); + + /* Select tdg */ hellcreek_select_tgd(hellcreek, port); /* Enable gating and keep defaults */ @@ -1772,7 +1824,10 @@ static int hellcreek_port_del_schedule(struct dsa_switch *ds, int port) hellcreek_port->current_schedule = NULL; } - /* Then select port */ + /* Reset max sdu */ + hellcreek_reset_maxsdu(hellcreek, port); + + /* Select tgd */ hellcreek_select_tgd(hellcreek, port); /* Disable gating and return to regular switching flow */ @@ -1809,12 +1864,29 @@ static bool hellcreek_validate_schedule(struct hellcreek *hellcreek, return true; } +static int hellcreek_tc_query_caps(struct tc_query_caps_base *base) +{ + switch (base->type) { + case TC_SETUP_QDISC_TAPRIO: { + struct tc_taprio_caps *caps = base->caps; + + caps->supports_queue_max_sdu = true; + + return 0; + } + default: + return -EOPNOTSUPP; + } +} + static int hellcreek_port_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type, void *type_data) { struct hellcreek *hellcreek = ds->priv; switch (type) { + case TC_QUERY_CAPS: + return hellcreek_tc_query_caps(type_data); case TC_SETUP_QDISC_TAPRIO: { struct tc_taprio_qopt_offload *taprio = type_data; diff --git a/drivers/net/dsa/hirschmann/hellcreek.h b/drivers/net/dsa/hirschmann/hellcreek.h index 9e303b8ab13c..4a678f7d61ae 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.h +++ b/drivers/net/dsa/hirschmann/hellcreek.h @@ -37,6 +37,7 @@ #define HELLCREEK_VLAN_UNTAGGED_MEMBER 0x1 #define HELLCREEK_VLAN_TAGGED_MEMBER 0x3 #define HELLCREEK_NUM_EGRESS_QUEUES 8 +#define HELLCREEK_DEFAULT_MAX_SDU 1536 /* Register definitions */ #define HR_MODID_C (0 * 2) @@ -72,6 +73,12 @@ #define HR_PRTCCFG_PCP_TC_MAP_SHIFT 0 #define HR_PRTCCFG_PCP_TC_MAP_MASK GENMASK(2, 0) +#define HR_PTPRTCCFG (0xa9 * 2) +#define HR_PTPRTCCFG_SET_QTRACK BIT(15) +#define HR_PTPRTCCFG_REJECT BIT(14) +#define HR_PTPRTCCFG_MAXSDU_SHIFT 0 +#define HR_PTPRTCCFG_MAXSDU_MASK GENMASK(10, 0) + #define HR_CSEL (0x8d * 2) #define HR_CSEL_SHIFT 0 #define HR_CSEL_MASK GENMASK(7, 0) -- cgit