701-v6.2-0010-net-dpaa2-eth-serialize-changes-to-priv-mac-with-a-m.patch 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. From 5e448a17dfa2e95166534df7f677a3694ef6187d Mon Sep 17 00:00:00 2001
  2. From: Vladimir Oltean <[email protected]>
  3. Date: Tue, 29 Nov 2022 16:12:19 +0200
  4. Subject: [PATCH 12/14] net: dpaa2-eth: serialize changes to priv->mac with a
  5. mutex
  6. The dpaa2 architecture permits dynamic connections between objects on
  7. the fsl-mc bus, specifically between a DPNI object (represented by a
  8. struct net_device) and a DPMAC object (represented by a struct phylink).
  9. The DPNI driver is notified when those connections are created/broken
  10. through the dpni_irq0_handler_thread() method. To ensure that ethtool
  11. operations, as well as netdev up/down operations serialize with the
  12. connection/disconnection of the DPNI with a DPMAC,
  13. dpni_irq0_handler_thread() takes the rtnl_lock() to block those other
  14. operations from taking place.
  15. There is code called by dpaa2_mac_connect() which wants to acquire the
  16. rtnl_mutex once again, see phylink_create() -> phylink_register_sfp() ->
  17. sfp_bus_add_upstream() -> rtnl_lock(). So the strategy doesn't quite
  18. work out, even though it's fairly simple.
  19. Create a different strategy, where all code paths in the dpaa2-eth
  20. driver access priv->mac only while they are holding priv->mac_lock.
  21. The phylink instance is not created or connected to the PHY under the
  22. priv->mac_lock, but only assigned to priv->mac then. This will eliminate
  23. the reliance on the rtnl_mutex.
  24. Add lockdep annotations and put comments where holding the lock is not
  25. necessary, and priv->mac can be dereferenced freely.
  26. Signed-off-by: Vladimir Oltean <[email protected]>
  27. Reviewed-by: Ioana Ciornei <[email protected]>
  28. Tested-by: Ioana Ciornei <[email protected]>
  29. Signed-off-by: Paolo Abeni <[email protected]>
  30. ---
  31. .../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 43 ++++++++++++--
  32. .../net/ethernet/freescale/dpaa2/dpaa2-eth.h | 6 ++
  33. .../ethernet/freescale/dpaa2/dpaa2-ethtool.c | 58 +++++++++++++++----
  34. 3 files changed, 91 insertions(+), 16 deletions(-)
  35. --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
  36. +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
  37. @@ -2021,8 +2021,11 @@ static int dpaa2_eth_link_state_update(s
  38. /* When we manage the MAC/PHY using phylink there is no need
  39. * to manually update the netif_carrier.
  40. + * We can avoid locking because we are called from the "link changed"
  41. + * IRQ handler, which is the same as the "endpoint changed" IRQ handler
  42. + * (the writer to priv->mac), so we cannot race with it.
  43. */
  44. - if (dpaa2_eth_is_type_phy(priv))
  45. + if (dpaa2_mac_is_type_phy(priv->mac))
  46. goto out;
  47. /* Chech link state; speed / duplex changes are not treated yet */
  48. @@ -2061,6 +2064,8 @@ static int dpaa2_eth_open(struct net_dev
  49. priv->dpbp_dev->obj_desc.id, priv->bpid);
  50. }
  51. + mutex_lock(&priv->mac_lock);
  52. +
  53. if (!dpaa2_eth_is_type_phy(priv)) {
  54. /* We'll only start the txqs when the link is actually ready;
  55. * make sure we don't race against the link up notification,
  56. @@ -2079,6 +2084,7 @@ static int dpaa2_eth_open(struct net_dev
  57. err = dpni_enable(priv->mc_io, 0, priv->mc_token);
  58. if (err < 0) {
  59. + mutex_unlock(&priv->mac_lock);
  60. netdev_err(net_dev, "dpni_enable() failed\n");
  61. goto enable_err;
  62. }
  63. @@ -2086,6 +2092,8 @@ static int dpaa2_eth_open(struct net_dev
  64. if (dpaa2_eth_is_type_phy(priv))
  65. dpaa2_mac_start(priv->mac);
  66. + mutex_unlock(&priv->mac_lock);
  67. +
  68. return 0;
  69. enable_err:
  70. @@ -2157,6 +2165,8 @@ static int dpaa2_eth_stop(struct net_dev
  71. int dpni_enabled = 0;
  72. int retries = 10;
  73. + mutex_lock(&priv->mac_lock);
  74. +
  75. if (dpaa2_eth_is_type_phy(priv)) {
  76. dpaa2_mac_stop(priv->mac);
  77. } else {
  78. @@ -2164,6 +2174,8 @@ static int dpaa2_eth_stop(struct net_dev
  79. netif_carrier_off(net_dev);
  80. }
  81. + mutex_unlock(&priv->mac_lock);
  82. +
  83. /* On dpni_disable(), the MC firmware will:
  84. * - stop MAC Rx and wait for all Rx frames to be enqueued to software
  85. * - cut off WRIOP dequeues from egress FQs and wait until transmission
  86. @@ -2489,12 +2501,20 @@ static int dpaa2_eth_ts_ioctl(struct net
  87. static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  88. {
  89. struct dpaa2_eth_priv *priv = netdev_priv(dev);
  90. + int err;
  91. if (cmd == SIOCSHWTSTAMP)
  92. return dpaa2_eth_ts_ioctl(dev, rq, cmd);
  93. - if (dpaa2_eth_is_type_phy(priv))
  94. - return phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
  95. + mutex_lock(&priv->mac_lock);
  96. +
  97. + if (dpaa2_eth_is_type_phy(priv)) {
  98. + err = phylink_mii_ioctl(priv->mac->phylink, rq, cmd);
  99. + mutex_unlock(&priv->mac_lock);
  100. + return err;
  101. + }
  102. +
  103. + mutex_unlock(&priv->mac_lock);
  104. return -EOPNOTSUPP;
  105. }
  106. @@ -4454,7 +4474,9 @@ static int dpaa2_eth_connect_mac(struct
  107. goto err_close_mac;
  108. }
  109. + mutex_lock(&priv->mac_lock);
  110. priv->mac = mac;
  111. + mutex_unlock(&priv->mac_lock);
  112. return 0;
  113. @@ -4467,9 +4489,12 @@ err_free_mac:
  114. static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
  115. {
  116. - struct dpaa2_mac *mac = priv->mac;
  117. + struct dpaa2_mac *mac;
  118. + mutex_lock(&priv->mac_lock);
  119. + mac = priv->mac;
  120. priv->mac = NULL;
  121. + mutex_unlock(&priv->mac_lock);
  122. if (!mac)
  123. return;
  124. @@ -4488,6 +4513,7 @@ static irqreturn_t dpni_irq0_handler_thr
  125. struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev);
  126. struct net_device *net_dev = dev_get_drvdata(dev);
  127. struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
  128. + bool had_mac;
  129. int err;
  130. err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle,
  131. @@ -4505,7 +4531,12 @@ static irqreturn_t dpni_irq0_handler_thr
  132. dpaa2_eth_update_tx_fqids(priv);
  133. rtnl_lock();
  134. - if (dpaa2_eth_has_mac(priv))
  135. + /* We can avoid locking because the "endpoint changed" IRQ
  136. + * handler is the only one who changes priv->mac at runtime,
  137. + * so we are not racing with anyone.
  138. + */
  139. + had_mac = !!priv->mac;
  140. + if (had_mac)
  141. dpaa2_eth_disconnect_mac(priv);
  142. else
  143. dpaa2_eth_connect_mac(priv);
  144. @@ -4606,6 +4637,8 @@ static int dpaa2_eth_probe(struct fsl_mc
  145. priv = netdev_priv(net_dev);
  146. priv->net_dev = net_dev;
  147. + mutex_init(&priv->mac_lock);
  148. +
  149. priv->iommu_domain = iommu_get_domain_for_dev(dev);
  150. priv->tx_tstamp_type = HWTSTAMP_TX_OFF;
  151. --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
  152. +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
  153. @@ -580,6 +580,8 @@ struct dpaa2_eth_priv {
  154. #endif
  155. struct dpaa2_mac *mac;
  156. + /* Serializes changes to priv->mac */
  157. + struct mutex mac_lock;
  158. struct workqueue_struct *dpaa2_ptp_wq;
  159. struct work_struct tx_onestep_tstamp;
  160. struct sk_buff_head tx_skbs;
  161. @@ -733,11 +735,15 @@ static inline unsigned int dpaa2_eth_rx_
  162. static inline bool dpaa2_eth_is_type_phy(struct dpaa2_eth_priv *priv)
  163. {
  164. + lockdep_assert_held(&priv->mac_lock);
  165. +
  166. return dpaa2_mac_is_type_phy(priv->mac);
  167. }
  168. static inline bool dpaa2_eth_has_mac(struct dpaa2_eth_priv *priv)
  169. {
  170. + lockdep_assert_held(&priv->mac_lock);
  171. +
  172. return priv->mac ? true : false;
  173. }
  174. --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
  175. +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
  176. @@ -86,11 +86,16 @@ static void dpaa2_eth_get_drvinfo(struct
  177. static int dpaa2_eth_nway_reset(struct net_device *net_dev)
  178. {
  179. struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
  180. + int err = -EOPNOTSUPP;
  181. +
  182. + mutex_lock(&priv->mac_lock);
  183. if (dpaa2_eth_is_type_phy(priv))
  184. - return phylink_ethtool_nway_reset(priv->mac->phylink);
  185. + err = phylink_ethtool_nway_reset(priv->mac->phylink);
  186. +
  187. + mutex_unlock(&priv->mac_lock);
  188. - return -EOPNOTSUPP;
  189. + return err;
  190. }
  191. static int
  192. @@ -98,10 +103,18 @@ dpaa2_eth_get_link_ksettings(struct net_
  193. struct ethtool_link_ksettings *link_settings)
  194. {
  195. struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
  196. + int err;
  197. - if (dpaa2_eth_is_type_phy(priv))
  198. - return phylink_ethtool_ksettings_get(priv->mac->phylink,
  199. - link_settings);
  200. + mutex_lock(&priv->mac_lock);
  201. +
  202. + if (dpaa2_eth_is_type_phy(priv)) {
  203. + err = phylink_ethtool_ksettings_get(priv->mac->phylink,
  204. + link_settings);
  205. + mutex_unlock(&priv->mac_lock);
  206. + return err;
  207. + }
  208. +
  209. + mutex_unlock(&priv->mac_lock);
  210. link_settings->base.autoneg = AUTONEG_DISABLE;
  211. if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX))
  212. @@ -116,11 +129,17 @@ dpaa2_eth_set_link_ksettings(struct net_
  213. const struct ethtool_link_ksettings *link_settings)
  214. {
  215. struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
  216. + int err = -EOPNOTSUPP;
  217. - if (!dpaa2_eth_is_type_phy(priv))
  218. - return -EOPNOTSUPP;
  219. + mutex_lock(&priv->mac_lock);
  220. +
  221. + if (dpaa2_eth_is_type_phy(priv))
  222. + err = phylink_ethtool_ksettings_set(priv->mac->phylink,
  223. + link_settings);
  224. - return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings);
  225. + mutex_unlock(&priv->mac_lock);
  226. +
  227. + return err;
  228. }
  229. static void dpaa2_eth_get_pauseparam(struct net_device *net_dev,
  230. @@ -129,11 +148,16 @@ static void dpaa2_eth_get_pauseparam(str
  231. struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
  232. u64 link_options = priv->link_state.options;
  233. + mutex_lock(&priv->mac_lock);
  234. +
  235. if (dpaa2_eth_is_type_phy(priv)) {
  236. phylink_ethtool_get_pauseparam(priv->mac->phylink, pause);
  237. + mutex_unlock(&priv->mac_lock);
  238. return;
  239. }
  240. + mutex_unlock(&priv->mac_lock);
  241. +
  242. pause->rx_pause = dpaa2_eth_rx_pause_enabled(link_options);
  243. pause->tx_pause = dpaa2_eth_tx_pause_enabled(link_options);
  244. pause->autoneg = AUTONEG_DISABLE;
  245. @@ -152,9 +176,17 @@ static int dpaa2_eth_set_pauseparam(stru
  246. return -EOPNOTSUPP;
  247. }
  248. - if (dpaa2_eth_is_type_phy(priv))
  249. - return phylink_ethtool_set_pauseparam(priv->mac->phylink,
  250. - pause);
  251. + mutex_lock(&priv->mac_lock);
  252. +
  253. + if (dpaa2_eth_is_type_phy(priv)) {
  254. + err = phylink_ethtool_set_pauseparam(priv->mac->phylink,
  255. + pause);
  256. + mutex_unlock(&priv->mac_lock);
  257. + return err;
  258. + }
  259. +
  260. + mutex_unlock(&priv->mac_lock);
  261. +
  262. if (pause->autoneg)
  263. return -EOPNOTSUPP;
  264. @@ -307,8 +339,12 @@ static void dpaa2_eth_get_ethtool_stats(
  265. }
  266. *(data + i++) = buf_cnt;
  267. + mutex_lock(&priv->mac_lock);
  268. +
  269. if (dpaa2_eth_has_mac(priv))
  270. dpaa2_mac_get_ethtool_stats(priv->mac, data + i);
  271. +
  272. + mutex_unlock(&priv->mac_lock);
  273. }
  274. static int dpaa2_eth_prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask,