Merge branch 'dsa-realtek-phy-read-corruption'
Alvin Šipraga says: ==================== net: dsa: realtek: fix PHY register read corruption These two patches fix the issue reported by Arınç where PHY register reads sometimes return garbage data. v1 -> v2: - no code changes - just update the commit message of patch 2 to reflect the conclusion of further investigation requested by Vladimir ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4767b7e2ed
@ -98,6 +98,20 @@ out_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void realtek_mdio_lock(void *ctx)
|
||||
{
|
||||
struct realtek_priv *priv = ctx;
|
||||
|
||||
mutex_lock(&priv->map_lock);
|
||||
}
|
||||
|
||||
static void realtek_mdio_unlock(void *ctx)
|
||||
{
|
||||
struct realtek_priv *priv = ctx;
|
||||
|
||||
mutex_unlock(&priv->map_lock);
|
||||
}
|
||||
|
||||
static const struct regmap_config realtek_mdio_regmap_config = {
|
||||
.reg_bits = 10, /* A4..A0 R4..R0 */
|
||||
.val_bits = 16,
|
||||
@ -108,6 +122,21 @@ static const struct regmap_config realtek_mdio_regmap_config = {
|
||||
.reg_read = realtek_mdio_read,
|
||||
.reg_write = realtek_mdio_write,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.lock = realtek_mdio_lock,
|
||||
.unlock = realtek_mdio_unlock,
|
||||
};
|
||||
|
||||
static const struct regmap_config realtek_mdio_nolock_regmap_config = {
|
||||
.reg_bits = 10, /* A4..A0 R4..R0 */
|
||||
.val_bits = 16,
|
||||
.reg_stride = 1,
|
||||
/* PHY regs are at 0x8000 */
|
||||
.max_register = 0xffff,
|
||||
.reg_format_endian = REGMAP_ENDIAN_BIG,
|
||||
.reg_read = realtek_mdio_read,
|
||||
.reg_write = realtek_mdio_write,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.disable_locking = true,
|
||||
};
|
||||
|
||||
static int realtek_mdio_probe(struct mdio_device *mdiodev)
|
||||
@ -115,8 +144,9 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
|
||||
struct realtek_priv *priv;
|
||||
struct device *dev = &mdiodev->dev;
|
||||
const struct realtek_variant *var;
|
||||
int ret;
|
||||
struct regmap_config rc;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
var = of_device_get_match_data(dev);
|
||||
if (!var)
|
||||
@ -126,13 +156,25 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->map = devm_regmap_init(dev, NULL, priv, &realtek_mdio_regmap_config);
|
||||
mutex_init(&priv->map_lock);
|
||||
|
||||
rc = realtek_mdio_regmap_config;
|
||||
rc.lock_arg = priv;
|
||||
priv->map = devm_regmap_init(dev, NULL, priv, &rc);
|
||||
if (IS_ERR(priv->map)) {
|
||||
ret = PTR_ERR(priv->map);
|
||||
dev_err(dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rc = realtek_mdio_nolock_regmap_config;
|
||||
priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
|
||||
if (IS_ERR(priv->map_nolock)) {
|
||||
ret = PTR_ERR(priv->map_nolock);
|
||||
dev_err(dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->mdio_addr = mdiodev->addr;
|
||||
priv->bus = mdiodev->bus;
|
||||
priv->dev = &mdiodev->dev;
|
||||
|
@ -311,7 +311,21 @@ static int realtek_smi_read(void *ctx, u32 reg, u32 *val)
|
||||
return realtek_smi_read_reg(priv, reg, val);
|
||||
}
|
||||
|
||||
static const struct regmap_config realtek_smi_mdio_regmap_config = {
|
||||
static void realtek_smi_lock(void *ctx)
|
||||
{
|
||||
struct realtek_priv *priv = ctx;
|
||||
|
||||
mutex_lock(&priv->map_lock);
|
||||
}
|
||||
|
||||
static void realtek_smi_unlock(void *ctx)
|
||||
{
|
||||
struct realtek_priv *priv = ctx;
|
||||
|
||||
mutex_unlock(&priv->map_lock);
|
||||
}
|
||||
|
||||
static const struct regmap_config realtek_smi_regmap_config = {
|
||||
.reg_bits = 10, /* A4..A0 R4..R0 */
|
||||
.val_bits = 16,
|
||||
.reg_stride = 1,
|
||||
@ -321,6 +335,21 @@ static const struct regmap_config realtek_smi_mdio_regmap_config = {
|
||||
.reg_read = realtek_smi_read,
|
||||
.reg_write = realtek_smi_write,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.lock = realtek_smi_lock,
|
||||
.unlock = realtek_smi_unlock,
|
||||
};
|
||||
|
||||
static const struct regmap_config realtek_smi_nolock_regmap_config = {
|
||||
.reg_bits = 10, /* A4..A0 R4..R0 */
|
||||
.val_bits = 16,
|
||||
.reg_stride = 1,
|
||||
/* PHY regs are at 0x8000 */
|
||||
.max_register = 0xffff,
|
||||
.reg_format_endian = REGMAP_ENDIAN_BIG,
|
||||
.reg_read = realtek_smi_read,
|
||||
.reg_write = realtek_smi_write,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.disable_locking = true,
|
||||
};
|
||||
|
||||
static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
@ -385,6 +414,7 @@ static int realtek_smi_probe(struct platform_device *pdev)
|
||||
const struct realtek_variant *var;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct realtek_priv *priv;
|
||||
struct regmap_config rc;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
@ -395,14 +425,26 @@ static int realtek_smi_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
priv->chip_data = (void *)priv + sizeof(*priv);
|
||||
priv->map = devm_regmap_init(dev, NULL, priv,
|
||||
&realtek_smi_mdio_regmap_config);
|
||||
|
||||
mutex_init(&priv->map_lock);
|
||||
|
||||
rc = realtek_smi_regmap_config;
|
||||
rc.lock_arg = priv;
|
||||
priv->map = devm_regmap_init(dev, NULL, priv, &rc);
|
||||
if (IS_ERR(priv->map)) {
|
||||
ret = PTR_ERR(priv->map);
|
||||
dev_err(dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rc = realtek_smi_nolock_regmap_config;
|
||||
priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
|
||||
if (IS_ERR(priv->map_nolock)) {
|
||||
ret = PTR_ERR(priv->map_nolock);
|
||||
dev_err(dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Link forward and backward */
|
||||
priv->dev = dev;
|
||||
priv->clk_delay = var->clk_delay;
|
||||
|
@ -52,6 +52,8 @@ struct realtek_priv {
|
||||
struct gpio_desc *mdc;
|
||||
struct gpio_desc *mdio;
|
||||
struct regmap *map;
|
||||
struct regmap *map_nolock;
|
||||
struct mutex map_lock;
|
||||
struct mii_bus *slave_mii_bus;
|
||||
struct mii_bus *bus;
|
||||
int mdio_addr;
|
||||
|
@ -590,7 +590,7 @@ static int rtl8365mb_phy_poll_busy(struct realtek_priv *priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return regmap_read_poll_timeout(priv->map,
|
||||
return regmap_read_poll_timeout(priv->map_nolock,
|
||||
RTL8365MB_INDIRECT_ACCESS_STATUS_REG,
|
||||
val, !val, 10, 100);
|
||||
}
|
||||
@ -604,7 +604,7 @@ static int rtl8365mb_phy_ocp_prepare(struct realtek_priv *priv, int phy,
|
||||
/* Set OCP prefix */
|
||||
val = FIELD_GET(RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK, ocp_addr);
|
||||
ret = regmap_update_bits(
|
||||
priv->map, RTL8365MB_GPHY_OCP_MSB_0_REG,
|
||||
priv->map_nolock, RTL8365MB_GPHY_OCP_MSB_0_REG,
|
||||
RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK,
|
||||
FIELD_PREP(RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, val));
|
||||
if (ret)
|
||||
@ -617,8 +617,8 @@ static int rtl8365mb_phy_ocp_prepare(struct realtek_priv *priv, int phy,
|
||||
ocp_addr >> 1);
|
||||
val |= FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK,
|
||||
ocp_addr >> 6);
|
||||
ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG,
|
||||
val);
|
||||
ret = regmap_write(priv->map_nolock,
|
||||
RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -631,36 +631,42 @@ static int rtl8365mb_phy_ocp_read(struct realtek_priv *priv, int phy,
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->map_lock);
|
||||
|
||||
ret = rtl8365mb_phy_poll_busy(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/* Execute read operation */
|
||||
val = FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK,
|
||||
RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) |
|
||||
FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK,
|
||||
RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ);
|
||||
ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val);
|
||||
ret = regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG,
|
||||
val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = rtl8365mb_phy_poll_busy(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/* Get PHY register data */
|
||||
ret = regmap_read(priv->map, RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG,
|
||||
&val);
|
||||
ret = regmap_read(priv->map_nolock,
|
||||
RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
*data = val & 0xFFFF;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
mutex_unlock(&priv->map_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy,
|
||||
@ -669,32 +675,38 @@ static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy,
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->map_lock);
|
||||
|
||||
ret = rtl8365mb_phy_poll_busy(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/* Set PHY register data */
|
||||
ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG,
|
||||
data);
|
||||
ret = regmap_write(priv->map_nolock,
|
||||
RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/* Execute write operation */
|
||||
val = FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK,
|
||||
RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) |
|
||||
FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK,
|
||||
RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE);
|
||||
ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val);
|
||||
ret = regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG,
|
||||
val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = rtl8365mb_phy_poll_busy(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->map_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user