Provide a software node for default settings when no phy, sfp or fixed link is specified. Signed-off-by: Russell King (Oracle) <rmk+kernel@xxxxxxxxxxxxxxx> --- drivers/net/dsa/mv88e6xxx/chip.c | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b73d1d6747b7..dde0c306fb3a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -26,6 +26,7 @@ #include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/of_mdio.h> +#include <linux/of_net.h> #include <linux/platform_data/mv88e6xxx.h> #include <linux/netdevice.h> #include <linux/gpio/consumer.h> @@ -841,6 +842,113 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, } } +static struct fwnode_handle *mv88e6xxx_create_fixed_swnode(struct fwnode_handle *parent, + int speed, + int duplex) +{ + struct property_entry fixed_link_props[3] = { }; + + fixed_link_props[0] = PROPERTY_ENTRY_U32("speed", speed); + if (duplex == DUPLEX_FULL) + fixed_link_props[1] = PROPERTY_ENTRY_BOOL("full-duplex"); + + return fwnode_create_named_software_node(fixed_link_props, parent, + "fixed-link"); +} + +static struct fwnode_handle *mv88e6xxx_create_port_swnode(phy_interface_t mode, + int speed, + int duplex) +{ + struct property_entry port_props[2] = {}; + struct fwnode_handle *fixed_link_fwnode; + struct fwnode_handle *new_port_fwnode; + + port_props[0] = PROPERTY_ENTRY_STRING("phy-mode", phy_modes(mode)); + new_port_fwnode = fwnode_create_software_node(port_props, NULL); + if (IS_ERR(new_port_fwnode)) + return new_port_fwnode; + + fixed_link_fwnode = mv88e6xxx_create_fixed_swnode(new_port_fwnode, + speed, duplex); + if (IS_ERR(fixed_link_fwnode)) { + fwnode_remove_software_node(new_port_fwnode); + return fixed_link_fwnode; + } + + return new_port_fwnode; +} + +static unsigned long mv88e6xxx_get_max_caps(struct phylink_config *config, + phy_interface_t *mode) +{ + unsigned long max_caps, caps, mac_caps; + phy_interface_t interface; + + mac_caps = config->mac_capabilities; + if (*mode != PHY_INTERFACE_MODE_NA) + return phylink_get_capabilities(*mode, mac_caps, + RATE_MATCH_NONE); + + max_caps = 0; + for_each_set_bit(interface, config->supported_interfaces, + PHY_INTERFACE_MODE_MAX) { + caps = phylink_get_capabilities(interface, mac_caps, + RATE_MATCH_NONE); + if (caps > max_caps) { + max_caps = caps; + *mode = interface; + } + } + + return max_caps; +} + +static struct fwnode_handle *mv88e6xxx_port_get_fwnode(struct dsa_switch *ds, + int port, + struct fwnode_handle *h) +{ + struct mv88e6xxx_chip *chip = ds->priv; + struct device_node *np, *phy_node; + int speed, duplex, err; + phy_interface_t mode; + struct dsa_port *dp; + unsigned long caps; + + dp = dsa_to_port(ds, port); + if (dsa_port_is_user(dp)) + return h; + + /* No DT? Eh? */ + np = to_of_node(h); + if (!np) + return h; + + /* If a PHY, fixed-link specification, or in-band mode, then we + * don't need to do any fixup. Simply return the provided fwnode. + */ + phy_node = of_parse_phandle(np, "phy-handle", 0); + of_node_put(phy_node); + if (phy_node || of_phy_is_fixed_link(np)) + return h; + + /* Get the DT specified phy-mode. If missing, try the chip's max speed + * mode method if implemented, otherwise try the supported_interfaces + * mask for the interface mode that gives the fastest speeds. + */ + err = of_get_phy_mode(np, &mode); + if (err && chip->info->ops->port_max_speed_mode) + mode = chip->info->ops->port_max_speed_mode(port); + + caps = mv88e6xxx_get_max_caps(&dp->pl_config, &mode); + + err = phylink_find_max_speed(caps, &speed, &duplex); + if (err) + return ERR_PTR(err); + + return mv88e6xxx_create_port_swnode(mode, speed, duplex); +} + static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) @@ -6994,6 +7102,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .teardown = mv88e6xxx_teardown, .port_setup = mv88e6xxx_port_setup, .port_teardown = mv88e6xxx_port_teardown, + .port_get_fwnode = mv88e6xxx_port_get_fwnode, .phylink_get_caps = mv88e6xxx_get_caps, .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, .phylink_mac_config = mv88e6xxx_mac_config, -- 2.30.2