mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
net: dsa: microchip: implement PHY loopback configuration for KSZ8794 and KSZ8873
Correct the PHY loopback bit handling in the ksz8_w_phy_bmcr and ksz8_r_phy_bmcr functions for KSZ8794 and KSZ8873 variants in the ksz8795 driver. Previously, the code erroneously used Bit 7 of port register 0xD for both chip variants, which is actually for LED configuration. This update ensures the correct registers and bits are used for the PHY loopback feature: - For KSZ8794: Use 0xF / Bit 7. - For KSZ8873: Use 0xD / Bit 0. The lack of loopback support was seen on KSZ8873 system by using "ethtool -t lanX". After this patch, the ethtool selftest will work, but only if port is not part of a bridge. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Arun Ramadoss <arun.ramadoss@microchip.com> Link: https://lore.kernel.org/r/20240124123314.734815-4-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d1b7d0d85d
commit
9e62bed6e1
|
|
@ -632,6 +632,57 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
|
|||
ksz8_w_table(dev, TABLE_VLAN, addr, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksz879x_get_loopback - KSZ879x specific function to get loopback
|
||||
* configuration status for a specific port
|
||||
* @dev: Pointer to the device structure
|
||||
* @port: Port number to query
|
||||
* @val: Pointer to store the result
|
||||
*
|
||||
* This function reads the SMI registers to determine whether loopback mode
|
||||
* is enabled for a specific port.
|
||||
*
|
||||
* Return: 0 on success, error code on failure.
|
||||
*/
|
||||
static int ksz879x_get_loopback(struct ksz_device *dev, u16 port,
|
||||
u16 *val)
|
||||
{
|
||||
u8 stat3;
|
||||
int ret;
|
||||
|
||||
ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (stat3 & PORT_PHY_LOOPBACK)
|
||||
*val |= BMCR_LOOPBACK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksz879x_set_loopback - KSZ879x specific function to set loopback mode for
|
||||
* a specific port
|
||||
* @dev: Pointer to the device structure.
|
||||
* @port: Port number to modify.
|
||||
* @val: Value indicating whether to enable or disable loopback mode.
|
||||
*
|
||||
* This function translates loopback bit of the BMCR register into the
|
||||
* corresponding hardware register bit value and writes it to the SMI interface.
|
||||
*
|
||||
* Return: 0 on success, error code on failure.
|
||||
*/
|
||||
static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val)
|
||||
{
|
||||
u8 stat3 = 0;
|
||||
|
||||
if (val & BMCR_LOOPBACK)
|
||||
stat3 |= PORT_PHY_LOOPBACK;
|
||||
|
||||
return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK,
|
||||
stat3);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY
|
||||
* Control register (Reg. 31).
|
||||
|
|
@ -731,16 +782,20 @@ static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (restart & PORT_PHY_LOOPBACK)
|
||||
*val |= BMCR_LOOPBACK;
|
||||
|
||||
if (ctrl & PORT_FORCE_100_MBIT)
|
||||
*val |= BMCR_SPEED100;
|
||||
|
||||
if (ksz_is_ksz88x3(dev)) {
|
||||
if (restart & KSZ8873_PORT_PHY_LOOPBACK)
|
||||
*val |= BMCR_LOOPBACK;
|
||||
|
||||
if ((ctrl & PORT_AUTO_NEG_ENABLE))
|
||||
*val |= BMCR_ANENABLE;
|
||||
} else {
|
||||
ret = ksz879x_get_loopback(dev, port, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(ctrl & PORT_AUTO_NEG_DISABLE))
|
||||
*val |= BMCR_ANENABLE;
|
||||
}
|
||||
|
|
@ -1001,8 +1056,7 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)
|
|||
|
||||
restart = 0;
|
||||
restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART |
|
||||
PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX |
|
||||
PORT_PHY_LOOPBACK;
|
||||
PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX;
|
||||
|
||||
if (val & KSZ886X_BMCR_DISABLE_LED)
|
||||
restart |= PORT_LED_OFF;
|
||||
|
|
@ -1022,8 +1076,16 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)
|
|||
if (val & KSZ886X_BMCR_FORCE_MDI)
|
||||
restart |= PORT_FORCE_MDIX;
|
||||
|
||||
if (val & BMCR_LOOPBACK)
|
||||
restart |= PORT_PHY_LOOPBACK;
|
||||
if (ksz_is_ksz88x3(dev)) {
|
||||
restart_mask |= KSZ8873_PORT_PHY_LOOPBACK;
|
||||
|
||||
if (val & BMCR_LOOPBACK)
|
||||
restart |= KSZ8873_PORT_PHY_LOOPBACK;
|
||||
} else {
|
||||
ret = ksz879x_set_loopback(dev, port, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask,
|
||||
restart);
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@
|
|||
#define PORT_AUTO_MDIX_DISABLE BIT(2)
|
||||
#define PORT_FORCE_MDIX BIT(1)
|
||||
#define PORT_MAC_LOOPBACK BIT(0)
|
||||
#define KSZ8873_PORT_PHY_LOOPBACK BIT(0)
|
||||
|
||||
#define REG_PORT_1_STATUS_2 0x1E
|
||||
#define REG_PORT_2_STATUS_2 0x2E
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user