Skip to content

Commit 267e317

Browse files
committed
Merge branch 'phy-listing-link_topology-tracking'
Maxime Chevallier says: ==================== Introduce PHY listing and link_topology tracking This is V11 for the link topology addition, allowing to track all PHYs that are linked to netdevices. This V11 addresses the various netlink-related issues that were raised by Jakub, and fixes some typos in the documentation. As a remainder, here's what the PHY listings would look like : - eth0 has a 88x3310 acting as media converter, and an SFP module with an embedded 88e1111 PHY - eth2 has a 88e1510 PHY PHY for eth0: PHY index: 1 Driver name: mv88x3310 PHY device name: f212a600.mdio-mii:00 Downstream SFP bus name: sfp-eth0 PHY id: 0 Upstream type: MAC PHY for eth0: PHY index: 2 Driver name: Marvell 88E1111 PHY device name: i2c:sfp-eth0:16 PHY id: 21040322 Upstream type: PHY Upstream PHY index: 1 Upstream SFP name: sfp-eth0 PHY for eth2: PHY index: 1 Driver name: Marvell 88E1510 PHY device name: f212a200.mdio-mii:00 PHY id: 21040593 Upstream type: MAC Ethtool patches : https://github.com/minimaxwell/ethtool/tree/link-topo-v6 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents d133ef1 + 841942b commit 267e317

File tree

22 files changed

+385
-8
lines changed

22 files changed

+385
-8
lines changed

Documentation/networking/ethtool-netlink.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Structure of this header is
5757
``ETHTOOL_A_HEADER_DEV_INDEX`` u32 device ifindex
5858
``ETHTOOL_A_HEADER_DEV_NAME`` string device name
5959
``ETHTOOL_A_HEADER_FLAGS`` u32 flags common for all requests
60+
``ETHTOOL_A_HEADER_PHY_INDEX`` u32 phy device index
6061
============================== ====== =============================
6162

6263
``ETHTOOL_A_HEADER_DEV_INDEX`` and ``ETHTOOL_A_HEADER_DEV_NAME`` identify the
@@ -81,6 +82,12 @@ the behaviour is backward compatible, i.e. requests from old clients not aware
8182
of the flag should be interpreted the way the client expects. A client must
8283
not set flags it does not understand.
8384

85+
``ETHTOOL_A_HEADER_PHY_INDEX`` identifies the Ethernet PHY the message relates to.
86+
As there are numerous commands that are related to PHY configuration, and because
87+
there may be more than one PHY on the link, the PHY index can be passed in the
88+
request for the commands that needs it. It is, however, not mandatory, and if it
89+
is not passed for commands that target a PHY, the net_device.phydev pointer
90+
is used.
8491

8592
Bit sets
8693
========

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8015,6 +8015,8 @@ F: include/linux/mii.h
80158015
F: include/linux/of_net.h
80168016
F: include/linux/phy.h
80178017
F: include/linux/phy_fixed.h
8018+
F: include/linux/phy_link_topology.h
8019+
F: include/linux/phy_link_topology_core.h
80188020
F: include/linux/phylib_stubs.h
80198021
F: include/linux/platform_data/mdio-bcm-unimac.h
80208022
F: include/linux/platform_data/mdio-gpio.h

drivers/net/phy/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Makefile for Linux PHY drivers
33

44
libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \
5-
linkmode.o
5+
linkmode.o phy_link_topology.o
66
mdio-bus-y += mdio_bus.o mdio_device.o
77

88
ifdef CONFIG_MDIO_DEVICE

drivers/net/phy/marvell-88x2222.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,8 @@ static const struct sfp_upstream_ops sfp_phy_ops = {
553553
.link_down = mv2222_sfp_link_down,
554554
.attach = phy_sfp_attach,
555555
.detach = phy_sfp_detach,
556+
.connect_phy = phy_sfp_connect_phy,
557+
.disconnect_phy = phy_sfp_disconnect_phy,
556558
};
557559

558560
static int mv2222_probe(struct phy_device *phydev)

drivers/net/phy/marvell.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3550,6 +3550,8 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = {
35503550
.module_remove = m88e1510_sfp_remove,
35513551
.attach = phy_sfp_attach,
35523552
.detach = phy_sfp_detach,
3553+
.connect_phy = phy_sfp_connect_phy,
3554+
.disconnect_phy = phy_sfp_disconnect_phy,
35533555
};
35543556

35553557
static int m88e1510_probe(struct phy_device *phydev)

drivers/net/phy/marvell10g.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@ static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
503503
static const struct sfp_upstream_ops mv3310_sfp_ops = {
504504
.attach = phy_sfp_attach,
505505
.detach = phy_sfp_detach,
506+
.connect_phy = phy_sfp_connect_phy,
507+
.disconnect_phy = phy_sfp_disconnect_phy,
506508
.module_insert = mv3310_sfp_insert,
507509
};
508510

drivers/net/phy/phy_device.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/phy.h>
3030
#include <linux/phylib_stubs.h>
3131
#include <linux/phy_led_triggers.h>
32+
#include <linux/phy_link_topology.h>
3233
#include <linux/pse-pd/pse.h>
3334
#include <linux/property.h>
3435
#include <linux/rtnetlink.h>
@@ -276,6 +277,14 @@ static void phy_mdio_device_remove(struct mdio_device *mdiodev)
276277

277278
static struct phy_driver genphy_driver;
278279

280+
static struct phy_link_topology *phy_get_link_topology(struct phy_device *phydev)
281+
{
282+
if (phydev->attached_dev)
283+
return phydev->attached_dev->link_topo;
284+
285+
return NULL;
286+
}
287+
279288
static LIST_HEAD(phy_fixup_list);
280289
static DEFINE_MUTEX(phy_fixup_lock);
281290

@@ -1369,6 +1378,46 @@ phy_standalone_show(struct device *dev, struct device_attribute *attr,
13691378
}
13701379
static DEVICE_ATTR_RO(phy_standalone);
13711380

1381+
/**
1382+
* phy_sfp_connect_phy - Connect the SFP module's PHY to the upstream PHY
1383+
* @upstream: pointer to the upstream phy device
1384+
* @phy: pointer to the SFP module's phy device
1385+
*
1386+
* This helper allows keeping track of PHY devices on the link. It adds the
1387+
* SFP module's phy to the phy namespace of the upstream phy
1388+
*/
1389+
int phy_sfp_connect_phy(void *upstream, struct phy_device *phy)
1390+
{
1391+
struct phy_device *phydev = upstream;
1392+
struct phy_link_topology *topo = phy_get_link_topology(phydev);
1393+
1394+
if (topo)
1395+
return phy_link_topo_add_phy(topo, phy, PHY_UPSTREAM_PHY, phydev);
1396+
1397+
return 0;
1398+
}
1399+
EXPORT_SYMBOL(phy_sfp_connect_phy);
1400+
1401+
/**
1402+
* phy_sfp_disconnect_phy - Disconnect the SFP module's PHY from the upstream PHY
1403+
* @upstream: pointer to the upstream phy device
1404+
* @phy: pointer to the SFP module's phy device
1405+
*
1406+
* This helper allows keeping track of PHY devices on the link. It removes the
1407+
* SFP module's phy to the phy namespace of the upstream phy. As the module phy
1408+
* will be destroyed, re-inserting the same module will add a new phy with a
1409+
* new index.
1410+
*/
1411+
void phy_sfp_disconnect_phy(void *upstream, struct phy_device *phy)
1412+
{
1413+
struct phy_device *phydev = upstream;
1414+
struct phy_link_topology *topo = phy_get_link_topology(phydev);
1415+
1416+
if (topo)
1417+
phy_link_topo_del_phy(topo, phy);
1418+
}
1419+
EXPORT_SYMBOL(phy_sfp_disconnect_phy);
1420+
13721421
/**
13731422
* phy_sfp_attach - attach the SFP bus to the PHY upstream network device
13741423
* @upstream: pointer to the phy device
@@ -1511,6 +1560,11 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
15111560

15121561
if (phydev->sfp_bus_attached)
15131562
dev->sfp_bus = phydev->sfp_bus;
1563+
1564+
err = phy_link_topo_add_phy(dev->link_topo, phydev,
1565+
PHY_UPSTREAM_MAC, dev);
1566+
if (err)
1567+
goto error;
15141568
}
15151569

15161570
/* Some Ethernet drivers try to connect to a PHY device before
@@ -1938,6 +1992,7 @@ void phy_detach(struct phy_device *phydev)
19381992
if (dev) {
19391993
phydev->attached_dev->phydev = NULL;
19401994
phydev->attached_dev = NULL;
1995+
phy_link_topo_del_phy(dev->link_topo, phydev);
19411996
}
19421997
phydev->phylink = NULL;
19431998

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
struct phy_link_topology *phy_link_topo_create(struct net_device *dev)
16+
{
17+
struct phy_link_topology *topo;
18+
19+
topo = kzalloc(sizeof(*topo), GFP_KERNEL);
20+
if (!topo)
21+
return ERR_PTR(-ENOMEM);
22+
23+
xa_init_flags(&topo->phys, XA_FLAGS_ALLOC1);
24+
topo->next_phy_index = 1;
25+
26+
return topo;
27+
}
28+
29+
void phy_link_topo_destroy(struct phy_link_topology *topo)
30+
{
31+
if (!topo)
32+
return;
33+
34+
xa_destroy(&topo->phys);
35+
kfree(topo);
36+
}
37+
38+
int phy_link_topo_add_phy(struct phy_link_topology *topo,
39+
struct phy_device *phy,
40+
enum phy_upstream upt, void *upstream)
41+
{
42+
struct phy_device_node *pdn;
43+
int ret;
44+
45+
pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
46+
if (!pdn)
47+
return -ENOMEM;
48+
49+
pdn->phy = phy;
50+
switch (upt) {
51+
case PHY_UPSTREAM_MAC:
52+
pdn->upstream.netdev = (struct net_device *)upstream;
53+
if (phy_on_sfp(phy))
54+
pdn->parent_sfp_bus = pdn->upstream.netdev->sfp_bus;
55+
break;
56+
case PHY_UPSTREAM_PHY:
57+
pdn->upstream.phydev = (struct phy_device *)upstream;
58+
if (phy_on_sfp(phy))
59+
pdn->parent_sfp_bus = pdn->upstream.phydev->sfp_bus;
60+
break;
61+
default:
62+
ret = -EINVAL;
63+
goto err;
64+
}
65+
pdn->upstream_type = upt;
66+
67+
/* Attempt to re-use a previously allocated phy_index */
68+
if (phy->phyindex) {
69+
ret = xa_insert(&topo->phys, phy->phyindex, pdn, GFP_KERNEL);
70+
71+
/* Errors could be either -ENOMEM or -EBUSY. If the phy has an
72+
* index, and there's another entry at the same index, this is
73+
* unexpected and we still error-out
74+
*/
75+
if (ret)
76+
goto err;
77+
return 0;
78+
}
79+
80+
ret = xa_alloc_cyclic(&topo->phys, &phy->phyindex, pdn, xa_limit_32b,
81+
&topo->next_phy_index, GFP_KERNEL);
82+
if (ret)
83+
goto err;
84+
85+
return 0;
86+
87+
err:
88+
kfree(pdn);
89+
return ret;
90+
}
91+
EXPORT_SYMBOL_GPL(phy_link_topo_add_phy);
92+
93+
void phy_link_topo_del_phy(struct phy_link_topology *topo,
94+
struct phy_device *phy)
95+
{
96+
struct phy_device_node *pdn = xa_erase(&topo->phys, phy->phyindex);
97+
98+
/* We delete the PHY from the topology, however we don't re-set the
99+
* phy->phyindex field. If the PHY isn't gone, we can re-assign it the
100+
* same index next time it's added back to the topology
101+
*/
102+
103+
kfree(pdn);
104+
}
105+
EXPORT_SYMBOL_GPL(phy_link_topo_del_phy);

drivers/net/phy/phylink.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3408,7 +3408,8 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
34083408
return ret;
34093409
}
34103410

3411-
static void phylink_sfp_disconnect_phy(void *upstream)
3411+
static void phylink_sfp_disconnect_phy(void *upstream,
3412+
struct phy_device *phydev)
34123413
{
34133414
phylink_disconnect_phy(upstream);
34143415
}

drivers/net/phy/qcom/at803x.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@ static const struct sfp_upstream_ops at8031_sfp_ops = {
770770
.attach = phy_sfp_attach,
771771
.detach = phy_sfp_detach,
772772
.module_insert = at8031_sfp_insert,
773+
.connect_phy = phy_sfp_connect_phy,
774+
.disconnect_phy = phy_sfp_disconnect_phy,
773775
};
774776

775777
static int at8031_parse_dt(struct phy_device *phydev)

0 commit comments

Comments
 (0)