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 9 #include <linux/phy_link_topology.h> 10 #include <linux/phy.h> 11 #include <linux/rtnetlink.h> 12 #include <linux/xarray.h> 13 #include <net/netdev_lock.h> 14 15 static int netdev_alloc_phy_link_topology(struct net_device *dev) 16 { 17 struct phy_link_topology *topo; 18 19 topo = kzalloc_obj(*topo); 20 if (!topo) 21 return -ENOMEM; 22 23 xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1); 24 topo->next_phy_index = 1; 25 26 dev->link_topo = topo; 27 28 return 0; 29 } 30 31 int phy_link_topo_add_phy(struct net_device *dev, 32 struct phy_device *phy, 33 enum phy_upstream upt, void *upstream) 34 { 35 struct phy_link_topology *topo = dev->link_topo; 36 struct phy_device_node *pdn; 37 int ret; 38 39 /* ethtool ops may run without rtnl_lock, and rtnl_lock is what 40 * currently protects the PHY topology. No driver currently mixes 41 * the two, flag if someone tries. See also: 42 * - ethnl_req_get_phydev() 43 * - phy_detach() 44 */ 45 if (WARN_ON_ONCE(netdev_need_ops_lock(dev))) 46 return -EOPNOTSUPP; 47 48 if (!topo) { 49 ret = netdev_alloc_phy_link_topology(dev); 50 if (ret) 51 return ret; 52 53 topo = dev->link_topo; 54 } 55 56 pdn = kzalloc_obj(*pdn); 57 if (!pdn) 58 return -ENOMEM; 59 60 pdn->phy = phy; 61 switch (upt) { 62 case PHY_UPSTREAM_MAC: 63 pdn->upstream.netdev = (struct net_device *)upstream; 64 if (phy_on_sfp(phy)) 65 pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus; 66 break; 67 case PHY_UPSTREAM_PHY: 68 pdn->upstream.phydev = (struct phy_device *)upstream; 69 if (phy_on_sfp(phy)) 70 pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus; 71 break; 72 default: 73 ret = -EINVAL; 74 goto err; 75 } 76 pdn->upstream_type = upt; 77 78 /* Attempt to re-use a previously allocated phy_index */ 79 if (phy->phyindex) 80 ret = xa_insert(&topo->phys, phy->phyindex, pdn, GFP_KERNEL); 81 else 82 ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn, 83 xa_limit_32b, &topo->next_phy_index, 84 GFP_KERNEL); 85 86 if (ret < 0) 87 goto err; 88 89 return 0; 90 91 err: 92 kfree(pdn); 93 return ret; 94 } 95 EXPORT_SYMBOL_GPL(phy_link_topo_add_phy); 96 97 void phy_link_topo_del_phy(struct net_device *dev, 98 struct phy_device *phy) 99 { 100 struct phy_link_topology *topo = dev->link_topo; 101 struct phy_device_node *pdn; 102 103 if (!topo) 104 return; 105 106 pdn = xa_erase(&topo->phys, phy->phyindex); 107 108 /* We delete the PHY from the topology, however we don't re-set the 109 * phy->phyindex field. If the PHY isn't gone, we can re-assign it the 110 * same index next time it's added back to the topology 111 */ 112 113 kfree(pdn); 114 } 115 EXPORT_SYMBOL_GPL(phy_link_topo_del_phy); 116