735-v5.14-18-net-dsa-qca8k-dsa-qca8k-protect-MASTER-busy_wait-wit.patch 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. From 60df02b6ea4581d72eb7a3ab7204504a54059b72 Mon Sep 17 00:00:00 2001
  2. From: Ansuel Smith <[email protected]>
  3. Date: Fri, 14 May 2021 23:00:08 +0200
  4. Subject: [PATCH] net: dsa: qca8k: dsa: qca8k: protect MASTER busy_wait with
  5. mdio mutex
  6. MDIO_MASTER operation have a dedicated busy wait that is not protected
  7. by the mdio mutex. This can cause situation where the MASTER operation
  8. is done and a normal operation is executed between the MASTER read/write
  9. and the MASTER busy_wait. Rework the qca8k_mdio_read/write function to
  10. address this issue by binding the lock for the whole MASTER operation
  11. and not only the mdio read/write common operation.
  12. Signed-off-by: Ansuel Smith <[email protected]>
  13. Reviewed-by: Andrew Lunn <[email protected]>
  14. Signed-off-by: David S. Miller <[email protected]>
  15. ---
  16. drivers/net/dsa/qca8k.c | 68 +++++++++++++++++++++++++++++++++--------
  17. 1 file changed, 55 insertions(+), 13 deletions(-)
  18. --- a/drivers/net/dsa/qca8k.c
  19. +++ b/drivers/net/dsa/qca8k.c
  20. @@ -628,8 +628,31 @@ qca8k_port_to_phy(int port)
  21. }
  22. static int
  23. +qca8k_mdio_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
  24. +{
  25. + u16 r1, r2, page;
  26. + u32 val;
  27. + int ret;
  28. +
  29. + qca8k_split_addr(reg, &r1, &r2, &page);
  30. +
  31. + ret = read_poll_timeout(qca8k_mii_read32, val, !(val & mask), 0,
  32. + QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
  33. + priv->bus, 0x10 | r2, r1);
  34. +
  35. + /* Check if qca8k_read has failed for a different reason
  36. + * before returnting -ETIMEDOUT
  37. + */
  38. + if (ret < 0 && val < 0)
  39. + return val;
  40. +
  41. + return ret;
  42. +}
  43. +
  44. +static int
  45. qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
  46. {
  47. + u16 r1, r2, page;
  48. u32 phy, val;
  49. int ret;
  50. @@ -645,12 +668,21 @@ qca8k_mdio_write(struct qca8k_priv *priv
  51. QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
  52. QCA8K_MDIO_MASTER_DATA(data);
  53. - ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
  54. + qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
  55. +
  56. + mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
  57. +
  58. + ret = qca8k_set_page(priv->bus, page);
  59. if (ret)
  60. - return ret;
  61. + goto exit;
  62. +
  63. + qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
  64. - ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
  65. - QCA8K_MDIO_MASTER_BUSY);
  66. + ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
  67. + QCA8K_MDIO_MASTER_BUSY);
  68. +
  69. +exit:
  70. + mutex_unlock(&priv->bus->mdio_lock);
  71. /* even if the busy_wait timeouts try to clear the MASTER_EN */
  72. qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
  73. @@ -662,6 +694,7 @@ qca8k_mdio_write(struct qca8k_priv *priv
  74. static int
  75. qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
  76. {
  77. + u16 r1, r2, page;
  78. u32 phy, val;
  79. int ret;
  80. @@ -676,21 +709,30 @@ qca8k_mdio_read(struct qca8k_priv *priv,
  81. QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
  82. QCA8K_MDIO_MASTER_REG_ADDR(regnum);
  83. - ret = qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
  84. - if (ret)
  85. - return ret;
  86. + qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
  87. +
  88. + mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
  89. - ret = qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
  90. - QCA8K_MDIO_MASTER_BUSY);
  91. + ret = qca8k_set_page(priv->bus, page);
  92. if (ret)
  93. - return ret;
  94. + goto exit;
  95. - val = qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL);
  96. - if (val < 0)
  97. - return val;
  98. + qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
  99. +
  100. + ret = qca8k_mdio_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
  101. + QCA8K_MDIO_MASTER_BUSY);
  102. + if (ret)
  103. + goto exit;
  104. + val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
  105. val &= QCA8K_MDIO_MASTER_DATA_MASK;
  106. +exit:
  107. + mutex_unlock(&priv->bus->mdio_lock);
  108. +
  109. + if (val >= 0)
  110. + val &= QCA8K_MDIO_MASTER_DATA_MASK;
  111. +
  112. /* even if the busy_wait timeouts try to clear the MASTER_EN */
  113. qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
  114. QCA8K_MDIO_MASTER_EN);