From: Greg Kroah-Hartman Date: Sun, 5 Dec 2021 12:54:14 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v4.4.294~39 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f637db0c7774754d8fd19101ed008a4cbc6fb86c;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch --- diff --git a/queue-5.15/net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch b/queue-5.15/net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch new file mode 100644 index 00000000000..c9665b05025 --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch @@ -0,0 +1,88 @@ +From 93fd8207bed80ce19aaf59932cbe1c03d418a37d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:49 +0100 +Subject: net: dsa: mv88e6xxx: Add fix for erratum 5.2 of 88E6393X family +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit 93fd8207bed80ce19aaf59932cbe1c03d418a37d upstream. + +Add fix for erratum 5.2 of the 88E6393X (Amethyst) family: for 10gbase-r +mode, some undocumented registers need to be written some special +values. + +Fixes: de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family") +Signed-off-by: Marek Behún +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 48 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -1375,6 +1375,50 @@ static int mv88e6393x_serdes_erratum_4_8 + MV88E6393X_ERRATA_4_8_REG, reg); + } + ++static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane, ++ u8 cmode) ++{ ++ static const struct { ++ u16 dev, reg, val, mask; ++ } fixes[] = { ++ { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff }, ++ { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff }, ++ { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff }, ++ { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f }, ++ { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 }, ++ { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff }, ++ { MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC, ++ MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET }, ++ }; ++ int err, i; ++ u16 reg; ++ ++ /* mv88e6393x family errata 5.2: ++ * For optimal signal integrity the following sequence should be applied ++ * to SERDES operating in 10G mode. These registers only apply to 10G ++ * operation and have no effect on other speeds. ++ */ ++ if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(fixes); ++i) { ++ err = mv88e6390_serdes_read(chip, lane, fixes[i].dev, ++ fixes[i].reg, ®); ++ if (err) ++ return err; ++ ++ reg &= ~fixes[i].mask; ++ reg |= fixes[i].val; ++ ++ err = mv88e6390_serdes_write(chip, lane, fixes[i].dev, ++ fixes[i].reg, reg); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ + int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane, + bool on) + { +@@ -1389,6 +1433,10 @@ int mv88e6393x_serdes_power(struct mv88e + if (err) + return err; + ++ err = mv88e6393x_serdes_erratum_5_2(chip, lane, cmode); ++ if (err) ++ return err; ++ + err = mv88e6393x_serdes_power_lane(chip, lane, true); + if (err) + return err; diff --git a/queue-5.15/net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch b/queue-5.15/net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch new file mode 100644 index 00000000000..edeb9cd9b6d --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch @@ -0,0 +1,62 @@ +From 8c3318b4874e2dee867f5ae8f6d38f78e044bf71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:47 +0100 +Subject: net: dsa: mv88e6xxx: Drop unnecessary check in mv88e6393x_serdes_erratum_4_6() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit 8c3318b4874e2dee867f5ae8f6d38f78e044bf71 upstream. + +The check for lane is unnecessary, since the function is called only +with allowed lane argument. + +Signed-off-by: Marek Behún +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 28 +++++++++++----------------- + 1 file changed, 11 insertions(+), 17 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -1284,26 +1284,20 @@ static int mv88e6393x_serdes_erratum_4_6 + * It seems that after this workaround the SERDES is automatically + * powered up (the bit is cleared), so power it down. + */ +- if (lane == MV88E6393X_PORT0_LANE || lane == MV88E6393X_PORT9_LANE || +- lane == MV88E6393X_PORT10_LANE) { +- err = mv88e6390_serdes_read(chip, lane, +- MDIO_MMD_PHYXS, +- MV88E6393X_SERDES_POC, ®); +- if (err) +- return err; ++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_POC, ®); ++ if (err) ++ return err; + +- reg &= ~MV88E6393X_SERDES_POC_PDOWN; +- reg |= MV88E6393X_SERDES_POC_RESET; ++ reg &= ~MV88E6393X_SERDES_POC_PDOWN; ++ reg |= MV88E6393X_SERDES_POC_RESET; + +- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, +- MV88E6393X_SERDES_POC, reg); +- if (err) +- return err; ++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_POC, reg); ++ if (err) ++ return err; + +- return mv88e6390_serdes_power_sgmii(chip, lane, false); +- } +- +- return 0; ++ return mv88e6390_serdes_power_sgmii(chip, lane, false); + } + + int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip) diff --git a/queue-5.15/net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch b/queue-5.15/net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch new file mode 100644 index 00000000000..03bcdc1d13a --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch @@ -0,0 +1,113 @@ +From 21635d9203e1cf2b73b67e9a86059a62f62a3563 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:46 +0100 +Subject: net: dsa: mv88e6xxx: Fix application of erratum 4.8 for 88E6393X +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit 21635d9203e1cf2b73b67e9a86059a62f62a3563 upstream. + +According to SERDES scripts for 88E6393X, erratum 4.8 has to be applied +every time before SerDes is powered on. + +Split the code for erratum 4.8 into separate function and call it in +mv88e6393x_serdes_power(). + +Fixes: de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family") +Signed-off-by: Marek Behún +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 53 +++++++++++++++++++++++-------------- + 1 file changed, 33 insertions(+), 20 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -1271,9 +1271,9 @@ void mv88e6390_serdes_get_regs(struct mv + } + } + +-static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane) ++static int mv88e6393x_serdes_erratum_4_6(struct mv88e6xxx_chip *chip, int lane) + { +- u16 reg, pcs; ++ u16 reg; + int err; + + /* mv88e6393x family errata 4.6: +@@ -1300,11 +1300,32 @@ static int mv88e6393x_serdes_port_errata + if (err) + return err; + +- err = mv88e6390_serdes_power_sgmii(chip, lane, false); +- if (err) +- return err; ++ return mv88e6390_serdes_power_sgmii(chip, lane, false); + } + ++ return 0; ++} ++ ++int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip) ++{ ++ int err; ++ ++ err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT0_LANE); ++ if (err) ++ return err; ++ ++ err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT9_LANE); ++ if (err) ++ return err; ++ ++ return mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT10_LANE); ++} ++ ++static int mv88e6393x_serdes_erratum_4_8(struct mv88e6xxx_chip *chip, int lane) ++{ ++ u16 reg, pcs; ++ int err; ++ + /* mv88e6393x family errata 4.8: + * When a SERDES port is operating in 1000BASE-X or SGMII mode link may + * not come up after hardware reset or software reset of SERDES core. +@@ -1334,29 +1355,21 @@ static int mv88e6393x_serdes_port_errata + MV88E6393X_ERRATA_4_8_REG, reg); + } + +-int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip) +-{ +- int err; +- +- err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT0_LANE); +- if (err) +- return err; +- +- err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT9_LANE); +- if (err) +- return err; +- +- return mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT10_LANE); +-} +- + int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane, + bool on) + { + u8 cmode = chip->ports[port].cmode; ++ int err; + + if (port != 0 && port != 9 && port != 10) + return -EOPNOTSUPP; + ++ if (on) { ++ err = mv88e6393x_serdes_erratum_4_8(chip, lane); ++ if (err) ++ return err; ++ } ++ + switch (cmode) { + case MV88E6XXX_PORT_STS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_1000BASEX: diff --git a/queue-5.15/net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch b/queue-5.15/net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch new file mode 100644 index 00000000000..eb6ef0763c3 --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch @@ -0,0 +1,166 @@ +From 163000dbc772c1eae9bdfe7c8fe30155db1efd74 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:50 +0100 +Subject: net: dsa: mv88e6xxx: Fix inband AN for 2500base-x on 88E6393X family +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit 163000dbc772c1eae9bdfe7c8fe30155db1efd74 upstream. + +Inband AN is broken on Amethyst in 2500base-x mode when set by standard +mechanism (via cmode). + +(There probably is some weird setting done by default in the switch for + this mode that make it cycle in some state or something, because when + the peer is the mvneta controller, it receives link change interrupts + every ~0.3ms, but the link is always down.) + +Get around this by configuring the PCS mode to 1000base-x (where inband +AN works), and then changing the SerDes frequency while SerDes +transmitter and receiver are disabled, before enabling SerDes PHY. After +disabling SerDes PHY, change the PCS mode back to 2500base-x, to avoid +confusing the device (if we leave it at 1000base-x PCS mode but with +different frequency, and then change cmode to sgmii, the device won't +change the frequency because it thinks it already has the correct one). + +The register which changes the frequency is undocumented. I discovered +it by going through all registers in the ranges 4.f000-4.f100 and +1e.8000-1e.8200 for all SerDes cmodes (sgmii, 1000base-x, 2500base-x, +5gbase-r, 10gbase-r, usxgmii) and filtering out registers that didn't +make sense (the value was the same for modes which have different +frequency). The result of this was: + + reg sgmii 1000base-x 2500base-x 5gbase-r 10gbase-r usxgmii + 04.f002 005b 0058 0059 005c 005d 005f + 04.f076 3000 0000 1000 4000 5000 7000 + 04.f07c 0950 0950 1850 0550 0150 0150 + 1e.8000 0059 0059 0058 0055 0051 0051 + 1e.8140 0e20 0e20 0e28 0e21 0e42 0e42 + +Register 04.f002 is the documented Port Operational Confiuration +register, it's last 3 bits select PCS type, so changing this register +also changes the frequency to the appropriate value. + +Registers 04.f076 and 04.f07c are not writable. + +Undocumented register 1e.8000 was the one: changing bits 3:0 from 9 to 8 +changed SerDes frequency to 3.125 GHz, while leaving the value of PCS +mode in register 04.f002.2:0 at 1000base-x. Inband autonegotiation +started working correctly. + +(I didn't try anything with register 1e.8140 since 1e.8000 solved the + problem.) + +Since I don't have documentation for this register 1e.8000.3:0, I am +using the constants without names, but my hypothesis is that this +register selects PHY frequency. If in the future I have access to an +oscilloscope able to handle these frequencies, I will try to test this +hypothesis. + +Fixes: de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family") +Signed-off-by: Marek Behún +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 61 ++++++++++++++++++++++++++++++++++++- + drivers/net/dsa/mv88e6xxx/serdes.h | 1 + 2 files changed, 61 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -1419,6 +1419,54 @@ static int mv88e6393x_serdes_erratum_5_2 + return 0; + } + ++static int mv88e6393x_serdes_fix_2500basex_an(struct mv88e6xxx_chip *chip, ++ int lane, u8 cmode, bool on) ++{ ++ u16 reg; ++ int err; ++ ++ if (cmode != MV88E6XXX_PORT_STS_CMODE_2500BASEX) ++ return 0; ++ ++ /* Inband AN is broken on Amethyst in 2500base-x mode when set by ++ * standard mechanism (via cmode). ++ * We can get around this by configuring the PCS mode to 1000base-x ++ * and then writing value 0x58 to register 1e.8000. (This must be done ++ * while SerDes receiver and transmitter are disabled, which is, when ++ * this function is called.) ++ * It seem that when we do this configuration to 2500base-x mode (by ++ * changing PCS mode to 1000base-x and frequency to 3.125 GHz from ++ * 1.25 GHz) and then configure to sgmii or 1000base-x, the device ++ * thinks that it already has SerDes at 1.25 GHz and does not change ++ * the 1e.8000 register, leaving SerDes at 3.125 GHz. ++ * To avoid this, change PCS mode back to 2500base-x when disabling ++ * SerDes from 2500base-x mode. ++ */ ++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_POC, ®); ++ if (err) ++ return err; ++ ++ reg &= ~(MV88E6393X_SERDES_POC_PCS_MASK | MV88E6393X_SERDES_POC_AN); ++ if (on) ++ reg |= MV88E6393X_SERDES_POC_PCS_1000BASEX | ++ MV88E6393X_SERDES_POC_AN; ++ else ++ reg |= MV88E6393X_SERDES_POC_PCS_2500BASEX; ++ reg |= MV88E6393X_SERDES_POC_RESET; ++ ++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_POC, reg); ++ if (err) ++ return err; ++ ++ err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_VEND1, 0x8000, 0x58); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ + int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane, + bool on) + { +@@ -1437,6 +1485,11 @@ int mv88e6393x_serdes_power(struct mv88e + if (err) + return err; + ++ err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode, ++ true); ++ if (err) ++ return err; ++ + err = mv88e6393x_serdes_power_lane(chip, lane, true); + if (err) + return err; +@@ -1457,8 +1510,14 @@ int mv88e6393x_serdes_power(struct mv88e + if (err) + return err; + +- if (!on) ++ if (!on) { + err = mv88e6393x_serdes_power_lane(chip, lane, false); ++ if (err) ++ return err; ++ ++ err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode, ++ false); ++ } + + return err; + } +--- a/drivers/net/dsa/mv88e6xxx/serdes.h ++++ b/drivers/net/dsa/mv88e6xxx/serdes.h +@@ -93,6 +93,7 @@ + #define MV88E6393X_SERDES_POC_PCS_MASK 0x0007 + #define MV88E6393X_SERDES_POC_RESET BIT(15) + #define MV88E6393X_SERDES_POC_PDOWN BIT(5) ++#define MV88E6393X_SERDES_POC_AN BIT(3) + #define MV88E6393X_SERDES_CTRL1 0xf003 + #define MV88E6393X_SERDES_CTRL1_TX_PDOWN BIT(9) + #define MV88E6393X_SERDES_CTRL1_RX_PDOWN BIT(8) diff --git a/queue-5.15/net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch b/queue-5.15/net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch new file mode 100644 index 00000000000..a105a224fbe --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch @@ -0,0 +1,133 @@ +From ede359d8843a2779d232ed30bc36089d4b5962e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:51 +0100 +Subject: net: dsa: mv88e6xxx: Link in pcs_get_state() if AN is bypassed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit ede359d8843a2779d232ed30bc36089d4b5962e4 upstream. + +Function mv88e6xxx_serdes_pcs_get_state() currently does not report link +up if AN is enabled, Link bit is set, but Speed and Duplex Resolved bit +is not set, which testing shows is the case for when auto-negotiation +was bypassed (we have AN enabled but link partner does not). + +An example of such link partner is Marvell 88X3310 PHY, when put into +the mode where host interface changes between 10gbase-r, 5gbase-r, +2500base-x and sgmii according to copper speed. The 88X3310 does not +enable AN in 2500base-x, and so SerDes on mv88e6xxx currently does not +link with it. + +Fix this. + +Fixes: a5a6858b793f ("net: dsa: mv88e6xxx: extend phylink to Serdes PHYs") +Signed-off-by: Marek Behún +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 48 ++++++++++++++++++++++++++++++++----- + 1 file changed, 42 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -50,11 +50,22 @@ static int mv88e6390_serdes_write(struct + } + + static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, +- u16 status, u16 lpa, ++ u16 ctrl, u16 status, u16 lpa, + struct phylink_link_state *state) + { ++ state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK); ++ + if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { +- state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK); ++ /* The Spped and Duplex Resolved register is 1 if AN is enabled ++ * and complete, or if AN is disabled. So with disabled AN we ++ * still get here on link up. But we want to set an_complete ++ * only if AN was enabled, thus we look at BMCR_ANENABLE. ++ * (According to 802.3-2008 section 22.2.4.2.10, we should be ++ * able to get this same value from BMSR_ANEGCAPABLE, but tests ++ * show that these Marvell PHYs don't conform to this part of ++ * the specificaion - BMSR_ANEGCAPABLE is simply always 1.) ++ */ ++ state->an_complete = !!(ctrl & BMCR_ANENABLE); + state->duplex = status & + MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? + DUPLEX_FULL : DUPLEX_HALF; +@@ -81,6 +92,18 @@ static int mv88e6xxx_serdes_pcs_get_stat + dev_err(chip->dev, "invalid PHY speed\n"); + return -EINVAL; + } ++ } else if (state->link && ++ state->interface != PHY_INTERFACE_MODE_SGMII) { ++ /* If Speed and Duplex Resolved register is 0 and link is up, it ++ * means that AN was enabled, but link partner had it disabled ++ * and the PHY invoked the Auto-Negotiation Bypass feature and ++ * linked anyway. ++ */ ++ state->duplex = DUPLEX_FULL; ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) ++ state->speed = SPEED_2500; ++ else ++ state->speed = SPEED_1000; + } else { + state->link = false; + } +@@ -168,9 +191,15 @@ int mv88e6352_serdes_pcs_config(struct m + int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, + int lane, struct phylink_link_state *state) + { +- u16 lpa, status; ++ u16 lpa, status, ctrl; + int err; + ++ err = mv88e6352_serdes_read(chip, MII_BMCR, &ctrl); ++ if (err) { ++ dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err); ++ return err; ++ } ++ + err = mv88e6352_serdes_read(chip, 0x11, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err); +@@ -183,7 +212,7 @@ int mv88e6352_serdes_pcs_get_state(struc + return err; + } + +- return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state); ++ return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state); + } + + int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, +@@ -883,10 +912,17 @@ int mv88e6390_serdes_pcs_config(struct m + static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip, + int port, int lane, struct phylink_link_state *state) + { +- u16 lpa, status; ++ u16 lpa, status, ctrl; + int err; + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6390_SGMII_BMCR, &ctrl); ++ if (err) { ++ dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err); ++ return err; ++ } ++ ++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_PHY_STATUS, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err); +@@ -900,7 +936,7 @@ static int mv88e6390_serdes_pcs_get_stat + return err; + } + +- return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state); ++ return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state); + } + + static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip, diff --git a/queue-5.15/net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch b/queue-5.15/net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch new file mode 100644 index 00000000000..0f61b485f08 --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch @@ -0,0 +1,113 @@ +From 7527d66260ac0c603c6baca5146748061fcddbd6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Tue, 30 Nov 2021 18:01:48 +0100 +Subject: net: dsa: mv88e6xxx: Save power by disabling SerDes trasmitter and receiver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marek Behún + +commit 7527d66260ac0c603c6baca5146748061fcddbd6 upstream. + +Save power on 88E6393X by disabling SerDes receiver and transmitter +after SerDes is SerDes is disabled. + +Signed-off-by: Marek Behún +Cc: stable@vger.kernel.org # de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family") +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/dsa/mv88e6xxx/serdes.c | 46 +++++++++++++++++++++++++++++++++---- + drivers/net/dsa/mv88e6xxx/serdes.h | 3 ++ + 2 files changed, 45 insertions(+), 4 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/serdes.c ++++ b/drivers/net/dsa/mv88e6xxx/serdes.c +@@ -1271,6 +1271,28 @@ void mv88e6390_serdes_get_regs(struct mv + } + } + ++static int mv88e6393x_serdes_power_lane(struct mv88e6xxx_chip *chip, int lane, ++ bool on) ++{ ++ u16 reg; ++ int err; ++ ++ err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_CTRL1, ®); ++ if (err) ++ return err; ++ ++ if (on) ++ reg &= ~(MV88E6393X_SERDES_CTRL1_TX_PDOWN | ++ MV88E6393X_SERDES_CTRL1_RX_PDOWN); ++ else ++ reg |= MV88E6393X_SERDES_CTRL1_TX_PDOWN | ++ MV88E6393X_SERDES_CTRL1_RX_PDOWN; ++ ++ return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, ++ MV88E6393X_SERDES_CTRL1, reg); ++} ++ + static int mv88e6393x_serdes_erratum_4_6(struct mv88e6xxx_chip *chip, int lane) + { + u16 reg; +@@ -1297,7 +1319,11 @@ static int mv88e6393x_serdes_erratum_4_6 + if (err) + return err; + +- return mv88e6390_serdes_power_sgmii(chip, lane, false); ++ err = mv88e6390_serdes_power_sgmii(chip, lane, false); ++ if (err) ++ return err; ++ ++ return mv88e6393x_serdes_power_lane(chip, lane, false); + } + + int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip) +@@ -1362,17 +1388,29 @@ int mv88e6393x_serdes_power(struct mv88e + err = mv88e6393x_serdes_erratum_4_8(chip, lane); + if (err) + return err; ++ ++ err = mv88e6393x_serdes_power_lane(chip, lane, true); ++ if (err) ++ return err; + } + + switch (cmode) { + case MV88E6XXX_PORT_STS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_1000BASEX: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: +- return mv88e6390_serdes_power_sgmii(chip, lane, on); ++ err = mv88e6390_serdes_power_sgmii(chip, lane, on); ++ break; + case MV88E6393X_PORT_STS_CMODE_5GBASER: + case MV88E6393X_PORT_STS_CMODE_10GBASER: +- return mv88e6390_serdes_power_10g(chip, lane, on); ++ err = mv88e6390_serdes_power_10g(chip, lane, on); ++ break; + } + +- return 0; ++ if (err) ++ return err; ++ ++ if (!on) ++ err = mv88e6393x_serdes_power_lane(chip, lane, false); ++ ++ return err; + } +--- a/drivers/net/dsa/mv88e6xxx/serdes.h ++++ b/drivers/net/dsa/mv88e6xxx/serdes.h +@@ -93,6 +93,9 @@ + #define MV88E6393X_SERDES_POC_PCS_MASK 0x0007 + #define MV88E6393X_SERDES_POC_RESET BIT(15) + #define MV88E6393X_SERDES_POC_PDOWN BIT(5) ++#define MV88E6393X_SERDES_CTRL1 0xf003 ++#define MV88E6393X_SERDES_CTRL1_TX_PDOWN BIT(9) ++#define MV88E6393X_SERDES_CTRL1_RX_PDOWN BIT(8) + + #define MV88E6393X_ERRATA_4_8_REG 0xF074 + #define MV88E6393X_ERRATA_4_8_BIT BIT(14) diff --git a/queue-5.15/series b/queue-5.15/series index db9f26df691..eb5a592e713 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -82,3 +82,9 @@ kvm-arm64-avoid-setting-the-upper-32-bits-of-tcr_el2-and-cptr_el2-to-1.patch kvm-x86-use-vcpu-arch.walk_mmu-for-kvm_mmu_invlpg.patch kvm-x86-check-pir-even-for-vcpus-with-disabled-apicv.patch tracing-histograms-string-compares-should-not-care-about-signed-values.patch +net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch +net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch +net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch +net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch +net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch +net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch