Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+124 -26
+44 -2
drivers/net/dsa/realtek/realtek-mdio.c
··· 98 98 return ret; 99 99 } 100 100 101 + static void realtek_mdio_lock(void *ctx) 102 + { 103 + struct realtek_priv *priv = ctx; 104 + 105 + mutex_lock(&priv->map_lock); 106 + } 107 + 108 + static void realtek_mdio_unlock(void *ctx) 109 + { 110 + struct realtek_priv *priv = ctx; 111 + 112 + mutex_unlock(&priv->map_lock); 113 + } 114 + 101 115 static const struct regmap_config realtek_mdio_regmap_config = { 102 116 .reg_bits = 10, /* A4..A0 R4..R0 */ 103 117 .val_bits = 16, ··· 122 108 .reg_read = realtek_mdio_read, 123 109 .reg_write = realtek_mdio_write, 124 110 .cache_type = REGCACHE_NONE, 111 + .lock = realtek_mdio_lock, 112 + .unlock = realtek_mdio_unlock, 113 + }; 114 + 115 + static const struct regmap_config realtek_mdio_nolock_regmap_config = { 116 + .reg_bits = 10, /* A4..A0 R4..R0 */ 117 + .val_bits = 16, 118 + .reg_stride = 1, 119 + /* PHY regs are at 0x8000 */ 120 + .max_register = 0xffff, 121 + .reg_format_endian = REGMAP_ENDIAN_BIG, 122 + .reg_read = realtek_mdio_read, 123 + .reg_write = realtek_mdio_write, 124 + .cache_type = REGCACHE_NONE, 125 + .disable_locking = true, 125 126 }; 126 127 127 128 static int realtek_mdio_probe(struct mdio_device *mdiodev) ··· 144 115 struct realtek_priv *priv; 145 116 struct device *dev = &mdiodev->dev; 146 117 const struct realtek_variant *var; 147 - int ret; 118 + struct regmap_config rc; 148 119 struct device_node *np; 120 + int ret; 149 121 150 122 var = of_device_get_match_data(dev); 151 123 if (!var) ··· 156 126 if (!priv) 157 127 return -ENOMEM; 158 128 159 - priv->map = devm_regmap_init(dev, NULL, priv, &realtek_mdio_regmap_config); 129 + mutex_init(&priv->map_lock); 130 + 131 + rc = realtek_mdio_regmap_config; 132 + rc.lock_arg = priv; 133 + priv->map = devm_regmap_init(dev, NULL, priv, &rc); 160 134 if (IS_ERR(priv->map)) { 161 135 ret = PTR_ERR(priv->map); 136 + dev_err(dev, "regmap init failed: %d\n", ret); 137 + return ret; 138 + } 139 + 140 + rc = realtek_mdio_nolock_regmap_config; 141 + priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); 142 + if (IS_ERR(priv->map_nolock)) { 143 + ret = PTR_ERR(priv->map_nolock); 162 144 dev_err(dev, "regmap init failed: %d\n", ret); 163 145 return ret; 164 146 }
+45 -3
drivers/net/dsa/realtek/realtek-smi.c
··· 311 311 return realtek_smi_read_reg(priv, reg, val); 312 312 } 313 313 314 - static const struct regmap_config realtek_smi_mdio_regmap_config = { 314 + static void realtek_smi_lock(void *ctx) 315 + { 316 + struct realtek_priv *priv = ctx; 317 + 318 + mutex_lock(&priv->map_lock); 319 + } 320 + 321 + static void realtek_smi_unlock(void *ctx) 322 + { 323 + struct realtek_priv *priv = ctx; 324 + 325 + mutex_unlock(&priv->map_lock); 326 + } 327 + 328 + static const struct regmap_config realtek_smi_regmap_config = { 315 329 .reg_bits = 10, /* A4..A0 R4..R0 */ 316 330 .val_bits = 16, 317 331 .reg_stride = 1, ··· 335 321 .reg_read = realtek_smi_read, 336 322 .reg_write = realtek_smi_write, 337 323 .cache_type = REGCACHE_NONE, 324 + .lock = realtek_smi_lock, 325 + .unlock = realtek_smi_unlock, 326 + }; 327 + 328 + static const struct regmap_config realtek_smi_nolock_regmap_config = { 329 + .reg_bits = 10, /* A4..A0 R4..R0 */ 330 + .val_bits = 16, 331 + .reg_stride = 1, 332 + /* PHY regs are at 0x8000 */ 333 + .max_register = 0xffff, 334 + .reg_format_endian = REGMAP_ENDIAN_BIG, 335 + .reg_read = realtek_smi_read, 336 + .reg_write = realtek_smi_write, 337 + .cache_type = REGCACHE_NONE, 338 + .disable_locking = true, 338 339 }; 339 340 340 341 static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) ··· 414 385 const struct realtek_variant *var; 415 386 struct device *dev = &pdev->dev; 416 387 struct realtek_priv *priv; 388 + struct regmap_config rc; 417 389 struct device_node *np; 418 390 int ret; 419 391 ··· 425 395 if (!priv) 426 396 return -ENOMEM; 427 397 priv->chip_data = (void *)priv + sizeof(*priv); 428 - priv->map = devm_regmap_init(dev, NULL, priv, 429 - &realtek_smi_mdio_regmap_config); 398 + 399 + mutex_init(&priv->map_lock); 400 + 401 + rc = realtek_smi_regmap_config; 402 + rc.lock_arg = priv; 403 + priv->map = devm_regmap_init(dev, NULL, priv, &rc); 430 404 if (IS_ERR(priv->map)) { 431 405 ret = PTR_ERR(priv->map); 406 + dev_err(dev, "regmap init failed: %d\n", ret); 407 + return ret; 408 + } 409 + 410 + rc = realtek_smi_nolock_regmap_config; 411 + priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); 412 + if (IS_ERR(priv->map_nolock)) { 413 + ret = PTR_ERR(priv->map_nolock); 432 414 dev_err(dev, "regmap init failed: %d\n", ret); 433 415 return ret; 434 416 }
+2
drivers/net/dsa/realtek/realtek.h
··· 52 52 struct gpio_desc *mdc; 53 53 struct gpio_desc *mdio; 54 54 struct regmap *map; 55 + struct regmap *map_nolock; 56 + struct mutex map_lock; 55 57 struct mii_bus *slave_mii_bus; 56 58 struct mii_bus *bus; 57 59 int mdio_addr;
+33 -21
drivers/net/dsa/realtek/rtl8365mb.c
··· 590 590 { 591 591 u32 val; 592 592 593 - return regmap_read_poll_timeout(priv->map, 593 + return regmap_read_poll_timeout(priv->map_nolock, 594 594 RTL8365MB_INDIRECT_ACCESS_STATUS_REG, 595 595 val, !val, 10, 100); 596 596 } ··· 604 604 /* Set OCP prefix */ 605 605 val = FIELD_GET(RTL8365MB_PHY_OCP_ADDR_PREFIX_MASK, ocp_addr); 606 606 ret = regmap_update_bits( 607 - priv->map, RTL8365MB_GPHY_OCP_MSB_0_REG, 607 + priv->map_nolock, RTL8365MB_GPHY_OCP_MSB_0_REG, 608 608 RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, 609 609 FIELD_PREP(RTL8365MB_GPHY_OCP_MSB_0_CFG_CPU_OCPADR_MASK, val)); 610 610 if (ret) ··· 617 617 ocp_addr >> 1); 618 618 val |= FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_ADDRESS_OCPADR_9_6_MASK, 619 619 ocp_addr >> 6); 620 - ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, 621 - val); 620 + ret = regmap_write(priv->map_nolock, 621 + RTL8365MB_INDIRECT_ACCESS_ADDRESS_REG, val); 622 622 if (ret) 623 623 return ret; 624 624 ··· 631 631 u32 val; 632 632 int ret; 633 633 634 + mutex_lock(&priv->map_lock); 635 + 634 636 ret = rtl8365mb_phy_poll_busy(priv); 635 637 if (ret) 636 - return ret; 638 + goto out; 637 639 638 640 ret = rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr); 639 641 if (ret) 640 - return ret; 642 + goto out; 641 643 642 644 /* Execute read operation */ 643 645 val = FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, 644 646 RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | 645 647 FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, 646 648 RTL8365MB_INDIRECT_ACCESS_CTRL_RW_READ); 647 - ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); 649 + ret = regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, 650 + val); 648 651 if (ret) 649 - return ret; 652 + goto out; 650 653 651 654 ret = rtl8365mb_phy_poll_busy(priv); 652 655 if (ret) 653 - return ret; 656 + goto out; 654 657 655 658 /* Get PHY register data */ 656 - ret = regmap_read(priv->map, RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, 657 - &val); 659 + ret = regmap_read(priv->map_nolock, 660 + RTL8365MB_INDIRECT_ACCESS_READ_DATA_REG, &val); 658 661 if (ret) 659 - return ret; 662 + goto out; 660 663 661 664 *data = val & 0xFFFF; 662 665 663 - return 0; 666 + out: 667 + mutex_unlock(&priv->map_lock); 668 + 669 + return ret; 664 670 } 665 671 666 672 static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy, ··· 675 669 u32 val; 676 670 int ret; 677 671 672 + mutex_lock(&priv->map_lock); 673 + 678 674 ret = rtl8365mb_phy_poll_busy(priv); 679 675 if (ret) 680 - return ret; 676 + goto out; 681 677 682 678 ret = rtl8365mb_phy_ocp_prepare(priv, phy, ocp_addr); 683 679 if (ret) 684 - return ret; 680 + goto out; 685 681 686 682 /* Set PHY register data */ 687 - ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, 688 - data); 683 + ret = regmap_write(priv->map_nolock, 684 + RTL8365MB_INDIRECT_ACCESS_WRITE_DATA_REG, data); 689 685 if (ret) 690 - return ret; 686 + goto out; 691 687 692 688 /* Execute write operation */ 693 689 val = FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_MASK, 694 690 RTL8365MB_INDIRECT_ACCESS_CTRL_CMD_VALUE) | 695 691 FIELD_PREP(RTL8365MB_INDIRECT_ACCESS_CTRL_RW_MASK, 696 692 RTL8365MB_INDIRECT_ACCESS_CTRL_RW_WRITE); 697 - ret = regmap_write(priv->map, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, val); 693 + ret = regmap_write(priv->map_nolock, RTL8365MB_INDIRECT_ACCESS_CTRL_REG, 694 + val); 698 695 if (ret) 699 - return ret; 696 + goto out; 700 697 701 698 ret = rtl8365mb_phy_poll_busy(priv); 702 699 if (ret) 703 - return ret; 700 + goto out; 701 + 702 + out: 703 + mutex_unlock(&priv->map_lock); 704 704 705 705 return 0; 706 706 }