summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2023-10-20 11:50:46 +0100
committerDavid S. Miller <davem@davemloft.net>2023-10-20 11:50:46 +0100
commit095c3ea6fd5bcb4fd3641146570bdf4ee3b57c75 (patch)
treecfe83a13ddeb46e11996548d06dd372a457b025e
parentc0518571545d2befdd978a39c490575f3e3dd15a (diff)
parent510f02febb10259919a41926ab6bf9ec5c72ee48 (diff)
downloadlwn-095c3ea6fd5bcb4fd3641146570bdf4ee3b57c75.tar.gz
lwn-095c3ea6fd5bcb4fd3641146570bdf4ee3b57c75.zip
Merge branch 'ksz886x-forced-link-modes'
Oleksij Rempel says: ==================== fix forced link mode for KSZ886X switches changes v3: - squash patch 1 and 2 - use genphy_config_aneg() instead of genphy_setup_forced() changes v2: - address kernel test robot warning - change comment explaining clearing of KSZ886X_CTRL_FORCE_LINK bit - s/PHY we create/PHY will create/ ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/microchip/ksz8795.c86
-rw-r--r--drivers/net/phy/micrel.c22
-rw-r--r--include/linux/micrel_phy.h4
3 files changed, 109 insertions, 3 deletions
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index 91aba470fb2f..4bf4d67557dc 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -632,6 +632,50 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
ksz8_w_table(dev, TABLE_VLAN, addr, buf);
}
+/**
+ * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY
+ * Control register (Reg. 31).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be read.
+ * @val: The value read from the SMI interface.
+ *
+ * This function reads the SMI interface and translates the hardware register
+ * bit values into their corresponding control settings for a MIIM PHY Control
+ * register.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)
+{
+ const u16 *regs = dev->info->regs;
+ u8 reg_val;
+ int ret;
+
+ *val = 0;
+
+ ret = ksz_pread8(dev, port, regs[P_LINK_STATUS], &reg_val);
+ if (ret < 0)
+ return ret;
+
+ if (reg_val & PORT_MDIX_STATUS)
+ *val |= KSZ886X_CTRL_MDIX_STAT;
+
+ ret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ if (reg_val & PORT_FORCE_LINK)
+ *val |= KSZ886X_CTRL_FORCE_LINK;
+
+ if (reg_val & PORT_POWER_SAVING)
+ *val |= KSZ886X_CTRL_PWRSAVE;
+
+ if (reg_val & PORT_PHY_REMOTE_LOOPBACK)
+ *val |= KSZ886X_CTRL_REMOTE_LOOPBACK;
+
+ return 0;
+}
+
int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{
u8 restart, speed, ctrl, link;
@@ -769,12 +813,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:
- ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
+ ret = ksz8_r_phy_ctrl(dev, p, &data);
if (ret)
return ret;
- if (link & PORT_MDIX_STATUS)
- data |= KSZ886X_CTRL_MDIX_STAT;
break;
default:
processed = false;
@@ -786,6 +828,38 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
return 0;
}
+/**
+ * ksz8_w_phy_ctrl - Translates and writes to the SMI interface from a MIIM PHY
+ * Control register (Reg. 31).
+ * @dev: The KSZ device instance.
+ * @port: The port number to be configured.
+ * @val: The register value to be written.
+ *
+ * This function translates control settings from a MIIM PHY Control register
+ * into their corresponding hardware register bit values for the SMI
+ * interface.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val)
+{
+ u8 reg_val = 0;
+ int ret;
+
+ if (val & KSZ886X_CTRL_FORCE_LINK)
+ reg_val |= PORT_FORCE_LINK;
+
+ if (val & KSZ886X_CTRL_PWRSAVE)
+ reg_val |= PORT_POWER_SAVING;
+
+ if (val & KSZ886X_CTRL_REMOTE_LOOPBACK)
+ reg_val |= PORT_PHY_REMOTE_LOOPBACK;
+
+ ret = ksz_prmw8(dev, port, REG_PORT_LINK_MD_CTRL, PORT_FORCE_LINK |
+ PORT_POWER_SAVING | PORT_PHY_REMOTE_LOOPBACK, reg_val);
+ return ret;
+}
+
int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{
u8 restart, speed, ctrl, data;
@@ -926,6 +1000,12 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
if (val & PHY_START_CABLE_DIAG)
ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
break;
+
+ case PHY_REG_PHY_CTRL:
+ ret = ksz8_w_phy_ctrl(dev, p, val);
+ if (ret)
+ return ret;
+ break;
default:
break;
}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 927d3d54658e..08e3915001c3 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -1733,6 +1733,28 @@ static int ksz886x_config_aneg(struct phy_device *phydev)
if (ret)
return ret;
+ if (phydev->autoneg != AUTONEG_ENABLE) {
+ /* When autonegotation is disabled, we need to manually force
+ * the link state. If we don't do this, the PHY will keep
+ * sending Fast Link Pulses (FLPs) which are part of the
+ * autonegotiation process. This is not desired when
+ * autonegotiation is off.
+ */
+ ret = phy_set_bits(phydev, MII_KSZPHY_CTRL,
+ KSZ886X_CTRL_FORCE_LINK);
+ if (ret)
+ return ret;
+ } else {
+ /* If we had previously forced the link state, we need to
+ * clear KSZ886X_CTRL_FORCE_LINK bit now. Otherwise, the PHY
+ * will not perform autonegotiation.
+ */
+ ret = phy_clear_bits(phydev, MII_KSZPHY_CTRL,
+ KSZ886X_CTRL_FORCE_LINK);
+ if (ret)
+ return ret;
+ }
+
/* The MDI-X configuration is automatically changed by the PHY after
* switching from autoneg off to on. So, take MDI-X configuration under
* own control and set it after autoneg configuration was done.
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index 4e27ca7c49de..591bf5b5e8dc 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -64,6 +64,10 @@
#define KSZ886X_BMCR_DISABLE_TRANSMIT BIT(1)
#define KSZ886X_BMCR_DISABLE_LED BIT(0)
+/* PHY Special Control/Status Register (Reg 31) */
#define KSZ886X_CTRL_MDIX_STAT BIT(4)
+#define KSZ886X_CTRL_FORCE_LINK BIT(3)
+#define KSZ886X_CTRL_PWRSAVE BIT(2)
+#define KSZ886X_CTRL_REMOTE_LOOPBACK BIT(1)
#endif /* _MICREL_PHY_H */