phy_link_topology.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Infrastructure to handle all PHY devices connected to a given netdev,
  4. * either directly or indirectly attached.
  5. *
  6. * Copyright (c) 2023 Maxime Chevallier<maxime.chevallier@bootlin.com>
  7. */
  8. #include <linux/phy_link_topology.h>
  9. #include <linux/phy.h>
  10. #include <linux/rtnetlink.h>
  11. #include <linux/xarray.h>
  12. static int netdev_alloc_phy_link_topology(struct net_device *dev)
  13. {
  14. struct phy_link_topology *topo;
  15. topo = kzalloc_obj(*topo);
  16. if (!topo)
  17. return -ENOMEM;
  18. xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1);
  19. topo->next_phy_index = 1;
  20. dev->link_topo = topo;
  21. return 0;
  22. }
  23. int phy_link_topo_add_phy(struct net_device *dev,
  24. struct phy_device *phy,
  25. enum phy_upstream upt, void *upstream)
  26. {
  27. struct phy_link_topology *topo = dev->link_topo;
  28. struct phy_device_node *pdn;
  29. int ret;
  30. if (!topo) {
  31. ret = netdev_alloc_phy_link_topology(dev);
  32. if (ret)
  33. return ret;
  34. topo = dev->link_topo;
  35. }
  36. pdn = kzalloc_obj(*pdn);
  37. if (!pdn)
  38. return -ENOMEM;
  39. pdn->phy = phy;
  40. switch (upt) {
  41. case PHY_UPSTREAM_MAC:
  42. pdn->upstream.netdev = (struct net_device *)upstream;
  43. if (phy_on_sfp(phy))
  44. pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus;
  45. break;
  46. case PHY_UPSTREAM_PHY:
  47. pdn->upstream.phydev = (struct phy_device *)upstream;
  48. if (phy_on_sfp(phy))
  49. pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus;
  50. break;
  51. default:
  52. ret = -EINVAL;
  53. goto err;
  54. }
  55. pdn->upstream_type = upt;
  56. /* Attempt to re-use a previously allocated phy_index */
  57. if (phy->phyindex)
  58. ret = xa_insert(&topo->phys, phy->phyindex, pdn, GFP_KERNEL);
  59. else
  60. ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn,
  61. xa_limit_32b, &topo->next_phy_index,
  62. GFP_KERNEL);
  63. if (ret < 0)
  64. goto err;
  65. return 0;
  66. err:
  67. kfree(pdn);
  68. return ret;
  69. }
  70. EXPORT_SYMBOL_GPL(phy_link_topo_add_phy);
  71. void phy_link_topo_del_phy(struct net_device *dev,
  72. struct phy_device *phy)
  73. {
  74. struct phy_link_topology *topo = dev->link_topo;
  75. struct phy_device_node *pdn;
  76. if (!topo)
  77. return;
  78. pdn = xa_erase(&topo->phys, phy->phyindex);
  79. /* We delete the PHY from the topology, however we don't re-set the
  80. * phy->phyindex field. If the PHY isn't gone, we can re-assign it the
  81. * same index next time it's added back to the topology
  82. */
  83. kfree(pdn);
  84. }
  85. EXPORT_SYMBOL_GPL(phy_link_topo_del_phy);