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/netdevice.h> 11 #include <linux/phy.h> 12 #include <linux/rtnetlink.h> 13 #include <linux/xarray.h> 14 15 int phy_link_topo_add_phy(struct phy_link_topology *topo, 16 struct phy_device *phy, 17 enum phy_upstream upt, void *upstream) 18 { 19 struct phy_device_node *pdn; 20 int ret; 21 22 pdn = kzalloc(sizeof(*pdn), GFP_KERNEL); 23 if (!pdn) 24 return -ENOMEM; 25 26 pdn->phy = phy; 27 switch (upt) { 28 case PHY_UPSTREAM_MAC: 29 pdn->upstream.netdev = (struct net_device *)upstream; 30 if (phy_on_sfp(phy)) 31 pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus; 32 break; 33 case PHY_UPSTREAM_PHY: 34 pdn->upstream.phydev = (struct phy_device *)upstream; 35 if (phy_on_sfp(phy)) 36 pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus; 37 break; 38 default: 39 ret = -EINVAL; 40 goto err; 41 } 42 pdn->upstream_type = upt; 43 44 ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn, xa_limit_32b, 45 &topo->next_phy_index, GFP_KERNEL); 46 if (ret) 47 goto err; 48 49 return 0; 50 51 err: 52 kfree(pdn); 53 return ret; 54 } 55 EXPORT_SYMBOL_GPL(phy_link_topo_add_phy); 56 57 void phy_link_topo_del_phy(struct phy_link_topology *topo, 58 struct phy_device *phy) 59 { 60 struct phy_device_node *pdn = xa_erase(&topo->phys, phy->phyindex); 61 62 phy->phyindex = 0; 63 64 kfree(pdn); 65 } 66 EXPORT_SYMBOL_GPL(phy_link_topo_del_phy); 67