Commit 706447f0 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'validate-of-nodes-for-dsa-shared-ports'

Vladimir Oltean says:

====================
Validate OF nodes for DSA shared ports

This is the first set of measures taken so that more drivers can be
transitioned towards phylink on shared (CPU and DSA) ports some time in
the future. It consists of:

- expanding the DT schema for DSA and related drivers to clarify the new
  requirements.

- introducing warnings for drivers that currently skip phylink due to
  incomplete DT descriptions.

- introducing warning for drivers that currently skip phylink due to
  using platform data (search for struct dsa_chip_data).

- closing the possibility for new(ish) drivers to skip phylink, by
  validating their DT descriptions.

- making the code paths used by shared ports more evident.

- preparing the code paths used by shared ports for further work to fake
  a link description where that is possible.

More details in patch 10/10.

DT binding (patches 1-6) and kernel (7-10) are in principle separable,
but are submitted together since they're part of the same story.

Patches 8 and 9 are DSA cleanups, and patch 7 is a dependency for patch
10.

v1 at
https://patchwork.kernel.org/project/netdevbpf/patch/20220723164635.1621911-1-vladimir.oltean@nxp.com/

v2 at
https://patchwork.kernel.org/project/netdevbpf/patch/20220729132119.1191227-5-vladimir.oltean@nxp.com/

v3 at
https://patchwork.kernel.org/project/netdevbpf/cover/20220806141059.2498226-1-vladimir.oltean@nxp.com/
====================

Link: https://lore.kernel.org/r/20220818115500.2592578-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 704438dd e09e9873
......@@ -63,6 +63,8 @@ examples:
reg = <3>;
label = "cpu";
ethernet = <&fec1>;
phy-mode = "rgmii-id";
fixed-link {
speed = <1000>;
full-duplex;
......
......@@ -254,6 +254,8 @@ examples:
ethernet = <&amac2>;
label = "cpu";
reg = <8>;
phy-mode = "internal";
fixed-link {
speed = <1000>;
full-duplex;
......
......@@ -76,6 +76,23 @@ properties:
required:
- reg
# CPU and DSA ports must have phylink-compatible link descriptions
if:
oneOf:
- required: [ ethernet ]
- required: [ link ]
then:
allOf:
- required:
- phy-mode
- oneOf:
- required:
- fixed-link
- required:
- phy-handle
- required:
- managed
additionalProperties: true
...
......@@ -93,6 +93,12 @@ examples:
reg = <0>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "mii";
fixed-link {
speed = <100>;
full-duplex;
};
};
port@2 {
......
......@@ -109,6 +109,8 @@ examples:
reg = <5>;
label = "cpu";
ethernet = <&eth0>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
......@@ -146,6 +148,8 @@ examples:
reg = <6>;
label = "cpu";
ethernet = <&eth0>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
......
......@@ -131,6 +131,8 @@ examples:
reg = <4>;
ethernet = <&gmac2>;
label = "cpu";
phy-mode = "internal";
fixed-link {
speed = <1000>;
full-duplex;
......
......@@ -578,6 +578,7 @@ int of_device_compatible_match(struct device_node *device,
return score;
}
EXPORT_SYMBOL_GPL(of_device_compatible_match);
/**
* of_machine_is_compatible - Test root of device tree for a given compatible value
......
......@@ -469,10 +469,16 @@ static int dsa_port_setup(struct dsa_port *dp)
dsa_port_disable(dp);
break;
case DSA_PORT_TYPE_CPU:
err = dsa_port_link_register_of(dp);
if (err)
break;
dsa_port_link_registered = true;
if (dp->dn) {
err = dsa_shared_port_link_register_of(dp);
if (err)
break;
dsa_port_link_registered = true;
} else {
dev_warn(ds->dev,
"skipping link registration for CPU port %d\n",
dp->index);
}
err = dsa_port_enable(dp, NULL);
if (err)
......@@ -481,10 +487,16 @@ static int dsa_port_setup(struct dsa_port *dp)
break;
case DSA_PORT_TYPE_DSA:
err = dsa_port_link_register_of(dp);
if (err)
break;
dsa_port_link_registered = true;
if (dp->dn) {
err = dsa_shared_port_link_register_of(dp);
if (err)
break;
dsa_port_link_registered = true;
} else {
dev_warn(ds->dev,
"skipping link registration for DSA port %d\n",
dp->index);
}
err = dsa_port_enable(dp, NULL);
if (err)
......@@ -505,7 +517,7 @@ static int dsa_port_setup(struct dsa_port *dp)
if (err && dsa_port_enabled)
dsa_port_disable(dp);
if (err && dsa_port_link_registered)
dsa_port_link_unregister_of(dp);
dsa_shared_port_link_unregister_of(dp);
if (err) {
if (ds->ops->port_teardown)
ds->ops->port_teardown(ds, dp->index);
......@@ -577,11 +589,13 @@ static void dsa_port_teardown(struct dsa_port *dp)
break;
case DSA_PORT_TYPE_CPU:
dsa_port_disable(dp);
dsa_port_link_unregister_of(dp);
if (dp->dn)
dsa_shared_port_link_unregister_of(dp);
break;
case DSA_PORT_TYPE_DSA:
dsa_port_disable(dp);
dsa_port_link_unregister_of(dp);
if (dp->dn)
dsa_shared_port_link_unregister_of(dp);
break;
case DSA_PORT_TYPE_USER:
if (dp->slave) {
......
......@@ -285,8 +285,8 @@ int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
const struct switchdev_obj_ring_role_mrp *mrp);
int dsa_port_phylink_create(struct dsa_port *dp);
int dsa_port_link_register_of(struct dsa_port *dp);
void dsa_port_link_unregister_of(struct dsa_port *dp);
int dsa_shared_port_link_register_of(struct dsa_port *dp);
void dsa_shared_port_link_unregister_of(struct dsa_port *dp);
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast);
......
......@@ -1555,7 +1555,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
return 0;
}
static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable)
{
struct dsa_switch *ds = dp->ds;
struct phy_device *phydev;
......@@ -1593,7 +1593,7 @@ static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
return err;
}
static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
static int dsa_shared_port_fixed_link_register_of(struct dsa_port *dp)
{
struct device_node *dn = dp->dn;
struct dsa_switch *ds = dp->ds;
......@@ -1627,7 +1627,7 @@ static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
return 0;
}
static int dsa_port_phylink_register(struct dsa_port *dp)
static int dsa_shared_port_phylink_register(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
struct device_node *port_dn = dp->dn;
......@@ -1653,22 +1653,184 @@ static int dsa_port_phylink_register(struct dsa_port *dp)
return err;
}
int dsa_port_link_register_of(struct dsa_port *dp)
/* During the initial DSA driver migration to OF, port nodes were sometimes
* added to device trees with no indication of how they should operate from a
* link management perspective (phy-handle, fixed-link, etc). Additionally, the
* phy-mode may be absent. The interpretation of these port OF nodes depends on
* their type.
*
* User ports with no phy-handle or fixed-link are expected to connect to an
* internal PHY located on the ds->slave_mii_bus at an MDIO address equal to
* the port number. This description is still actively supported.
*
* Shared (CPU and DSA) ports with no phy-handle or fixed-link are expected to
* operate at the maximum speed that their phy-mode is capable of. If the
* phy-mode is absent, they are expected to operate using the phy-mode
* supported by the port that gives the highest link speed. It is unspecified
* if the port should use flow control or not, half duplex or full duplex, or
* if the phy-mode is a SERDES link, whether in-band autoneg is expected to be
* enabled or not.
*
* In the latter case of shared ports, omitting the link management description
* from the firmware node is deprecated and strongly discouraged. DSA uses
* phylink, which rejects the firmware nodes of these ports for lacking
* required properties.
*
* For switches in this table, DSA will skip enforcing validation and will
* later omit registering a phylink instance for the shared ports, if they lack
* a fixed-link, a phy-handle, or a managed = "in-band-status" property.
* It becomes the responsibility of the driver to ensure that these ports
* operate at the maximum speed (whatever this means) and will interoperate
* with the DSA master or other cascade port, since phylink methods will not be
* invoked for them.
*
* If you are considering expanding this table for newly introduced switches,
* think again. It is OK to remove switches from this table if there aren't DT
* blobs in circulation which rely on defaulting the shared ports.
*/
static const char * const dsa_switches_apply_workarounds[] = {
#if IS_ENABLED(CONFIG_NET_DSA_XRS700X)
"arrow,xrs7003e",
"arrow,xrs7003f",
"arrow,xrs7004e",
"arrow,xrs7004f",
#endif
#if IS_ENABLED(CONFIG_B53)
"brcm,bcm5325",
"brcm,bcm53115",
"brcm,bcm53125",
"brcm,bcm53128",
"brcm,bcm5365",
"brcm,bcm5389",
"brcm,bcm5395",
"brcm,bcm5397",
"brcm,bcm5398",
"brcm,bcm53010-srab",
"brcm,bcm53011-srab",
"brcm,bcm53012-srab",
"brcm,bcm53018-srab",
"brcm,bcm53019-srab",
"brcm,bcm5301x-srab",
"brcm,bcm11360-srab",
"brcm,bcm58522-srab",
"brcm,bcm58525-srab",
"brcm,bcm58535-srab",
"brcm,bcm58622-srab",
"brcm,bcm58623-srab",
"brcm,bcm58625-srab",
"brcm,bcm88312-srab",
"brcm,cygnus-srab",
"brcm,nsp-srab",
"brcm,omega-srab",
"brcm,bcm3384-switch",
"brcm,bcm6328-switch",
"brcm,bcm6368-switch",
"brcm,bcm63xx-switch",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_BCM_SF2)
"brcm,bcm7445-switch-v4.0",
"brcm,bcm7278-switch-v4.0",
"brcm,bcm7278-switch-v4.8",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_LANTIQ_GSWIP)
"lantiq,xrx200-gswip",
"lantiq,xrx300-gswip",
"lantiq,xrx330-gswip",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6060)
"marvell,mv88e6060",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6XXX)
"marvell,mv88e6085",
"marvell,mv88e6190",
"marvell,mv88e6250",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)
"microchip,ksz8765",
"microchip,ksz8794",
"microchip,ksz8795",
"microchip,ksz8863",
"microchip,ksz8873",
"microchip,ksz9477",
"microchip,ksz9897",
"microchip,ksz9893",
"microchip,ksz9563",
"microchip,ksz8563",
"microchip,ksz9567",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_MDIO)
"smsc,lan9303-mdio",
#endif
#if IS_ENABLED(CONFIG_NET_DSA_SMSC_LAN9303_I2C)
"smsc,lan9303-i2c",
#endif
NULL,
};
static void dsa_shared_port_validate_of(struct dsa_port *dp,
bool *missing_phy_mode,
bool *missing_link_description)
{
struct device_node *dn = dp->dn, *phy_np;
struct dsa_switch *ds = dp->ds;
struct device_node *phy_np;
phy_interface_t mode;
*missing_phy_mode = false;
*missing_link_description = false;
if (of_get_phy_mode(dn, &mode)) {
*missing_phy_mode = true;
dev_err(ds->dev,
"OF node %pOF of %s port %d lacks the required \"phy-mode\" property\n",
dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
}
/* Note: of_phy_is_fixed_link() also returns true for
* managed = "in-band-status"
*/
if (of_phy_is_fixed_link(dn))
return;
phy_np = of_parse_phandle(dn, "phy-handle", 0);
if (phy_np) {
of_node_put(phy_np);
return;
}
*missing_link_description = true;
dev_err(ds->dev,
"OF node %pOF of %s port %d lacks the required \"phy-handle\", \"fixed-link\" or \"managed\" properties\n",
dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
}
int dsa_shared_port_link_register_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
bool missing_link_description;
bool missing_phy_mode;
int port = dp->index;
dsa_shared_port_validate_of(dp, &missing_phy_mode,
&missing_link_description);
if ((missing_phy_mode || missing_link_description) &&
!of_device_compatible_match(ds->dev->of_node,
dsa_switches_apply_workarounds))
return -EINVAL;
if (!ds->ops->adjust_link) {
phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
if (of_phy_is_fixed_link(dp->dn) || phy_np) {
if (missing_link_description) {
dev_warn(ds->dev,
"Skipping phylink registration for %s port %d\n",
dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
} else {
if (ds->ops->phylink_mac_link_down)
ds->ops->phylink_mac_link_down(ds, port,
MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
of_node_put(phy_np);
return dsa_port_phylink_register(dp);
return dsa_shared_port_phylink_register(dp);
}
of_node_put(phy_np);
return 0;
}
......@@ -1676,12 +1838,12 @@ int dsa_port_link_register_of(struct dsa_port *dp)
"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);
return dsa_shared_port_fixed_link_register_of(dp);
else
return dsa_port_setup_phy_of(dp, true);
return dsa_shared_port_setup_phy_of(dp, true);
}
void dsa_port_link_unregister_of(struct dsa_port *dp)
void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
......@@ -1697,7 +1859,7 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
if (of_phy_is_fixed_link(dp->dn))
of_phy_deregister_fixed_link(dp->dn);
else
dsa_port_setup_phy_of(dp, false);
dsa_shared_port_setup_phy_of(dp, false);
}
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr)
......
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