Merge branch 'net-dsa-mt7530-fix-remaining-swallowed-mdio-access-errors'

Daniel Golle says:

====================
net: dsa: mt7530: fix remaining swallowed MDIO access errors

The original series, "net: dsa: mt7530: fix swallowed MDIO read
errors", landed on net as its v1 [1] just before its v2 [2] was sent.
This series started from the fixes in that original v2 which its v1
had not already carried: the two standalone patches that original v2
grew from the Sashiko AI review of its v1 (the mtk-lynxi read check
and the regmap IRQ serialization), plus, split into patches of their
own, the companion fixes original v2 had folded into the
already-applied patches -- the unchecked bus->read() in core_rmw() and
the unchecked PHY_IAC command writes in the MT7531 indirect PHY access
functions.

The Sashiko AI review of this series' own v1 [3] then flagged two more
swallowed MDIO errors of the same kind, added here as patches of their
own: the unchecked CORE_PLL_GROUP4 read-modify-write in mt7531_setup(),
and the unchecked ATC/VTCR command-register writes in mt7530_fdb_cmd()
and mt7530_vlan_cmd().

The remaining non-fix changes from the original v2, dropping a
redundant read-back and improving the poll failure messages, will
follow via net-next.

[1] https://lore.kernel.org/netdev/cover.1785213071.git.daniel@makrotopia.org/
[2] https://lore.kernel.org/netdev/cover.1785368701.git.daniel@makrotopia.org/
[3] https://lore.kernel.org/netdev/cover.1785427248.git.daniel@makrotopia.org/
====================

Link: https://patch.msgid.link/cover.1785811140.git.daniel@makrotopia.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-07 16:37:50 -07:00
2 changed files with 75 additions and 18 deletions

View File

@@ -124,8 +124,12 @@ core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
goto err;
/* Read the content of the MMD's selected register */
val = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
ret = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MII_MMD_DATA);
if (ret < 0)
goto err;
val = ret;
val &= ~mask;
val |= set;
/* Write the data into MMD's selected register */
@@ -181,14 +185,18 @@ mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
return val;
}
static void
static int
mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
{
int ret;
mt7530_mutex_lock(priv);
mt7530_mii_write(priv, reg, val);
ret = mt7530_mii_write(priv, reg, val);
mt7530_mutex_unlock(priv);
return ret;
}
static u32
@@ -245,7 +253,9 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
/* Set the command operating upon the MAC address entries */
val = ATC_BUSY | ATC_MAT(0) | cmd;
mt7530_write(priv, MT7530_ATC, val);
ret = mt7530_write(priv, MT7530_ATC, val);
if (ret)
return ret;
mt7530_mutex_lock(priv);
@@ -561,7 +571,9 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -572,7 +584,9 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad);
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -606,7 +620,9 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -617,7 +633,9 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -650,7 +668,9 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum);
mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -685,7 +705,9 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
if (ret < 0)
goto out;
ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
@@ -1616,7 +1638,9 @@ mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
int ret;
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
mt7530_write(priv, MT7530_VTCR, val);
ret = mt7530_write(priv, MT7530_VTCR, val);
if (ret)
return ret;
mt7530_mutex_lock(priv);
@@ -2295,6 +2319,21 @@ static const struct regmap_irq mt7530_irqs[] = {
REGMAP_IRQ_REG_LINE(31, 32), /* ACL */
};
/* Serialize regmap-irq's mask sync like every other regmap user */
static int mt7530_irq_mask_sync(int index, unsigned int mask_buf_def,
unsigned int mask_buf, void *irq_drv_data)
{
struct mt7530_priv *priv = irq_drv_data;
int ret;
mt7530_mutex_lock(priv);
ret = regmap_update_bits(priv->regmap, MT7530_SYS_INT_EN,
mask_buf_def, ~mask_buf);
mt7530_mutex_unlock(priv);
return ret;
}
static const struct regmap_irq_chip mt7530_regmap_irq_chip = {
.name = KBUILD_MODNAME,
.status_base = MT7530_SYS_INT_STS,
@@ -2304,12 +2343,14 @@ static const struct regmap_irq_chip mt7530_regmap_irq_chip = {
.irqs = mt7530_irqs,
.num_irqs = ARRAY_SIZE(mt7530_irqs),
.num_regs = 1,
.handle_mask_sync = mt7530_irq_mask_sync,
};
static int
mt7530_setup_irq(struct mt7530_priv *priv)
{
struct regmap_irq_chip_data *irq_data;
struct regmap_irq_chip *chip;
struct device *dev = priv->dev;
struct device_node *np = dev->of_node;
int irq, ret;
@@ -2329,10 +2370,17 @@ mt7530_setup_irq(struct mt7530_priv *priv)
if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
chip = devm_kmemdup(dev, &mt7530_regmap_irq_chip, sizeof(*chip),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->irq_drv_data = priv;
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
priv->regmap, irq,
IRQF_ONESHOT,
0, &mt7530_regmap_irq_chip,
0, chip,
&irq_data);
if (ret)
return ret;
@@ -2765,14 +2813,20 @@ mt7531_setup(struct dsa_switch *ds)
* phy_[read,write]_mmd_indirect is called, we provide our own
* mt7531_ind_mmd_phy_[read,write] to complete this function.
*/
val = mt7531_ind_c45_phy_read(priv,
ret = mt7531_ind_c45_phy_read(priv,
MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MDIO_MMD_VEND2, CORE_PLL_GROUP4);
if (ret < 0)
return ret;
val = ret;
val |= MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE;
val &= ~MT7531_PHY_PLL_OFF;
mt7531_ind_c45_phy_write(priv,
MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
ret = mt7531_ind_c45_phy_write(priv,
MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
if (ret < 0)
return ret;
/* Disable EEE advertisement on the switch PHYs. */
for (i = MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr);

View File

@@ -113,8 +113,11 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
unsigned int bm, adv;
/* Read the BMSR and LPA */
regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
if (regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm) ||
regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv)) {
state->link = false;
return;
}
phylink_mii_c22_pcs_decode_state(state, neg_mode,
FIELD_GET(SGMII_BMSR, bm),