]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 5 Dec 2021 12:54:14 +0000 (13:54 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 5 Dec 2021 12:54:14 +0000 (13:54 +0100)
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

queue-5.15/net-dsa-mv88e6xxx-add-fix-for-erratum-5.2-of-88e6393x-family.patch [new file with mode: 0644]
queue-5.15/net-dsa-mv88e6xxx-drop-unnecessary-check-in-mv88e6393x_serdes_erratum_4_6.patch [new file with mode: 0644]
queue-5.15/net-dsa-mv88e6xxx-fix-application-of-erratum-4.8-for-88e6393x.patch [new file with mode: 0644]
queue-5.15/net-dsa-mv88e6xxx-fix-inband-an-for-2500base-x-on-88e6393x-family.patch [new file with mode: 0644]
queue-5.15/net-dsa-mv88e6xxx-link-in-pcs_get_state-if-an-is-bypassed.patch [new file with mode: 0644]
queue-5.15/net-dsa-mv88e6xxx-save-power-by-disabling-serdes-trasmitter-and-receiver.patch [new file with mode: 0644]
queue-5.15/series

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 (file)
index 0000000..c9665b0
--- /dev/null
@@ -0,0 +1,88 @@
+From 93fd8207bed80ce19aaf59932cbe1c03d418a37d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &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 (file)
index 0000000..edeb9cd
--- /dev/null
@@ -0,0 +1,62 @@
+From 8c3318b4874e2dee867f5ae8f6d38f78e044bf71 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &reg);
+-              if (err)
+-                      return err;
++      err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
++                                  MV88E6393X_SERDES_POC, &reg);
++      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 (file)
index 0000000..03bcdc1
--- /dev/null
@@ -0,0 +1,113 @@
+From 21635d9203e1cf2b73b67e9a86059a62f62a3563 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..eb6ef07
--- /dev/null
@@ -0,0 +1,166 @@
+From 163000dbc772c1eae9bdfe7c8fe30155db1efd74 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &reg);
++      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 (file)
index 0000000..a105a22
--- /dev/null
@@ -0,0 +1,133 @@
+From ede359d8843a2779d232ed30bc36089d4b5962e4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..0f61b48
--- /dev/null
@@ -0,0 +1,113 @@
+From 7527d66260ac0c603c6baca5146748061fcddbd6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
+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 <kabel@kernel.org>
+
+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 <kabel@kernel.org>
+Cc: stable@vger.kernel.org # de776d0d316f ("net: dsa: mv88e6xxx: add support for mv88e6393x family")
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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, &reg);
++      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)
index db9f26df691e20a4ab54571e521f734b69dea546..eb5a592e713820453e7a7fee0519d65da5aec2a9 100644 (file)
@@ -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