diff options
author | Marek Behún <kabel@kernel.org> | 2021-04-08 08:18:29 +0200 |
---|---|---|
committer | Marek Behún <kabel@kernel.org> | 2021-04-08 08:18:29 +0200 |
commit | 8a3b1f3480e7689d1f5f1c64296df9a043bb42ef (patch) | |
tree | a3895ce7401a3c464337588646ab916c7dc9e0bc | |
parent | 182a0912b5ef37d619ded90b502495aa7e9d0f95 (diff) |
WIP: net: phylink: pass supported PHY interface modes to phylibmarvell10g-updates
Pass the supported PHY interface types to phylib so that PHY drivers
can select an appropriate host configuration mode for their interface
according to the host capabilities.
Signed-off-by: Marek Behún <kabel@kernel.org>
-rw-r--r-- | drivers/net/phy/phylink.c | 59 | ||||
-rw-r--r-- | include/linux/phy.h | 2 |
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 96d8e88b4e4660..5a6f036709645b 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1051,6 +1051,10 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) { int ret; + /* Set the PHY's host supported interfaces */ + phy_interface_and(phy->host_interfaces, phy->supported_interfaces, + pl->config->supported_interfaces); + /* Use PHY device/driver interface */ if (pl->link_interface == PHY_INTERFACE_MODE_NA) { pl->link_interface = phy->interface; @@ -1069,6 +1073,51 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) } EXPORT_SYMBOL_GPL(phylink_connect_phy); +static int phylink_of_read_modes_property(struct device_node *dn, + const char *property, + unsigned long *interfaces) +{ + const char *modes[PHY_INTERFACE_MODE_MAX]; + int i, j; + int ret; + + phy_interface_zero(interfaces); + + ret = of_property_read_string_array(dn, property, modes, + PHY_INTERFACE_MODE_MAX); + if (ret < 0) + return ret; + + for (i = 0; i < ret; ++i) { + for (j = 0; j < PHY_INTERFACE_MODE_MAX; j++) + if (!strcasecmp(modes[i], phy_modes(j))) + break; + + if (j == PHY_INTERFACE_MODE_MAX) { + pr_warn("%pOF: unknown PHY mode %s in property %s\n", + dn, modes[i], property); + continue; + } + + __set_bit(j, interfaces); + } + + return 0; +} + +static int phylink_of_phy_modes(struct device_node *dn, + unsigned long *interfaces) +{ + int ret; + + ret = phylink_of_read_modes_property(dn, "phy-mode", interfaces); + if (ret < 0) + ret = phylink_of_read_modes_property(dn, "phy-connection-type", + interfaces); + + return ret; +} + /** * phylink_of_phy_connect() - connect the PHY specified in the DT mode. * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -1084,6 +1133,7 @@ EXPORT_SYMBOL_GPL(phylink_connect_phy); int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, u32 flags) { + DECLARE_PHY_INTERFACE_MASK(of_interfaces); struct device_node *phy_node; struct phy_device *phy_dev; int ret; @@ -1112,6 +1162,15 @@ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, if (!phy_dev) return -ENODEV; + /* Set the PHY's host supported interfaces */ + phy_interface_and(phy_dev->host_interfaces, + phy_dev->supported_interfaces, + pl->config->supported_interfaces); + if (!phylink_of_phy_modes(dn, of_interfaces)) + phy_interface_and(phy_dev->host_interfaces, + phy_dev->host_interfaces, + of_interfaces); + ret = phy_attach_direct(pl->netdev, phy_dev, flags, pl->link_interface); if (ret) diff --git a/include/linux/phy.h b/include/linux/phy.h index d1b0c3df7b98c4..de5960acf205a3 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -540,6 +540,7 @@ struct macsec_ops; * @advertising: Currently advertised linkmodes * @adv_old: Saved advertised while power saving for WoL * @lp_advertising: Current link partner advertised linkmodes + * @host_interfaces: Interface modes supported by the host with this PHY * @supported_interfaces: Interface modes supported by the PHY * @eee_broken_modes: Energy efficient ethernet modes which should be prohibited * @autoneg: Flag autoneg being used @@ -630,6 +631,7 @@ struct phy_device { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old); /* supported PHY interface types */ + DECLARE_PHY_INTERFACE_MASK(host_interfaces); DECLARE_PHY_INTERFACE_MASK(supported_interfaces); /* Energy efficient ethernet modes which should be prohibited */ |