net: dsa: microchip: ksz8795: handle eee specif erratum
authorOleksij Rempel <o.rempel@pengutronix.de>
Wed, 16 Mar 2022 12:55:29 +0000 (13:55 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 18 Mar 2022 00:19:16 +0000 (17:19 -0700)
According to erratum described in DS80000687C[1]: "Module 2: Link drops with
some EEE link partners.", we need to "Disable the EEE next page
exchange in EEE Global Register 2"

1 - https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ87xx-Errata-DS80000687C.pdf

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://lore.kernel.org/r/20220316125529.1489045-1-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/microchip/ksz8.h
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz8795_reg.h
drivers/net/dsa/microchip/ksz_common.h

index 9d61189..03da369 100644 (file)
@@ -16,6 +16,7 @@ enum ksz_regs {
        REG_IND_DATA_HI,
        REG_IND_DATA_LO,
        REG_IND_MIB_CHECK,
+       REG_IND_BYTE,
        P_FORCE_CTRL,
        P_LINK_STATUS,
        P_LOCAL_CTRL,
index 5dc9899..6f9cdd5 100644 (file)
@@ -33,6 +33,7 @@ static const u8 ksz8795_regs[] = {
        [REG_IND_DATA_HI]               = 0x71,
        [REG_IND_DATA_LO]               = 0x75,
        [REG_IND_MIB_CHECK]             = 0x74,
+       [REG_IND_BYTE]                  = 0xA0,
        [P_FORCE_CTRL]                  = 0x0C,
        [P_LINK_STATUS]                 = 0x0E,
        [P_LOCAL_CTRL]                  = 0x07,
@@ -222,6 +223,25 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
                           bits, set ? bits : 0);
 }
 
+static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
+{
+       struct ksz8 *ksz8 = dev->priv;
+       const u8 *regs = ksz8->regs;
+       u16 ctrl_addr;
+       int ret = 0;
+
+       mutex_lock(&dev->alu_mutex);
+
+       ctrl_addr = IND_ACC_TABLE(table) | addr;
+       ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
+       if (!ret)
+               ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+
+       mutex_unlock(&dev->alu_mutex);
+
+       return ret;
+}
+
 static int ksz8_reset_switch(struct ksz_device *dev)
 {
        if (ksz_is_ksz88x3(dev)) {
@@ -1391,6 +1411,23 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
        }
 }
 
+static int ksz8_handle_global_errata(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret = 0;
+
+       /* KSZ87xx Errata DS80000687C.
+        * Module 2: Link drops with some EEE link partners.
+        *   An issue with the EEE next page exchange between the
+        *   KSZ879x/KSZ877x/KSZ876x and some EEE link partners may result in
+        *   the link dropping.
+        */
+       if (dev->ksz87xx_eee_link_erratum)
+               ret = ksz8_ind_write8(dev, TABLE_EEE, REG_IND_EEE_GLOB2_HI, 0);
+
+       return ret;
+}
+
 static int ksz8_setup(struct dsa_switch *ds)
 {
        struct ksz_device *dev = ds->priv;
@@ -1458,7 +1495,7 @@ static int ksz8_setup(struct dsa_switch *ds)
 
        ds->configure_vlan_while_not_filtering = false;
 
-       return 0;
+       return ksz8_handle_global_errata(ds);
 }
 
 static void ksz8_get_caps(struct dsa_switch *ds, int port,
@@ -1575,6 +1612,7 @@ struct ksz_chip_data {
        int num_statics;
        int cpu_ports;
        int port_cnt;
+       bool ksz87xx_eee_link_erratum;
 };
 
 static const struct ksz_chip_data ksz8_switch_chips[] = {
@@ -1586,6 +1624,7 @@ static const struct ksz_chip_data ksz8_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total cpu and user ports */
+               .ksz87xx_eee_link_erratum = true,
        },
        {
                /*
@@ -1609,6 +1648,7 @@ static const struct ksz_chip_data ksz8_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 4,          /* total cpu and user ports */
+               .ksz87xx_eee_link_erratum = true,
        },
        {
                .chip_id = 0x8765,
@@ -1618,6 +1658,7 @@ static const struct ksz_chip_data ksz8_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total cpu and user ports */
+               .ksz87xx_eee_link_erratum = true,
        },
        {
                .chip_id = 0x8830,
@@ -1652,6 +1693,8 @@ static int ksz8_switch_init(struct ksz_device *dev)
                        dev->host_mask = chip->cpu_ports;
                        dev->port_mask = (BIT(dev->phy_port_cnt) - 1) |
                                         chip->cpu_ports;
+                       dev->ksz87xx_eee_link_erratum =
+                               chip->ksz87xx_eee_link_erratum;
                        break;
                }
        }
index 6b40bc2..d74defc 100644 (file)
 
 #define IND_ACC_TABLE(table)           ((table) << 8)
 
+/* */
+#define REG_IND_EEE_GLOB2_LO           0x34
+#define REG_IND_EEE_GLOB2_HI           0x35
+
 /* Driver set switch broadcast storm protection at 10% rate. */
 #define BROADCAST_STORM_PROT_RATE      10
 
index fa39ee7..485d4a9 100644 (file)
@@ -77,6 +77,7 @@ struct ksz_device {
        phy_interface_t compat_interface;
        u32 regs_size;
        bool phy_errata_9477;
+       bool ksz87xx_eee_link_erratum;
        bool synclko_125;
        bool synclko_disable;