/** * phylink_start() - start a phylink instance * @pl: a pointer to a &struct phylink returned from phylink_create() * * Start the phylink instance specified by @pl, configuring the MAC for the * desired link mode(s) and negotiation style. This should be called from the * network device driver's &struct net_device_ops ndo_open() method. */ void phylink_start(struct phylink *pl) { ASSERT_RTNL(); netdev_info(pl->netdev, "configuring for %s/%s link mode\n", phylink_an_mode_str(pl->link_an_mode), phy_modes(pl->link_config.interface)); /* Always set the carrier off */ netif_carrier_off(pl->netdev); /* Apply the link configuration to the MAC when starting. This allows * a fixed-link to start with the correct parameters, and also * ensures that we set the appropriate advertisement for Serdes links. */ phylink_resolve_flow(pl, &pl->link_config); phylink_mac_config(pl, &pl->link_config); /* Restart autonegotiation if using 802.3z to ensure that the link * parameters are properly negotiated. This is necessary for DSA * switches using 802.3z negotiation to ensure they see our modes. */ phylink_mac_an_restart(pl); clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); phylink_run_resolve(pl); if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio)) mod_timer(&pl->link_poll, jiffies + HZ); if (pl->sfp_bus) sfp_upstream_start(pl->sfp_bus); if (pl->phydev) phy_start(pl->phydev); }
static void phylink_mac_config(struct phylink *pl, const struct phylink_link_state *state) { netdev_dbg(pl->netdev, "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", __func__, phylink_an_mode_str(pl->link_an_mode), phy_modes(state->interface), phy_speed_to_str(state->speed), phy_duplex_to_str(state->duplex), __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, state->pause, state->link, state->an_enabled); pl->ops->mac_config(pl->netdev, pl->link_an_mode, state); }
void phylink_start(struct phylink *pl) { WARN_ON(!lockdep_rtnl_is_held()); netdev_info(pl->netdev, "configuring for %s/%s link mode\n", phylink_an_mode_str(pl->link_an_mode), phy_modes(pl->link_config.interface)); /* Apply the link configuration to the MAC when starting. This allows * a fixed-link to start with the correct parameters, and also * ensures that we set the appropriate advertisment for Serdes links. */ phylink_resolve_flow(pl, &pl->link_config); phylink_mac_config(pl, &pl->link_config); clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); phylink_run_resolve(pl); if (pl->sfp_bus) sfp_upstream_start(pl->sfp_bus); if (pl->phydev) phy_start(pl->phydev); }
static int phylink_sfp_module_insert(void *upstream, const struct sfp_eeprom_id *id) { struct phylink *pl = upstream; __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; struct phylink_link_state config; phy_interface_t iface; int mode, ret = 0; bool changed; u8 port; sfp_parse_support(pl->sfp_bus, id, support); port = sfp_parse_port(pl->sfp_bus, id, support); iface = sfp_parse_interface(pl->sfp_bus, id); WARN_ON(!lockdep_rtnl_is_held()); switch (iface) { case PHY_INTERFACE_MODE_SGMII: mode = MLO_AN_SGMII; break; case PHY_INTERFACE_MODE_1000BASEX: mode = MLO_AN_8023Z; break; default: return -EINVAL; } memset(&config, 0, sizeof(config)); linkmode_copy(config.advertising, support); config.interface = iface; config.speed = SPEED_UNKNOWN; config.duplex = DUPLEX_UNKNOWN; config.pause = MLO_PAUSE_AN; config.an_enabled = pl->link_config.an_enabled; /* Ignore errors if we're expecting a PHY to attach later */ ret = phylink_validate(pl, support, &config); if (ret) { netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n", phylink_an_mode_str(mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); return ret; } netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n", phylink_an_mode_str(mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support); if (mode == MLO_AN_8023Z && pl->phydev) return -EINVAL; changed = !bitmap_equal(pl->supported, support, __ETHTOOL_LINK_MODE_MASK_NBITS); if (changed) { linkmode_copy(pl->supported, support); linkmode_copy(pl->link_config.advertising, config.advertising); } if (pl->link_an_mode != mode || pl->link_config.interface != config.interface) { pl->link_config.interface = config.interface; pl->link_an_mode = mode; changed = true; netdev_info(pl->netdev, "switched to %s/%s link mode\n", phylink_an_mode_str(mode), phy_modes(config.interface)); } pl->link_port = port; if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) phylink_mac_config(pl, &pl->link_config); return ret; }
static int phylink_sfp_module_insert(void *upstream, const struct sfp_eeprom_id *id) { struct phylink *pl = upstream; __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; struct phylink_link_state config; phy_interface_t iface; int ret = 0; bool changed; u8 port; ASSERT_RTNL(); sfp_parse_support(pl->sfp_bus, id, support); port = sfp_parse_port(pl->sfp_bus, id, support); memset(&config, 0, sizeof(config)); linkmode_copy(config.advertising, support); config.interface = PHY_INTERFACE_MODE_NA; config.speed = SPEED_UNKNOWN; config.duplex = DUPLEX_UNKNOWN; config.pause = MLO_PAUSE_AN; config.an_enabled = pl->link_config.an_enabled; /* Ignore errors if we're expecting a PHY to attach later */ ret = phylink_validate(pl, support, &config); if (ret) { netdev_err(pl->netdev, "validation with support %*pb failed: %d\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); return ret; } iface = sfp_select_interface(pl->sfp_bus, id, config.advertising); if (iface == PHY_INTERFACE_MODE_NA) { netdev_err(pl->netdev, "selection of interface failed, advertisement %*pb\n", __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising); return -EINVAL; } config.interface = iface; ret = phylink_validate(pl, support, &config); if (ret) { netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); return ret; } netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support); if (phy_interface_mode_is_8023z(iface) && pl->phydev) return -EINVAL; changed = !bitmap_equal(pl->supported, support, __ETHTOOL_LINK_MODE_MASK_NBITS); if (changed) { linkmode_copy(pl->supported, support); linkmode_copy(pl->link_config.advertising, config.advertising); } if (pl->link_an_mode != MLO_AN_INBAND || pl->link_config.interface != config.interface) { pl->link_config.interface = config.interface; pl->link_an_mode = MLO_AN_INBAND; changed = true; netdev_info(pl->netdev, "switched to %s/%s link mode\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface)); } pl->link_port = port; if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) phylink_mac_config(pl, &pl->link_config); return ret; }