diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-06-02 05:11:17 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-02 05:11:17 +0300 |
| commit | 925f3ec7d3a30501312ef4ffa9374cd7f92feb1a (patch) | |
| tree | 25d48e323c6aa0cdc9039a50e17f719b2336be31 | |
| parent | 046c89c45e321b4fe6051199eb3c05c4dbc89d7c (diff) | |
| parent | f456c9b936b62d755719acd929c8de57c2f1affe (diff) | |
| download | linux-925f3ec7d3a30501312ef4ffa9374cd7f92feb1a.tar.xz | |
Merge branch 'mv88e6xxx-serdes-on-mv88e6321'
Fidan Aliyeva says:
====================
mv88e6xxx: SERDES on mv88e6321
This patch series add code support to be able to use SERDES feature of
mv88e6321 version of Marvel mv88e6xxx series. mv88e6321 has 2 ports to
support high speed SERDES but the support is lacking in the driver.
mv88e6321 version has a similar architecture to mv88e6352 version making it
possible to reuse its pcs functions. That's why the patch series consist of
2 parts:
1. Refactor the serdes functions and pcs_init of mv88e6352 to be more
generic (patches 1-2).
2. Add the SERDES support for mv88e6321 reusing 6352's pcs functions
The final code has been tested on mv88e6321 ethernet device directly by ip
ping tests, performance tests and also verifying the switch's expected
register values.
Referred document: 88E6321/88E6320 Functional Specification
====================
Link: https://patch.msgid.link/20260528210310.1365858-1-fidan.aliyeva.ext@ericsson.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 8 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/pcs-6352.c | 10 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/serdes.c | 82 | ||||
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/serdes.h | 4 |
4 files changed, 74 insertions, 30 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c30e4c13565a..80b877c74513 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4672,6 +4672,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .stu_getnext = mv88e6352_g1_stu_getnext, .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .serdes_get_lane = mv88e6352_serdes_get_lane, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, @@ -4775,6 +4776,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .stu_getnext = mv88e6352_g1_stu_getnext, .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .serdes_get_lane = mv88e6352_serdes_get_lane, .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, @@ -5047,6 +5049,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .stu_getnext = mv88e6352_g1_stu_getnext, .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .serdes_get_lane = mv88e6352_serdes_get_lane, .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, @@ -5269,10 +5272,14 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .stu_getnext = mv88e6352_g1_stu_getnext, .stu_loadpurge = mv88e6352_g1_stu_loadpurge, + .serdes_get_lane = mv88e6321_serdes_get_lane, + .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, + .serdes_get_regs = mv88e6352_serdes_get_regs, .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, .phylink_get_caps = mv88e632x_phylink_get_caps, + .pcs_ops = &mv88e6352_pcs_ops, }; static const struct mv88e6xxx_ops mv88e6341_ops = { @@ -5487,6 +5494,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .gpio_ops = &mv88e6352_gpio_ops, .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6352_ptp_ops, + .serdes_get_lane = mv88e6352_serdes_get_lane, .serdes_get_sset_count = mv88e6352_serdes_get_sset_count, .serdes_get_strings = mv88e6352_serdes_get_strings, .serdes_get_stats = mv88e6352_serdes_get_stats, diff --git a/drivers/net/dsa/mv88e6xxx/pcs-6352.c b/drivers/net/dsa/mv88e6xxx/pcs-6352.c index 308655d72d52..4228ae5bb9db 100644 --- a/drivers/net/dsa/mv88e6xxx/pcs-6352.c +++ b/drivers/net/dsa/mv88e6xxx/pcs-6352.c @@ -324,17 +324,17 @@ static int mv88e6352_pcs_init(struct mv88e6xxx_chip *chip, int port) struct mii_bus *bus; struct device *dev; unsigned int irq; - int err; + int lane, err; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) + return 0; irq = mv88e6xxx_serdes_irq_mapping(chip, port); bus = mv88e6xxx_default_mdio_bus(chip); dev = chip->dev; - mpcs = marvell_c22_pcs_alloc(dev, bus, MV88E6352_ADDR_SERDES); + mpcs = marvell_c22_pcs_alloc(dev, bus, lane); if (!mpcs) return -ENOMEM; diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index d3d3c121a32d..4a394d47923e 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -17,10 +17,10 @@ #include "port.h" #include "serdes.h" -static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, - u16 *val) +static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int lane, + int reg, u16 *val) { - return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, + return mv88e6xxx_phy_page_read(chip, lane, MV88E6352_SERDES_PAGE_FIBER, reg, val); } @@ -102,6 +102,17 @@ int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa, return 0; } +int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +{ + int has_serdes; + + has_serdes = mv88e6352_g2_scratch_port_has_serdes(chip, port); + if (has_serdes == 0) + return -ENODEV; + + return MV88E6352_ADDR_SERDES; +} + struct mv88e6352_serdes_hw_stat { char string[ETH_GSTRING_LEN]; int sizeof_stat; @@ -115,11 +126,11 @@ static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = { int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) { - int err; + int lane = -ENODEV; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) + return 0; return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } @@ -128,11 +139,12 @@ int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, uint8_t **data) { struct mv88e6352_serdes_hw_stat *stat; - int err, i; + int lane = -ENODEV; + int i; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) + return 0; for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { stat = &mv88e6352_serdes_hw_stats[i]; @@ -141,14 +153,14 @@ int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } -static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, +static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane, struct mv88e6352_serdes_hw_stat *stat) { u64 val = 0; u16 reg; int err; - err = mv88e6352_serdes_read(chip, stat->reg, ®); + err = mv88e6352_serdes_read(chip, lane, stat->reg, ®); if (err) { dev_err(chip->dev, "failed to read statistic\n"); return 0; @@ -157,7 +169,7 @@ static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip, val = reg; if (stat->sizeof_stat == 32) { - err = mv88e6352_serdes_read(chip, stat->reg + 1, ®); + err = mv88e6352_serdes_read(chip, lane, stat->reg + 1, ®); if (err) { dev_err(chip->dev, "failed to read statistic\n"); return 0; @@ -173,11 +185,12 @@ size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, { struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port]; struct mv88e6352_serdes_hw_stat *stat; - int i, err; + int lane = -ENODEV; u64 value; + int i; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) return 0; BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) > @@ -185,7 +198,7 @@ size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { stat = &mv88e6352_serdes_hw_stats[i]; - value = mv88e6352_serdes_get_stat(chip, stat); + value = mv88e6352_serdes_get_stat(chip, lane, stat); mv88e6xxx_port->serdes_stats[i] += value; data[i] = mv88e6xxx_port->serdes_stats[i]; } @@ -200,33 +213,52 @@ unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) { - int err; + int lane = -ENODEV; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) - return err; + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) + return 0; return 32 * sizeof(u16); } void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) { + int lane = -ENODEV; u16 *p = _p; u16 reg; int err; int i; - err = mv88e6352_g2_scratch_port_has_serdes(chip, port); - if (err <= 0) + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane < 0) return; for (i = 0 ; i < 32; i++) { - err = mv88e6352_serdes_read(chip, i, ®); + err = mv88e6352_serdes_read(chip, lane, i, ®); if (!err) p[i] = reg; } } +int mv88e6321_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +{ + int lane = -ENODEV; + u8 cmode; + + if (port != 0 && port != 1) + return lane; + + cmode = chip->ports[port].cmode; + + if (cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX || + cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || + cmode == MV88E6XXX_PORT_STS_CMODE_SGMII) + lane = port + MV88E6321_PORT0_LANE; + + return lane; +} + int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) { u8 cmode = chip->ports[port].cmode; diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 17a3e85fabaa..e8f254909d6b 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -14,6 +14,8 @@ struct phylink_link_state; +#define MV88E6321_PORT0_LANE 0x0c + #define MV88E6352_ADDR_SERDES 0x0f #define MV88E6352_SERDES_PAGE_FIBER 0x01 #define MV88E6352_SERDES_IRQ 0x0b @@ -114,7 +116,9 @@ struct phylink_link_state; int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa, u16 status, struct phylink_link_state *state); +int mv88e6321_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); +int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); |
