Commit 6faaffb3 authored by David S. Miller's avatar David S. Miller

Merge branch 'Decoupling-PHYLINK-from-struct-net_device'

Ioana Ciornei says:

====================
Decoupling PHYLINK from struct net_device

Following two separate discussion threads in:
  https://www.spinics.net/lists/netdev/msg569087.html
and:
  https://www.spinics.net/lists/netdev/msg570450.html

Previous RFC patch set: https://www.spinics.net/lists/netdev/msg571995.html

PHYLINK was reworked in order to accept multiple operation types,
PHYLINK_NETDEV and PHYLINK_DEV, passed through a phylink_config
structure alongside the corresponding struct device.

One of the main concerns expressed in the RFC was that using notifiers
to signal the corresponding phylink_mac_ops would break PHYLINK's API
unity and that it would become harder to grep for its users.
Using the current approach, we maintain a common API for all users.
Also, printing useful information in PHYLINK, when decoupled from a
net_device, is achieved using dev_err&co on the struct device received
(in DSA's case is the device corresponding to the dsa_switch).

PHYLIB (which PHYLINK uses) was reworked to the extent that it does not
crash when connecting to a PHY and the net_device pointer is NULL.

Lastly, DSA has been reworked in its way that it handles PHYs for ports
that lack a net_device (CPU and DSA ports).  For these, it was
previously using PHYLIB and is now using the PHYLINK_DEV operation type.
Previously, a driver that wanted to support PHY operations on CPU/DSA
ports has to implement .adjust_link(). This patch set not only gives
drivers the options to use PHYLINK uniformly but also urges them to
convert to it. For compatibility, the old code is kept but it will be
removed once all drivers switch over.

The patchset was tested on the NXP LS1021A-TSN board having the
following Ethernet layout:
  https://lkml.org/lkml/2019/5/5/279
The CPU port was moved from the internal RGMII fixed-link (enet2 ->
switch port 4) to an external loopback Cat5 cable between the enet1 port
and the front-facing swp2 SJA1105 port. In this mode, both the master
and the CPU port have an attached PHY which detects link change events:

[   49.105426] fsl-gianfar soc:ethernet@2d50000 eth1: Link is Down
[   50.305486] sja1105 spi0.1: Link is Down
[   53.265596] fsl-gianfar soc:ethernet@2d50000 eth1: Link is Up - 1Gbps/Full - flow control off
[   54.466304] sja1105 spi0.1: Link is Up - 1Gbps/Full - flow control off

Changes in v2:
  - fixed sparse warnings
  - updated 'Documentation/ABI/testing/sysfs-class-net-phydev'
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 24ec483c af7cd036
......@@ -34,3 +34,11 @@ Description:
xgmii, moca, qsgmii, trgmii, 1000base-x, 2500base-x, rxaui,
xaui, 10gbase-kr, unknown
What: /sys/class/mdio_bus/<bus>/<device>/phy_standalone
Date: May 2019
KernelVersion: 5.3
Contact: netdev@vger.kernel.org
Description:
Boolean value indicating whether the PHY device is used in
standalone mode, without a net_device associated, by PHYLINK.
Attribute created only when this is the case.
......@@ -98,6 +98,7 @@ this documentation.
4. Add::
struct phylink *phylink;
struct phylink_config phylink_config;
to the driver's private data structure. We shall refer to the
driver's private data pointer as ``priv`` below, and the driver's
......@@ -223,8 +224,10 @@ this documentation.
.. code-block:: c
struct phylink *phylink;
priv->phylink_config.dev = &dev.dev;
priv->phylink_config.type = PHYLINK_NETDEV;
phylink = phylink_create(dev, node, phy_mode, &phylink_ops);
phylink = phylink_create(&priv->phylink_config, node, phy_mode, &phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
fail probe;
......
......@@ -734,15 +734,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
return sja1105_clocking_setup_port(priv, port);
}
static void sja1105_adjust_link(struct dsa_switch *ds, int port,
struct phy_device *phydev)
static void sja1105_mac_config(struct dsa_switch *ds, int port,
unsigned int link_an_mode,
const struct phylink_link_state *state)
{
struct sja1105_private *priv = ds->priv;
if (!phydev->link)
if (!state->link)
sja1105_adjust_port_config(priv, port, 0, false);
else
sja1105_adjust_port_config(priv, port, phydev->speed, true);
sja1105_adjust_port_config(priv, port, state->speed, true);
}
static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
......@@ -1515,9 +1516,9 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds,
static const struct dsa_switch_ops sja1105_switch_ops = {
.get_tag_protocol = sja1105_get_tag_protocol,
.setup = sja1105_setup,
.adjust_link = sja1105_adjust_link,
.set_ageing_time = sja1105_set_ageing_time,
.phylink_validate = sja1105_phylink_validate,
.phylink_mac_config = sja1105_mac_config,
.get_strings = sja1105_get_strings,
.get_ethtool_stats = sja1105_get_ethtool_stats,
.get_sset_count = sja1105_get_sset_count,
......
......@@ -437,6 +437,7 @@ struct mvneta_port {
struct device_node *dn;
unsigned int tx_csum_limit;
struct phylink *phylink;
struct phylink_config phylink_config;
struct phy *comphy;
struct mvneta_bm *bm_priv;
......@@ -3356,9 +3357,11 @@ static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
return 0;
}
static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
static void mvneta_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
......@@ -3408,9 +3411,10 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
phylink_helper_basex_speed(state);
}
static int mvneta_mac_link_state(struct net_device *ndev,
static int mvneta_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 gmac_stat;
......@@ -3438,8 +3442,9 @@ static int mvneta_mac_link_state(struct net_device *ndev,
return 1;
}
static void mvneta_mac_an_restart(struct net_device *ndev)
static void mvneta_mac_an_restart(struct phylink_config *config)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
......@@ -3449,9 +3454,10 @@ static void mvneta_mac_an_restart(struct net_device *ndev)
gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN);
}
static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
const struct phylink_link_state *state)
static void mvneta_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
......@@ -3581,9 +3587,10 @@ static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
}
static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
phy_interface_t interface)
static void mvneta_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 val;
......@@ -3600,10 +3607,11 @@ static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode,
mvneta_set_eee(pp, false);
}
static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface,
struct phy_device *phy)
{
struct net_device *ndev = to_net_dev(config->dev);
struct mvneta_port *pp = netdev_priv(ndev);
u32 val;
......@@ -4500,8 +4508,14 @@ static int mvneta_probe(struct platform_device *pdev)
comphy = NULL;
}
phylink = phylink_create(dev, pdev->dev.fwnode, phy_mode,
&mvneta_phylink_ops);
pp = netdev_priv(dev);
spin_lock_init(&pp->lock);
pp->phylink_config.dev = &dev->dev;
pp->phylink_config.type = PHYLINK_NETDEV;
phylink = phylink_create(&pp->phylink_config, pdev->dev.fwnode,
phy_mode, &mvneta_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
goto err_free_irq;
......@@ -4513,8 +4527,6 @@ static int mvneta_probe(struct platform_device *pdev)
dev->ethtool_ops = &mvneta_eth_tool_ops;
pp = netdev_priv(dev);
spin_lock_init(&pp->lock);
pp->phylink = phylink;
pp->comphy = comphy;
pp->phy_interface = phy_mode;
......
......@@ -915,6 +915,7 @@ struct mvpp2_port {
phy_interface_t phy_interface;
struct phylink *phylink;
struct phylink_config phylink_config;
struct phy *comphy;
struct mvpp2_bm_pool *pool_long;
......
......@@ -56,9 +56,9 @@ static struct {
/* The prototype is added here to be used in start_dev when using ACPI. This
* will be removed once phylink is used for all modes (dt+ACPI).
*/
static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state);
static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, struct phy_device *phy);
/* Queue modes */
......@@ -3239,9 +3239,9 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
struct phylink_link_state state = {
.interface = port->phy_interface,
};
mvpp2_mac_config(port->dev, MLO_AN_INBAND, &state);
mvpp2_mac_link_up(port->dev, MLO_AN_INBAND, port->phy_interface,
NULL);
mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
mvpp2_mac_link_up(&port->phylink_config, MLO_AN_INBAND,
port->phy_interface, NULL);
}
netif_tx_start_all_queues(port->dev);
......@@ -4463,11 +4463,12 @@ static void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
eth_hw_addr_random(dev);
}
static void mvpp2_phylink_validate(struct net_device *dev,
static void mvpp2_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
{
struct mvpp2_port *port = netdev_priv(dev);
struct mvpp2_port *port = container_of(config, struct mvpp2_port,
phylink_config);
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
/* Invalid combinations */
......@@ -4591,10 +4592,11 @@ static void mvpp2_gmac_link_state(struct mvpp2_port *port,
state->pause |= MLO_PAUSE_TX;
}
static int mvpp2_phylink_mac_link_state(struct net_device *dev,
static int mvpp2_phylink_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct mvpp2_port *port = netdev_priv(dev);
struct mvpp2_port *port = container_of(config, struct mvpp2_port,
phylink_config);
if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
u32 mode = readl(port->base + MVPP22_XLG_CTRL3_REG);
......@@ -4610,9 +4612,10 @@ static int mvpp2_phylink_mac_link_state(struct net_device *dev,
return 1;
}
static void mvpp2_mac_an_restart(struct net_device *dev)
static void mvpp2_mac_an_restart(struct phylink_config *config)
{
struct mvpp2_port *port = netdev_priv(dev);
struct mvpp2_port *port = container_of(config, struct mvpp2_port,
phylink_config);
u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
......@@ -4797,9 +4800,10 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
}
}
static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
bool change_interface = port->phy_interface != state->interface;
......@@ -4839,9 +4843,10 @@ static void mvpp2_mac_config(struct net_device *dev, unsigned int mode,
mvpp2_port_enable(port);
}
static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, struct phy_device *phy)
{
struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
u32 val;
......@@ -4866,9 +4871,10 @@ static void mvpp2_mac_link_up(struct net_device *dev, unsigned int mode,
netif_tx_wake_all_queues(dev);
}
static void mvpp2_mac_link_down(struct net_device *dev, unsigned int mode,
phy_interface_t interface)
static void mvpp2_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct net_device *dev = to_net_dev(config->dev);
struct mvpp2_port *port = netdev_priv(dev);
u32 val;
......@@ -5125,8 +5131,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
/* Phylink isn't used w/ ACPI as of now */
if (port_node) {
phylink = phylink_create(dev, port_fwnode, phy_mode,
&mvpp2_phylink_ops);
port->phylink_config.dev = &dev->dev;
port->phylink_config.type = PHYLINK_NETDEV;
phylink = phylink_create(&port->phylink_config, port_fwnode,
phy_mode, &mvpp2_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
goto err_free_port_pcpu;
......
......@@ -948,6 +948,9 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
{
int rc;
if (!dev)
return -EINVAL;
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return rc;
......@@ -1133,6 +1136,44 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
}
EXPORT_SYMBOL(phy_attached_print);
static void phy_sysfs_create_links(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
int err;
if (!dev)
return;
err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
"attached_dev");
if (err)
return;
err = sysfs_create_link_nowarn(&dev->dev.kobj,
&phydev->mdio.dev.kobj,
"phydev");
if (err) {
dev_err(&dev->dev, "could not add device link to %s err %d\n",
kobject_name(&phydev->mdio.dev.kobj),
err);
/* non-fatal - some net drivers can use one netdevice
* with more then one phy
*/
}
phydev->sysfs_links = true;
}
static ssize_t
phy_standalone_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct phy_device *phydev = to_phy_device(dev);
return sprintf(buf, "%d\n", !phydev->attached_dev);
}
static DEVICE_ATTR_RO(phy_standalone);
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
......@@ -1151,9 +1192,9 @@ EXPORT_SYMBOL(phy_attached_print);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus = phydev->mdio.bus;
struct device *d = &phydev->mdio.dev;
struct module *ndev_owner = NULL;
bool using_genphy = false;
int err;
......@@ -1162,8 +1203,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
* our own module->refcnt here, otherwise we would not be able to
* unload later on.
*/
if (dev)
ndev_owner = dev->dev.parent->driver->owner;
if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
dev_err(&dev->dev, "failed to get the bus module\n");
phydev_err(phydev, "failed to get the bus module\n");
return -EIO;
}
......@@ -1182,7 +1225,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
}
if (!try_module_get(d->driver->owner)) {
dev_err(&dev->dev, "failed to get the device driver module\n");
phydev_err(phydev, "failed to get the device driver module\n");
err = -EIO;
goto error_put_device;
}
......@@ -1203,8 +1246,10 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
}
phydev->phy_link_change = phy_link_change;
phydev->attached_dev = dev;
dev->phydev = phydev;
if (dev) {
phydev->attached_dev = dev;
dev->phydev = phydev;
}
/* Some Ethernet drivers try to connect to a PHY device before
* calling register_netdevice() -> netdev_register_kobject() and
......@@ -1216,22 +1261,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
*/
phydev->sysfs_links = false;
err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
"attached_dev");
if (!err) {
err = sysfs_create_link_nowarn(&dev->dev.kobj,
&phydev->mdio.dev.kobj,
"phydev");
if (err) {
dev_err(&dev->dev, "could not add device link to %s err %d\n",
kobject_name(&phydev->mdio.dev.kobj),
err);
/* non-fatal - some net drivers can use one netdevice
* with more then one phy
*/
}
phy_sysfs_create_links(phydev);
phydev->sysfs_links = true;
if (!phydev->attached_dev) {
err = sysfs_create_file(&phydev->mdio.dev.kobj,
&dev_attr_phy_standalone.attr);
if (err)
phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n");
}
phydev->dev_flags = flags;
......@@ -1243,7 +1279,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Initial carrier state is off as the phy is about to be
* (re)initialized.
*/
netif_carrier_off(phydev->attached_dev);
if (dev)
netif_carrier_off(phydev->attached_dev);
/* Do initial configuration here, now that
* we have certain key parameters
......@@ -1290,6 +1327,9 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
struct device *d;
int rc;
if (!dev)
return ERR_PTR(-EINVAL);
/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name
*/
......@@ -1349,16 +1389,24 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
void phy_detach(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
struct module *ndev_owner = dev->dev.parent->driver->owner;
struct module *ndev_owner = NULL;
struct mii_bus *bus;
if (phydev->sysfs_links) {
sysfs_remove_link(&dev->dev.kobj, "phydev");
if (dev)
sysfs_remove_link(&dev->dev.kobj, "phydev");
sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
}
if (!phydev->attached_dev)
sysfs_remove_file(&phydev->mdio.dev.kobj,
&dev_attr_phy_standalone.attr);
phy_suspend(phydev);
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
if (dev) {
phydev->attached_dev->phydev = NULL;
phydev->attached_dev = NULL;
}
phydev->phylink = NULL;
phy_led_triggers_unregister(phydev);
......@@ -1381,6 +1429,8 @@ void phy_detach(struct phy_device *phydev)
bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev);
if (dev)
ndev_owner = dev->dev.parent->driver->owner;
if (ndev_owner != bus->owner)
module_put(bus->owner);
......
This diff is collapsed.
......@@ -54,6 +54,21 @@ struct phylink_link_state {
unsigned int an_complete:1;
};
enum phylink_op_type {
PHYLINK_NETDEV = 0,
PHYLINK_DEV,
};
/**
* struct phylink_config - PHYLINK configuration structure
* @dev: a pointer to a struct device associated with the MAC
* @type: operation type of PHYLINK instance
*/
struct phylink_config {
struct device *dev;
enum phylink_op_type type;
};
/**
* struct phylink_mac_ops - MAC operations structure.
* @validate: Validate and update the link configuration.
......@@ -66,16 +81,17 @@ struct phylink_link_state {
* The individual methods are described more fully below.
*/
struct phylink_mac_ops {
void (*validate)(struct net_device *ndev, unsigned long *supported,
void (*validate)(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state);
int (*mac_link_state)(struct net_device *ndev,
int (*mac_link_state)(struct phylink_config *config,
struct phylink_link_state *state);
void (*mac_config)(struct net_device *ndev, unsigned int mode,
void (*mac_config)(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state);
void (*mac_an_restart)(struct net_device *ndev);
void (*mac_link_down)(struct net_device *ndev, unsigned int mode,
void (*mac_an_restart)(struct phylink_config *config);
void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
phy_interface_t interface);
void (*mac_link_up)(struct net_device *ndev, unsigned int mode,
void (*mac_link_up)(struct phylink_config *config, unsigned int mode,
phy_interface_t interface,
struct phy_device *phy);
};
......@@ -83,7 +99,7 @@ struct phylink_mac_ops {
#if 0 /* For kernel-doc purposes only. */
/**
* validate - Validate and update the link configuration
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
* @supported: ethtool bitmask for supported link modes.
* @state: a pointer to a &struct phylink_link_state.
*
......@@ -100,12 +116,12 @@ struct phylink_mac_ops {
* based on @state->advertising and/or @state->speed and update
* @state->interface accordingly.
*/
void validate(struct net_device *ndev, unsigned long *supported,
void validate(struct phylink_config *config, unsigned long *supported,
struct phylink_link_state *state);
/**
* mac_link_state() - Read the current link state from the hardware
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
* @state: a pointer to a &struct phylink_link_state.
*
* Read the current link state from the MAC, reporting the current
......@@ -114,12 +130,12 @@ void validate(struct net_device *ndev, unsigned long *supported,
* negotiation completion state in @state->an_complete, and link
* up state in @state->link.
*/
int mac_link_state(struct net_device *ndev,
int mac_link_state(struct phylink_config *config,
struct phylink_link_state *state);
/**
* mac_config() - configure the MAC for the selected mode and state
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
* @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
* @state: a pointer to a &struct phylink_link_state.
*
......@@ -157,18 +173,18 @@ int mac_link_state(struct net_device *ndev,
* down. This "update" behaviour is critical to avoid bouncing the
* link up status.
*/
void mac_config(struct net_device *ndev, unsigned int mode,
void mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state);
/**
* mac_an_restart() - restart 802.3z BaseX autonegotiation
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
*/
void mac_an_restart(struct net_device *ndev);
void mac_an_restart(struct phylink_config *config);
/**
* mac_link_down() - take the link down
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
* @mode: link autonegotiation mode
* @interface: link &typedef phy_interface_t mode
*
......@@ -177,12 +193,12 @@ void mac_an_restart(struct net_device *ndev);
* Energy Efficient Ethernet MAC configuration. Interface type
* selection must be done in mac_config().
*/
void mac_link_down(struct net_device *ndev, unsigned int mode,
void mac_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface);
/**
* mac_link_up() - allow the link to come up
* @ndev: a pointer to a &struct net_device for the MAC.
* @config: a pointer to a &struct phylink_config.
* @mode: link autonegotiation mode
* @interface: link &typedef phy_interface_t mode
* @phy: any attached phy
......@@ -193,13 +209,14 @@ void mac_link_down(struct net_device *ndev, unsigned int mode,
* phy_init_eee() and perform appropriate MAC configuration for EEE.
* Interface type selection must be done in mac_config().
*/
void mac_link_up(struct net_device *ndev, unsigned int mode,
void mac_link_up(struct phylink_config *config, unsigned int mode,
phy_interface_t interface,
struct phy_device *phy);
#endif
struct phylink *phylink_create(struct net_device *, struct fwnode_handle *,
phy_interface_t iface, const struct phylink_mac_ops *ops);
struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
phy_interface_t iface,
const struct phylink_mac_ops *ops);
void phylink_destroy(struct phylink *);
int phylink_connect_phy(struct phylink *, struct phy_device *);
......
......@@ -22,6 +22,7 @@
#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/platform_data/dsa.h>
#include <linux/phylink.h>
#include <net/devlink.h>
#include <net/switchdev.h>
......@@ -193,6 +194,7 @@ struct dsa_port {
struct net_device *bridge_dev;
struct devlink_port devlink_port;
struct phylink *pl;
struct phylink_config pl_config;
struct work_struct xmit_work;
struct sk_buff_head xmit_queue;
......
......@@ -163,6 +163,23 @@ int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags);
int dsa_port_vid_del(struct dsa_port *dp, u16 vid);
int dsa_port_link_register_of(struct dsa_port *dp);
void dsa_port_link_unregister_of(struct dsa_port *dp);
void dsa_port_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state);
int dsa_port_phylink_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state);
void dsa_port_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state);
void dsa_port_phylink_mac_an_restart(struct phylink_config *config);
void dsa_port_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface);
void dsa_port_phylink_mac_link_up(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev);
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;
......
......@@ -422,6 +422,108 @@ static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
return phydev;
}
void dsa_port_phylink_validate(struct phylink_config *config,
unsigned long *supported,
struct phylink_link_state *state)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_validate)
return;
ds->ops->phylink_validate(ds, dp->index, supported, state);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_validate);
int dsa_port_phylink_mac_link_state(struct phylink_config *config,
struct phylink_link_state *state)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
/* Only called for SGMII and 802.3z */
if (!ds->ops->phylink_mac_link_state)
return -EOPNOTSUPP;
return ds->ops->phylink_mac_link_state(ds, dp->index, state);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_state);
void dsa_port_phylink_mac_config(struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_config)
return;
ds->ops->phylink_mac_config(ds, dp->index, mode, state);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_config);
void dsa_port_phylink_mac_an_restart(struct phylink_config *config)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_an_restart)
return;
ds->ops->phylink_mac_an_restart(ds, dp->index);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_an_restart);
void dsa_port_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct phy_device *phydev = NULL;
struct dsa_switch *ds = dp->ds;
if (dsa_is_user_port(ds, dp->index))
phydev = dp->slave->phydev;
if (!ds->ops->phylink_mac_link_down) {
if (ds->ops->adjust_link && phydev)
ds->ops->adjust_link(ds, dp->index, phydev);
return;
}
ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_down);
void dsa_port_phylink_mac_link_up(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_link_up) {
if (ds->ops->adjust_link && phydev)
ds->ops->adjust_link(ds, dp->index, phydev);
return;
}
ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev);
}
EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_up);
const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
.validate = dsa_port_phylink_validate,
.mac_link_state = dsa_port_phylink_mac_link_state,
.mac_config = dsa_port_phylink_mac_config,
.mac_an_restart = dsa_port_phylink_mac_an_restart,
.mac_link_down = dsa_port_phylink_mac_link_down,
.mac_link_up = dsa_port_phylink_mac_link_up,
};
static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
{
struct dsa_switch *ds = dp->ds;
......@@ -499,8 +601,53 @@ static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
return 0;
}
static int dsa_port_phylink_register(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
struct device_node *port_dn = dp->dn;
int mode, err;
mode = of_get_phy_mode(port_dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
dp->pl_config.dev = ds->dev;
dp->pl_config.type = PHYLINK_DEV;
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn),
mode, &dsa_port_phylink_mac_ops);
if (IS_ERR(dp->pl)) {
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
return PTR_ERR(dp->pl);
}
err = phylink_of_phy_connect(dp->pl, port_dn, 0);
if (err) {
pr_err("could not attach to PHY: %d\n", err);
goto err_phy_connect;
}
rtnl_lock();
phylink_start(dp->pl);
rtnl_unlock();
return 0;
err_phy_connect:
phylink_destroy(dp->pl);
return err;
}
int dsa_port_link_register_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
if (!ds->ops->adjust_link)
return dsa_port_phylink_register(dp);
dev_warn(ds->dev,
"Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");
if (of_phy_is_fixed_link(dp->dn))
return dsa_port_fixed_link_register_of(dp);
else
......@@ -509,6 +656,16 @@ int dsa_port_link_register_of(struct dsa_port *dp)
void dsa_port_link_unregister_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
if (!ds->ops->adjust_link) {
rtnl_lock();
phylink_disconnect_phy(dp->pl);
rtnl_unlock();
phylink_destroy(dp->pl);
return;
}
if (of_phy_is_fixed_link(dp->dn))
of_phy_deregister_fixed_link(dp->dn);
else
......
......@@ -1164,98 +1164,6 @@ static struct device_type dsa_type = {
.name = "dsa",
};
static void dsa_slave_phylink_validate(struct net_device *dev,
unsigned long *supported,
struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_validate)
return;
ds->ops->phylink_validate(ds, dp->index, supported, state);
}
static int dsa_slave_phylink_mac_link_state(struct net_device *dev,
struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
/* Only called for SGMII and 802.3z */
if (!ds->ops->phylink_mac_link_state)
return -EOPNOTSUPP;
return ds->ops->phylink_mac_link_state(ds, dp->index, state);
}
static void dsa_slave_phylink_mac_config(struct net_device *dev,
unsigned int mode,
const struct phylink_link_state *state)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_config)
return;
ds->ops->phylink_mac_config(ds, dp->index, mode, state);
}
static void dsa_slave_phylink_mac_an_restart(struct net_device *dev)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_an_restart)
return;
ds->ops->phylink_mac_an_restart(ds, dp->index);
}
static void dsa_slave_phylink_mac_link_down(struct net_device *dev,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_link_down) {
if (ds->ops->adjust_link && dev->phydev)
ds->ops->adjust_link(ds, dp->index, dev->phydev);
return;
}
ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
}
static void dsa_slave_phylink_mac_link_up(struct net_device *dev,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev)
{
struct dsa_port *dp = dsa_slave_to_port(dev);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_link_up) {
if (ds->ops->adjust_link && dev->phydev)
ds->ops->adjust_link(ds, dp->index, dev->phydev);
return;
}
ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev);
}
static const struct phylink_mac_ops dsa_slave_phylink_mac_ops = {
.validate = dsa_slave_phylink_validate,
.mac_link_state = dsa_slave_phylink_mac_link_state,
.mac_config = dsa_slave_phylink_mac_config,
.mac_an_restart = dsa_slave_phylink_mac_an_restart,
.mac_link_down = dsa_slave_phylink_mac_link_down,
.mac_link_up = dsa_slave_phylink_mac_link_up,
};
void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up)
{
const struct dsa_port *dp = dsa_to_port(ds, port);
......@@ -1303,8 +1211,11 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
dp->pl = phylink_create(slave_dev, of_fwnode_handle(port_dn), mode,
&dsa_slave_phylink_mac_ops);
dp->pl_config.dev = &slave_dev->dev;
dp->pl_config.type = PHYLINK_NETDEV;
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode,
&dsa_port_phylink_mac_ops);
if (IS_ERR(dp->pl)) {
netdev_err(slave_dev,
"error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment