static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx, struct ethtool_link_ksettings *cmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); int rc; cmd->base.speed = efx->link_state.speed; cmd->base.duplex = efx->link_state.fd; cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media); cmd->base.phy_address = phy_cfg->port; cmd->base.autoneg = !!(efx->link_advertising[0] & ADVERTISED_Autoneg); cmd->base.mdio_support = (efx->mdio.mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); mcdi_to_ethtool_linkset(phy_cfg->media, phy_cfg->supported_cap, cmd->link_modes.supported); memcpy(cmd->link_modes.advertising, efx->link_advertising, sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK())); BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) return; mcdi_to_ethtool_linkset(phy_cfg->media, MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP), cmd->link_modes.lp_advertising); }
static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy) { struct phylink_link_state config; __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); u32 advertising; int ret; memset(&config, 0, sizeof(config)); ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported); ethtool_convert_legacy_u32_to_link_mode(config.advertising, phy->advertising); config.interface = pl->link_config.interface; /* * This is the new way of dealing with flow control for PHYs, * as described by Timur Tabi in commit 529ed1275263 ("net: phy: * phy drivers should not set SUPPORTED_[Asym_]Pause") except * using our validate call to the MAC, we rely upon the MAC * clearing the bits from both supported and advertising fields. */ if (phylink_test(supported, Pause)) phylink_set(config.advertising, Pause); if (phylink_test(supported, Asym_Pause)) phylink_set(config.advertising, Asym_Pause); ret = phylink_validate(pl, supported, &config); if (ret) return ret; phy->phylink = pl; phy->phy_link_change = phylink_phy_change; netdev_info(pl->netdev, "PHY [%s] driver [%s]\n", dev_name(&phy->mdio.dev), phy->drv->name); mutex_lock(&phy->lock); mutex_lock(&pl->state_mutex); pl->netdev->phydev = phy; pl->phydev = phy; linkmode_copy(pl->supported, supported); linkmode_copy(pl->link_config.advertising, config.advertising); /* Restrict the phy advertisment according to the MAC support. */ ethtool_convert_link_mode_to_legacy_u32(&advertising, config.advertising); phy->advertising = advertising; mutex_unlock(&pl->state_mutex); mutex_unlock(&phy->lock); netdev_dbg(pl->netdev, "phy: setting supported %*pb advertising 0x%08x\n", __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported, phy->advertising); phy_start_machine(phy); if (phy->irq > 0) phy_start_interrupts(phy); return 0; }
static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b) { __ETHTOOL_DECLARE_LINK_MODE_MASK(mask); linkmode_zero(mask); phylink_set_port_modes(mask); linkmode_and(dst, dst, mask); linkmode_or(dst, dst, b); }
static int phylink_is_empty_linkmode(const unsigned long *linkmode) { __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = { 0, }; phylink_set_port_modes(tmp); phylink_set(tmp, Autoneg); phylink_set(tmp, Pause); phylink_set(tmp, Asym_Pause); bitmap_andnot(tmp, linkmode, tmp, __ETHTOOL_LINK_MODE_MASK_NBITS); return linkmode_empty(tmp); }
static void bcm_sf2_sw_validate(struct dsa_switch *ds, int port, unsigned long *supported, struct phylink_link_state *state) { __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; if (!phy_interface_mode_is_rgmii(state->interface) && state->interface != PHY_INTERFACE_MODE_MII && state->interface != PHY_INTERFACE_MODE_REVMII && state->interface != PHY_INTERFACE_MODE_GMII && state->interface != PHY_INTERFACE_MODE_INTERNAL && state->interface != PHY_INTERFACE_MODE_MOCA) { bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); dev_err(ds->dev, "Unsupported interface: %d\n", state->interface); return; } /* Allow all the expected bits */ phylink_set(mask, Autoneg); phylink_set_port_modes(mask); phylink_set(mask, Pause); phylink_set(mask, Asym_Pause); /* With the exclusion of MII and Reverse MII, we support Gigabit, * including Half duplex */ if (state->interface != PHY_INTERFACE_MODE_MII && state->interface != PHY_INTERFACE_MODE_REVMII) { phylink_set(mask, 1000baseT_Full); phylink_set(mask, 1000baseT_Half); } phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); phylink_set(mask, 100baseT_Half); phylink_set(mask, 100baseT_Full); bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); bitmap_and(state->advertising, state->advertising, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); }
static bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, const unsigned long *src) { bool retval = true; /* TODO: following test will soon always be true */ if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) { __ETHTOOL_DECLARE_LINK_MODE_MASK(ext); bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS); bitmap_fill(ext, 32); bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS); if (bitmap_intersects(ext, src, __ETHTOOL_LINK_MODE_MASK_NBITS)) { /* src mask goes beyond bit 31 */ retval = false; } } *legacy_u32 = src[0]; return retval; }
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; }
static int mv3310_config_init(struct phy_device *phydev) { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; u32 mask; int val; /* Check that the PHY interface type is compatible */ if (phydev->interface != PHY_INTERFACE_MODE_SGMII && phydev->interface != PHY_INTERFACE_MODE_XAUI && phydev->interface != PHY_INTERFACE_MODE_RXAUI && phydev->interface != PHY_INTERFACE_MODE_10GKR) return -ENODEV; __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported); __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported); if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) { val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); if (val < 0) return val; if (val & MDIO_AN_STAT1_ABLE) __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported); } val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2); if (val < 0) return val; /* Ethtool does not support the WAN mode bits */ if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR | MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 | MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW | MDIO_PMA_STAT2_10GBEW)) __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); if (val & MDIO_PMA_STAT2_10GBSR) __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported); if (val & MDIO_PMA_STAT2_10GBLR) __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported); if (val & MDIO_PMA_STAT2_10GBER) __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported); if (val & MDIO_PMA_STAT2_EXTABLE) { val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); if (val < 0) return val; if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT | MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT)) __set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported); if (val & MDIO_PMA_EXTABLE_10GBLRM) __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR | MDIO_PMA_EXTABLE_1000BKX)) __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported); if (val & MDIO_PMA_EXTABLE_10GBLRM) __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_10GBT) __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_10GBKX4) __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_10GBKR) __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_1000BT) __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_1000BKX) __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, supported); if (val & MDIO_PMA_EXTABLE_100BTX) { __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, supported); __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, supported); } if (val & MDIO_PMA_EXTABLE_10BT) { __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, supported); __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, supported); } } if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported)) dev_warn(&phydev->mdio.dev, "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n", __ETHTOOL_LINK_MODE_MASK_NBITS, supported); phydev->supported &= mask; phydev->advertising &= phydev->supported; return 0; }