static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) { struct fwnode_handle *dn; const char *managed; dn = fwnode_get_named_child_node(fwnode, "fixed-link"); if (dn || fwnode_property_present(fwnode, "fixed-link")) pl->link_an_mode = MLO_AN_FIXED; fwnode_handle_put(dn); if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 && strcmp(managed, "in-band-status") == 0) { if (pl->link_an_mode == MLO_AN_FIXED) { netdev_err(pl->netdev, "can't use both fixed-link and in-band-status\n"); return -EINVAL; } linkmode_zero(pl->supported); phylink_set(pl->supported, MII); phylink_set(pl->supported, Autoneg); phylink_set(pl->supported, Asym_Pause); phylink_set(pl->supported, Pause); pl->link_config.an_enabled = true; pl->link_an_mode = MLO_AN_INBAND; switch (pl->link_config.interface) { case PHY_INTERFACE_MODE_SGMII: phylink_set(pl->supported, 10baseT_Half); phylink_set(pl->supported, 10baseT_Full); phylink_set(pl->supported, 100baseT_Half); phylink_set(pl->supported, 100baseT_Full); phylink_set(pl->supported, 1000baseT_Half); phylink_set(pl->supported, 1000baseT_Full); break; case PHY_INTERFACE_MODE_1000BASEX: phylink_set(pl->supported, 1000baseX_Full); break; case PHY_INTERFACE_MODE_2500BASEX: phylink_set(pl->supported, 2500baseX_Full); break; case PHY_INTERFACE_MODE_10GKR: phylink_set(pl->supported, 10baseT_Half); phylink_set(pl->supported, 10baseT_Full); phylink_set(pl->supported, 100baseT_Half); phylink_set(pl->supported, 100baseT_Full); phylink_set(pl->supported, 1000baseT_Half); phylink_set(pl->supported, 1000baseT_Full); phylink_set(pl->supported, 1000baseX_Full); phylink_set(pl->supported, 10000baseKR_Full); phylink_set(pl->supported, 10000baseCR_Full); phylink_set(pl->supported, 10000baseSR_Full); phylink_set(pl->supported, 10000baseLR_Full); phylink_set(pl->supported, 10000baseLRM_Full); phylink_set(pl->supported, 10000baseER_Full); break; default: netdev_err(pl->netdev, "incorrect link mode %s for in-band status\n", phy_modes(pl->link_config.interface)); return -EINVAL; } linkmode_copy(pl->link_config.advertising, pl->supported); if (phylink_validate(pl, pl->supported, &pl->link_config)) { netdev_err(pl->netdev, "failed to validate link configuration for in-band status\n"); return -EINVAL; } } return 0; }
/** * device_get_named_child_node - Return first matching named child node handle * @dev: Device to find the named child node for. * @childname: String to match child node name against. */ struct fwnode_handle *device_get_named_child_node(struct device *dev, const char *childname) { return fwnode_get_named_child_node(dev_fwnode(dev), childname); }
static int phylink_parse_fixedlink(struct phylink *pl, struct fwnode_handle *fwnode) { struct fwnode_handle *fixed_node; const struct phy_setting *s; struct gpio_desc *desc; u32 speed; int ret; fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); if (fixed_node) { ret = fwnode_property_read_u32(fixed_node, "speed", &speed); pl->link_config.speed = speed; pl->link_config.duplex = DUPLEX_HALF; if (fwnode_property_read_bool(fixed_node, "full-duplex")) pl->link_config.duplex = DUPLEX_FULL; /* We treat the "pause" and "asym-pause" terminology as * defining the link partner's ability. */ if (fwnode_property_read_bool(fixed_node, "pause")) pl->link_config.pause |= MLO_PAUSE_SYM; if (fwnode_property_read_bool(fixed_node, "asym-pause")) pl->link_config.pause |= MLO_PAUSE_ASYM; if (ret == 0) { desc = fwnode_get_named_gpiod(fixed_node, "link-gpios", 0, GPIOD_IN, "?"); if (!IS_ERR(desc)) pl->link_gpio = desc; else if (desc == ERR_PTR(-EPROBE_DEFER)) ret = -EPROBE_DEFER; } fwnode_handle_put(fixed_node); if (ret) return ret; } else { u32 prop[5]; ret = fwnode_property_read_u32_array(fwnode, "fixed-link", NULL, 0); if (ret != ARRAY_SIZE(prop)) { netdev_err(pl->netdev, "broken fixed-link?\n"); return -EINVAL; } ret = fwnode_property_read_u32_array(fwnode, "fixed-link", prop, ARRAY_SIZE(prop)); if (!ret) { pl->link_config.duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF; pl->link_config.speed = prop[2]; if (prop[3]) pl->link_config.pause |= MLO_PAUSE_SYM; if (prop[4]) pl->link_config.pause |= MLO_PAUSE_ASYM; } } if (pl->link_config.speed > SPEED_1000 && pl->link_config.duplex != DUPLEX_FULL) netdev_warn(pl->netdev, "fixed link specifies half duplex for %dMbps link?\n", pl->link_config.speed); bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); linkmode_copy(pl->link_config.advertising, pl->supported); phylink_validate(pl, pl->supported, &pl->link_config); s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex, pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS, true); linkmode_zero(pl->supported); phylink_set(pl->supported, MII); if (s) { __set_bit(s->bit, pl->supported); } else { netdev_warn(pl->netdev, "fixed link %s duplex %dMbps not recognised\n", pl->link_config.duplex == DUPLEX_FULL ? "full" : "half", pl->link_config.speed); } linkmode_and(pl->link_config.advertising, pl->link_config.advertising, pl->supported); pl->link_config.link = 1; pl->link_config.an_complete = 1; return 0; }