15f857575SAndrew Lunn // SPDX-License-Identifier: GPL-2.0 29525ae83SRussell King /* 39525ae83SRussell King * phylink models the MAC to optional PHY connection, supporting 49525ae83SRussell King * technologies such as SFP cages where the PHY is hot-pluggable. 59525ae83SRussell King * 69525ae83SRussell King * Copyright (C) 2015 Russell King 79525ae83SRussell King */ 825396f68SCalvin Johnson #include <linux/acpi.h> 99525ae83SRussell King #include <linux/ethtool.h> 109525ae83SRussell King #include <linux/export.h> 119525ae83SRussell King #include <linux/gpio/consumer.h> 129525ae83SRussell King #include <linux/netdevice.h> 139525ae83SRussell King #include <linux/of.h> 149525ae83SRussell King #include <linux/of_mdio.h> 159525ae83SRussell King #include <linux/phy.h> 169525ae83SRussell King #include <linux/phy_fixed.h> 179525ae83SRussell King #include <linux/phylink.h> 189525ae83SRussell King #include <linux/rtnetlink.h> 199525ae83SRussell King #include <linux/spinlock.h> 209cd00a8aSRussell King #include <linux/timer.h> 219525ae83SRussell King #include <linux/workqueue.h> 229525ae83SRussell King 23ce0aa27fSRussell King #include "sfp.h" 249525ae83SRussell King #include "swphy.h" 259525ae83SRussell King 269525ae83SRussell King #define SUPPORTED_INTERFACES \ 279525ae83SRussell King (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_FIBRE | \ 289525ae83SRussell King SUPPORTED_BNC | SUPPORTED_AUI | SUPPORTED_Backplane) 299525ae83SRussell King #define ADVERTISED_INTERFACES \ 309525ae83SRussell King (ADVERTISED_TP | ADVERTISED_MII | ADVERTISED_FIBRE | \ 319525ae83SRussell King ADVERTISED_BNC | ADVERTISED_AUI | ADVERTISED_Backplane) 329525ae83SRussell King 339525ae83SRussell King enum { 349525ae83SRussell King PHYLINK_DISABLE_STOPPED, 35ce0aa27fSRussell King PHYLINK_DISABLE_LINK, 36f9749365SRussell King (Oracle) PHYLINK_DISABLE_MAC_WOL, 379525ae83SRussell King }; 389525ae83SRussell King 398796c892SRussell King /** 408796c892SRussell King * struct phylink - internal data type for phylink 418796c892SRussell King */ 429525ae83SRussell King struct phylink { 438796c892SRussell King /* private: */ 449525ae83SRussell King struct net_device *netdev; 45e7765d63SRussell King const struct phylink_mac_ops *mac_ops; 4644cc27e4SIoana Ciornei struct phylink_config *config; 477137e18fSRussell King struct phylink_pcs *pcs; 4843de6195SIoana Ciornei struct device *dev; 4943de6195SIoana Ciornei unsigned int old_link_state:1; 509525ae83SRussell King 519525ae83SRussell King unsigned long phylink_disable_state; /* bitmask of disables */ 529525ae83SRussell King struct phy_device *phydev; 539525ae83SRussell King phy_interface_t link_interface; /* PHY_INTERFACE_xxx */ 5424cf0e69SRussell King u8 cfg_link_an_mode; /* MLO_AN_xxx */ 5524cf0e69SRussell King u8 cur_link_an_mode; 569525ae83SRussell King u8 link_port; /* The current non-phy ethtool port */ 579525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 589525ae83SRussell King 599525ae83SRussell King /* The link configuration settings */ 609525ae83SRussell King struct phylink_link_state link_config; 61c6787263SRussell King 62c6787263SRussell King /* The current settings */ 63c6787263SRussell King phy_interface_t cur_interface; 64c6787263SRussell King 659525ae83SRussell King struct gpio_desc *link_gpio; 667b3b0e89SRussell King unsigned int link_irq; 679cd00a8aSRussell King struct timer_list link_poll; 681ac63e39SFlorian Fainelli void (*get_fixed_state)(struct net_device *dev, 691ac63e39SFlorian Fainelli struct phylink_link_state *s); 709525ae83SRussell King 719525ae83SRussell King struct mutex state_mutex; 729525ae83SRussell King struct phylink_link_state phy_state; 739525ae83SRussell King struct work_struct resolve; 749525ae83SRussell King 759525ae83SRussell King bool mac_link_dropped; 7610544570SRussell King (Oracle) bool using_mac_select_pcs; 77ce0aa27fSRussell King 78ce0aa27fSRussell King struct sfp_bus *sfp_bus; 7952c95600SRussell King bool sfp_may_have_phy; 80fd580c98SRussell King DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); 8152c95600SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); 8252c95600SRussell King u8 sfp_port; 839525ae83SRussell King }; 849525ae83SRussell King 8517091180SIoana Ciornei #define phylink_printk(level, pl, fmt, ...) \ 8617091180SIoana Ciornei do { \ 8717091180SIoana Ciornei if ((pl)->config->type == PHYLINK_NETDEV) \ 8817091180SIoana Ciornei netdev_printk(level, (pl)->netdev, fmt, ##__VA_ARGS__); \ 8917091180SIoana Ciornei else if ((pl)->config->type == PHYLINK_DEV) \ 9017091180SIoana Ciornei dev_printk(level, (pl)->dev, fmt, ##__VA_ARGS__); \ 9117091180SIoana Ciornei } while (0) 9217091180SIoana Ciornei 9317091180SIoana Ciornei #define phylink_err(pl, fmt, ...) \ 9417091180SIoana Ciornei phylink_printk(KERN_ERR, pl, fmt, ##__VA_ARGS__) 9517091180SIoana Ciornei #define phylink_warn(pl, fmt, ...) \ 9617091180SIoana Ciornei phylink_printk(KERN_WARNING, pl, fmt, ##__VA_ARGS__) 9717091180SIoana Ciornei #define phylink_info(pl, fmt, ...) \ 9817091180SIoana Ciornei phylink_printk(KERN_INFO, pl, fmt, ##__VA_ARGS__) 999d68db50SFlorian Fainelli #if defined(CONFIG_DYNAMIC_DEBUG) 1009d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \ 1019d68db50SFlorian Fainelli do { \ 1029d68db50SFlorian Fainelli if ((pl)->config->type == PHYLINK_NETDEV) \ 1039d68db50SFlorian Fainelli netdev_dbg((pl)->netdev, fmt, ##__VA_ARGS__); \ 1049d68db50SFlorian Fainelli else if ((pl)->config->type == PHYLINK_DEV) \ 1059d68db50SFlorian Fainelli dev_dbg((pl)->dev, fmt, ##__VA_ARGS__); \ 1069d68db50SFlorian Fainelli } while (0) 1079d68db50SFlorian Fainelli #elif defined(DEBUG) 10817091180SIoana Ciornei #define phylink_dbg(pl, fmt, ...) \ 10917091180SIoana Ciornei phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__) 1109d68db50SFlorian Fainelli #else 1119d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \ 1129d68db50SFlorian Fainelli ({ \ 1139d68db50SFlorian Fainelli if (0) \ 1149d68db50SFlorian Fainelli phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__); \ 1159d68db50SFlorian Fainelli }) 1169d68db50SFlorian Fainelli #endif 11717091180SIoana Ciornei 1188796c892SRussell King /** 1198796c892SRussell King * phylink_set_port_modes() - set the port type modes in the ethtool mask 1208796c892SRussell King * @mask: ethtool link mode mask 1218796c892SRussell King * 1228796c892SRussell King * Sets all the port type modes in the ethtool mask. MAC drivers should 1238796c892SRussell King * use this in their 'validate' callback. 1248796c892SRussell King */ 1259525ae83SRussell King void phylink_set_port_modes(unsigned long *mask) 1269525ae83SRussell King { 1279525ae83SRussell King phylink_set(mask, TP); 1289525ae83SRussell King phylink_set(mask, AUI); 1299525ae83SRussell King phylink_set(mask, MII); 1309525ae83SRussell King phylink_set(mask, FIBRE); 1319525ae83SRussell King phylink_set(mask, BNC); 1329525ae83SRussell King phylink_set(mask, Backplane); 1339525ae83SRussell King } 1349525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_set_port_modes); 1359525ae83SRussell King 1369525ae83SRussell King static int phylink_is_empty_linkmode(const unsigned long *linkmode) 1379525ae83SRussell King { 1389525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = { 0, }; 1399525ae83SRussell King 1409525ae83SRussell King phylink_set_port_modes(tmp); 1419525ae83SRussell King phylink_set(tmp, Autoneg); 1429525ae83SRussell King phylink_set(tmp, Pause); 1439525ae83SRussell King phylink_set(tmp, Asym_Pause); 1449525ae83SRussell King 145554032cdSRussell King return linkmode_subset(linkmode, tmp); 1469525ae83SRussell King } 1479525ae83SRussell King 1489525ae83SRussell King static const char *phylink_an_mode_str(unsigned int mode) 1499525ae83SRussell King { 1509525ae83SRussell King static const char *modestr[] = { 1519525ae83SRussell King [MLO_AN_PHY] = "phy", 1529525ae83SRussell King [MLO_AN_FIXED] = "fixed", 15386a362c4SRussell King [MLO_AN_INBAND] = "inband", 1549525ae83SRussell King }; 1559525ae83SRussell King 1569525ae83SRussell King return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; 1579525ae83SRussell King } 1589525ae83SRussell King 15960611652SSean Anderson /** 160ae0e4bb2SSean Anderson * phylink_interface_max_speed() - get the maximum speed of a phy interface 161ae0e4bb2SSean Anderson * @interface: phy interface mode defined by &typedef phy_interface_t 162ae0e4bb2SSean Anderson * 163ae0e4bb2SSean Anderson * Determine the maximum speed of a phy interface. This is intended to help 164ae0e4bb2SSean Anderson * determine the correct speed to pass to the MAC when the phy is performing 165ae0e4bb2SSean Anderson * rate matching. 166ae0e4bb2SSean Anderson * 167ae0e4bb2SSean Anderson * Return: The maximum speed of @interface 168ae0e4bb2SSean Anderson */ 169ae0e4bb2SSean Anderson static int phylink_interface_max_speed(phy_interface_t interface) 170ae0e4bb2SSean Anderson { 171ae0e4bb2SSean Anderson switch (interface) { 172ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_100BASEX: 173ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_REVRMII: 174ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RMII: 175ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_SMII: 176ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_REVMII: 177ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MII: 178ae0e4bb2SSean Anderson return SPEED_100; 179ae0e4bb2SSean Anderson 180ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_TBI: 181ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MOCA: 182ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RTBI: 183ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_1000BASEX: 184ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_1000BASEKX: 185ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_TRGMII: 186ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_TXID: 187ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_RXID: 188ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_ID: 189ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII: 190ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_QSGMII: 191ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_SGMII: 192ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_GMII: 193ae0e4bb2SSean Anderson return SPEED_1000; 194ae0e4bb2SSean Anderson 195ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_2500BASEX: 196ae0e4bb2SSean Anderson return SPEED_2500; 197ae0e4bb2SSean Anderson 198ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_5GBASER: 199ae0e4bb2SSean Anderson return SPEED_5000; 200ae0e4bb2SSean Anderson 201ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XGMII: 202ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RXAUI: 203ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XAUI: 204ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_10GBASER: 205ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_10GKR: 206ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_USXGMII: 207ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_QUSGMII: 208ae0e4bb2SSean Anderson return SPEED_10000; 209ae0e4bb2SSean Anderson 210ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_25GBASER: 211ae0e4bb2SSean Anderson return SPEED_25000; 212ae0e4bb2SSean Anderson 213ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XLGMII: 214ae0e4bb2SSean Anderson return SPEED_40000; 215ae0e4bb2SSean Anderson 216ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_INTERNAL: 217ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_NA: 218ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MAX: 219ae0e4bb2SSean Anderson /* No idea! Garbage in, unknown out */ 220ae0e4bb2SSean Anderson return SPEED_UNKNOWN; 221ae0e4bb2SSean Anderson } 222ae0e4bb2SSean Anderson 223ae0e4bb2SSean Anderson /* If we get here, someone forgot to add an interface mode above */ 224ae0e4bb2SSean Anderson WARN_ON_ONCE(1); 225ae0e4bb2SSean Anderson return SPEED_UNKNOWN; 226ae0e4bb2SSean Anderson } 227ae0e4bb2SSean Anderson 228ae0e4bb2SSean Anderson /** 22960611652SSean Anderson * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes 23060611652SSean Anderson * @linkmodes: ethtool linkmode mask (must be already initialised) 23160611652SSean Anderson * @caps: bitmask of MAC capabilities 23260611652SSean Anderson * 23360611652SSean Anderson * Set all possible pause, speed and duplex linkmodes in @linkmodes that are 23460611652SSean Anderson * supported by the @caps. @linkmodes must have been initialised previously. 23560611652SSean Anderson */ 23660611652SSean Anderson void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps) 23734ae2c09SRussell King (Oracle) { 23834ae2c09SRussell King (Oracle) if (caps & MAC_SYM_PAUSE) 23934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes); 24034ae2c09SRussell King (Oracle) 24134ae2c09SRussell King (Oracle) if (caps & MAC_ASYM_PAUSE) 24234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes); 24334ae2c09SRussell King (Oracle) 24434ae2c09SRussell King (Oracle) if (caps & MAC_10HD) 24534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes); 24634ae2c09SRussell King (Oracle) 2473254e0b9SAlexandru Tachici if (caps & MAC_10FD) { 24834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes); 2493254e0b9SAlexandru Tachici __set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, linkmodes); 2503254e0b9SAlexandru Tachici } 25134ae2c09SRussell King (Oracle) 25234ae2c09SRussell King (Oracle) if (caps & MAC_100HD) { 25334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, linkmodes); 25434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, linkmodes); 25534ae2c09SRussell King (Oracle) } 25634ae2c09SRussell King (Oracle) 25734ae2c09SRussell King (Oracle) if (caps & MAC_100FD) { 25834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, linkmodes); 25934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, linkmodes); 26034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, linkmodes); 26134ae2c09SRussell King (Oracle) } 26234ae2c09SRussell King (Oracle) 26334ae2c09SRussell King (Oracle) if (caps & MAC_1000HD) 26434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, linkmodes); 26534ae2c09SRussell King (Oracle) 26634ae2c09SRussell King (Oracle) if (caps & MAC_1000FD) { 26734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, linkmodes); 268ec574d9eSRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, linkmodes); 26934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, linkmodes); 27034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, linkmodes); 27134ae2c09SRussell King (Oracle) } 27234ae2c09SRussell King (Oracle) 27334ae2c09SRussell King (Oracle) if (caps & MAC_2500FD) { 27434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, linkmodes); 27534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, linkmodes); 27634ae2c09SRussell King (Oracle) } 27734ae2c09SRussell King (Oracle) 27834ae2c09SRussell King (Oracle) if (caps & MAC_5000FD) 27934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, linkmodes); 28034ae2c09SRussell King (Oracle) 28134ae2c09SRussell King (Oracle) if (caps & MAC_10000FD) { 28234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, linkmodes); 28334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, linkmodes); 28434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, linkmodes); 28534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, linkmodes); 28634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, linkmodes); 28734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, linkmodes); 28834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, linkmodes); 28934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, linkmodes); 29034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, linkmodes); 29134ae2c09SRussell King (Oracle) } 29234ae2c09SRussell King (Oracle) 29334ae2c09SRussell King (Oracle) if (caps & MAC_25000FD) { 29434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, linkmodes); 29534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, linkmodes); 29634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, linkmodes); 29734ae2c09SRussell King (Oracle) } 29834ae2c09SRussell King (Oracle) 29934ae2c09SRussell King (Oracle) if (caps & MAC_40000FD) { 30034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, linkmodes); 30134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, linkmodes); 30234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, linkmodes); 30334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, linkmodes); 30434ae2c09SRussell King (Oracle) } 30534ae2c09SRussell King (Oracle) 30634ae2c09SRussell King (Oracle) if (caps & MAC_50000FD) { 30734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, linkmodes); 30834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, linkmodes); 30934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, linkmodes); 31034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, linkmodes); 31134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, linkmodes); 31234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, linkmodes); 31334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 31434ae2c09SRussell King (Oracle) linkmodes); 31534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, linkmodes); 31634ae2c09SRussell King (Oracle) } 31734ae2c09SRussell King (Oracle) 31834ae2c09SRussell King (Oracle) if (caps & MAC_56000FD) { 31934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, linkmodes); 32034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, linkmodes); 32134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, linkmodes); 32234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, linkmodes); 32334ae2c09SRussell King (Oracle) } 32434ae2c09SRussell King (Oracle) 32534ae2c09SRussell King (Oracle) if (caps & MAC_100000FD) { 32634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, linkmodes); 32734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, linkmodes); 32834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, linkmodes); 32934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 33034ae2c09SRussell King (Oracle) linkmodes); 33134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, linkmodes); 33234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, linkmodes); 33334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, linkmodes); 33434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 33534ae2c09SRussell King (Oracle) linkmodes); 33634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, linkmodes); 33734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, linkmodes); 33834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, linkmodes); 33934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, 34034ae2c09SRussell King (Oracle) linkmodes); 34134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, linkmodes); 34234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, linkmodes); 34334ae2c09SRussell King (Oracle) } 34434ae2c09SRussell King (Oracle) 34534ae2c09SRussell King (Oracle) if (caps & MAC_200000FD) { 34634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, linkmodes); 34734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, linkmodes); 34834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, 34934ae2c09SRussell King (Oracle) linkmodes); 35034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, linkmodes); 35134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, linkmodes); 35234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, linkmodes); 35334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, linkmodes); 35434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, 35534ae2c09SRussell King (Oracle) linkmodes); 35634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, linkmodes); 35734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, linkmodes); 35834ae2c09SRussell King (Oracle) } 35934ae2c09SRussell King (Oracle) 36034ae2c09SRussell King (Oracle) if (caps & MAC_400000FD) { 36134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, linkmodes); 36234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, linkmodes); 36334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, 36434ae2c09SRussell King (Oracle) linkmodes); 36534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, linkmodes); 36634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, linkmodes); 36734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, linkmodes); 36834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, linkmodes); 36934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, 37034ae2c09SRussell King (Oracle) linkmodes); 37134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, linkmodes); 37234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes); 37334ae2c09SRussell King (Oracle) } 37434ae2c09SRussell King (Oracle) } 37560611652SSean Anderson EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes); 37634ae2c09SRussell King (Oracle) 377b7e92948SSean Anderson static struct { 378b7e92948SSean Anderson unsigned long mask; 379b7e92948SSean Anderson int speed; 380b7e92948SSean Anderson unsigned int duplex; 381b7e92948SSean Anderson } phylink_caps_params[] = { 382b7e92948SSean Anderson { MAC_400000FD, SPEED_400000, DUPLEX_FULL }, 383b7e92948SSean Anderson { MAC_200000FD, SPEED_200000, DUPLEX_FULL }, 384b7e92948SSean Anderson { MAC_100000FD, SPEED_100000, DUPLEX_FULL }, 385b7e92948SSean Anderson { MAC_56000FD, SPEED_56000, DUPLEX_FULL }, 386b7e92948SSean Anderson { MAC_50000FD, SPEED_50000, DUPLEX_FULL }, 387b7e92948SSean Anderson { MAC_40000FD, SPEED_40000, DUPLEX_FULL }, 388b7e92948SSean Anderson { MAC_25000FD, SPEED_25000, DUPLEX_FULL }, 389b7e92948SSean Anderson { MAC_20000FD, SPEED_20000, DUPLEX_FULL }, 390b7e92948SSean Anderson { MAC_10000FD, SPEED_10000, DUPLEX_FULL }, 391b7e92948SSean Anderson { MAC_5000FD, SPEED_5000, DUPLEX_FULL }, 392b7e92948SSean Anderson { MAC_2500FD, SPEED_2500, DUPLEX_FULL }, 393b7e92948SSean Anderson { MAC_1000FD, SPEED_1000, DUPLEX_FULL }, 394b7e92948SSean Anderson { MAC_1000HD, SPEED_1000, DUPLEX_HALF }, 395b7e92948SSean Anderson { MAC_100FD, SPEED_100, DUPLEX_FULL }, 396b7e92948SSean Anderson { MAC_100HD, SPEED_100, DUPLEX_HALF }, 397b7e92948SSean Anderson { MAC_10FD, SPEED_10, DUPLEX_FULL }, 398b7e92948SSean Anderson { MAC_10HD, SPEED_10, DUPLEX_HALF }, 399b7e92948SSean Anderson }; 400b7e92948SSean Anderson 401b7e92948SSean Anderson /** 402b7e92948SSean Anderson * phylink_cap_from_speed_duplex - Get mac capability from speed/duplex 403b7e92948SSean Anderson * @speed: the speed to search for 404b7e92948SSean Anderson * @duplex: the duplex to search for 405b7e92948SSean Anderson * 406b7e92948SSean Anderson * Find the mac capability for a given speed and duplex. 407b7e92948SSean Anderson * 408b7e92948SSean Anderson * Return: A mask with the mac capability patching @speed and @duplex, or 0 if 409b7e92948SSean Anderson * there were no matches. 410b7e92948SSean Anderson */ 411b7e92948SSean Anderson static unsigned long phylink_cap_from_speed_duplex(int speed, 412b7e92948SSean Anderson unsigned int duplex) 413b7e92948SSean Anderson { 414b7e92948SSean Anderson int i; 415b7e92948SSean Anderson 416b7e92948SSean Anderson for (i = 0; i < ARRAY_SIZE(phylink_caps_params); i++) { 417b7e92948SSean Anderson if (speed == phylink_caps_params[i].speed && 418b7e92948SSean Anderson duplex == phylink_caps_params[i].duplex) 419b7e92948SSean Anderson return phylink_caps_params[i].mask; 420b7e92948SSean Anderson } 421b7e92948SSean Anderson 422b7e92948SSean Anderson return 0; 423b7e92948SSean Anderson } 424b7e92948SSean Anderson 42534ae2c09SRussell King (Oracle) /** 4263e6eab8fSSean Anderson * phylink_get_capabilities() - get capabilities for a given MAC 42734ae2c09SRussell King (Oracle) * @interface: phy interface mode defined by &typedef phy_interface_t 42834ae2c09SRussell King (Oracle) * @mac_capabilities: bitmask of MAC capabilities 429b7e92948SSean Anderson * @rate_matching: type of rate matching being performed 43034ae2c09SRussell King (Oracle) * 4313e6eab8fSSean Anderson * Get the MAC capabilities that are supported by the @interface mode and 4323e6eab8fSSean Anderson * @mac_capabilities. 43334ae2c09SRussell King (Oracle) */ 4343e6eab8fSSean Anderson unsigned long phylink_get_capabilities(phy_interface_t interface, 435b7e92948SSean Anderson unsigned long mac_capabilities, 436b7e92948SSean Anderson int rate_matching) 43734ae2c09SRussell King (Oracle) { 438b7e92948SSean Anderson int max_speed = phylink_interface_max_speed(interface); 43934ae2c09SRussell King (Oracle) unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; 440b7e92948SSean Anderson unsigned long matched_caps = 0; 44134ae2c09SRussell King (Oracle) 44234ae2c09SRussell King (Oracle) switch (interface) { 44334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_USXGMII: 44434ae2c09SRussell King (Oracle) caps |= MAC_10000FD | MAC_5000FD | MAC_2500FD; 44534ae2c09SRussell King (Oracle) fallthrough; 44634ae2c09SRussell King (Oracle) 44734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_TXID: 44834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_RXID: 44934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_ID: 45034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII: 45134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_QSGMII: 4525e61fe15SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII: 45334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_SGMII: 45434ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_GMII: 45534ae2c09SRussell King (Oracle) caps |= MAC_1000HD | MAC_1000FD; 45634ae2c09SRussell King (Oracle) fallthrough; 45734ae2c09SRussell King (Oracle) 45834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_REVRMII: 45934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RMII: 460b9241f54SRussell King (Oracle) case PHY_INTERFACE_MODE_SMII: 46134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_REVMII: 46234ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MII: 46334ae2c09SRussell King (Oracle) caps |= MAC_10HD | MAC_10FD; 46434ae2c09SRussell King (Oracle) fallthrough; 46534ae2c09SRussell King (Oracle) 46634ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_100BASEX: 46734ae2c09SRussell King (Oracle) caps |= MAC_100HD | MAC_100FD; 46834ae2c09SRussell King (Oracle) break; 46934ae2c09SRussell King (Oracle) 47034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_TBI: 47134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MOCA: 47234ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RTBI: 47334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_1000BASEX: 47434ae2c09SRussell King (Oracle) caps |= MAC_1000HD; 47534ae2c09SRussell King (Oracle) fallthrough; 47605ad5d45SSean Anderson case PHY_INTERFACE_MODE_1000BASEKX: 47734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_TRGMII: 47834ae2c09SRussell King (Oracle) caps |= MAC_1000FD; 47934ae2c09SRussell King (Oracle) break; 48034ae2c09SRussell King (Oracle) 48134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_2500BASEX: 48234ae2c09SRussell King (Oracle) caps |= MAC_2500FD; 48334ae2c09SRussell King (Oracle) break; 48434ae2c09SRussell King (Oracle) 48534ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_5GBASER: 48634ae2c09SRussell King (Oracle) caps |= MAC_5000FD; 48734ae2c09SRussell King (Oracle) break; 48834ae2c09SRussell King (Oracle) 48934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XGMII: 49034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RXAUI: 49134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XAUI: 49234ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_10GBASER: 49334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_10GKR: 49434ae2c09SRussell King (Oracle) caps |= MAC_10000FD; 49534ae2c09SRussell King (Oracle) break; 49634ae2c09SRussell King (Oracle) 49734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_25GBASER: 49834ae2c09SRussell King (Oracle) caps |= MAC_25000FD; 49934ae2c09SRussell King (Oracle) break; 50034ae2c09SRussell King (Oracle) 50134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XLGMII: 50234ae2c09SRussell King (Oracle) caps |= MAC_40000FD; 50334ae2c09SRussell King (Oracle) break; 50434ae2c09SRussell King (Oracle) 50534ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_INTERNAL: 50634ae2c09SRussell King (Oracle) caps |= ~0; 50734ae2c09SRussell King (Oracle) break; 50834ae2c09SRussell King (Oracle) 50934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_NA: 51034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MAX: 51134ae2c09SRussell King (Oracle) break; 51234ae2c09SRussell King (Oracle) } 51334ae2c09SRussell King (Oracle) 514b7e92948SSean Anderson switch (rate_matching) { 515b7e92948SSean Anderson case RATE_MATCH_OPEN_LOOP: 516b7e92948SSean Anderson /* TODO */ 517b7e92948SSean Anderson fallthrough; 518b7e92948SSean Anderson case RATE_MATCH_NONE: 519b7e92948SSean Anderson matched_caps = 0; 520b7e92948SSean Anderson break; 521b7e92948SSean Anderson case RATE_MATCH_PAUSE: { 522b7e92948SSean Anderson /* The MAC must support asymmetric pause towards the local 523b7e92948SSean Anderson * device for this. We could allow just symmetric pause, but 524b7e92948SSean Anderson * then we might have to renegotiate if the link partner 525b7e92948SSean Anderson * doesn't support pause. This is because there's no way to 526b7e92948SSean Anderson * accept pause frames without transmitting them if we only 527b7e92948SSean Anderson * support symmetric pause. 528b7e92948SSean Anderson */ 529b7e92948SSean Anderson if (!(mac_capabilities & MAC_SYM_PAUSE) || 530b7e92948SSean Anderson !(mac_capabilities & MAC_ASYM_PAUSE)) 531b7e92948SSean Anderson break; 532b7e92948SSean Anderson 533b7e92948SSean Anderson /* We can't adapt if the MAC doesn't support the interface's 534b7e92948SSean Anderson * max speed at full duplex. 535b7e92948SSean Anderson */ 536b7e92948SSean Anderson if (mac_capabilities & 537b7e92948SSean Anderson phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) { 538b7e92948SSean Anderson /* Although a duplex-matching phy might exist, we 539b7e92948SSean Anderson * conservatively remove these modes because the MAC 540b7e92948SSean Anderson * will not be aware of the half-duplex nature of the 541b7e92948SSean Anderson * link. 542b7e92948SSean Anderson */ 543b7e92948SSean Anderson matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); 544b7e92948SSean Anderson matched_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD); 545b7e92948SSean Anderson } 546b7e92948SSean Anderson break; 547b7e92948SSean Anderson } 548b7e92948SSean Anderson case RATE_MATCH_CRS: 549b7e92948SSean Anderson /* The MAC must support half duplex at the interface's max 550b7e92948SSean Anderson * speed. 551b7e92948SSean Anderson */ 552b7e92948SSean Anderson if (mac_capabilities & 553b7e92948SSean Anderson phylink_cap_from_speed_duplex(max_speed, DUPLEX_HALF)) { 554b7e92948SSean Anderson matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); 555b7e92948SSean Anderson matched_caps &= mac_capabilities; 556b7e92948SSean Anderson } 557b7e92948SSean Anderson break; 558b7e92948SSean Anderson } 559b7e92948SSean Anderson 560b7e92948SSean Anderson return (caps & mac_capabilities) | matched_caps; 56134ae2c09SRussell King (Oracle) } 5623e6eab8fSSean Anderson EXPORT_SYMBOL_GPL(phylink_get_capabilities); 56334ae2c09SRussell King (Oracle) 56434ae2c09SRussell King (Oracle) /** 56534ae2c09SRussell King (Oracle) * phylink_generic_validate() - generic validate() callback implementation 56634ae2c09SRussell King (Oracle) * @config: a pointer to a &struct phylink_config. 56734ae2c09SRussell King (Oracle) * @supported: ethtool bitmask for supported link modes. 56834ae2c09SRussell King (Oracle) * @state: a pointer to a &struct phylink_link_state. 56934ae2c09SRussell King (Oracle) * 57034ae2c09SRussell King (Oracle) * Generic implementation of the validate() callback that MAC drivers can 57134ae2c09SRussell King (Oracle) * use when they pass the range of supported interfaces and MAC capabilities. 57234ae2c09SRussell King (Oracle) * This makes use of phylink_get_linkmodes(). 57334ae2c09SRussell King (Oracle) */ 57434ae2c09SRussell King (Oracle) void phylink_generic_validate(struct phylink_config *config, 57534ae2c09SRussell King (Oracle) unsigned long *supported, 57634ae2c09SRussell King (Oracle) struct phylink_link_state *state) 57734ae2c09SRussell King (Oracle) { 57834ae2c09SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 5793e6eab8fSSean Anderson unsigned long caps; 58034ae2c09SRussell King (Oracle) 58134ae2c09SRussell King (Oracle) phylink_set_port_modes(mask); 58234ae2c09SRussell King (Oracle) phylink_set(mask, Autoneg); 5833e6eab8fSSean Anderson caps = phylink_get_capabilities(state->interface, 584b7e92948SSean Anderson config->mac_capabilities, 585b7e92948SSean Anderson state->rate_matching); 5863e6eab8fSSean Anderson phylink_caps_to_linkmodes(mask, caps); 58734ae2c09SRussell King (Oracle) 58834ae2c09SRussell King (Oracle) linkmode_and(supported, supported, mask); 58934ae2c09SRussell King (Oracle) linkmode_and(state->advertising, state->advertising, mask); 59034ae2c09SRussell King (Oracle) } 59134ae2c09SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_generic_validate); 59234ae2c09SRussell King (Oracle) 593d1e86325SRussell King (Oracle) static int phylink_validate_mac_and_pcs(struct phylink *pl, 594d1e86325SRussell King (Oracle) unsigned long *supported, 595d1e86325SRussell King (Oracle) struct phylink_link_state *state) 596d1e86325SRussell King (Oracle) { 597d1e86325SRussell King (Oracle) struct phylink_pcs *pcs; 5980d22d4b6SRussell King (Oracle) int ret; 599d1e86325SRussell King (Oracle) 6000d22d4b6SRussell King (Oracle) /* Get the PCS for this interface mode */ 60110544570SRussell King (Oracle) if (pl->using_mac_select_pcs) { 602d1e86325SRussell King (Oracle) pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); 603d1e86325SRussell King (Oracle) if (IS_ERR(pcs)) 604d1e86325SRussell King (Oracle) return PTR_ERR(pcs); 6050d22d4b6SRussell King (Oracle) } else { 6060d22d4b6SRussell King (Oracle) pcs = pl->pcs; 607d1e86325SRussell King (Oracle) } 608d1e86325SRussell King (Oracle) 6090d22d4b6SRussell King (Oracle) if (pcs) { 6100d22d4b6SRussell King (Oracle) /* The PCS, if present, must be setup before phylink_create() 6110d22d4b6SRussell King (Oracle) * has been called. If the ops is not initialised, print an 6120d22d4b6SRussell King (Oracle) * error and backtrace rather than oopsing the kernel. 6130d22d4b6SRussell King (Oracle) */ 6140d22d4b6SRussell King (Oracle) if (!pcs->ops) { 6150d22d4b6SRussell King (Oracle) phylink_err(pl, "interface %s: uninitialised PCS\n", 6160d22d4b6SRussell King (Oracle) phy_modes(state->interface)); 6170d22d4b6SRussell King (Oracle) dump_stack(); 6180d22d4b6SRussell King (Oracle) return -EINVAL; 6190d22d4b6SRussell King (Oracle) } 6200d22d4b6SRussell King (Oracle) 6210d22d4b6SRussell King (Oracle) /* Validate the link parameters with the PCS */ 6220d22d4b6SRussell King (Oracle) if (pcs->ops->pcs_validate) { 6230d22d4b6SRussell King (Oracle) ret = pcs->ops->pcs_validate(pcs, supported, state); 6240d22d4b6SRussell King (Oracle) if (ret < 0 || phylink_is_empty_linkmode(supported)) 6250d22d4b6SRussell King (Oracle) return -EINVAL; 6260d22d4b6SRussell King (Oracle) 6270d22d4b6SRussell King (Oracle) /* Ensure the advertising mask is a subset of the 6280d22d4b6SRussell King (Oracle) * supported mask. 6290d22d4b6SRussell King (Oracle) */ 6300d22d4b6SRussell King (Oracle) linkmode_and(state->advertising, state->advertising, 6310d22d4b6SRussell King (Oracle) supported); 6320d22d4b6SRussell King (Oracle) } 6330d22d4b6SRussell King (Oracle) } 6340d22d4b6SRussell King (Oracle) 6350d22d4b6SRussell King (Oracle) /* Then validate the link parameters with the MAC */ 636d1e86325SRussell King (Oracle) pl->mac_ops->validate(pl->config, supported, state); 637d1e86325SRussell King (Oracle) 638d1e86325SRussell King (Oracle) return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; 639d1e86325SRussell King (Oracle) } 640d1e86325SRussell King (Oracle) 6411645f44dSRussell King (Oracle) static int phylink_validate_mask(struct phylink *pl, unsigned long *supported, 6421645f44dSRussell King (Oracle) struct phylink_link_state *state, 6431645f44dSRussell King (Oracle) const unsigned long *interfaces) 644d25f3a74SRussell King (Oracle) { 645d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, }; 646d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; 647d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(s); 648d25f3a74SRussell King (Oracle) struct phylink_link_state t; 649d25f3a74SRussell King (Oracle) int intf; 650d25f3a74SRussell King (Oracle) 651d25f3a74SRussell King (Oracle) for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { 6521645f44dSRussell King (Oracle) if (test_bit(intf, interfaces)) { 653d25f3a74SRussell King (Oracle) linkmode_copy(s, supported); 654d25f3a74SRussell King (Oracle) 655d25f3a74SRussell King (Oracle) t = *state; 656d25f3a74SRussell King (Oracle) t.interface = intf; 657d1e86325SRussell King (Oracle) if (!phylink_validate_mac_and_pcs(pl, s, &t)) { 658d25f3a74SRussell King (Oracle) linkmode_or(all_s, all_s, s); 659d25f3a74SRussell King (Oracle) linkmode_or(all_adv, all_adv, t.advertising); 660d25f3a74SRussell King (Oracle) } 661d25f3a74SRussell King (Oracle) } 662d1e86325SRussell King (Oracle) } 663d25f3a74SRussell King (Oracle) 664d25f3a74SRussell King (Oracle) linkmode_copy(supported, all_s); 665d25f3a74SRussell King (Oracle) linkmode_copy(state->advertising, all_adv); 666d25f3a74SRussell King (Oracle) 667d25f3a74SRussell King (Oracle) return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; 668d25f3a74SRussell King (Oracle) } 669d25f3a74SRussell King (Oracle) 6709525ae83SRussell King static int phylink_validate(struct phylink *pl, unsigned long *supported, 6719525ae83SRussell King struct phylink_link_state *state) 6729525ae83SRussell King { 6731645f44dSRussell King (Oracle) const unsigned long *interfaces = pl->config->supported_interfaces; 674d25f3a74SRussell King (Oracle) 6751645f44dSRussell King (Oracle) if (!phy_interface_empty(interfaces)) { 6761645f44dSRussell King (Oracle) if (state->interface == PHY_INTERFACE_MODE_NA) 6771645f44dSRussell King (Oracle) return phylink_validate_mask(pl, supported, state, 6781645f44dSRussell King (Oracle) interfaces); 6791645f44dSRussell King (Oracle) 6801645f44dSRussell King (Oracle) if (!test_bit(state->interface, interfaces)) 681d25f3a74SRussell King (Oracle) return -EINVAL; 682d25f3a74SRussell King (Oracle) } 683d25f3a74SRussell King (Oracle) 684d1e86325SRussell King (Oracle) return phylink_validate_mac_and_pcs(pl, supported, state); 6859525ae83SRussell King } 6869525ae83SRussell King 6878fa7b9b6SRussell King static int phylink_parse_fixedlink(struct phylink *pl, 6888fa7b9b6SRussell King struct fwnode_handle *fwnode) 6899525ae83SRussell King { 6908fa7b9b6SRussell King struct fwnode_handle *fixed_node; 6919525ae83SRussell King const struct phy_setting *s; 6929525ae83SRussell King struct gpio_desc *desc; 6939525ae83SRussell King u32 speed; 6948fa7b9b6SRussell King int ret; 6959525ae83SRussell King 6968fa7b9b6SRussell King fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); 6979525ae83SRussell King if (fixed_node) { 6988fa7b9b6SRussell King ret = fwnode_property_read_u32(fixed_node, "speed", &speed); 6999525ae83SRussell King 7009525ae83SRussell King pl->link_config.speed = speed; 7019525ae83SRussell King pl->link_config.duplex = DUPLEX_HALF; 7029525ae83SRussell King 7038fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "full-duplex")) 7049525ae83SRussell King pl->link_config.duplex = DUPLEX_FULL; 7059525ae83SRussell King 7069525ae83SRussell King /* We treat the "pause" and "asym-pause" terminology as 7071953feb0SWenpeng Liang * defining the link partner's ability. 7081953feb0SWenpeng Liang */ 7098fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "pause")) 7104e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, 7114e5aeb41SRussell King pl->link_config.lp_advertising); 7128fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "asym-pause")) 7134e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 7144e5aeb41SRussell King pl->link_config.lp_advertising); 7159525ae83SRussell King 7169525ae83SRussell King if (ret == 0) { 717b605c9abSDmitry Torokhov desc = fwnode_gpiod_get_index(fixed_node, "link", 0, 718b605c9abSDmitry Torokhov GPIOD_IN, "?"); 7199525ae83SRussell King 7209525ae83SRussell King if (!IS_ERR(desc)) 7219525ae83SRussell King pl->link_gpio = desc; 7229525ae83SRussell King else if (desc == ERR_PTR(-EPROBE_DEFER)) 7239525ae83SRussell King ret = -EPROBE_DEFER; 7249525ae83SRussell King } 7258fa7b9b6SRussell King fwnode_handle_put(fixed_node); 7269525ae83SRussell King 7279525ae83SRussell King if (ret) 7289525ae83SRussell King return ret; 7299525ae83SRussell King } else { 7308fa7b9b6SRussell King u32 prop[5]; 7318fa7b9b6SRussell King 7328fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link", 7338fa7b9b6SRussell King NULL, 0); 7348fa7b9b6SRussell King if (ret != ARRAY_SIZE(prop)) { 73517091180SIoana Ciornei phylink_err(pl, "broken fixed-link?\n"); 7369525ae83SRussell King return -EINVAL; 7379525ae83SRussell King } 7388fa7b9b6SRussell King 7398fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link", 7408fa7b9b6SRussell King prop, ARRAY_SIZE(prop)); 7418fa7b9b6SRussell King if (!ret) { 7428fa7b9b6SRussell King pl->link_config.duplex = prop[1] ? 7439525ae83SRussell King DUPLEX_FULL : DUPLEX_HALF; 7448fa7b9b6SRussell King pl->link_config.speed = prop[2]; 7458fa7b9b6SRussell King if (prop[3]) 7464e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, 7474e5aeb41SRussell King pl->link_config.lp_advertising); 7488fa7b9b6SRussell King if (prop[4]) 7494e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 7504e5aeb41SRussell King pl->link_config.lp_advertising); 7519525ae83SRussell King } 7529525ae83SRussell King } 7539525ae83SRussell King 7549525ae83SRussell King if (pl->link_config.speed > SPEED_1000 && 7559525ae83SRussell King pl->link_config.duplex != DUPLEX_FULL) 75617091180SIoana Ciornei phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n", 7579525ae83SRussell King pl->link_config.speed); 7589525ae83SRussell King 7599525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 7609525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 7619525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config); 7629525ae83SRussell King 7639525ae83SRussell King s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex, 7643c1bcc86SAndrew Lunn pl->supported, true); 7659525ae83SRussell King linkmode_zero(pl->supported); 7669525ae83SRussell King phylink_set(pl->supported, MII); 7678aace4f3SRené van Dorst phylink_set(pl->supported, Pause); 7688aace4f3SRené van Dorst phylink_set(pl->supported, Asym_Pause); 7691ceb7ee7SRussell King phylink_set(pl->supported, Autoneg); 7709525ae83SRussell King if (s) { 7719525ae83SRussell King __set_bit(s->bit, pl->supported); 7721ceb7ee7SRussell King __set_bit(s->bit, pl->link_config.lp_advertising); 7739525ae83SRussell King } else { 77417091180SIoana Ciornei phylink_warn(pl, "fixed link %s duplex %dMbps not recognised\n", 7759525ae83SRussell King pl->link_config.duplex == DUPLEX_FULL ? "full" : "half", 7769525ae83SRussell King pl->link_config.speed); 7779525ae83SRussell King } 7789525ae83SRussell King 7799525ae83SRussell King linkmode_and(pl->link_config.advertising, pl->link_config.advertising, 7809525ae83SRussell King pl->supported); 7819525ae83SRussell King 7829525ae83SRussell King pl->link_config.link = 1; 7839525ae83SRussell King pl->link_config.an_complete = 1; 7849525ae83SRussell King 7859525ae83SRussell King return 0; 7869525ae83SRussell King } 7879525ae83SRussell King 7888fa7b9b6SRussell King static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) 7899525ae83SRussell King { 7908fa7b9b6SRussell King struct fwnode_handle *dn; 7919525ae83SRussell King const char *managed; 7929525ae83SRussell King 7938fa7b9b6SRussell King dn = fwnode_get_named_child_node(fwnode, "fixed-link"); 7948fa7b9b6SRussell King if (dn || fwnode_property_present(fwnode, "fixed-link")) 79524cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_FIXED; 7968fa7b9b6SRussell King fwnode_handle_put(dn); 7979525ae83SRussell King 798ab393850SOng Boon Leong if ((fwnode_property_read_string(fwnode, "managed", &managed) == 0 && 799ab393850SOng Boon Leong strcmp(managed, "in-band-status") == 0) || 800ab393850SOng Boon Leong pl->config->ovr_an_inband) { 80124cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) { 80217091180SIoana Ciornei phylink_err(pl, 8039525ae83SRussell King "can't use both fixed-link and in-band-status\n"); 8049525ae83SRussell King return -EINVAL; 8059525ae83SRussell King } 8069525ae83SRussell King 8079525ae83SRussell King linkmode_zero(pl->supported); 8089525ae83SRussell King phylink_set(pl->supported, MII); 8099525ae83SRussell King phylink_set(pl->supported, Autoneg); 8109525ae83SRussell King phylink_set(pl->supported, Asym_Pause); 8119525ae83SRussell King phylink_set(pl->supported, Pause); 8129525ae83SRussell King pl->link_config.an_enabled = true; 81324cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_INBAND; 8149525ae83SRussell King 8159525ae83SRussell King switch (pl->link_config.interface) { 8169525ae83SRussell King case PHY_INTERFACE_MODE_SGMII: 8173a68ba6fSVladimir Oltean case PHY_INTERFACE_MODE_QSGMII: 8185e61fe15SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII: 819d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII: 820d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_ID: 821d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_RXID: 822d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_TXID: 823d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RTBI: 8249525ae83SRussell King phylink_set(pl->supported, 10baseT_Half); 8259525ae83SRussell King phylink_set(pl->supported, 10baseT_Full); 8269525ae83SRussell King phylink_set(pl->supported, 100baseT_Half); 8279525ae83SRussell King phylink_set(pl->supported, 100baseT_Full); 8289525ae83SRussell King phylink_set(pl->supported, 1000baseT_Half); 8299525ae83SRussell King phylink_set(pl->supported, 1000baseT_Full); 8309525ae83SRussell King break; 8319525ae83SRussell King 8329525ae83SRussell King case PHY_INTERFACE_MODE_1000BASEX: 8339525ae83SRussell King phylink_set(pl->supported, 1000baseX_Full); 8349525ae83SRussell King break; 8359525ae83SRussell King 8369525ae83SRussell King case PHY_INTERFACE_MODE_2500BASEX: 8379525ae83SRussell King phylink_set(pl->supported, 2500baseX_Full); 8389525ae83SRussell King break; 8399525ae83SRussell King 840f6813bdaSMarek Behún case PHY_INTERFACE_MODE_5GBASER: 841f6813bdaSMarek Behún phylink_set(pl->supported, 5000baseT_Full); 842f6813bdaSMarek Behún break; 843f6813bdaSMarek Behún 84421e0c59eSSteen Hegelund case PHY_INTERFACE_MODE_25GBASER: 84521e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseCR_Full); 84621e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseKR_Full); 84721e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseSR_Full); 84821e0c59eSSteen Hegelund fallthrough; 84904e22463SAlex Marginean case PHY_INTERFACE_MODE_USXGMII: 850da7c1862SRussell King case PHY_INTERFACE_MODE_10GKR: 851e0f909bcSRussell King case PHY_INTERFACE_MODE_10GBASER: 852da7c1862SRussell King phylink_set(pl->supported, 10baseT_Half); 853da7c1862SRussell King phylink_set(pl->supported, 10baseT_Full); 854da7c1862SRussell King phylink_set(pl->supported, 100baseT_Half); 855da7c1862SRussell King phylink_set(pl->supported, 100baseT_Full); 856da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Half); 857da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Full); 858da7c1862SRussell King phylink_set(pl->supported, 1000baseX_Full); 859c580165fSJose Abreu phylink_set(pl->supported, 1000baseKX_Full); 8606cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseT_Full); 8616cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseX_Full); 8626cbdcf25SVladimir Oltean phylink_set(pl->supported, 5000baseT_Full); 8636cbdcf25SVladimir Oltean phylink_set(pl->supported, 10000baseT_Full); 864da7c1862SRussell King phylink_set(pl->supported, 10000baseKR_Full); 865c580165fSJose Abreu phylink_set(pl->supported, 10000baseKX4_Full); 866da7c1862SRussell King phylink_set(pl->supported, 10000baseCR_Full); 867da7c1862SRussell King phylink_set(pl->supported, 10000baseSR_Full); 868da7c1862SRussell King phylink_set(pl->supported, 10000baseLR_Full); 869da7c1862SRussell King phylink_set(pl->supported, 10000baseLRM_Full); 870da7c1862SRussell King phylink_set(pl->supported, 10000baseER_Full); 871da7c1862SRussell King break; 872da7c1862SRussell King 8731671c42dSJose Abreu case PHY_INTERFACE_MODE_XLGMII: 8741671c42dSJose Abreu phylink_set(pl->supported, 25000baseCR_Full); 8751671c42dSJose Abreu phylink_set(pl->supported, 25000baseKR_Full); 8761671c42dSJose Abreu phylink_set(pl->supported, 25000baseSR_Full); 8771671c42dSJose Abreu phylink_set(pl->supported, 40000baseKR4_Full); 8781671c42dSJose Abreu phylink_set(pl->supported, 40000baseCR4_Full); 8791671c42dSJose Abreu phylink_set(pl->supported, 40000baseSR4_Full); 8801671c42dSJose Abreu phylink_set(pl->supported, 40000baseLR4_Full); 8811671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR2_Full); 8821671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR2_Full); 8831671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR2_Full); 8841671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR_Full); 8851671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR_Full); 8861671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR_Full); 8871671c42dSJose Abreu phylink_set(pl->supported, 50000baseLR_ER_FR_Full); 8881671c42dSJose Abreu phylink_set(pl->supported, 50000baseDR_Full); 8891671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR4_Full); 8901671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR4_Full); 8911671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR4_Full); 8921671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR4_ER4_Full); 8931671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR2_Full); 8941671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR2_Full); 8951671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR2_Full); 8961671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR2_ER2_FR2_Full); 8971671c42dSJose Abreu phylink_set(pl->supported, 100000baseDR2_Full); 8981671c42dSJose Abreu break; 8991671c42dSJose Abreu 9009525ae83SRussell King default: 90117091180SIoana Ciornei phylink_err(pl, 9029525ae83SRussell King "incorrect link mode %s for in-band status\n", 9039525ae83SRussell King phy_modes(pl->link_config.interface)); 9049525ae83SRussell King return -EINVAL; 9059525ae83SRussell King } 9069525ae83SRussell King 9079525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 9089525ae83SRussell King 9099525ae83SRussell King if (phylink_validate(pl, pl->supported, &pl->link_config)) { 91017091180SIoana Ciornei phylink_err(pl, 9119525ae83SRussell King "failed to validate link configuration for in-band status\n"); 9129525ae83SRussell King return -EINVAL; 9139525ae83SRussell King } 91494148196SJose Abreu 91594148196SJose Abreu /* Check if MAC/PCS also supports Autoneg. */ 91694148196SJose Abreu pl->link_config.an_enabled = phylink_test(pl->supported, Autoneg); 9179525ae83SRussell King } 9189525ae83SRussell King 9199525ae83SRussell King return 0; 9209525ae83SRussell King } 9219525ae83SRussell King 9222d5fbef0SRussell King static void phylink_apply_manual_flow(struct phylink *pl, 9232d5fbef0SRussell King struct phylink_link_state *state) 9242d5fbef0SRussell King { 9252d5fbef0SRussell King /* If autoneg is disabled, pause AN is also disabled */ 9262d5fbef0SRussell King if (!state->an_enabled) 9272d5fbef0SRussell King state->pause &= ~MLO_PAUSE_AN; 9282d5fbef0SRussell King 9292d5fbef0SRussell King /* Manual configuration of pause modes */ 9302d5fbef0SRussell King if (!(pl->link_config.pause & MLO_PAUSE_AN)) 9312d5fbef0SRussell King state->pause = pl->link_config.pause; 9322d5fbef0SRussell King } 9332d5fbef0SRussell King 9344e5aeb41SRussell King static void phylink_resolve_flow(struct phylink_link_state *state) 9354e5aeb41SRussell King { 9364e5aeb41SRussell King bool tx_pause, rx_pause; 9374e5aeb41SRussell King 9384e5aeb41SRussell King state->pause = MLO_PAUSE_NONE; 9394e5aeb41SRussell King if (state->duplex == DUPLEX_FULL) { 9404e5aeb41SRussell King linkmode_resolve_pause(state->advertising, 9414e5aeb41SRussell King state->lp_advertising, 9424e5aeb41SRussell King &tx_pause, &rx_pause); 9434e5aeb41SRussell King if (tx_pause) 9444e5aeb41SRussell King state->pause |= MLO_PAUSE_TX; 9454e5aeb41SRussell King if (rx_pause) 9464e5aeb41SRussell King state->pause |= MLO_PAUSE_RX; 9474e5aeb41SRussell King } 9484e5aeb41SRussell King } 9494e5aeb41SRussell King 950bfac8c49SRussell King (Oracle) static void phylink_pcs_poll_stop(struct phylink *pl) 951bfac8c49SRussell King (Oracle) { 952bfac8c49SRussell King (Oracle) if (pl->cfg_link_an_mode == MLO_AN_INBAND) 953bfac8c49SRussell King (Oracle) del_timer(&pl->link_poll); 954bfac8c49SRussell King (Oracle) } 955bfac8c49SRussell King (Oracle) 956bfac8c49SRussell King (Oracle) static void phylink_pcs_poll_start(struct phylink *pl) 957bfac8c49SRussell King (Oracle) { 958b7d78b46SVladimir Oltean if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND) 959bfac8c49SRussell King (Oracle) mod_timer(&pl->link_poll, jiffies + HZ); 960bfac8c49SRussell King (Oracle) } 961bfac8c49SRussell King (Oracle) 9629525ae83SRussell King static void phylink_mac_config(struct phylink *pl, 9639525ae83SRussell King const struct phylink_link_state *state) 9649525ae83SRussell King { 96517091180SIoana Ciornei phylink_dbg(pl, 966ae0e4bb2SSean Anderson "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", 96724cf0e69SRussell King __func__, phylink_an_mode_str(pl->cur_link_an_mode), 9689525ae83SRussell King phy_modes(state->interface), 9699525ae83SRussell King phy_speed_to_str(state->speed), 9709525ae83SRussell King phy_duplex_to_str(state->duplex), 971ae0e4bb2SSean Anderson phy_rate_matching_to_str(state->rate_matching), 9729525ae83SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, 9739525ae83SRussell King state->pause, state->link, state->an_enabled); 9749525ae83SRussell King 975e7765d63SRussell King pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state); 9769525ae83SRussell King } 9779525ae83SRussell King 9784c0d6d3aSRussell King static void phylink_mac_pcs_an_restart(struct phylink *pl) 9799525ae83SRussell King { 9809525ae83SRussell King if (pl->link_config.an_enabled && 981575691b3SRussell King phy_interface_mode_is_8023z(pl->link_config.interface) && 982575691b3SRussell King phylink_autoneg_inband(pl->cur_link_an_mode)) { 9834f1dd48fSRussell King (Oracle) if (pl->pcs) 9844f1dd48fSRussell King (Oracle) pl->pcs->ops->pcs_an_restart(pl->pcs); 985001f4261SRussell King (Oracle) else if (pl->config->legacy_pre_march2020) 986e7765d63SRussell King pl->mac_ops->mac_an_restart(pl->config); 9879525ae83SRussell King } 9884c0d6d3aSRussell King } 9894c0d6d3aSRussell King 990b7ad14c2SRussell King static void phylink_major_config(struct phylink *pl, bool restart, 9914c0d6d3aSRussell King const struct phylink_link_state *state) 9924c0d6d3aSRussell King { 993d1e86325SRussell King (Oracle) struct phylink_pcs *pcs = NULL; 994bfac8c49SRussell King (Oracle) bool pcs_changed = false; 995b7ad14c2SRussell King int err; 9964c0d6d3aSRussell King 997b7ad14c2SRussell King phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); 998b7ad14c2SRussell King 99910544570SRussell King (Oracle) if (pl->using_mac_select_pcs) { 1000d1e86325SRussell King (Oracle) pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); 1001d1e86325SRussell King (Oracle) if (IS_ERR(pcs)) { 1002d1e86325SRussell King (Oracle) phylink_err(pl, 1003d1e86325SRussell King (Oracle) "mac_select_pcs unexpectedly failed: %pe\n", 1004d1e86325SRussell King (Oracle) pcs); 1005d1e86325SRussell King (Oracle) return; 1006d1e86325SRussell King (Oracle) } 1007bfac8c49SRussell King (Oracle) 1008bfac8c49SRussell King (Oracle) pcs_changed = pcs && pl->pcs != pcs; 1009d1e86325SRussell King (Oracle) } 1010d1e86325SRussell King (Oracle) 1011bfac8c49SRussell King (Oracle) phylink_pcs_poll_stop(pl); 1012bfac8c49SRussell King (Oracle) 1013b7ad14c2SRussell King if (pl->mac_ops->mac_prepare) { 1014b7ad14c2SRussell King err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, 1015b7ad14c2SRussell King state->interface); 1016b7ad14c2SRussell King if (err < 0) { 1017b7ad14c2SRussell King phylink_err(pl, "mac_prepare failed: %pe\n", 1018b7ad14c2SRussell King ERR_PTR(err)); 1019b7ad14c2SRussell King return; 1020b7ad14c2SRussell King } 1021b7ad14c2SRussell King } 10224c0d6d3aSRussell King 1023d1e86325SRussell King (Oracle) /* If we have a new PCS, switch to the new PCS after preparing the MAC 1024d1e86325SRussell King (Oracle) * for the change. 1025d1e86325SRussell King (Oracle) */ 1026bfac8c49SRussell King (Oracle) if (pcs_changed) 1027a5081badSRussell King (Oracle) pl->pcs = pcs; 1028a5081badSRussell King (Oracle) 10294c0d6d3aSRussell King phylink_mac_config(pl, state); 10304c0d6d3aSRussell King 10314f1dd48fSRussell King (Oracle) if (pl->pcs) { 10324f1dd48fSRussell King (Oracle) err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode, 1033b7ad14c2SRussell King state->interface, 1034b7ad14c2SRussell King state->advertising, 1035b7ad14c2SRussell King !!(pl->link_config.pause & 1036b7ad14c2SRussell King MLO_PAUSE_AN)); 1037b7ad14c2SRussell King if (err < 0) 1038b7ad14c2SRussell King phylink_err(pl, "pcs_config failed: %pe\n", 1039b7ad14c2SRussell King ERR_PTR(err)); 1040b7ad14c2SRussell King if (err > 0) 1041b7ad14c2SRussell King restart = true; 1042b7ad14c2SRussell King } 10434c0d6d3aSRussell King if (restart) 10444c0d6d3aSRussell King phylink_mac_pcs_an_restart(pl); 1045b7ad14c2SRussell King 1046b7ad14c2SRussell King if (pl->mac_ops->mac_finish) { 1047b7ad14c2SRussell King err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode, 1048b7ad14c2SRussell King state->interface); 1049b7ad14c2SRussell King if (err < 0) 1050d82c6c1aSOng Boon Leong phylink_err(pl, "mac_finish failed: %pe\n", 1051b7ad14c2SRussell King ERR_PTR(err)); 1052b7ad14c2SRussell King } 1053bfac8c49SRussell King (Oracle) 1054bfac8c49SRussell King (Oracle) phylink_pcs_poll_start(pl); 10554c0d6d3aSRussell King } 10569525ae83SRussell King 10571571e700SRussell King /* 10581571e700SRussell King * Reconfigure for a change of inband advertisement. 10591571e700SRussell King * If we have a separate PCS, we only need to call its pcs_config() method, 10601571e700SRussell King * and then restart AN if it indicates something changed. Otherwise, we do 10611571e700SRussell King * the full MAC reconfiguration. 10621571e700SRussell King */ 10631571e700SRussell King static int phylink_change_inband_advert(struct phylink *pl) 10641571e700SRussell King { 10651571e700SRussell King int ret; 10661571e700SRussell King 10671571e700SRussell King if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) 10681571e700SRussell King return 0; 10691571e700SRussell King 10704f1dd48fSRussell King (Oracle) if (!pl->pcs && pl->config->legacy_pre_march2020) { 10711571e700SRussell King /* Legacy method */ 10721571e700SRussell King phylink_mac_config(pl, &pl->link_config); 10731571e700SRussell King phylink_mac_pcs_an_restart(pl); 10741571e700SRussell King return 0; 10751571e700SRussell King } 10761571e700SRussell King 10771571e700SRussell King phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__, 10781571e700SRussell King phylink_an_mode_str(pl->cur_link_an_mode), 10791571e700SRussell King phy_modes(pl->link_config.interface), 10801571e700SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising, 10811571e700SRussell King pl->link_config.pause); 10821571e700SRussell King 10831571e700SRussell King /* Modern PCS-based method; update the advert at the PCS, and 10841571e700SRussell King * restart negotiation if the pcs_config() helper indicates that 10851571e700SRussell King * the programmed advertisement has changed. 10861571e700SRussell King */ 10874f1dd48fSRussell King (Oracle) ret = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode, 10881571e700SRussell King pl->link_config.interface, 10891571e700SRussell King pl->link_config.advertising, 10904f1dd48fSRussell King (Oracle) !!(pl->link_config.pause & 10914f1dd48fSRussell King (Oracle) MLO_PAUSE_AN)); 10921571e700SRussell King if (ret < 0) 10931571e700SRussell King return ret; 10941571e700SRussell King 10951571e700SRussell King if (ret > 0) 10961571e700SRussell King phylink_mac_pcs_an_restart(pl); 10971571e700SRussell King 10981571e700SRussell King return 0; 10991571e700SRussell King } 11001571e700SRussell King 1101d46b7e4fSRussell King static void phylink_mac_pcs_get_state(struct phylink *pl, 1102d46b7e4fSRussell King struct phylink_link_state *state) 11039525ae83SRussell King { 11049525ae83SRussell King linkmode_copy(state->advertising, pl->link_config.advertising); 11059525ae83SRussell King linkmode_zero(state->lp_advertising); 11069525ae83SRussell King state->interface = pl->link_config.interface; 11079525ae83SRussell King state->an_enabled = pl->link_config.an_enabled; 1108ae0e4bb2SSean Anderson state->rate_matching = pl->link_config.rate_matching; 110992817dadSRobert Hancock if (state->an_enabled) { 1110d25ed413SHeiner Kallweit state->speed = SPEED_UNKNOWN; 1111d25ed413SHeiner Kallweit state->duplex = DUPLEX_UNKNOWN; 1112d25ed413SHeiner Kallweit state->pause = MLO_PAUSE_NONE; 111392817dadSRobert Hancock } else { 111492817dadSRobert Hancock state->speed = pl->link_config.speed; 111592817dadSRobert Hancock state->duplex = pl->link_config.duplex; 111692817dadSRobert Hancock state->pause = pl->link_config.pause; 111792817dadSRobert Hancock } 1118d25ed413SHeiner Kallweit state->an_complete = 0; 11199525ae83SRussell King state->link = 1; 11209525ae83SRussell King 11214f1dd48fSRussell King (Oracle) if (pl->pcs) 11224f1dd48fSRussell King (Oracle) pl->pcs->ops->pcs_get_state(pl->pcs, state); 1123001f4261SRussell King (Oracle) else if (pl->mac_ops->mac_pcs_get_state && 1124001f4261SRussell King (Oracle) pl->config->legacy_pre_march2020) 1125e7765d63SRussell King pl->mac_ops->mac_pcs_get_state(pl->config, state); 1126e859a60aSRussell King else 1127e859a60aSRussell King state->link = 0; 11289525ae83SRussell King } 11299525ae83SRussell King 11309525ae83SRussell King /* The fixed state is... fixed except for the link state, 11311ac63e39SFlorian Fainelli * which may be determined by a GPIO or a callback. 11329525ae83SRussell King */ 11334e5aeb41SRussell King static void phylink_get_fixed_state(struct phylink *pl, 11344e5aeb41SRussell King struct phylink_link_state *state) 11359525ae83SRussell King { 11369525ae83SRussell King *state = pl->link_config; 11375c05c1dbSRussell King if (pl->config->get_fixed_state) 11385c05c1dbSRussell King pl->config->get_fixed_state(pl->config, state); 11391ac63e39SFlorian Fainelli else if (pl->link_gpio) 1140bb322a90SFlorian Fainelli state->link = !!gpiod_get_value_cansleep(pl->link_gpio); 11419525ae83SRussell King 11424e5aeb41SRussell King phylink_resolve_flow(state); 11439525ae83SRussell King } 11449525ae83SRussell King 11454c0d6d3aSRussell King static void phylink_mac_initial_config(struct phylink *pl, bool force_restart) 114697fec51fSRussell King { 114797fec51fSRussell King struct phylink_link_state link_state; 114897fec51fSRussell King 114997fec51fSRussell King switch (pl->cur_link_an_mode) { 115097fec51fSRussell King case MLO_AN_PHY: 115197fec51fSRussell King link_state = pl->phy_state; 115297fec51fSRussell King break; 115397fec51fSRussell King 115497fec51fSRussell King case MLO_AN_FIXED: 115597fec51fSRussell King phylink_get_fixed_state(pl, &link_state); 115697fec51fSRussell King break; 115797fec51fSRussell King 115897fec51fSRussell King case MLO_AN_INBAND: 115997fec51fSRussell King link_state = pl->link_config; 116097fec51fSRussell King if (link_state.interface == PHY_INTERFACE_MODE_SGMII) 116197fec51fSRussell King link_state.pause = MLO_PAUSE_NONE; 116297fec51fSRussell King break; 116397fec51fSRussell King 116497fec51fSRussell King default: /* can't happen */ 116597fec51fSRussell King return; 116697fec51fSRussell King } 116797fec51fSRussell King 116897fec51fSRussell King link_state.link = false; 116997fec51fSRussell King 117097fec51fSRussell King phylink_apply_manual_flow(pl, &link_state); 1171b7ad14c2SRussell King phylink_major_config(pl, force_restart, &link_state); 117297fec51fSRussell King } 117397fec51fSRussell King 11749525ae83SRussell King static const char *phylink_pause_to_str(int pause) 11759525ae83SRussell King { 11769525ae83SRussell King switch (pause & MLO_PAUSE_TXRX_MASK) { 11779525ae83SRussell King case MLO_PAUSE_TX | MLO_PAUSE_RX: 11789525ae83SRussell King return "rx/tx"; 11799525ae83SRussell King case MLO_PAUSE_TX: 11809525ae83SRussell King return "tx"; 11819525ae83SRussell King case MLO_PAUSE_RX: 11829525ae83SRussell King return "rx"; 11839525ae83SRussell King default: 11849525ae83SRussell King return "off"; 11859525ae83SRussell King } 11869525ae83SRussell King } 11879525ae83SRussell King 11884c0d6d3aSRussell King static void phylink_link_up(struct phylink *pl, 118927755ff8SIoana Ciornei struct phylink_link_state link_state) 119027755ff8SIoana Ciornei { 119127755ff8SIoana Ciornei struct net_device *ndev = pl->netdev; 1192ae0e4bb2SSean Anderson int speed, duplex; 1193ae0e4bb2SSean Anderson bool rx_pause; 1194ae0e4bb2SSean Anderson 1195ae0e4bb2SSean Anderson speed = link_state.speed; 1196ae0e4bb2SSean Anderson duplex = link_state.duplex; 1197ae0e4bb2SSean Anderson rx_pause = !!(link_state.pause & MLO_PAUSE_RX); 1198ae0e4bb2SSean Anderson 1199ae0e4bb2SSean Anderson switch (link_state.rate_matching) { 1200ae0e4bb2SSean Anderson case RATE_MATCH_PAUSE: 1201ae0e4bb2SSean Anderson /* The PHY is doing rate matchion from the media rate (in 1202ae0e4bb2SSean Anderson * the link_state) to the interface speed, and will send 1203ae0e4bb2SSean Anderson * pause frames to the MAC to limit its transmission speed. 1204ae0e4bb2SSean Anderson */ 1205ae0e4bb2SSean Anderson speed = phylink_interface_max_speed(link_state.interface); 1206ae0e4bb2SSean Anderson duplex = DUPLEX_FULL; 1207ae0e4bb2SSean Anderson rx_pause = true; 1208ae0e4bb2SSean Anderson break; 1209ae0e4bb2SSean Anderson 1210ae0e4bb2SSean Anderson case RATE_MATCH_CRS: 1211ae0e4bb2SSean Anderson /* The PHY is doing rate matchion from the media rate (in 1212ae0e4bb2SSean Anderson * the link_state) to the interface speed, and will cause 1213ae0e4bb2SSean Anderson * collisions to the MAC to limit its transmission speed. 1214ae0e4bb2SSean Anderson */ 1215ae0e4bb2SSean Anderson speed = phylink_interface_max_speed(link_state.interface); 1216ae0e4bb2SSean Anderson duplex = DUPLEX_HALF; 1217ae0e4bb2SSean Anderson break; 1218ae0e4bb2SSean Anderson } 121927755ff8SIoana Ciornei 1220b4b12b0dSDavid S. Miller pl->cur_interface = link_state.interface; 12214c0d6d3aSRussell King 12224f1dd48fSRussell King (Oracle) if (pl->pcs && pl->pcs->ops->pcs_link_up) 12234f1dd48fSRussell King (Oracle) pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode, 1224ae0e4bb2SSean Anderson pl->cur_interface, speed, duplex); 12254c0d6d3aSRussell King 1226ae0e4bb2SSean Anderson pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, 1227ae0e4bb2SSean Anderson pl->cur_interface, speed, duplex, 1228ae0e4bb2SSean Anderson !!(link_state.pause & MLO_PAUSE_TX), rx_pause); 122927755ff8SIoana Ciornei 123043de6195SIoana Ciornei if (ndev) 123127755ff8SIoana Ciornei netif_carrier_on(ndev); 123227755ff8SIoana Ciornei 123317091180SIoana Ciornei phylink_info(pl, 123427755ff8SIoana Ciornei "Link is Up - %s/%s - flow control %s\n", 123527755ff8SIoana Ciornei phy_speed_to_str(link_state.speed), 123627755ff8SIoana Ciornei phy_duplex_to_str(link_state.duplex), 123727755ff8SIoana Ciornei phylink_pause_to_str(link_state.pause)); 123827755ff8SIoana Ciornei } 123927755ff8SIoana Ciornei 12404c0d6d3aSRussell King static void phylink_link_down(struct phylink *pl) 124127755ff8SIoana Ciornei { 124227755ff8SIoana Ciornei struct net_device *ndev = pl->netdev; 124327755ff8SIoana Ciornei 124443de6195SIoana Ciornei if (ndev) 124527755ff8SIoana Ciornei netif_carrier_off(ndev); 1246e7765d63SRussell King pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode, 1247b4b12b0dSDavid S. Miller pl->cur_interface); 124817091180SIoana Ciornei phylink_info(pl, "Link is Down\n"); 124927755ff8SIoana Ciornei } 125027755ff8SIoana Ciornei 12519525ae83SRussell King static void phylink_resolve(struct work_struct *w) 12529525ae83SRussell King { 12539525ae83SRussell King struct phylink *pl = container_of(w, struct phylink, resolve); 12549525ae83SRussell King struct phylink_link_state link_state; 12559525ae83SRussell King struct net_device *ndev = pl->netdev; 1256319bfafeSRussell King bool mac_config = false; 125780662f4fSRussell King (Oracle) bool retrigger = false; 1258b06e5cacSRussell King bool cur_link_state; 12599525ae83SRussell King 12609525ae83SRussell King mutex_lock(&pl->state_mutex); 1261b06e5cacSRussell King if (pl->netdev) 1262b06e5cacSRussell King cur_link_state = netif_carrier_ok(ndev); 1263b06e5cacSRussell King else 1264b06e5cacSRussell King cur_link_state = pl->old_link_state; 1265b06e5cacSRussell King 12669525ae83SRussell King if (pl->phylink_disable_state) { 12679525ae83SRussell King pl->mac_link_dropped = false; 12689525ae83SRussell King link_state.link = false; 12699525ae83SRussell King } else if (pl->mac_link_dropped) { 12709525ae83SRussell King link_state.link = false; 127180662f4fSRussell King (Oracle) retrigger = true; 12729525ae83SRussell King } else { 127324cf0e69SRussell King switch (pl->cur_link_an_mode) { 12749525ae83SRussell King case MLO_AN_PHY: 12759525ae83SRussell King link_state = pl->phy_state; 12762d5fbef0SRussell King phylink_apply_manual_flow(pl, &link_state); 1277319bfafeSRussell King mac_config = link_state.link; 12789525ae83SRussell King break; 12799525ae83SRussell King 12809525ae83SRussell King case MLO_AN_FIXED: 12819525ae83SRussell King phylink_get_fixed_state(pl, &link_state); 1282319bfafeSRussell King mac_config = link_state.link; 12839525ae83SRussell King break; 12849525ae83SRussell King 128586a362c4SRussell King case MLO_AN_INBAND: 1286d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state); 12879525ae83SRussell King 1288dbae3388SRussell King (Oracle) /* The PCS may have a latching link-fail indicator. 1289dbae3388SRussell King (Oracle) * If the link was up, bring the link down and 1290dbae3388SRussell King (Oracle) * re-trigger the resolve. Otherwise, re-read the 1291dbae3388SRussell King (Oracle) * PCS state to get the current status of the link. 1292dbae3388SRussell King (Oracle) */ 1293dbae3388SRussell King (Oracle) if (!link_state.link) { 1294dbae3388SRussell King (Oracle) if (cur_link_state) 1295dbae3388SRussell King (Oracle) retrigger = true; 1296dbae3388SRussell King (Oracle) else 1297dbae3388SRussell King (Oracle) phylink_mac_pcs_get_state(pl, 1298dbae3388SRussell King (Oracle) &link_state); 1299dbae3388SRussell King (Oracle) } 1300dbae3388SRussell King (Oracle) 1301406cb0c4SRussell King /* If we have a phy, the "up" state is the union of 13021953feb0SWenpeng Liang * both the PHY and the MAC 13031953feb0SWenpeng Liang */ 1304406cb0c4SRussell King if (pl->phydev) 1305406cb0c4SRussell King link_state.link &= pl->phy_state.link; 13069525ae83SRussell King 1307406cb0c4SRussell King /* Only update if the PHY link is up */ 1308406cb0c4SRussell King if (pl->phydev && pl->phy_state.link) { 130980662f4fSRussell King (Oracle) /* If the interface has changed, force a 131080662f4fSRussell King (Oracle) * link down event if the link isn't already 131180662f4fSRussell King (Oracle) * down, and re-resolve. 131280662f4fSRussell King (Oracle) */ 131380662f4fSRussell King (Oracle) if (link_state.interface != 131480662f4fSRussell King (Oracle) pl->phy_state.interface) { 131580662f4fSRussell King (Oracle) retrigger = true; 131680662f4fSRussell King (Oracle) link_state.link = false; 131780662f4fSRussell King (Oracle) } 13189525ae83SRussell King link_state.interface = pl->phy_state.interface; 13199525ae83SRussell King 1320ae0e4bb2SSean Anderson /* If we are doing rate matching, then the 1321ae0e4bb2SSean Anderson * link speed/duplex comes from the PHY 1322ae0e4bb2SSean Anderson */ 1323ae0e4bb2SSean Anderson if (pl->phy_state.rate_matching) { 1324ae0e4bb2SSean Anderson link_state.rate_matching = 1325ae0e4bb2SSean Anderson pl->phy_state.rate_matching; 1326ae0e4bb2SSean Anderson link_state.speed = pl->phy_state.speed; 1327ae0e4bb2SSean Anderson link_state.duplex = 1328ae0e4bb2SSean Anderson pl->phy_state.duplex; 1329ae0e4bb2SSean Anderson } 1330ae0e4bb2SSean Anderson 1331406cb0c4SRussell King /* If we have a PHY, we need to update with 13321953feb0SWenpeng Liang * the PHY flow control bits. 13331953feb0SWenpeng Liang */ 133433faac8eSRussell King link_state.pause = pl->phy_state.pause; 1335319bfafeSRussell King mac_config = true; 13369525ae83SRussell King } 1337319bfafeSRussell King phylink_apply_manual_flow(pl, &link_state); 13389525ae83SRussell King break; 13399525ae83SRussell King } 13409525ae83SRussell King } 13419525ae83SRussell King 134216319a7dSRussell King if (mac_config) { 134316319a7dSRussell King if (link_state.interface != pl->link_config.interface) { 134416319a7dSRussell King /* The interface has changed, force the link down and 134516319a7dSRussell King * then reconfigure. 134616319a7dSRussell King */ 134716319a7dSRussell King if (cur_link_state) { 134816319a7dSRussell King phylink_link_down(pl); 134916319a7dSRussell King cur_link_state = false; 135016319a7dSRussell King } 1351b7ad14c2SRussell King phylink_major_config(pl, false, &link_state); 13525005b163SRussell King pl->link_config.interface = link_state.interface; 13534f1dd48fSRussell King (Oracle) } else if (!pl->pcs && pl->config->legacy_pre_march2020) { 13545005b163SRussell King /* The interface remains unchanged, only the speed, 13555005b163SRussell King * duplex or pause settings have changed. Call the 13567cceb599SRussell King * old mac_config() method to configure the MAC/PCS 1357001f4261SRussell King (Oracle) * only if we do not have a legacy MAC driver. 13585005b163SRussell King */ 1359319bfafeSRussell King phylink_mac_config(pl, &link_state); 136016319a7dSRussell King } 13615005b163SRussell King } 1362319bfafeSRussell King 1363b06e5cacSRussell King if (link_state.link != cur_link_state) { 136443de6195SIoana Ciornei pl->old_link_state = link_state.link; 136527755ff8SIoana Ciornei if (!link_state.link) 13664c0d6d3aSRussell King phylink_link_down(pl); 136727755ff8SIoana Ciornei else 13684c0d6d3aSRussell King phylink_link_up(pl, link_state); 13699525ae83SRussell King } 137080662f4fSRussell King (Oracle) if (!link_state.link && retrigger) { 13719525ae83SRussell King pl->mac_link_dropped = false; 13729525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve); 13739525ae83SRussell King } 13749525ae83SRussell King mutex_unlock(&pl->state_mutex); 13759525ae83SRussell King } 13769525ae83SRussell King 13779525ae83SRussell King static void phylink_run_resolve(struct phylink *pl) 13789525ae83SRussell King { 13799525ae83SRussell King if (!pl->phylink_disable_state) 13809525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve); 13819525ae83SRussell King } 13829525ae83SRussell King 138387454b6eSRussell King static void phylink_run_resolve_and_disable(struct phylink *pl, int bit) 138487454b6eSRussell King { 138587454b6eSRussell King unsigned long state = pl->phylink_disable_state; 138687454b6eSRussell King 138787454b6eSRussell King set_bit(bit, &pl->phylink_disable_state); 138887454b6eSRussell King if (state == 0) { 138987454b6eSRussell King queue_work(system_power_efficient_wq, &pl->resolve); 139087454b6eSRussell King flush_work(&pl->resolve); 139187454b6eSRussell King } 139287454b6eSRussell King } 139387454b6eSRussell King 1394aa729c43SRussell King static void phylink_enable_and_run_resolve(struct phylink *pl, int bit) 1395aa729c43SRussell King { 1396aa729c43SRussell King clear_bit(bit, &pl->phylink_disable_state); 1397aa729c43SRussell King phylink_run_resolve(pl); 1398aa729c43SRussell King } 1399aa729c43SRussell King 14009cd00a8aSRussell King static void phylink_fixed_poll(struct timer_list *t) 14019cd00a8aSRussell King { 14029cd00a8aSRussell King struct phylink *pl = container_of(t, struct phylink, link_poll); 14039cd00a8aSRussell King 14049cd00a8aSRussell King mod_timer(t, jiffies + HZ); 14059cd00a8aSRussell King 14069cd00a8aSRussell King phylink_run_resolve(pl); 14079cd00a8aSRussell King } 14089cd00a8aSRussell King 1409ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops; 1410ce0aa27fSRussell King 14118fa7b9b6SRussell King static int phylink_register_sfp(struct phylink *pl, 14128fa7b9b6SRussell King struct fwnode_handle *fwnode) 1413ce0aa27fSRussell King { 14142203cbf2SRussell King struct sfp_bus *bus; 14158fa7b9b6SRussell King int ret; 1416ce0aa27fSRussell King 1417eed70fd9SRussell King if (!fwnode) 1418eed70fd9SRussell King return 0; 1419eed70fd9SRussell King 1420727b3668SRussell King bus = sfp_bus_find_fwnode(fwnode); 14212203cbf2SRussell King if (IS_ERR(bus)) { 1422ab1198e5SRussell King (Oracle) phylink_err(pl, "unable to attach SFP bus: %pe\n", bus); 1423ab1198e5SRussell King (Oracle) return PTR_ERR(bus); 14248fa7b9b6SRussell King } 14258fa7b9b6SRussell King 14262203cbf2SRussell King pl->sfp_bus = bus; 1427ce0aa27fSRussell King 1428727b3668SRussell King ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops); 1429727b3668SRussell King sfp_bus_put(bus); 1430727b3668SRussell King 1431727b3668SRussell King return ret; 1432ce0aa27fSRussell King } 1433ce0aa27fSRussell King 14348796c892SRussell King /** 14358796c892SRussell King * phylink_create() - create a phylink instance 14369db74e51SRandy Dunlap * @config: a pointer to the target &struct phylink_config 14378fa7b9b6SRussell King * @fwnode: a pointer to a &struct fwnode_handle describing the network 14388fa7b9b6SRussell King * interface 14398796c892SRussell King * @iface: the desired link mode defined by &typedef phy_interface_t 1440e7765d63SRussell King * @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC. 14418796c892SRussell King * 14428796c892SRussell King * Create a new phylink instance, and parse the link parameters found in @np. 14438796c892SRussell King * This will parse in-band modes, fixed-link or SFP configuration. 14448796c892SRussell King * 1445269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function. 1446269a6b5fSRussell King * 14478796c892SRussell King * Returns a pointer to a &struct phylink, or an error-pointer value. Users 14488796c892SRussell King * must use IS_ERR() to check for errors from this function. 14498796c892SRussell King */ 145044cc27e4SIoana Ciornei struct phylink *phylink_create(struct phylink_config *config, 14518fa7b9b6SRussell King struct fwnode_handle *fwnode, 1452516b29edSFlorian Fainelli phy_interface_t iface, 1453e7765d63SRussell King const struct phylink_mac_ops *mac_ops) 14549525ae83SRussell King { 145510544570SRussell King (Oracle) bool using_mac_select_pcs = false; 14569525ae83SRussell King struct phylink *pl; 14579525ae83SRussell King int ret; 14589525ae83SRussell King 1459d1e86325SRussell King (Oracle) if (mac_ops->mac_select_pcs && 146010544570SRussell King (Oracle) mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != 146110544570SRussell King (Oracle) ERR_PTR(-EOPNOTSUPP)) 146210544570SRussell King (Oracle) using_mac_select_pcs = true; 146310544570SRussell King (Oracle) 146410544570SRussell King (Oracle) /* Validate the supplied configuration */ 146510544570SRussell King (Oracle) if (using_mac_select_pcs && 1466d1e86325SRussell King (Oracle) phy_interface_empty(config->supported_interfaces)) { 1467d1e86325SRussell King (Oracle) dev_err(config->dev, 1468d1e86325SRussell King (Oracle) "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); 1469d1e86325SRussell King (Oracle) return ERR_PTR(-EINVAL); 1470d1e86325SRussell King (Oracle) } 1471d1e86325SRussell King (Oracle) 14729525ae83SRussell King pl = kzalloc(sizeof(*pl), GFP_KERNEL); 14739525ae83SRussell King if (!pl) 14749525ae83SRussell King return ERR_PTR(-ENOMEM); 14759525ae83SRussell King 14769525ae83SRussell King mutex_init(&pl->state_mutex); 14779525ae83SRussell King INIT_WORK(&pl->resolve, phylink_resolve); 147844cc27e4SIoana Ciornei 147944cc27e4SIoana Ciornei pl->config = config; 148044cc27e4SIoana Ciornei if (config->type == PHYLINK_NETDEV) { 148144cc27e4SIoana Ciornei pl->netdev = to_net_dev(config->dev); 148243de6195SIoana Ciornei } else if (config->type == PHYLINK_DEV) { 148343de6195SIoana Ciornei pl->dev = config->dev; 148444cc27e4SIoana Ciornei } else { 148544cc27e4SIoana Ciornei kfree(pl); 148644cc27e4SIoana Ciornei return ERR_PTR(-EINVAL); 148744cc27e4SIoana Ciornei } 148844cc27e4SIoana Ciornei 148910544570SRussell King (Oracle) pl->using_mac_select_pcs = using_mac_select_pcs; 14909525ae83SRussell King pl->phy_state.interface = iface; 14919525ae83SRussell King pl->link_interface = iface; 14924be11ef0SFlorian Fainelli if (iface == PHY_INTERFACE_MODE_MOCA) 14934be11ef0SFlorian Fainelli pl->link_port = PORT_BNC; 14944be11ef0SFlorian Fainelli else 14959525ae83SRussell King pl->link_port = PORT_MII; 14969525ae83SRussell King pl->link_config.interface = iface; 14979525ae83SRussell King pl->link_config.pause = MLO_PAUSE_AN; 14989525ae83SRussell King pl->link_config.speed = SPEED_UNKNOWN; 14999525ae83SRussell King pl->link_config.duplex = DUPLEX_UNKNOWN; 150074ee0e8cSRussell King pl->link_config.an_enabled = true; 1501e7765d63SRussell King pl->mac_ops = mac_ops; 15029525ae83SRussell King __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); 15039cd00a8aSRussell King timer_setup(&pl->link_poll, phylink_fixed_poll, 0); 15049525ae83SRussell King 15059525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 15069525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 15079525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config); 15089525ae83SRussell King 15098fa7b9b6SRussell King ret = phylink_parse_mode(pl, fwnode); 15109525ae83SRussell King if (ret < 0) { 15119525ae83SRussell King kfree(pl); 15129525ae83SRussell King return ERR_PTR(ret); 15139525ae83SRussell King } 15149525ae83SRussell King 151524cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) { 15168fa7b9b6SRussell King ret = phylink_parse_fixedlink(pl, fwnode); 15179525ae83SRussell King if (ret < 0) { 15189525ae83SRussell King kfree(pl); 15199525ae83SRussell King return ERR_PTR(ret); 15209525ae83SRussell King } 15219525ae83SRussell King } 15229525ae83SRussell King 152324cf0e69SRussell King pl->cur_link_an_mode = pl->cfg_link_an_mode; 152424cf0e69SRussell King 15258fa7b9b6SRussell King ret = phylink_register_sfp(pl, fwnode); 1526ce0aa27fSRussell King if (ret < 0) { 1527ce0aa27fSRussell King kfree(pl); 1528ce0aa27fSRussell King return ERR_PTR(ret); 1529ce0aa27fSRussell King } 1530ce0aa27fSRussell King 15319525ae83SRussell King return pl; 15329525ae83SRussell King } 15339525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_create); 15349525ae83SRussell King 15357137e18fSRussell King /** 15368796c892SRussell King * phylink_destroy() - cleanup and destroy the phylink instance 15378796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 15388796c892SRussell King * 15398796c892SRussell King * Destroy a phylink instance. Any PHY that has been attached must have been 15408796c892SRussell King * cleaned up via phylink_disconnect_phy() prior to calling this function. 1541269a6b5fSRussell King * 1542269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function. 15438796c892SRussell King */ 15449525ae83SRussell King void phylink_destroy(struct phylink *pl) 15459525ae83SRussell King { 1546727b3668SRussell King sfp_bus_del_upstream(pl->sfp_bus); 15477b3b0e89SRussell King if (pl->link_gpio) 1548daab3349SFlorian Fainelli gpiod_put(pl->link_gpio); 1549ce0aa27fSRussell King 15509525ae83SRussell King cancel_work_sync(&pl->resolve); 15519525ae83SRussell King kfree(pl); 15529525ae83SRussell King } 15539525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_destroy); 15549525ae83SRussell King 1555a307593aSDoug Berger static void phylink_phy_change(struct phy_device *phydev, bool up) 15569525ae83SRussell King { 15579525ae83SRussell King struct phylink *pl = phydev->phylink; 155833faac8eSRussell King bool tx_pause, rx_pause; 155933faac8eSRussell King 156033faac8eSRussell King phy_get_pause(phydev, &tx_pause, &rx_pause); 15619525ae83SRussell King 15629525ae83SRussell King mutex_lock(&pl->state_mutex); 15639525ae83SRussell King pl->phy_state.speed = phydev->speed; 15649525ae83SRussell King pl->phy_state.duplex = phydev->duplex; 1565ae0e4bb2SSean Anderson pl->phy_state.rate_matching = phydev->rate_matching; 15669525ae83SRussell King pl->phy_state.pause = MLO_PAUSE_NONE; 156733faac8eSRussell King if (tx_pause) 156833faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_TX; 156933faac8eSRussell King if (rx_pause) 157033faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_RX; 15719525ae83SRussell King pl->phy_state.interface = phydev->interface; 15729525ae83SRussell King pl->phy_state.link = up; 15739525ae83SRussell King mutex_unlock(&pl->state_mutex); 15749525ae83SRussell King 15759525ae83SRussell King phylink_run_resolve(pl); 15769525ae83SRussell King 1577ae0e4bb2SSean Anderson phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s\n", up ? "up" : "down", 15789525ae83SRussell King phy_modes(phydev->interface), 15799525ae83SRussell King phy_speed_to_str(phydev->speed), 1580d34869b4SRussell King (Oracle) phy_duplex_to_str(phydev->duplex), 1581ae0e4bb2SSean Anderson phy_rate_matching_to_str(phydev->rate_matching), 1582d34869b4SRussell King (Oracle) phylink_pause_to_str(pl->phy_state.pause)); 15839525ae83SRussell King } 15849525ae83SRussell King 1585e45d1f52SRussell King static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, 1586e45d1f52SRussell King phy_interface_t interface) 15879525ae83SRussell King { 15889525ae83SRussell King struct phylink_link_state config; 15899525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 1590e27f1787SFlorian Fainelli char *irq_str; 15919525ae83SRussell King int ret; 15929525ae83SRussell King 15939525ae83SRussell King /* 15949525ae83SRussell King * This is the new way of dealing with flow control for PHYs, 15959525ae83SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy: 15969525ae83SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except 15979525ae83SRussell King * using our validate call to the MAC, we rely upon the MAC 15989525ae83SRussell King * clearing the bits from both supported and advertising fields. 15999525ae83SRussell King */ 1600725ea4bfSRussell King phy_support_asym_pause(phy); 1601725ea4bfSRussell King 1602725ea4bfSRussell King memset(&config, 0, sizeof(config)); 1603725ea4bfSRussell King linkmode_copy(supported, phy->supported); 1604725ea4bfSRussell King linkmode_copy(config.advertising, phy->advertising); 1605df3f57acSRussell King 1606df3f57acSRussell King /* Clause 45 PHYs switch their Serdes lane between several different 1607df3f57acSRussell King * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G 1608df3f57acSRussell King * speeds. We really need to know which interface modes the PHY and 1609df3f57acSRussell King * MAC supports to properly work out which linkmodes can be supported. 1610df3f57acSRussell King */ 1611df3f57acSRussell King if (phy->is_c45 && 1612df3f57acSRussell King interface != PHY_INTERFACE_MODE_RXAUI && 1613df3f57acSRussell King interface != PHY_INTERFACE_MODE_XAUI && 1614df3f57acSRussell King interface != PHY_INTERFACE_MODE_USXGMII) 1615df3f57acSRussell King config.interface = PHY_INTERFACE_MODE_NA; 1616df3f57acSRussell King else 1617e45d1f52SRussell King config.interface = interface; 1618b7e92948SSean Anderson config.rate_matching = phy_get_rate_matching(phy, config.interface); 16199525ae83SRussell King 16209525ae83SRussell King ret = phylink_validate(pl, supported, &config); 162120d8bb0dSHauke Mehrtens if (ret) { 1622ab1198e5SRussell King (Oracle) phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n", 162320d8bb0dSHauke Mehrtens phy_modes(config.interface), 162420d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported, 162520d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising, 1626ab1198e5SRussell King (Oracle) ERR_PTR(ret)); 16279525ae83SRussell King return ret; 162820d8bb0dSHauke Mehrtens } 16299525ae83SRussell King 16309525ae83SRussell King phy->phylink = pl; 16319525ae83SRussell King phy->phy_link_change = phylink_phy_change; 16329525ae83SRussell King 1633e27f1787SFlorian Fainelli irq_str = phy_attached_info_irq(phy); 163417091180SIoana Ciornei phylink_info(pl, 1635e27f1787SFlorian Fainelli "PHY [%s] driver [%s] (irq=%s)\n", 1636e27f1787SFlorian Fainelli dev_name(&phy->mdio.dev), phy->drv->name, irq_str); 1637e27f1787SFlorian Fainelli kfree(irq_str); 16389525ae83SRussell King 16399525ae83SRussell King mutex_lock(&phy->lock); 16409525ae83SRussell King mutex_lock(&pl->state_mutex); 16419525ae83SRussell King pl->phydev = phy; 1642e45d1f52SRussell King pl->phy_state.interface = interface; 164397fec51fSRussell King pl->phy_state.pause = MLO_PAUSE_NONE; 164497fec51fSRussell King pl->phy_state.speed = SPEED_UNKNOWN; 164597fec51fSRussell King pl->phy_state.duplex = DUPLEX_UNKNOWN; 1646ae0e4bb2SSean Anderson pl->phy_state.rate_matching = RATE_MATCH_NONE; 16479525ae83SRussell King linkmode_copy(pl->supported, supported); 16489525ae83SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 16499525ae83SRussell King 1650cc1122b0SColin Ian King /* Restrict the phy advertisement according to the MAC support. */ 16513c1bcc86SAndrew Lunn linkmode_copy(phy->advertising, config.advertising); 16529525ae83SRussell King mutex_unlock(&pl->state_mutex); 16539525ae83SRussell King mutex_unlock(&phy->lock); 16549525ae83SRussell King 165517091180SIoana Ciornei phylink_dbg(pl, 1656a18e6521SRussell King (Oracle) "phy: %s setting supported %*pb advertising %*pb\n", 1657a18e6521SRussell King (Oracle) phy_modes(interface), 16589525ae83SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported, 16593c1bcc86SAndrew Lunn __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising); 16609525ae83SRussell King 1661434a4315SHeiner Kallweit if (phy_interrupt_is_valid(phy)) 1662434a4315SHeiner Kallweit phy_request_interrupt(phy); 16639525ae83SRussell King 16649525ae83SRussell King return 0; 16659525ae83SRussell King } 16669525ae83SRussell King 1667938d44c2SRussell King static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, 16687e418375SBaruch Siach phy_interface_t interface) 16697e418375SBaruch Siach { 167024cf0e69SRussell King if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || 167124cf0e69SRussell King (pl->cfg_link_an_mode == MLO_AN_INBAND && 16727e418375SBaruch Siach phy_interface_mode_is_8023z(interface)))) 16737e418375SBaruch Siach return -EINVAL; 16747e418375SBaruch Siach 16757e418375SBaruch Siach if (pl->phydev) 16767e418375SBaruch Siach return -EBUSY; 16777e418375SBaruch Siach 1678938d44c2SRussell King return phy_attach_direct(pl->netdev, phy, 0, interface); 16797e418375SBaruch Siach } 16807e418375SBaruch Siach 16818796c892SRussell King /** 16828796c892SRussell King * phylink_connect_phy() - connect a PHY to the phylink instance 16838796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 16848796c892SRussell King * @phy: a pointer to a &struct phy_device. 16858796c892SRussell King * 16868796c892SRussell King * Connect @phy to the phylink instance specified by @pl by calling 16878796c892SRussell King * phy_attach_direct(). Configure the @phy according to the MAC driver's 16888796c892SRussell King * capabilities, start the PHYLIB state machine and enable any interrupts 16898796c892SRussell King * that the PHY supports. 16908796c892SRussell King * 16918796c892SRussell King * This updates the phylink's ethtool supported and advertising link mode 16928796c892SRussell King * masks. 16938796c892SRussell King * 16948796c892SRussell King * Returns 0 on success or a negative errno. 16958796c892SRussell King */ 16969525ae83SRussell King int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) 16979525ae83SRussell King { 1698938d44c2SRussell King int ret; 1699938d44c2SRussell King 17004904b6eaSFlorian Fainelli /* Use PHY device/driver interface */ 17014904b6eaSFlorian Fainelli if (pl->link_interface == PHY_INTERFACE_MODE_NA) { 17024904b6eaSFlorian Fainelli pl->link_interface = phy->interface; 17034904b6eaSFlorian Fainelli pl->link_config.interface = pl->link_interface; 17044904b6eaSFlorian Fainelli } 17054904b6eaSFlorian Fainelli 1706938d44c2SRussell King ret = phylink_attach_phy(pl, phy, pl->link_interface); 1707938d44c2SRussell King if (ret < 0) 1708938d44c2SRussell King return ret; 1709938d44c2SRussell King 1710e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, pl->link_config.interface); 1711938d44c2SRussell King if (ret) 1712938d44c2SRussell King phy_detach(phy); 1713938d44c2SRussell King 1714938d44c2SRussell King return ret; 17159525ae83SRussell King } 17169525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_connect_phy); 17179525ae83SRussell King 17188796c892SRussell King /** 17198796c892SRussell King * phylink_of_phy_connect() - connect the PHY specified in the DT mode. 17208796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 17218796c892SRussell King * @dn: a pointer to a &struct device_node. 17220a62964cSFlorian Fainelli * @flags: PHY-specific flags to communicate to the PHY device driver 17238796c892SRussell King * 17248796c892SRussell King * Connect the phy specified in the device node @dn to the phylink instance 17258796c892SRussell King * specified by @pl. Actions specified in phylink_connect_phy() will be 17268796c892SRussell King * performed. 17278796c892SRussell King * 17288796c892SRussell King * Returns 0 on success or a negative errno. 17298796c892SRussell King */ 17300a62964cSFlorian Fainelli int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, 17310a62964cSFlorian Fainelli u32 flags) 17329525ae83SRussell King { 1733423e6e89SCalvin Johnson return phylink_fwnode_phy_connect(pl, of_fwnode_handle(dn), flags); 17349525ae83SRussell King } 17359525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_of_phy_connect); 17369525ae83SRussell King 17378796c892SRussell King /** 173825396f68SCalvin Johnson * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode. 173925396f68SCalvin Johnson * @pl: a pointer to a &struct phylink returned from phylink_create() 174025396f68SCalvin Johnson * @fwnode: a pointer to a &struct fwnode_handle. 174125396f68SCalvin Johnson * @flags: PHY-specific flags to communicate to the PHY device driver 174225396f68SCalvin Johnson * 174325396f68SCalvin Johnson * Connect the phy specified @fwnode to the phylink instance specified 174425396f68SCalvin Johnson * by @pl. 174525396f68SCalvin Johnson * 174625396f68SCalvin Johnson * Returns 0 on success or a negative errno. 174725396f68SCalvin Johnson */ 174825396f68SCalvin Johnson int phylink_fwnode_phy_connect(struct phylink *pl, 174925396f68SCalvin Johnson struct fwnode_handle *fwnode, 175025396f68SCalvin Johnson u32 flags) 175125396f68SCalvin Johnson { 175225396f68SCalvin Johnson struct fwnode_handle *phy_fwnode; 175325396f68SCalvin Johnson struct phy_device *phy_dev; 175425396f68SCalvin Johnson int ret; 175525396f68SCalvin Johnson 175625396f68SCalvin Johnson /* Fixed links and 802.3z are handled without needing a PHY */ 175725396f68SCalvin Johnson if (pl->cfg_link_an_mode == MLO_AN_FIXED || 175825396f68SCalvin Johnson (pl->cfg_link_an_mode == MLO_AN_INBAND && 175925396f68SCalvin Johnson phy_interface_mode_is_8023z(pl->link_interface))) 176025396f68SCalvin Johnson return 0; 176125396f68SCalvin Johnson 176225396f68SCalvin Johnson phy_fwnode = fwnode_get_phy_node(fwnode); 176325396f68SCalvin Johnson if (IS_ERR(phy_fwnode)) { 176425396f68SCalvin Johnson if (pl->cfg_link_an_mode == MLO_AN_PHY) 176525396f68SCalvin Johnson return -ENODEV; 176625396f68SCalvin Johnson return 0; 176725396f68SCalvin Johnson } 176825396f68SCalvin Johnson 176925396f68SCalvin Johnson phy_dev = fwnode_phy_find_device(phy_fwnode); 177025396f68SCalvin Johnson /* We're done with the phy_node handle */ 177125396f68SCalvin Johnson fwnode_handle_put(phy_fwnode); 177225396f68SCalvin Johnson if (!phy_dev) 177325396f68SCalvin Johnson return -ENODEV; 177425396f68SCalvin Johnson 1775a18e6521SRussell King (Oracle) /* Use PHY device/driver interface */ 1776a18e6521SRussell King (Oracle) if (pl->link_interface == PHY_INTERFACE_MODE_NA) { 1777a18e6521SRussell King (Oracle) pl->link_interface = phy_dev->interface; 1778a18e6521SRussell King (Oracle) pl->link_config.interface = pl->link_interface; 1779a18e6521SRussell King (Oracle) } 1780a18e6521SRussell King (Oracle) 178125396f68SCalvin Johnson ret = phy_attach_direct(pl->netdev, phy_dev, flags, 178225396f68SCalvin Johnson pl->link_interface); 178325396f68SCalvin Johnson if (ret) { 178425396f68SCalvin Johnson phy_device_free(phy_dev); 178525396f68SCalvin Johnson return ret; 178625396f68SCalvin Johnson } 178725396f68SCalvin Johnson 178825396f68SCalvin Johnson ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); 178925396f68SCalvin Johnson if (ret) 179025396f68SCalvin Johnson phy_detach(phy_dev); 179125396f68SCalvin Johnson 179225396f68SCalvin Johnson return ret; 179325396f68SCalvin Johnson } 179425396f68SCalvin Johnson EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect); 179525396f68SCalvin Johnson 179625396f68SCalvin Johnson /** 17978796c892SRussell King * phylink_disconnect_phy() - disconnect any PHY attached to the phylink 17988796c892SRussell King * instance. 17998796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 18008796c892SRussell King * 18018796c892SRussell King * Disconnect any current PHY from the phylink instance described by @pl. 18028796c892SRussell King */ 18039525ae83SRussell King void phylink_disconnect_phy(struct phylink *pl) 18049525ae83SRussell King { 18059525ae83SRussell King struct phy_device *phy; 18069525ae83SRussell King 18078b874514SRussell King ASSERT_RTNL(); 18089525ae83SRussell King 18099525ae83SRussell King phy = pl->phydev; 18109525ae83SRussell King if (phy) { 18119525ae83SRussell King mutex_lock(&phy->lock); 18129525ae83SRussell King mutex_lock(&pl->state_mutex); 18139525ae83SRussell King pl->phydev = NULL; 18149525ae83SRussell King mutex_unlock(&pl->state_mutex); 18159525ae83SRussell King mutex_unlock(&phy->lock); 18169525ae83SRussell King flush_work(&pl->resolve); 18179525ae83SRussell King 18189525ae83SRussell King phy_disconnect(phy); 18199525ae83SRussell King } 18209525ae83SRussell King } 18219525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_disconnect_phy); 18229525ae83SRussell King 18238796c892SRussell King /** 18248796c892SRussell King * phylink_mac_change() - notify phylink of a change in MAC state 18258796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 18268796c892SRussell King * @up: indicates whether the link is currently up. 18278796c892SRussell King * 18288796c892SRussell King * The MAC driver should call this driver when the state of its link 18298796c892SRussell King * changes (eg, link failure, new negotiation results, etc.) 18308796c892SRussell King */ 18319525ae83SRussell King void phylink_mac_change(struct phylink *pl, bool up) 18329525ae83SRussell King { 18339525ae83SRussell King if (!up) 18349525ae83SRussell King pl->mac_link_dropped = true; 18359525ae83SRussell King phylink_run_resolve(pl); 183617091180SIoana Ciornei phylink_dbg(pl, "mac link %s\n", up ? "up" : "down"); 18379525ae83SRussell King } 18389525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mac_change); 18399525ae83SRussell King 18407b3b0e89SRussell King static irqreturn_t phylink_link_handler(int irq, void *data) 18417b3b0e89SRussell King { 18427b3b0e89SRussell King struct phylink *pl = data; 18437b3b0e89SRussell King 18447b3b0e89SRussell King phylink_run_resolve(pl); 18457b3b0e89SRussell King 18467b3b0e89SRussell King return IRQ_HANDLED; 18477b3b0e89SRussell King } 18487b3b0e89SRussell King 18498796c892SRussell King /** 18508796c892SRussell King * phylink_start() - start a phylink instance 18518796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 18528796c892SRussell King * 18538796c892SRussell King * Start the phylink instance specified by @pl, configuring the MAC for the 18548796c892SRussell King * desired link mode(s) and negotiation style. This should be called from the 18558796c892SRussell King * network device driver's &struct net_device_ops ndo_open() method. 18568796c892SRussell King */ 18579525ae83SRussell King void phylink_start(struct phylink *pl) 18589525ae83SRussell King { 18595c05c1dbSRussell King bool poll = false; 18605c05c1dbSRussell King 18618b874514SRussell King ASSERT_RTNL(); 18629525ae83SRussell King 186317091180SIoana Ciornei phylink_info(pl, "configuring for %s/%s link mode\n", 186424cf0e69SRussell King phylink_an_mode_str(pl->cur_link_an_mode), 18659525ae83SRussell King phy_modes(pl->link_config.interface)); 18669525ae83SRussell King 1867aeeb2e8fSAntoine Tenart /* Always set the carrier off */ 186843de6195SIoana Ciornei if (pl->netdev) 1869aeeb2e8fSAntoine Tenart netif_carrier_off(pl->netdev); 1870aeeb2e8fSAntoine Tenart 18719525ae83SRussell King /* Apply the link configuration to the MAC when starting. This allows 18729525ae83SRussell King * a fixed-link to start with the correct parameters, and also 1873cc1122b0SColin Ian King * ensures that we set the appropriate advertisement for Serdes links. 18744c0d6d3aSRussell King * 18754c0d6d3aSRussell King * Restart autonegotiation if using 802.3z to ensure that the link 187685b43945SRussell King * parameters are properly negotiated. This is necessary for DSA 187785b43945SRussell King * switches using 802.3z negotiation to ensure they see our modes. 187885b43945SRussell King */ 18794c0d6d3aSRussell King phylink_mac_initial_config(pl, true); 188085b43945SRussell King 1881aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_STOPPED); 18829525ae83SRussell King 188324cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) { 18847b3b0e89SRussell King int irq = gpiod_to_irq(pl->link_gpio); 18857b3b0e89SRussell King 18867b3b0e89SRussell King if (irq > 0) { 18877b3b0e89SRussell King if (!request_irq(irq, phylink_link_handler, 18887b3b0e89SRussell King IRQF_TRIGGER_RISING | 18897b3b0e89SRussell King IRQF_TRIGGER_FALLING, 18907b3b0e89SRussell King "netdev link", pl)) 18917b3b0e89SRussell King pl->link_irq = irq; 18927b3b0e89SRussell King else 18937b3b0e89SRussell King irq = 0; 18947b3b0e89SRussell King } 18957b3b0e89SRussell King if (irq <= 0) 18965c05c1dbSRussell King poll = true; 18977b3b0e89SRussell King } 18985c05c1dbSRussell King 18995c05c1dbSRussell King switch (pl->cfg_link_an_mode) { 19005c05c1dbSRussell King case MLO_AN_FIXED: 19015c05c1dbSRussell King poll |= pl->config->poll_fixed_state; 19025c05c1dbSRussell King break; 19035c05c1dbSRussell King case MLO_AN_INBAND: 19047137e18fSRussell King if (pl->pcs) 19057137e18fSRussell King poll |= pl->pcs->poll; 19065c05c1dbSRussell King break; 19075c05c1dbSRussell King } 19085c05c1dbSRussell King if (poll) 19099cd00a8aSRussell King mod_timer(&pl->link_poll, jiffies + HZ); 19109525ae83SRussell King if (pl->phydev) 19119525ae83SRussell King phy_start(pl->phydev); 1912c7fa7f56SArseny Solokha if (pl->sfp_bus) 1913c7fa7f56SArseny Solokha sfp_upstream_start(pl->sfp_bus); 19149525ae83SRussell King } 19159525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_start); 19169525ae83SRussell King 19178796c892SRussell King /** 19188796c892SRussell King * phylink_stop() - stop a phylink instance 19198796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 19208796c892SRussell King * 19218796c892SRussell King * Stop the phylink instance specified by @pl. This should be called from the 19228796c892SRussell King * network device driver's &struct net_device_ops ndo_stop() method. The 19238796c892SRussell King * network device's carrier state should not be changed prior to calling this 19248796c892SRussell King * function. 1925f9749365SRussell King (Oracle) * 1926f9749365SRussell King (Oracle) * This will synchronously bring down the link if the link is not already 1927f9749365SRussell King (Oracle) * down (in other words, it will trigger a mac_link_down() method call.) 19288796c892SRussell King */ 19299525ae83SRussell King void phylink_stop(struct phylink *pl) 19309525ae83SRussell King { 19318b874514SRussell King ASSERT_RTNL(); 19329525ae83SRussell King 1933ce0aa27fSRussell King if (pl->sfp_bus) 1934ce0aa27fSRussell King sfp_upstream_stop(pl->sfp_bus); 1935c7fa7f56SArseny Solokha if (pl->phydev) 1936c7fa7f56SArseny Solokha phy_stop(pl->phydev); 19379cd00a8aSRussell King del_timer_sync(&pl->link_poll); 19387b3b0e89SRussell King if (pl->link_irq) { 19397b3b0e89SRussell King free_irq(pl->link_irq, pl); 19407b3b0e89SRussell King pl->link_irq = 0; 19417b3b0e89SRussell King } 19429525ae83SRussell King 194387454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED); 19449525ae83SRussell King } 19459525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_stop); 19469525ae83SRussell King 19478796c892SRussell King /** 1948f9749365SRussell King (Oracle) * phylink_suspend() - handle a network device suspend event 1949f9749365SRussell King (Oracle) * @pl: a pointer to a &struct phylink returned from phylink_create() 1950f9749365SRussell King (Oracle) * @mac_wol: true if the MAC needs to receive packets for Wake-on-Lan 1951f9749365SRussell King (Oracle) * 1952f9749365SRussell King (Oracle) * Handle a network device suspend event. There are several cases: 1953c35e8de7SYanteng Si * 1954f9749365SRussell King (Oracle) * - If Wake-on-Lan is not active, we can bring down the link between 1955f9749365SRussell King (Oracle) * the MAC and PHY by calling phylink_stop(). 1956f9749365SRussell King (Oracle) * - If Wake-on-Lan is active, and being handled only by the PHY, we 1957f9749365SRussell King (Oracle) * can also bring down the link between the MAC and PHY. 1958f9749365SRussell King (Oracle) * - If Wake-on-Lan is active, but being handled by the MAC, the MAC 1959f9749365SRussell King (Oracle) * still needs to receive packets, so we can not bring the link down. 1960f9749365SRussell King (Oracle) */ 1961f9749365SRussell King (Oracle) void phylink_suspend(struct phylink *pl, bool mac_wol) 1962f9749365SRussell King (Oracle) { 1963f9749365SRussell King (Oracle) ASSERT_RTNL(); 1964f9749365SRussell King (Oracle) 1965f9749365SRussell King (Oracle) if (mac_wol && (!pl->netdev || pl->netdev->wol_enabled)) { 1966f9749365SRussell King (Oracle) /* Wake-on-Lan enabled, MAC handling */ 1967f9749365SRussell King (Oracle) mutex_lock(&pl->state_mutex); 1968f9749365SRussell King (Oracle) 1969f9749365SRussell King (Oracle) /* Stop the resolver bringing the link up */ 1970f9749365SRussell King (Oracle) __set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state); 1971f9749365SRussell King (Oracle) 1972f9749365SRussell King (Oracle) /* Disable the carrier, to prevent transmit timeouts, 1973f9749365SRussell King (Oracle) * but one would hope all packets have been sent. This 1974f9749365SRussell King (Oracle) * also means phylink_resolve() will do nothing. 1975f9749365SRussell King (Oracle) */ 1976cbcca2e3SRussell King (Oracle) if (pl->netdev) 1977f9749365SRussell King (Oracle) netif_carrier_off(pl->netdev); 1978cbcca2e3SRussell King (Oracle) else 1979cbcca2e3SRussell King (Oracle) pl->old_link_state = false; 1980f9749365SRussell King (Oracle) 1981f9749365SRussell King (Oracle) /* We do not call mac_link_down() here as we want the 1982f9749365SRussell King (Oracle) * link to remain up to receive the WoL packets. 1983f9749365SRussell King (Oracle) */ 1984f9749365SRussell King (Oracle) mutex_unlock(&pl->state_mutex); 1985f9749365SRussell King (Oracle) } else { 1986f9749365SRussell King (Oracle) phylink_stop(pl); 1987f9749365SRussell King (Oracle) } 1988f9749365SRussell King (Oracle) } 1989f9749365SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_suspend); 1990f9749365SRussell King (Oracle) 1991f9749365SRussell King (Oracle) /** 1992f9749365SRussell King (Oracle) * phylink_resume() - handle a network device resume event 1993f9749365SRussell King (Oracle) * @pl: a pointer to a &struct phylink returned from phylink_create() 1994f9749365SRussell King (Oracle) * 1995f9749365SRussell King (Oracle) * Undo the effects of phylink_suspend(), returning the link to an 1996f9749365SRussell King (Oracle) * operational state. 1997f9749365SRussell King (Oracle) */ 1998f9749365SRussell King (Oracle) void phylink_resume(struct phylink *pl) 1999f9749365SRussell King (Oracle) { 2000f9749365SRussell King (Oracle) ASSERT_RTNL(); 2001f9749365SRussell King (Oracle) 2002f9749365SRussell King (Oracle) if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) { 2003f9749365SRussell King (Oracle) /* Wake-on-Lan enabled, MAC handling */ 2004f9749365SRussell King (Oracle) 2005f9749365SRussell King (Oracle) /* Call mac_link_down() so we keep the overall state balanced. 2006f9749365SRussell King (Oracle) * Do this under the state_mutex lock for consistency. This 2007f9749365SRussell King (Oracle) * will cause a "Link Down" message to be printed during 2008f9749365SRussell King (Oracle) * resume, which is harmless - the true link state will be 2009f9749365SRussell King (Oracle) * printed when we run a resolve. 2010f9749365SRussell King (Oracle) */ 2011f9749365SRussell King (Oracle) mutex_lock(&pl->state_mutex); 2012f9749365SRussell King (Oracle) phylink_link_down(pl); 2013f9749365SRussell King (Oracle) mutex_unlock(&pl->state_mutex); 2014f9749365SRussell King (Oracle) 2015f9749365SRussell King (Oracle) /* Re-apply the link parameters so that all the settings get 2016f9749365SRussell King (Oracle) * restored to the MAC. 2017f9749365SRussell King (Oracle) */ 2018f9749365SRussell King (Oracle) phylink_mac_initial_config(pl, true); 2019f9749365SRussell King (Oracle) 2020f9749365SRussell King (Oracle) /* Re-enable and re-resolve the link parameters */ 2021aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_MAC_WOL); 2022f9749365SRussell King (Oracle) } else { 2023f9749365SRussell King (Oracle) phylink_start(pl); 2024f9749365SRussell King (Oracle) } 2025f9749365SRussell King (Oracle) } 2026f9749365SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_resume); 2027f9749365SRussell King (Oracle) 2028f9749365SRussell King (Oracle) /** 20298796c892SRussell King * phylink_ethtool_get_wol() - get the wake on lan parameters for the PHY 20308796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 20318796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo to hold the read parameters 20328796c892SRussell King * 20338796c892SRussell King * Read the wake on lan parameters from the PHY attached to the phylink 20348796c892SRussell King * instance specified by @pl. If no PHY is currently attached, report no 20358796c892SRussell King * support for wake on lan. 20368796c892SRussell King */ 20379525ae83SRussell King void phylink_ethtool_get_wol(struct phylink *pl, struct ethtool_wolinfo *wol) 20389525ae83SRussell King { 20398b874514SRussell King ASSERT_RTNL(); 20409525ae83SRussell King 20419525ae83SRussell King wol->supported = 0; 20429525ae83SRussell King wol->wolopts = 0; 20439525ae83SRussell King 20449525ae83SRussell King if (pl->phydev) 20459525ae83SRussell King phy_ethtool_get_wol(pl->phydev, wol); 20469525ae83SRussell King } 20479525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_wol); 20489525ae83SRussell King 20498796c892SRussell King /** 20508796c892SRussell King * phylink_ethtool_set_wol() - set wake on lan parameters 20518796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 20528796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo for the desired parameters 20538796c892SRussell King * 20548796c892SRussell King * Set the wake on lan parameters for the PHY attached to the phylink 20558796c892SRussell King * instance specified by @pl. If no PHY is attached, returns %EOPNOTSUPP 20568796c892SRussell King * error. 20578796c892SRussell King * 20588796c892SRussell King * Returns zero on success or negative errno code. 20598796c892SRussell King */ 20609525ae83SRussell King int phylink_ethtool_set_wol(struct phylink *pl, struct ethtool_wolinfo *wol) 20619525ae83SRussell King { 20629525ae83SRussell King int ret = -EOPNOTSUPP; 20639525ae83SRussell King 20648b874514SRussell King ASSERT_RTNL(); 20659525ae83SRussell King 20669525ae83SRussell King if (pl->phydev) 20679525ae83SRussell King ret = phy_ethtool_set_wol(pl->phydev, wol); 20689525ae83SRussell King 20699525ae83SRussell King return ret; 20709525ae83SRussell King } 20719525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_wol); 20729525ae83SRussell King 20739525ae83SRussell King static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b) 20749525ae83SRussell King { 20759525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask); 20769525ae83SRussell King 20779525ae83SRussell King linkmode_zero(mask); 20789525ae83SRussell King phylink_set_port_modes(mask); 20799525ae83SRussell King 20809525ae83SRussell King linkmode_and(dst, dst, mask); 20819525ae83SRussell King linkmode_or(dst, dst, b); 20829525ae83SRussell King } 20839525ae83SRussell King 20849525ae83SRussell King static void phylink_get_ksettings(const struct phylink_link_state *state, 20859525ae83SRussell King struct ethtool_link_ksettings *kset) 20869525ae83SRussell King { 20879525ae83SRussell King phylink_merge_link_mode(kset->link_modes.advertising, state->advertising); 20889525ae83SRussell King linkmode_copy(kset->link_modes.lp_advertising, state->lp_advertising); 2089ae0e4bb2SSean Anderson if (kset->base.rate_matching == RATE_MATCH_NONE) { 20909525ae83SRussell King kset->base.speed = state->speed; 20919525ae83SRussell King kset->base.duplex = state->duplex; 2092ae0e4bb2SSean Anderson } 20939525ae83SRussell King kset->base.autoneg = state->an_enabled ? AUTONEG_ENABLE : 20949525ae83SRussell King AUTONEG_DISABLE; 20959525ae83SRussell King } 20969525ae83SRussell King 20978796c892SRussell King /** 20988796c892SRussell King * phylink_ethtool_ksettings_get() - get the current link settings 20998796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 21008796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings to hold link settings 21018796c892SRussell King * 21028796c892SRussell King * Read the current link settings for the phylink instance specified by @pl. 21038796c892SRussell King * This will be the link settings read from the MAC, PHY or fixed link 21048796c892SRussell King * settings depending on the current negotiation mode. 21058796c892SRussell King */ 21069525ae83SRussell King int phylink_ethtool_ksettings_get(struct phylink *pl, 21079525ae83SRussell King struct ethtool_link_ksettings *kset) 21089525ae83SRussell King { 21099525ae83SRussell King struct phylink_link_state link_state; 21109525ae83SRussell King 21118b874514SRussell King ASSERT_RTNL(); 21129525ae83SRussell King 2113169d7a40SWenpeng Liang if (pl->phydev) 21149525ae83SRussell King phy_ethtool_ksettings_get(pl->phydev, kset); 2115169d7a40SWenpeng Liang else 21169525ae83SRussell King kset->base.port = pl->link_port; 21179525ae83SRussell King 21189525ae83SRussell King linkmode_copy(kset->link_modes.supported, pl->supported); 21199525ae83SRussell King 212024cf0e69SRussell King switch (pl->cur_link_an_mode) { 21219525ae83SRussell King case MLO_AN_FIXED: 21229525ae83SRussell King /* We are using fixed settings. Report these as the 21239525ae83SRussell King * current link settings - and note that these also 21249525ae83SRussell King * represent the supported speeds/duplex/pause modes. 21259525ae83SRussell King */ 21269525ae83SRussell King phylink_get_fixed_state(pl, &link_state); 21279525ae83SRussell King phylink_get_ksettings(&link_state, kset); 21289525ae83SRussell King break; 21299525ae83SRussell King 213086a362c4SRussell King case MLO_AN_INBAND: 21319525ae83SRussell King /* If there is a phy attached, then use the reported 21329525ae83SRussell King * settings from the phy with no modification. 21339525ae83SRussell King */ 21349525ae83SRussell King if (pl->phydev) 21359525ae83SRussell King break; 21369525ae83SRussell King 2137d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state); 21389525ae83SRussell King 21399525ae83SRussell King /* The MAC is reporting the link results from its own PCS 21409525ae83SRussell King * layer via in-band status. Report these as the current 21419525ae83SRussell King * link settings. 21429525ae83SRussell King */ 21439525ae83SRussell King phylink_get_ksettings(&link_state, kset); 21449525ae83SRussell King break; 21459525ae83SRussell King } 21469525ae83SRussell King 21479525ae83SRussell King return 0; 21489525ae83SRussell King } 21499525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get); 21509525ae83SRussell King 21518796c892SRussell King /** 21528796c892SRussell King * phylink_ethtool_ksettings_set() - set the link settings 21538796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 21548796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings for the desired modes 21558796c892SRussell King */ 21569525ae83SRussell King int phylink_ethtool_ksettings_set(struct phylink *pl, 21579525ae83SRussell King const struct ethtool_link_ksettings *kset) 21589525ae83SRussell King { 215977316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support); 21609525ae83SRussell King struct phylink_link_state config; 2161c8cab719SRussell King const struct phy_setting *s; 21629525ae83SRussell King 21638b874514SRussell King ASSERT_RTNL(); 21649525ae83SRussell King 2165cbc1bb1eSRussell King if (pl->phydev) { 2166cbc1bb1eSRussell King /* We can rely on phylib for this update; we also do not need 2167cbc1bb1eSRussell King * to update the pl->link_config settings: 2168cbc1bb1eSRussell King * - the configuration returned via ksettings_get() will come 2169cbc1bb1eSRussell King * from phylib whenever a PHY is present. 2170cbc1bb1eSRussell King * - link_config.interface will be updated by the PHY calling 2171cbc1bb1eSRussell King * back via phylink_phy_change() and a subsequent resolve. 2172cbc1bb1eSRussell King * - initial link configuration for PHY mode comes from the 2173cbc1bb1eSRussell King * last phy state updated via phylink_phy_change(). 2174cbc1bb1eSRussell King * - other configuration changes (e.g. pause modes) are 2175cbc1bb1eSRussell King * performed directly via phylib. 2176cbc1bb1eSRussell King * - if in in-band mode with a PHY, the link configuration 2177cbc1bb1eSRussell King * is passed on the link from the PHY, and all of 2178cbc1bb1eSRussell King * link_config.{speed,duplex,an_enabled,pause} are not used. 2179cbc1bb1eSRussell King * - the only possible use would be link_config.advertising 2180cbc1bb1eSRussell King * pause modes when in 1000base-X mode with a PHY, but in 2181cbc1bb1eSRussell King * the presence of a PHY, this should not be changed as that 2182cbc1bb1eSRussell King * should be determined from the media side advertisement. 2183cbc1bb1eSRussell King */ 2184cbc1bb1eSRussell King return phy_ethtool_ksettings_set(pl->phydev, kset); 2185cbc1bb1eSRussell King } 2186cbc1bb1eSRussell King 21879525ae83SRussell King config = pl->link_config; 21889525ae83SRussell King 21897cefb0b0SRussell King (Oracle) /* Mask out unsupported advertisements */ 21909525ae83SRussell King linkmode_and(config.advertising, kset->link_modes.advertising, 21917cefb0b0SRussell King (Oracle) pl->supported); 21929525ae83SRussell King 21939525ae83SRussell King /* FIXME: should we reject autoneg if phy/mac does not support it? */ 2194c8cab719SRussell King switch (kset->base.autoneg) { 2195c8cab719SRussell King case AUTONEG_DISABLE: 21969525ae83SRussell King /* Autonegotiation disabled, select a suitable speed and 21979525ae83SRussell King * duplex. 21989525ae83SRussell King */ 21999525ae83SRussell King s = phy_lookup_setting(kset->base.speed, kset->base.duplex, 22007cefb0b0SRussell King (Oracle) pl->supported, false); 22019525ae83SRussell King if (!s) 22029525ae83SRussell King return -EINVAL; 22039525ae83SRussell King 22041e1bf14aSRussell King /* If we have a fixed link, refuse to change link parameters. 22051e1bf14aSRussell King * If the link parameters match, accept them but do nothing. 22069525ae83SRussell King */ 22071e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) { 22081e1bf14aSRussell King if (s->speed != pl->link_config.speed || 22091e1bf14aSRussell King s->duplex != pl->link_config.duplex) 22109525ae83SRussell King return -EINVAL; 22111e1bf14aSRussell King return 0; 22121e1bf14aSRussell King } 22139525ae83SRussell King 22149525ae83SRussell King config.speed = s->speed; 22159525ae83SRussell King config.duplex = s->duplex; 2216c8cab719SRussell King break; 22179525ae83SRussell King 2218c8cab719SRussell King case AUTONEG_ENABLE: 22191e1bf14aSRussell King /* If we have a fixed link, allow autonegotiation (since that 22201e1bf14aSRussell King * is our default case) but do not allow the advertisement to 22211e1bf14aSRussell King * be changed. If the advertisement matches, simply return. 22221e1bf14aSRussell King */ 22231e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) { 22241e1bf14aSRussell King if (!linkmode_equal(config.advertising, 22251e1bf14aSRussell King pl->link_config.advertising)) 22269525ae83SRussell King return -EINVAL; 22271e1bf14aSRussell King return 0; 22281e1bf14aSRussell King } 22299525ae83SRussell King 22309525ae83SRussell King config.speed = SPEED_UNKNOWN; 22319525ae83SRussell King config.duplex = DUPLEX_UNKNOWN; 2232c8cab719SRussell King break; 22339525ae83SRussell King 2234c8cab719SRussell King default: 2235c8cab719SRussell King return -EINVAL; 22369525ae83SRussell King } 22379525ae83SRussell King 22381e1bf14aSRussell King /* We have ruled out the case with a PHY attached, and the 22391e1bf14aSRussell King * fixed-link cases. All that is left are in-band links. 22405d57c327SRussell King */ 22417cefb0b0SRussell King (Oracle) config.an_enabled = kset->base.autoneg == AUTONEG_ENABLE; 22427cefb0b0SRussell King (Oracle) linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising, 22437cefb0b0SRussell King (Oracle) config.an_enabled); 22447cefb0b0SRussell King (Oracle) 2245ea269a6fSNathan Rossi /* If this link is with an SFP, ensure that changes to advertised modes 2246ea269a6fSNathan Rossi * also cause the associated interface to be selected such that the 2247ea269a6fSNathan Rossi * link can be configured correctly. 2248ea269a6fSNathan Rossi */ 2249dc90604bSRussell King (Oracle) if (pl->sfp_bus) { 2250ea269a6fSNathan Rossi config.interface = sfp_select_interface(pl->sfp_bus, 2251ea269a6fSNathan Rossi config.advertising); 2252ea269a6fSNathan Rossi if (config.interface == PHY_INTERFACE_MODE_NA) { 2253ea269a6fSNathan Rossi phylink_err(pl, 2254ea269a6fSNathan Rossi "selection of interface failed, advertisement %*pb\n", 2255ea269a6fSNathan Rossi __ETHTOOL_LINK_MODE_MASK_NBITS, 2256ea269a6fSNathan Rossi config.advertising); 2257ea269a6fSNathan Rossi return -EINVAL; 2258ea269a6fSNathan Rossi } 2259ea269a6fSNathan Rossi 2260ea269a6fSNathan Rossi /* Revalidate with the selected interface */ 2261ea269a6fSNathan Rossi linkmode_copy(support, pl->supported); 2262ea269a6fSNathan Rossi if (phylink_validate(pl, support, &config)) { 2263ea269a6fSNathan Rossi phylink_err(pl, "validation of %s/%s with support %*pb failed\n", 2264ea269a6fSNathan Rossi phylink_an_mode_str(pl->cur_link_an_mode), 2265ea269a6fSNathan Rossi phy_modes(config.interface), 2266ea269a6fSNathan Rossi __ETHTOOL_LINK_MODE_MASK_NBITS, support); 2267ea269a6fSNathan Rossi return -EINVAL; 2268ea269a6fSNathan Rossi } 2269dc90604bSRussell King (Oracle) } else { 2270dc90604bSRussell King (Oracle) /* Validate without changing the current supported mask. */ 2271dc90604bSRussell King (Oracle) linkmode_copy(support, pl->supported); 2272dc90604bSRussell King (Oracle) if (phylink_validate(pl, support, &config)) 2273dc90604bSRussell King (Oracle) return -EINVAL; 2274ea269a6fSNathan Rossi } 2275ea269a6fSNathan Rossi 2276dc90604bSRussell King (Oracle) /* If autonegotiation is enabled, we must have an advertisement */ 2277dc90604bSRussell King (Oracle) if (config.an_enabled && phylink_is_empty_linkmode(config.advertising)) 2278dc90604bSRussell King (Oracle) return -EINVAL; 2279dc90604bSRussell King (Oracle) 22809525ae83SRussell King mutex_lock(&pl->state_mutex); 22815d57c327SRussell King pl->link_config.speed = config.speed; 22825d57c327SRussell King pl->link_config.duplex = config.duplex; 2283a83c8829SRussell King pl->link_config.an_enabled = config.an_enabled; 22849525ae83SRussell King 2285b7ad14c2SRussell King if (pl->link_config.interface != config.interface) { 2286b7ad14c2SRussell King /* The interface changed, e.g. 1000base-X <-> 2500base-X */ 2287b7ad14c2SRussell King /* We need to force the link down, then change the interface */ 2288b7ad14c2SRussell King if (pl->old_link_state) { 2289b7ad14c2SRussell King phylink_link_down(pl); 2290b7ad14c2SRussell King pl->old_link_state = false; 2291b7ad14c2SRussell King } 2292b7ad14c2SRussell King if (!test_bit(PHYLINK_DISABLE_STOPPED, 2293b7ad14c2SRussell King &pl->phylink_disable_state)) 2294b7ad14c2SRussell King phylink_major_config(pl, false, &config); 2295b7ad14c2SRussell King pl->link_config.interface = config.interface; 2296b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 2297b7ad14c2SRussell King } else if (!linkmode_equal(pl->link_config.advertising, 2298b7ad14c2SRussell King config.advertising)) { 2299b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 2300b7ad14c2SRussell King phylink_change_inband_advert(pl); 23019525ae83SRussell King } 23029525ae83SRussell King mutex_unlock(&pl->state_mutex); 23039525ae83SRussell King 2304d18c2a1bSDan Carpenter return 0; 23059525ae83SRussell King } 23069525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_set); 23079525ae83SRussell King 23088796c892SRussell King /** 23098796c892SRussell King * phylink_ethtool_nway_reset() - restart negotiation 23108796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 23118796c892SRussell King * 23128796c892SRussell King * Restart negotiation for the phylink instance specified by @pl. This will 23138796c892SRussell King * cause any attached phy to restart negotiation with the link partner, and 23148796c892SRussell King * if the MAC is in a BaseX mode, the MAC will also be requested to restart 23158796c892SRussell King * negotiation. 23168796c892SRussell King * 23178796c892SRussell King * Returns zero on success, or negative error code. 23188796c892SRussell King */ 23199525ae83SRussell King int phylink_ethtool_nway_reset(struct phylink *pl) 23209525ae83SRussell King { 23219525ae83SRussell King int ret = 0; 23229525ae83SRussell King 23238b874514SRussell King ASSERT_RTNL(); 23249525ae83SRussell King 23259525ae83SRussell King if (pl->phydev) 23269525ae83SRussell King ret = phy_restart_aneg(pl->phydev); 23274c0d6d3aSRussell King phylink_mac_pcs_an_restart(pl); 23289525ae83SRussell King 23299525ae83SRussell King return ret; 23309525ae83SRussell King } 23319525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_nway_reset); 23329525ae83SRussell King 23338796c892SRussell King /** 23348796c892SRussell King * phylink_ethtool_get_pauseparam() - get the current pause parameters 23358796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 23368796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam 23378796c892SRussell King */ 23389525ae83SRussell King void phylink_ethtool_get_pauseparam(struct phylink *pl, 23399525ae83SRussell King struct ethtool_pauseparam *pause) 23409525ae83SRussell King { 23418b874514SRussell King ASSERT_RTNL(); 23429525ae83SRussell King 23439525ae83SRussell King pause->autoneg = !!(pl->link_config.pause & MLO_PAUSE_AN); 23449525ae83SRussell King pause->rx_pause = !!(pl->link_config.pause & MLO_PAUSE_RX); 23459525ae83SRussell King pause->tx_pause = !!(pl->link_config.pause & MLO_PAUSE_TX); 23469525ae83SRussell King } 23479525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_pauseparam); 23489525ae83SRussell King 23498796c892SRussell King /** 23508796c892SRussell King * phylink_ethtool_set_pauseparam() - set the current pause parameters 23518796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 23528796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam 23538796c892SRussell King */ 23549525ae83SRussell King int phylink_ethtool_set_pauseparam(struct phylink *pl, 23559525ae83SRussell King struct ethtool_pauseparam *pause) 23569525ae83SRussell King { 23579525ae83SRussell King struct phylink_link_state *config = &pl->link_config; 23582e919bc4SRussell King bool manual_changed; 23592e919bc4SRussell King int pause_state; 23609525ae83SRussell King 23618b874514SRussell King ASSERT_RTNL(); 23629525ae83SRussell King 23638cdfa256SRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) 23648cdfa256SRussell King return -EOPNOTSUPP; 23658cdfa256SRussell King 23669525ae83SRussell King if (!phylink_test(pl->supported, Pause) && 23679525ae83SRussell King !phylink_test(pl->supported, Asym_Pause)) 23689525ae83SRussell King return -EOPNOTSUPP; 23699525ae83SRussell King 23709525ae83SRussell King if (!phylink_test(pl->supported, Asym_Pause) && 2371fd8d9731SRussell King (Oracle) pause->rx_pause != pause->tx_pause) 23729525ae83SRussell King return -EINVAL; 23739525ae83SRussell King 23742e919bc4SRussell King pause_state = 0; 23759525ae83SRussell King if (pause->autoneg) 23762e919bc4SRussell King pause_state |= MLO_PAUSE_AN; 23779525ae83SRussell King if (pause->rx_pause) 23782e919bc4SRussell King pause_state |= MLO_PAUSE_RX; 23799525ae83SRussell King if (pause->tx_pause) 23802e919bc4SRussell King pause_state |= MLO_PAUSE_TX; 23819525ae83SRussell King 23822e919bc4SRussell King mutex_lock(&pl->state_mutex); 2383f904f15eSRussell King /* 2384f904f15eSRussell King * See the comments for linkmode_set_pause(), wrt the deficiencies 2385f904f15eSRussell King * with the current implementation. A solution to this issue would 2386f904f15eSRussell King * be: 2387f904f15eSRussell King * ethtool Local device 2388f904f15eSRussell King * rx tx Pause AsymDir 2389f904f15eSRussell King * 0 0 0 0 2390f904f15eSRussell King * 1 0 1 1 2391f904f15eSRussell King * 0 1 0 1 2392f904f15eSRussell King * 1 1 1 1 2393f904f15eSRussell King * and then use the ethtool rx/tx enablement status to mask the 2394f904f15eSRussell King * rx/tx pause resolution. 2395f904f15eSRussell King */ 2396f904f15eSRussell King linkmode_set_pause(config->advertising, pause->tx_pause, 2397f904f15eSRussell King pause->rx_pause); 2398f904f15eSRussell King 23992e919bc4SRussell King manual_changed = (config->pause ^ pause_state) & MLO_PAUSE_AN || 24002e919bc4SRussell King (!(pause_state & MLO_PAUSE_AN) && 24012e919bc4SRussell King (config->pause ^ pause_state) & MLO_PAUSE_TXRX_MASK); 24022e919bc4SRussell King 24032e919bc4SRussell King config->pause = pause_state; 24042e919bc4SRussell King 24051571e700SRussell King /* Update our in-band advertisement, triggering a renegotiation if 24061571e700SRussell King * the advertisement changed. 24071571e700SRussell King */ 24081571e700SRussell King if (!pl->phydev) 24091571e700SRussell King phylink_change_inband_advert(pl); 2410c718af2dSRussell King 2411c718af2dSRussell King mutex_unlock(&pl->state_mutex); 2412c718af2dSRussell King 2413c718af2dSRussell King /* If we have a PHY, a change of the pause frame advertisement will 2414c718af2dSRussell King * cause phylib to renegotiate (if AN is enabled) which will in turn 2415c718af2dSRussell King * call our phylink_phy_change() and trigger a resolve. Note that 2416c718af2dSRussell King * we can't hold our state mutex while calling phy_set_asym_pause(). 2417d9922c0eSRussell King */ 2418c718af2dSRussell King if (pl->phydev) 2419d9922c0eSRussell King phy_set_asym_pause(pl->phydev, pause->rx_pause, 2420d9922c0eSRussell King pause->tx_pause); 24219525ae83SRussell King 24222e919bc4SRussell King /* If the manual pause settings changed, make sure we trigger a 24232e919bc4SRussell King * resolve to update their state; we can not guarantee that the 24242e919bc4SRussell King * link will cycle. 24252e919bc4SRussell King */ 24262e919bc4SRussell King if (manual_changed) { 24272e919bc4SRussell King pl->mac_link_dropped = true; 24282e919bc4SRussell King phylink_run_resolve(pl); 24299525ae83SRussell King } 24309525ae83SRussell King 24319525ae83SRussell King return 0; 24329525ae83SRussell King } 24339525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam); 24349525ae83SRussell King 24359525ae83SRussell King /** 243669280228SMauro Carvalho Chehab * phylink_get_eee_err() - read the energy efficient ethernet error 24379525ae83SRussell King * counter 24389525ae83SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create(). 24399525ae83SRussell King * 24409525ae83SRussell King * Read the Energy Efficient Ethernet error counter from the PHY associated 24419525ae83SRussell King * with the phylink instance specified by @pl. 24429525ae83SRussell King * 24439525ae83SRussell King * Returns positive error counter value, or negative error code. 24449525ae83SRussell King */ 24459525ae83SRussell King int phylink_get_eee_err(struct phylink *pl) 24469525ae83SRussell King { 24479525ae83SRussell King int ret = 0; 24489525ae83SRussell King 24498b874514SRussell King ASSERT_RTNL(); 24509525ae83SRussell King 24519525ae83SRussell King if (pl->phydev) 24529525ae83SRussell King ret = phy_get_eee_err(pl->phydev); 24539525ae83SRussell King 24549525ae83SRussell King return ret; 24559525ae83SRussell King } 24569525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_get_eee_err); 24579525ae83SRussell King 24588796c892SRussell King /** 245986e58135SRussell King * phylink_init_eee() - init and check the EEE features 246086e58135SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 246186e58135SRussell King * @clk_stop_enable: allow PHY to stop receive clock 246286e58135SRussell King * 246386e58135SRussell King * Must be called either with RTNL held or within mac_link_up() 246486e58135SRussell King */ 246586e58135SRussell King int phylink_init_eee(struct phylink *pl, bool clk_stop_enable) 246686e58135SRussell King { 246786e58135SRussell King int ret = -EOPNOTSUPP; 246886e58135SRussell King 246986e58135SRussell King if (pl->phydev) 247086e58135SRussell King ret = phy_init_eee(pl->phydev, clk_stop_enable); 247186e58135SRussell King 247286e58135SRussell King return ret; 247386e58135SRussell King } 247486e58135SRussell King EXPORT_SYMBOL_GPL(phylink_init_eee); 247586e58135SRussell King 247686e58135SRussell King /** 24778796c892SRussell King * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters 24788796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 24798796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the read parameters 24808796c892SRussell King */ 24819525ae83SRussell King int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee) 24829525ae83SRussell King { 24839525ae83SRussell King int ret = -EOPNOTSUPP; 24849525ae83SRussell King 24858b874514SRussell King ASSERT_RTNL(); 24869525ae83SRussell King 24879525ae83SRussell King if (pl->phydev) 24889525ae83SRussell King ret = phy_ethtool_get_eee(pl->phydev, eee); 24899525ae83SRussell King 24909525ae83SRussell King return ret; 24919525ae83SRussell King } 24929525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); 24939525ae83SRussell King 24948796c892SRussell King /** 24958796c892SRussell King * phylink_ethtool_set_eee() - set the energy efficient ethernet parameters 24968796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 24978796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the desired parameters 24988796c892SRussell King */ 24999525ae83SRussell King int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee) 25009525ae83SRussell King { 25019525ae83SRussell King int ret = -EOPNOTSUPP; 25029525ae83SRussell King 25038b874514SRussell King ASSERT_RTNL(); 25049525ae83SRussell King 25059525ae83SRussell King if (pl->phydev) 25069525ae83SRussell King ret = phy_ethtool_set_eee(pl->phydev, eee); 25079525ae83SRussell King 25089525ae83SRussell King return ret; 25099525ae83SRussell King } 25109525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee); 25119525ae83SRussell King 25129525ae83SRussell King /* This emulates MII registers for a fixed-mode phy operating as per the 25139525ae83SRussell King * passed in state. "aneg" defines if we report negotiation is possible. 25149525ae83SRussell King * 25159525ae83SRussell King * FIXME: should deal with negotiation state too. 25169525ae83SRussell King */ 25177fdc455eSRussell King static int phylink_mii_emul_read(unsigned int reg, 25187fdc455eSRussell King struct phylink_link_state *state) 25199525ae83SRussell King { 25209525ae83SRussell King struct fixed_phy_status fs; 25214e5aeb41SRussell King unsigned long *lpa = state->lp_advertising; 25229525ae83SRussell King int val; 25239525ae83SRussell King 25249525ae83SRussell King fs.link = state->link; 25259525ae83SRussell King fs.speed = state->speed; 25269525ae83SRussell King fs.duplex = state->duplex; 25274e5aeb41SRussell King fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa); 25284e5aeb41SRussell King fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa); 25299525ae83SRussell King 25309525ae83SRussell King val = swphy_read_reg(reg, &fs); 25319525ae83SRussell King if (reg == MII_BMSR) { 25329525ae83SRussell King if (!state->an_complete) 25339525ae83SRussell King val &= ~BMSR_ANEGCOMPLETE; 25349525ae83SRussell King } 25359525ae83SRussell King return val; 25369525ae83SRussell King } 25379525ae83SRussell King 2538ecbd87b8SRussell King static int phylink_phy_read(struct phylink *pl, unsigned int phy_id, 2539ecbd87b8SRussell King unsigned int reg) 2540ecbd87b8SRussell King { 2541ecbd87b8SRussell King struct phy_device *phydev = pl->phydev; 2542ecbd87b8SRussell King int prtad, devad; 2543ecbd87b8SRussell King 2544ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) { 2545ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id); 2546ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id); 254770dcf3cdSAndrew Lunn return mdiobus_c45_read(pl->phydev->mdio.bus, prtad, devad, 254870dcf3cdSAndrew Lunn reg); 254970dcf3cdSAndrew Lunn } 255070dcf3cdSAndrew Lunn 255170dcf3cdSAndrew Lunn if (phydev->is_c45) { 2552ecbd87b8SRussell King switch (reg) { 2553ecbd87b8SRussell King case MII_BMCR: 2554ecbd87b8SRussell King case MII_BMSR: 2555ecbd87b8SRussell King case MII_PHYSID1: 2556ecbd87b8SRussell King case MII_PHYSID2: 2557320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present); 2558ecbd87b8SRussell King break; 2559ecbd87b8SRussell King case MII_ADVERTISE: 2560ecbd87b8SRussell King case MII_LPA: 2561320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN)) 2562ecbd87b8SRussell King return -EINVAL; 2563ecbd87b8SRussell King devad = MDIO_MMD_AN; 2564ecbd87b8SRussell King if (reg == MII_ADVERTISE) 2565ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE; 2566ecbd87b8SRussell King else 2567ecbd87b8SRussell King reg = MDIO_AN_LPA; 2568ecbd87b8SRussell King break; 2569ecbd87b8SRussell King default: 2570ecbd87b8SRussell King return -EINVAL; 2571ecbd87b8SRussell King } 2572ecbd87b8SRussell King prtad = phy_id; 257370dcf3cdSAndrew Lunn return mdiobus_c45_read(pl->phydev->mdio.bus, prtad, devad, 257470dcf3cdSAndrew Lunn reg); 2575ecbd87b8SRussell King } 257670dcf3cdSAndrew Lunn 257770dcf3cdSAndrew Lunn return mdiobus_read(pl->phydev->mdio.bus, phy_id, reg); 2578ecbd87b8SRussell King } 2579ecbd87b8SRussell King 2580ecbd87b8SRussell King static int phylink_phy_write(struct phylink *pl, unsigned int phy_id, 2581ecbd87b8SRussell King unsigned int reg, unsigned int val) 2582ecbd87b8SRussell King { 2583ecbd87b8SRussell King struct phy_device *phydev = pl->phydev; 2584ecbd87b8SRussell King int prtad, devad; 2585ecbd87b8SRussell King 2586ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) { 2587ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id); 2588ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id); 258970dcf3cdSAndrew Lunn return mdiobus_c45_write(pl->phydev->mdio.bus, prtad, devad, 259070dcf3cdSAndrew Lunn reg, val); 259170dcf3cdSAndrew Lunn } 259270dcf3cdSAndrew Lunn 259370dcf3cdSAndrew Lunn if (phydev->is_c45) { 2594ecbd87b8SRussell King switch (reg) { 2595ecbd87b8SRussell King case MII_BMCR: 2596ecbd87b8SRussell King case MII_BMSR: 2597ecbd87b8SRussell King case MII_PHYSID1: 2598ecbd87b8SRussell King case MII_PHYSID2: 2599320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present); 2600ecbd87b8SRussell King break; 2601ecbd87b8SRussell King case MII_ADVERTISE: 2602ecbd87b8SRussell King case MII_LPA: 2603320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN)) 2604ecbd87b8SRussell King return -EINVAL; 2605ecbd87b8SRussell King devad = MDIO_MMD_AN; 2606ecbd87b8SRussell King if (reg == MII_ADVERTISE) 2607ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE; 2608ecbd87b8SRussell King else 2609ecbd87b8SRussell King reg = MDIO_AN_LPA; 2610ecbd87b8SRussell King break; 2611ecbd87b8SRussell King default: 2612ecbd87b8SRussell King return -EINVAL; 2613ecbd87b8SRussell King } 261470dcf3cdSAndrew Lunn return mdiobus_c45_write(pl->phydev->mdio.bus, phy_id, devad, 261570dcf3cdSAndrew Lunn reg, val); 2616ecbd87b8SRussell King } 2617ecbd87b8SRussell King 261870dcf3cdSAndrew Lunn return mdiobus_write(phydev->mdio.bus, phy_id, reg, val); 2619ecbd87b8SRussell King } 2620ecbd87b8SRussell King 26219525ae83SRussell King static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, 26229525ae83SRussell King unsigned int reg) 26239525ae83SRussell King { 26249525ae83SRussell King struct phylink_link_state state; 26259525ae83SRussell King int val = 0xffff; 26269525ae83SRussell King 262724cf0e69SRussell King switch (pl->cur_link_an_mode) { 26289525ae83SRussell King case MLO_AN_FIXED: 26299525ae83SRussell King if (phy_id == 0) { 26309525ae83SRussell King phylink_get_fixed_state(pl, &state); 26317fdc455eSRussell King val = phylink_mii_emul_read(reg, &state); 26329525ae83SRussell King } 26339525ae83SRussell King break; 26349525ae83SRussell King 26359525ae83SRussell King case MLO_AN_PHY: 26369525ae83SRussell King return -EOPNOTSUPP; 26379525ae83SRussell King 263886a362c4SRussell King case MLO_AN_INBAND: 26399525ae83SRussell King if (phy_id == 0) { 2640d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &state); 26417fdc455eSRussell King val = phylink_mii_emul_read(reg, &state); 26429525ae83SRussell King } 26439525ae83SRussell King break; 26449525ae83SRussell King } 26459525ae83SRussell King 26469525ae83SRussell King return val & 0xffff; 26479525ae83SRussell King } 26489525ae83SRussell King 26499525ae83SRussell King static int phylink_mii_write(struct phylink *pl, unsigned int phy_id, 26509525ae83SRussell King unsigned int reg, unsigned int val) 26519525ae83SRussell King { 265224cf0e69SRussell King switch (pl->cur_link_an_mode) { 26539525ae83SRussell King case MLO_AN_FIXED: 26549525ae83SRussell King break; 26559525ae83SRussell King 26569525ae83SRussell King case MLO_AN_PHY: 26579525ae83SRussell King return -EOPNOTSUPP; 26589525ae83SRussell King 265986a362c4SRussell King case MLO_AN_INBAND: 26609525ae83SRussell King break; 26619525ae83SRussell King } 26629525ae83SRussell King 26639525ae83SRussell King return 0; 26649525ae83SRussell King } 26659525ae83SRussell King 26668796c892SRussell King /** 26678796c892SRussell King * phylink_mii_ioctl() - generic mii ioctl interface 26688796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 26698796c892SRussell King * @ifr: a pointer to a &struct ifreq for socket ioctls 26708796c892SRussell King * @cmd: ioctl cmd to execute 26718796c892SRussell King * 26728796c892SRussell King * Perform the specified MII ioctl on the PHY attached to the phylink instance 26738796c892SRussell King * specified by @pl. If no PHY is attached, emulate the presence of the PHY. 26748796c892SRussell King * 26758796c892SRussell King * Returns: zero on success or negative error code. 26768796c892SRussell King * 26778796c892SRussell King * %SIOCGMIIPHY: 26788796c892SRussell King * read register from the current PHY. 26798796c892SRussell King * %SIOCGMIIREG: 26808796c892SRussell King * read register from the specified PHY. 26818796c892SRussell King * %SIOCSMIIREG: 26828796c892SRussell King * set a register on the specified PHY. 26838796c892SRussell King */ 26849525ae83SRussell King int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd) 26859525ae83SRussell King { 2686ecbd87b8SRussell King struct mii_ioctl_data *mii = if_mii(ifr); 2687ecbd87b8SRussell King int ret; 26889525ae83SRussell King 26898b874514SRussell King ASSERT_RTNL(); 26909525ae83SRussell King 2691ecbd87b8SRussell King if (pl->phydev) { 269286a362c4SRussell King /* PHYs only exist for MLO_AN_PHY and SGMII */ 26939525ae83SRussell King switch (cmd) { 26949525ae83SRussell King case SIOCGMIIPHY: 2695ecbd87b8SRussell King mii->phy_id = pl->phydev->mdio.addr; 2696df561f66SGustavo A. R. Silva fallthrough; 26979525ae83SRussell King 26989525ae83SRussell King case SIOCGMIIREG: 2699ecbd87b8SRussell King ret = phylink_phy_read(pl, mii->phy_id, mii->reg_num); 2700ecbd87b8SRussell King if (ret >= 0) { 2701ecbd87b8SRussell King mii->val_out = ret; 27029525ae83SRussell King ret = 0; 27039525ae83SRussell King } 27049525ae83SRussell King break; 27059525ae83SRussell King 27069525ae83SRussell King case SIOCSMIIREG: 2707ecbd87b8SRussell King ret = phylink_phy_write(pl, mii->phy_id, mii->reg_num, 2708ecbd87b8SRussell King mii->val_in); 2709ecbd87b8SRussell King break; 2710ecbd87b8SRussell King 2711ecbd87b8SRussell King default: 2712ecbd87b8SRussell King ret = phy_mii_ioctl(pl->phydev, ifr, cmd); 2713ecbd87b8SRussell King break; 2714ecbd87b8SRussell King } 2715ecbd87b8SRussell King } else { 2716ecbd87b8SRussell King switch (cmd) { 2717ecbd87b8SRussell King case SIOCGMIIPHY: 2718ecbd87b8SRussell King mii->phy_id = 0; 2719df561f66SGustavo A. R. Silva fallthrough; 2720ecbd87b8SRussell King 2721ecbd87b8SRussell King case SIOCGMIIREG: 2722ecbd87b8SRussell King ret = phylink_mii_read(pl, mii->phy_id, mii->reg_num); 2723ecbd87b8SRussell King if (ret >= 0) { 2724ecbd87b8SRussell King mii->val_out = ret; 2725ecbd87b8SRussell King ret = 0; 2726ecbd87b8SRussell King } 2727ecbd87b8SRussell King break; 2728ecbd87b8SRussell King 2729ecbd87b8SRussell King case SIOCSMIIREG: 2730ecbd87b8SRussell King ret = phylink_mii_write(pl, mii->phy_id, mii->reg_num, 2731ecbd87b8SRussell King mii->val_in); 27329525ae83SRussell King break; 27339525ae83SRussell King 27349525ae83SRussell King default: 27359525ae83SRussell King ret = -EOPNOTSUPP; 27369525ae83SRussell King break; 27379525ae83SRussell King } 2738ecbd87b8SRussell King } 27399525ae83SRussell King 27409525ae83SRussell King return ret; 27419525ae83SRussell King } 27429525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mii_ioctl); 27439525ae83SRussell King 2744c6d5d843SRussell King /** 2745c6d5d843SRussell King * phylink_speed_down() - set the non-SFP PHY to lowest speed supported by both 2746c6d5d843SRussell King * link partners 2747c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 2748c6d5d843SRussell King * @sync: perform action synchronously 2749c6d5d843SRussell King * 2750c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then set the speed 2751c6d5d843SRussell King * as described in the phy_speed_down() function. Please see this function 2752c6d5d843SRussell King * for a description of the @sync parameter. 2753c6d5d843SRussell King * 2754c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_down(). 2755c6d5d843SRussell King */ 2756c6d5d843SRussell King int phylink_speed_down(struct phylink *pl, bool sync) 2757c6d5d843SRussell King { 2758c6d5d843SRussell King int ret = 0; 2759c6d5d843SRussell King 2760c6d5d843SRussell King ASSERT_RTNL(); 2761c6d5d843SRussell King 2762c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev) 2763c6d5d843SRussell King ret = phy_speed_down(pl->phydev, sync); 2764c6d5d843SRussell King 2765c6d5d843SRussell King return ret; 2766c6d5d843SRussell King } 2767c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_down); 2768c6d5d843SRussell King 2769c6d5d843SRussell King /** 2770c6d5d843SRussell King * phylink_speed_up() - restore the advertised speeds prior to the call to 2771c6d5d843SRussell King * phylink_speed_down() 2772c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 2773c6d5d843SRussell King * 2774c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then restore the 2775c6d5d843SRussell King * PHY speeds as per phy_speed_up(). 2776c6d5d843SRussell King * 2777c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_up(). 2778c6d5d843SRussell King */ 2779c6d5d843SRussell King int phylink_speed_up(struct phylink *pl) 2780c6d5d843SRussell King { 2781c6d5d843SRussell King int ret = 0; 2782c6d5d843SRussell King 2783c6d5d843SRussell King ASSERT_RTNL(); 2784c6d5d843SRussell King 2785c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev) 2786c6d5d843SRussell King ret = phy_speed_up(pl->phydev); 2787c6d5d843SRussell King 2788c6d5d843SRussell King return ret; 2789c6d5d843SRussell King } 2790c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_up); 2791c6d5d843SRussell King 2792320587e6SRussell King static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus) 2793320587e6SRussell King { 2794320587e6SRussell King struct phylink *pl = upstream; 2795320587e6SRussell King 2796320587e6SRussell King pl->netdev->sfp_bus = bus; 2797320587e6SRussell King } 2798320587e6SRussell King 2799320587e6SRussell King static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus) 2800320587e6SRussell King { 2801320587e6SRussell King struct phylink *pl = upstream; 2802320587e6SRussell King 2803320587e6SRussell King pl->netdev->sfp_bus = NULL; 2804320587e6SRussell King } 2805320587e6SRussell King 2806f81fa96dSRussell King static const phy_interface_t phylink_sfp_interface_preference[] = { 2807f81fa96dSRussell King PHY_INTERFACE_MODE_25GBASER, 2808f81fa96dSRussell King PHY_INTERFACE_MODE_USXGMII, 2809f81fa96dSRussell King PHY_INTERFACE_MODE_10GBASER, 2810f81fa96dSRussell King PHY_INTERFACE_MODE_5GBASER, 2811f81fa96dSRussell King PHY_INTERFACE_MODE_2500BASEX, 2812f81fa96dSRussell King PHY_INTERFACE_MODE_SGMII, 2813f81fa96dSRussell King PHY_INTERFACE_MODE_1000BASEX, 2814f81fa96dSRussell King PHY_INTERFACE_MODE_100BASEX, 2815f81fa96dSRussell King }; 2816f81fa96dSRussell King 2817*eca68a3cSMarek Behún static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces); 2818*eca68a3cSMarek Behún 2819f81fa96dSRussell King static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, 2820f81fa96dSRussell King const unsigned long *intf) 2821f81fa96dSRussell King { 2822f81fa96dSRussell King phy_interface_t interface; 2823f81fa96dSRussell King size_t i; 2824f81fa96dSRussell King 2825f81fa96dSRussell King interface = PHY_INTERFACE_MODE_NA; 2826f81fa96dSRussell King for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) 2827f81fa96dSRussell King if (test_bit(phylink_sfp_interface_preference[i], intf)) { 2828f81fa96dSRussell King interface = phylink_sfp_interface_preference[i]; 2829f81fa96dSRussell King break; 2830f81fa96dSRussell King } 2831f81fa96dSRussell King 2832f81fa96dSRussell King return interface; 2833f81fa96dSRussell King } 2834f81fa96dSRussell King 2835f81fa96dSRussell King static void phylink_sfp_set_config(struct phylink *pl, u8 mode, 2836f81fa96dSRussell King unsigned long *supported, 2837f81fa96dSRussell King struct phylink_link_state *state) 2838f81fa96dSRussell King { 2839f81fa96dSRussell King bool changed = false; 2840f81fa96dSRussell King 2841f81fa96dSRussell King phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", 2842f81fa96dSRussell King phylink_an_mode_str(mode), phy_modes(state->interface), 2843f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, supported); 2844f81fa96dSRussell King 2845f81fa96dSRussell King if (!linkmode_equal(pl->supported, supported)) { 2846f81fa96dSRussell King linkmode_copy(pl->supported, supported); 2847f81fa96dSRussell King changed = true; 2848f81fa96dSRussell King } 2849f81fa96dSRussell King 2850f81fa96dSRussell King if (!linkmode_equal(pl->link_config.advertising, state->advertising)) { 2851f81fa96dSRussell King linkmode_copy(pl->link_config.advertising, state->advertising); 2852f81fa96dSRussell King changed = true; 2853f81fa96dSRussell King } 2854f81fa96dSRussell King 2855f81fa96dSRussell King if (pl->cur_link_an_mode != mode || 2856f81fa96dSRussell King pl->link_config.interface != state->interface) { 2857f81fa96dSRussell King pl->cur_link_an_mode = mode; 2858f81fa96dSRussell King pl->link_config.interface = state->interface; 2859f81fa96dSRussell King 2860f81fa96dSRussell King changed = true; 2861f81fa96dSRussell King 2862f81fa96dSRussell King phylink_info(pl, "switched to %s/%s link mode\n", 2863f81fa96dSRussell King phylink_an_mode_str(mode), 2864f81fa96dSRussell King phy_modes(state->interface)); 2865f81fa96dSRussell King } 2866f81fa96dSRussell King 2867f81fa96dSRussell King if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, 2868f81fa96dSRussell King &pl->phylink_disable_state)) 2869f81fa96dSRussell King phylink_mac_initial_config(pl, false); 2870f81fa96dSRussell King } 2871f81fa96dSRussell King 2872e6084637SRussell King (Oracle) static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, 2873e6084637SRussell King (Oracle) struct phy_device *phy) 2874ce0aa27fSRussell King { 287577316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); 2876c0de2f47SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support); 2877ce0aa27fSRussell King struct phylink_link_state config; 2878ce0aa27fSRussell King phy_interface_t iface; 2879c0de2f47SRussell King int ret; 2880ce0aa27fSRussell King 2881e6084637SRussell King (Oracle) linkmode_copy(support, phy->supported); 2882ce0aa27fSRussell King 2883ce0aa27fSRussell King memset(&config, 0, sizeof(config)); 2884e6084637SRussell King (Oracle) linkmode_copy(config.advertising, phy->advertising); 2885a9c79364SRussell King config.interface = PHY_INTERFACE_MODE_NA; 2886ce0aa27fSRussell King config.speed = SPEED_UNKNOWN; 2887ce0aa27fSRussell King config.duplex = DUPLEX_UNKNOWN; 2888ce0aa27fSRussell King config.pause = MLO_PAUSE_AN; 2889ce0aa27fSRussell King config.an_enabled = pl->link_config.an_enabled; 2890ce0aa27fSRussell King 2891ce0aa27fSRussell King /* Ignore errors if we're expecting a PHY to attach later */ 2892ce0aa27fSRussell King ret = phylink_validate(pl, support, &config); 2893ce0aa27fSRussell King if (ret) { 2894ab1198e5SRussell King (Oracle) phylink_err(pl, "validation with support %*pb failed: %pe\n", 2895ab1198e5SRussell King (Oracle) __ETHTOOL_LINK_MODE_MASK_NBITS, support, 2896ab1198e5SRussell King (Oracle) ERR_PTR(ret)); 2897a9c79364SRussell King return ret; 2898a9c79364SRussell King } 2899a9c79364SRussell King 2900a4516c70SRussell King iface = sfp_select_interface(pl->sfp_bus, config.advertising); 2901a9c79364SRussell King if (iface == PHY_INTERFACE_MODE_NA) { 290217091180SIoana Ciornei phylink_err(pl, 2903cc1122b0SColin Ian King "selection of interface failed, advertisement %*pb\n", 2904a9c79364SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising); 2905a9c79364SRussell King return -EINVAL; 2906a9c79364SRussell King } 2907a9c79364SRussell King 2908a9c79364SRussell King config.interface = iface; 2909c0de2f47SRussell King linkmode_copy(support1, support); 291077316763SRussell King ret = phylink_validate(pl, support1, &config); 2911a9c79364SRussell King if (ret) { 2912ab1198e5SRussell King (Oracle) phylink_err(pl, 2913ab1198e5SRussell King (Oracle) "validation of %s/%s with support %*pb failed: %pe\n", 2914c0de2f47SRussell King phylink_an_mode_str(mode), 2915444d3502SRussell King phy_modes(config.interface), 2916ab1198e5SRussell King (Oracle) __ETHTOOL_LINK_MODE_MASK_NBITS, support, 2917ab1198e5SRussell King (Oracle) ERR_PTR(ret)); 2918ce0aa27fSRussell King return ret; 2919ce0aa27fSRussell King } 2920ce0aa27fSRussell King 292186a362c4SRussell King if (phy_interface_mode_is_8023z(iface) && pl->phydev) 2922ce0aa27fSRussell King return -EINVAL; 2923ce0aa27fSRussell King 2924f81fa96dSRussell King pl->link_port = pl->sfp_port; 2925f81fa96dSRussell King 2926f81fa96dSRussell King phylink_sfp_set_config(pl, mode, support, &config); 2927f81fa96dSRussell King 2928f81fa96dSRussell King return 0; 2929ce0aa27fSRussell King } 2930ce0aa27fSRussell King 2931f81fa96dSRussell King static int phylink_sfp_config_optical(struct phylink *pl) 2932f81fa96dSRussell King { 2933f81fa96dSRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support); 2934f81fa96dSRussell King DECLARE_PHY_INTERFACE_MASK(interfaces); 2935f81fa96dSRussell King struct phylink_link_state config; 2936f81fa96dSRussell King phy_interface_t interface; 2937f81fa96dSRussell King int ret; 2938ce0aa27fSRussell King 2939f81fa96dSRussell King phylink_dbg(pl, "optical SFP: interfaces=[mac=%*pbl, sfp=%*pbl]\n", 2940f81fa96dSRussell King (int)PHY_INTERFACE_MODE_MAX, 2941f81fa96dSRussell King pl->config->supported_interfaces, 2942f81fa96dSRussell King (int)PHY_INTERFACE_MODE_MAX, 2943f81fa96dSRussell King pl->sfp_interfaces); 2944ce0aa27fSRussell King 2945f81fa96dSRussell King /* Find the union of the supported interfaces by the PCS/MAC and 2946f81fa96dSRussell King * the SFP module. 2947f81fa96dSRussell King */ 2948f81fa96dSRussell King phy_interface_and(interfaces, pl->config->supported_interfaces, 2949f81fa96dSRussell King pl->sfp_interfaces); 2950f81fa96dSRussell King if (phy_interface_empty(interfaces)) { 2951f81fa96dSRussell King phylink_err(pl, "unsupported SFP module: no common interface modes\n"); 2952f81fa96dSRussell King return -EINVAL; 2953f81fa96dSRussell King } 2954f81fa96dSRussell King 2955f81fa96dSRussell King memset(&config, 0, sizeof(config)); 2956f81fa96dSRussell King linkmode_copy(support, pl->sfp_support); 2957f81fa96dSRussell King linkmode_copy(config.advertising, pl->sfp_support); 2958f81fa96dSRussell King config.speed = SPEED_UNKNOWN; 2959f81fa96dSRussell King config.duplex = DUPLEX_UNKNOWN; 2960f81fa96dSRussell King config.pause = MLO_PAUSE_AN; 2961f81fa96dSRussell King config.an_enabled = true; 2962f81fa96dSRussell King 2963f81fa96dSRussell King /* For all the interfaces that are supported, reduce the sfp_support 2964f81fa96dSRussell King * mask to only those link modes that can be supported. 2965f81fa96dSRussell King */ 2966f81fa96dSRussell King ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces); 2967f81fa96dSRussell King if (ret) { 2968f81fa96dSRussell King phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n", 2969f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support); 2970f81fa96dSRussell King return ret; 2971f81fa96dSRussell King } 2972f81fa96dSRussell King 2973f81fa96dSRussell King interface = phylink_choose_sfp_interface(pl, interfaces); 2974f81fa96dSRussell King if (interface == PHY_INTERFACE_MODE_NA) { 2975f81fa96dSRussell King phylink_err(pl, "failed to select SFP interface\n"); 2976f81fa96dSRussell King return -EINVAL; 2977f81fa96dSRussell King } 2978f81fa96dSRussell King 2979f81fa96dSRussell King phylink_dbg(pl, "optical SFP: chosen %s interface\n", 2980f81fa96dSRussell King phy_modes(interface)); 2981f81fa96dSRussell King 2982f81fa96dSRussell King config.interface = interface; 2983f81fa96dSRussell King 2984f81fa96dSRussell King /* Ignore errors if we're expecting a PHY to attach later */ 2985f81fa96dSRussell King ret = phylink_validate(pl, support, &config); 2986f81fa96dSRussell King if (ret) { 2987f81fa96dSRussell King phylink_err(pl, "validation with support %*pb failed: %pe\n", 2988f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support, 2989f81fa96dSRussell King ERR_PTR(ret)); 2990f81fa96dSRussell King return ret; 2991ce0aa27fSRussell King } 2992ce0aa27fSRussell King 299352c95600SRussell King pl->link_port = pl->sfp_port; 2994ce0aa27fSRussell King 2995f81fa96dSRussell King phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config); 2996ce0aa27fSRussell King 2997f81fa96dSRussell King return 0; 2998ce0aa27fSRussell King } 2999ce0aa27fSRussell King 3000c0de2f47SRussell King static int phylink_sfp_module_insert(void *upstream, 3001c0de2f47SRussell King const struct sfp_eeprom_id *id) 3002c0de2f47SRussell King { 3003c0de2f47SRussell King struct phylink *pl = upstream; 3004c0de2f47SRussell King 3005c0de2f47SRussell King ASSERT_RTNL(); 3006c0de2f47SRussell King 3007f81fa96dSRussell King linkmode_zero(pl->sfp_support); 3008fd580c98SRussell King phy_interface_zero(pl->sfp_interfaces); 3009f81fa96dSRussell King sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces); 3010f81fa96dSRussell King pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support); 3011c0de2f47SRussell King 301252c95600SRussell King /* If this module may have a PHY connecting later, defer until later */ 301352c95600SRussell King pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); 301452c95600SRussell King if (pl->sfp_may_have_phy) 301552c95600SRussell King return 0; 301652c95600SRussell King 3017f81fa96dSRussell King return phylink_sfp_config_optical(pl); 3018c0de2f47SRussell King } 3019c0de2f47SRussell King 30204882057aSRussell King static int phylink_sfp_module_start(void *upstream) 30214882057aSRussell King { 30224882057aSRussell King struct phylink *pl = upstream; 30234882057aSRussell King 30244882057aSRussell King /* If this SFP module has a PHY, start the PHY now. */ 302552c95600SRussell King if (pl->phydev) { 30264882057aSRussell King phy_start(pl->phydev); 30274882057aSRussell King return 0; 30284882057aSRussell King } 30294882057aSRussell King 303052c95600SRussell King /* If the module may have a PHY but we didn't detect one we 303152c95600SRussell King * need to configure the MAC here. 303252c95600SRussell King */ 303352c95600SRussell King if (!pl->sfp_may_have_phy) 303452c95600SRussell King return 0; 303552c95600SRussell King 3036f81fa96dSRussell King return phylink_sfp_config_optical(pl); 303752c95600SRussell King } 303852c95600SRussell King 30394882057aSRussell King static void phylink_sfp_module_stop(void *upstream) 30404882057aSRussell King { 30414882057aSRussell King struct phylink *pl = upstream; 30424882057aSRussell King 30434882057aSRussell King /* If this SFP module has a PHY, stop it. */ 30444882057aSRussell King if (pl->phydev) 30454882057aSRussell King phy_stop(pl->phydev); 30464882057aSRussell King } 30474882057aSRussell King 3048ce0aa27fSRussell King static void phylink_sfp_link_down(void *upstream) 3049ce0aa27fSRussell King { 3050ce0aa27fSRussell King struct phylink *pl = upstream; 3051ce0aa27fSRussell King 30528b874514SRussell King ASSERT_RTNL(); 3053ce0aa27fSRussell King 305487454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_LINK); 3055ce0aa27fSRussell King } 3056ce0aa27fSRussell King 3057ce0aa27fSRussell King static void phylink_sfp_link_up(void *upstream) 3058ce0aa27fSRussell King { 3059ce0aa27fSRussell King struct phylink *pl = upstream; 3060ce0aa27fSRussell King 30618b874514SRussell King ASSERT_RTNL(); 3062ce0aa27fSRussell King 3063aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK); 3064ce0aa27fSRussell King } 3065ce0aa27fSRussell King 30667adb5b21SRussell King /* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII 30677adb5b21SRussell King * or 802.3z control word, so inband will not work. 30687adb5b21SRussell King */ 30697adb5b21SRussell King static bool phylink_phy_no_inband(struct phy_device *phy) 30707adb5b21SRussell King { 30717adb5b21SRussell King return phy->is_c45 && 30727adb5b21SRussell King (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150; 30737adb5b21SRussell King } 30747adb5b21SRussell King 3075ce0aa27fSRussell King static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) 3076ce0aa27fSRussell King { 30777e418375SBaruch Siach struct phylink *pl = upstream; 307852c95600SRussell King phy_interface_t interface; 30797adb5b21SRussell King u8 mode; 3080938d44c2SRussell King int ret; 30817e418375SBaruch Siach 308252c95600SRussell King /* 308352c95600SRussell King * This is the new way of dealing with flow control for PHYs, 308452c95600SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy: 308552c95600SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except 308652c95600SRussell King * using our validate call to the MAC, we rely upon the MAC 308752c95600SRussell King * clearing the bits from both supported and advertising fields. 308852c95600SRussell King */ 308952c95600SRussell King phy_support_asym_pause(phy); 309052c95600SRussell King 30917adb5b21SRussell King if (phylink_phy_no_inband(phy)) 30927adb5b21SRussell King mode = MLO_AN_PHY; 30937adb5b21SRussell King else 30947adb5b21SRussell King mode = MLO_AN_INBAND; 30957adb5b21SRussell King 3096*eca68a3cSMarek Behún /* Set the PHY's host supported interfaces */ 3097*eca68a3cSMarek Behún phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, 3098*eca68a3cSMarek Behún pl->config->supported_interfaces); 3099*eca68a3cSMarek Behún 310052c95600SRussell King /* Do the initial configuration */ 3101e6084637SRussell King (Oracle) ret = phylink_sfp_config_phy(pl, mode, phy); 310252c95600SRussell King if (ret < 0) 310352c95600SRussell King return ret; 310452c95600SRussell King 310552c95600SRussell King interface = pl->link_config.interface; 310652c95600SRussell King ret = phylink_attach_phy(pl, phy, interface); 3107938d44c2SRussell King if (ret < 0) 3108938d44c2SRussell King return ret; 3109938d44c2SRussell King 3110e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, interface); 3111938d44c2SRussell King if (ret) 3112938d44c2SRussell King phy_detach(phy); 3113938d44c2SRussell King 3114938d44c2SRussell King return ret; 3115ce0aa27fSRussell King } 3116ce0aa27fSRussell King 3117ce0aa27fSRussell King static void phylink_sfp_disconnect_phy(void *upstream) 3118ce0aa27fSRussell King { 3119ce0aa27fSRussell King phylink_disconnect_phy(upstream); 3120ce0aa27fSRussell King } 3121ce0aa27fSRussell King 3122ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops = { 3123320587e6SRussell King .attach = phylink_sfp_attach, 3124320587e6SRussell King .detach = phylink_sfp_detach, 3125ce0aa27fSRussell King .module_insert = phylink_sfp_module_insert, 31264882057aSRussell King .module_start = phylink_sfp_module_start, 31274882057aSRussell King .module_stop = phylink_sfp_module_stop, 3128ce0aa27fSRussell King .link_up = phylink_sfp_link_up, 3129ce0aa27fSRussell King .link_down = phylink_sfp_link_down, 3130ce0aa27fSRussell King .connect_phy = phylink_sfp_connect_phy, 3131ce0aa27fSRussell King .disconnect_phy = phylink_sfp_disconnect_phy, 3132ce0aa27fSRussell King }; 3133ce0aa27fSRussell King 3134624c0f02SRussell King /* Helpers for MAC drivers */ 3135624c0f02SRussell King 313674db1c18SRussell King static void phylink_decode_c37_word(struct phylink_link_state *state, 313774db1c18SRussell King uint16_t config_reg, int speed) 313874db1c18SRussell King { 313974db1c18SRussell King bool tx_pause, rx_pause; 314074db1c18SRussell King int fd_bit; 314174db1c18SRussell King 314274db1c18SRussell King if (speed == SPEED_2500) 314374db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT; 314474db1c18SRussell King else 314574db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT; 314674db1c18SRussell King 314774db1c18SRussell King mii_lpa_mod_linkmode_x(state->lp_advertising, config_reg, fd_bit); 314874db1c18SRussell King 314974db1c18SRussell King if (linkmode_test_bit(fd_bit, state->advertising) && 315074db1c18SRussell King linkmode_test_bit(fd_bit, state->lp_advertising)) { 315174db1c18SRussell King state->speed = speed; 315274db1c18SRussell King state->duplex = DUPLEX_FULL; 315374db1c18SRussell King } else { 315474db1c18SRussell King /* negotiation failure */ 315574db1c18SRussell King state->link = false; 315674db1c18SRussell King } 315774db1c18SRussell King 315874db1c18SRussell King linkmode_resolve_pause(state->advertising, state->lp_advertising, 315974db1c18SRussell King &tx_pause, &rx_pause); 316074db1c18SRussell King 316174db1c18SRussell King if (tx_pause) 316274db1c18SRussell King state->pause |= MLO_PAUSE_TX; 316374db1c18SRussell King if (rx_pause) 316474db1c18SRussell King state->pause |= MLO_PAUSE_RX; 316574db1c18SRussell King } 316674db1c18SRussell King 316774db1c18SRussell King static void phylink_decode_sgmii_word(struct phylink_link_state *state, 316874db1c18SRussell King uint16_t config_reg) 316974db1c18SRussell King { 317074db1c18SRussell King if (!(config_reg & LPA_SGMII_LINK)) { 317174db1c18SRussell King state->link = false; 317274db1c18SRussell King return; 317374db1c18SRussell King } 317474db1c18SRussell King 317574db1c18SRussell King switch (config_reg & LPA_SGMII_SPD_MASK) { 317674db1c18SRussell King case LPA_SGMII_10: 317774db1c18SRussell King state->speed = SPEED_10; 317874db1c18SRussell King break; 317974db1c18SRussell King case LPA_SGMII_100: 318074db1c18SRussell King state->speed = SPEED_100; 318174db1c18SRussell King break; 318274db1c18SRussell King case LPA_SGMII_1000: 318374db1c18SRussell King state->speed = SPEED_1000; 318474db1c18SRussell King break; 318574db1c18SRussell King default: 318674db1c18SRussell King state->link = false; 318774db1c18SRussell King return; 318874db1c18SRussell King } 318974db1c18SRussell King if (config_reg & LPA_SGMII_FULL_DUPLEX) 319074db1c18SRussell King state->duplex = DUPLEX_FULL; 319174db1c18SRussell King else 319274db1c18SRussell King state->duplex = DUPLEX_HALF; 319374db1c18SRussell King } 319474db1c18SRussell King 319574db1c18SRussell King /** 3196afd62209SIoana Ciornei * phylink_decode_usxgmii_word() - decode the USXGMII word from a MAC PCS 3197afd62209SIoana Ciornei * @state: a pointer to a struct phylink_link_state. 3198afd62209SIoana Ciornei * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word 3199afd62209SIoana Ciornei * 3200afd62209SIoana Ciornei * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation 3201afd62209SIoana Ciornei * code word. Decode the USXGMII code word and populate the corresponding fields 3202afd62209SIoana Ciornei * (speed, duplex) into the phylink_link_state structure. 3203afd62209SIoana Ciornei */ 3204afd62209SIoana Ciornei void phylink_decode_usxgmii_word(struct phylink_link_state *state, 3205afd62209SIoana Ciornei uint16_t lpa) 3206afd62209SIoana Ciornei { 3207afd62209SIoana Ciornei switch (lpa & MDIO_USXGMII_SPD_MASK) { 3208afd62209SIoana Ciornei case MDIO_USXGMII_10: 3209afd62209SIoana Ciornei state->speed = SPEED_10; 3210afd62209SIoana Ciornei break; 3211afd62209SIoana Ciornei case MDIO_USXGMII_100: 3212afd62209SIoana Ciornei state->speed = SPEED_100; 3213afd62209SIoana Ciornei break; 3214afd62209SIoana Ciornei case MDIO_USXGMII_1000: 3215afd62209SIoana Ciornei state->speed = SPEED_1000; 3216afd62209SIoana Ciornei break; 3217afd62209SIoana Ciornei case MDIO_USXGMII_2500: 3218afd62209SIoana Ciornei state->speed = SPEED_2500; 3219afd62209SIoana Ciornei break; 3220afd62209SIoana Ciornei case MDIO_USXGMII_5000: 3221afd62209SIoana Ciornei state->speed = SPEED_5000; 3222afd62209SIoana Ciornei break; 3223afd62209SIoana Ciornei case MDIO_USXGMII_10G: 3224afd62209SIoana Ciornei state->speed = SPEED_10000; 3225afd62209SIoana Ciornei break; 3226afd62209SIoana Ciornei default: 3227afd62209SIoana Ciornei state->link = false; 3228afd62209SIoana Ciornei return; 3229afd62209SIoana Ciornei } 3230afd62209SIoana Ciornei 3231afd62209SIoana Ciornei if (lpa & MDIO_USXGMII_FULL_DUPLEX) 3232afd62209SIoana Ciornei state->duplex = DUPLEX_FULL; 3233afd62209SIoana Ciornei else 3234afd62209SIoana Ciornei state->duplex = DUPLEX_HALF; 3235afd62209SIoana Ciornei } 3236afd62209SIoana Ciornei EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word); 3237afd62209SIoana Ciornei 3238afd62209SIoana Ciornei /** 3239291dcae3SSean Anderson * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers 324074db1c18SRussell King * @state: a pointer to a &struct phylink_link_state. 3241291dcae3SSean Anderson * @bmsr: The value of the %MII_BMSR register 3242291dcae3SSean Anderson * @lpa: The value of the %MII_LPA register 324374db1c18SRussell King * 324474db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 324574db1c18SRussell King * clause 37 negotiation and/or SGMII control. 324674db1c18SRussell King * 3247291dcae3SSean Anderson * Parse the Clause 37 or Cisco SGMII link partner negotiation word into 3248291dcae3SSean Anderson * the phylink @state structure. This is suitable to be used for implementing 3249291dcae3SSean Anderson * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if 3250291dcae3SSean Anderson * accessing @bmsr and @lpa cannot be done with MDIO directly. 325174db1c18SRussell King */ 3252291dcae3SSean Anderson void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, 3253291dcae3SSean Anderson u16 bmsr, u16 lpa) 325474db1c18SRussell King { 325574db1c18SRussell King state->link = !!(bmsr & BMSR_LSTATUS); 325674db1c18SRussell King state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); 325792817dadSRobert Hancock /* If there is no link or autonegotiation is disabled, the LP advertisement 325892817dadSRobert Hancock * data is not meaningful, so don't go any further. 325992817dadSRobert Hancock */ 326092817dadSRobert Hancock if (!state->link || !state->an_enabled) 326174db1c18SRussell King return; 326274db1c18SRussell King 326374db1c18SRussell King switch (state->interface) { 326474db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX: 326574db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_1000); 326674db1c18SRussell King break; 326774db1c18SRussell King 326874db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX: 326974db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_2500); 327074db1c18SRussell King break; 327174db1c18SRussell King 327274db1c18SRussell King case PHY_INTERFACE_MODE_SGMII: 327329f02ee4SIoana Ciornei case PHY_INTERFACE_MODE_QSGMII: 32745e61fe15SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII: 327574db1c18SRussell King phylink_decode_sgmii_word(state, lpa); 327674db1c18SRussell King break; 327774db1c18SRussell King 327874db1c18SRussell King default: 327974db1c18SRussell King state->link = false; 328074db1c18SRussell King break; 328174db1c18SRussell King } 328274db1c18SRussell King } 3283291dcae3SSean Anderson EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); 3284291dcae3SSean Anderson 3285291dcae3SSean Anderson /** 3286291dcae3SSean Anderson * phylink_mii_c22_pcs_get_state() - read the MAC PCS state 3287291dcae3SSean Anderson * @pcs: a pointer to a &struct mdio_device. 3288291dcae3SSean Anderson * @state: a pointer to a &struct phylink_link_state. 3289291dcae3SSean Anderson * 3290291dcae3SSean Anderson * Helper for MAC PCS supporting the 802.3 clause 22 register set for 3291291dcae3SSean Anderson * clause 37 negotiation and/or SGMII control. 3292291dcae3SSean Anderson * 3293291dcae3SSean Anderson * Read the MAC PCS state from the MII device configured in @config and 3294291dcae3SSean Anderson * parse the Clause 37 or Cisco SGMII link partner negotiation word into 3295291dcae3SSean Anderson * the phylink @state structure. This is suitable to be directly plugged 3296291dcae3SSean Anderson * into the mac_pcs_get_state() member of the struct phylink_mac_ops 3297291dcae3SSean Anderson * structure. 3298291dcae3SSean Anderson */ 3299291dcae3SSean Anderson void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, 3300291dcae3SSean Anderson struct phylink_link_state *state) 3301291dcae3SSean Anderson { 3302291dcae3SSean Anderson int bmsr, lpa; 3303291dcae3SSean Anderson 3304291dcae3SSean Anderson bmsr = mdiodev_read(pcs, MII_BMSR); 3305291dcae3SSean Anderson lpa = mdiodev_read(pcs, MII_LPA); 3306291dcae3SSean Anderson if (bmsr < 0 || lpa < 0) { 3307291dcae3SSean Anderson state->link = false; 3308291dcae3SSean Anderson return; 3309291dcae3SSean Anderson } 3310291dcae3SSean Anderson 3311291dcae3SSean Anderson phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); 3312291dcae3SSean Anderson } 331374db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); 331474db1c18SRussell King 331574db1c18SRussell King /** 3316291dcae3SSean Anderson * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS 331774db1c18SRussell King * advertisement 33180bd27406SRussell King * @interface: the PHY interface mode being configured 33190bd27406SRussell King * @advertising: the ethtool advertisement mask 332074db1c18SRussell King * 332174db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 332274db1c18SRussell King * clause 37 negotiation and/or SGMII control. 332374db1c18SRussell King * 3324291dcae3SSean Anderson * Encode the clause 37 PCS advertisement as specified by @interface and 3325291dcae3SSean Anderson * @advertising. 332674db1c18SRussell King * 3327291dcae3SSean Anderson * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed. 332874db1c18SRussell King */ 3329291dcae3SSean Anderson int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, 33300bd27406SRussell King const unsigned long *advertising) 333174db1c18SRussell King { 333274db1c18SRussell King u16 adv; 333374db1c18SRussell King 33340bd27406SRussell King switch (interface) { 333574db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX: 333674db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX: 333774db1c18SRussell King adv = ADVERTISE_1000XFULL; 333874db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, 33390bd27406SRussell King advertising)) 334074db1c18SRussell King adv |= ADVERTISE_1000XPAUSE; 334174db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 33420bd27406SRussell King advertising)) 334374db1c18SRussell King adv |= ADVERTISE_1000XPSE_ASYM; 3344291dcae3SSean Anderson return adv; 334574db1c18SRussell King case PHY_INTERFACE_MODE_SGMII: 3346f56866c4SRussell King (Oracle) case PHY_INTERFACE_MODE_QSGMII: 3347291dcae3SSean Anderson return 0x0001; 334874db1c18SRussell King default: 334974db1c18SRussell King /* Nothing to do for other modes */ 3350291dcae3SSean Anderson return -EINVAL; 335174db1c18SRussell King } 335274db1c18SRussell King } 3353291dcae3SSean Anderson EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); 335474db1c18SRussell King 335574db1c18SRussell King /** 335693eaceb0SRussell King * phylink_mii_c22_pcs_config() - configure clause 22 PCS 335793eaceb0SRussell King * @pcs: a pointer to a &struct mdio_device. 335893eaceb0SRussell King * @mode: link autonegotiation mode 335993eaceb0SRussell King * @interface: the PHY interface mode being configured 336093eaceb0SRussell King * @advertising: the ethtool advertisement mask 336193eaceb0SRussell King * 336293eaceb0SRussell King * Configure a Clause 22 PCS PHY with the appropriate negotiation 336393eaceb0SRussell King * parameters for the @mode, @interface and @advertising parameters. 336493eaceb0SRussell King * Returns negative error number on failure, zero if the advertisement 336593eaceb0SRussell King * has not changed, or positive if there is a change. 336693eaceb0SRussell King */ 336793eaceb0SRussell King int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, 336893eaceb0SRussell King phy_interface_t interface, 336993eaceb0SRussell King const unsigned long *advertising) 337093eaceb0SRussell King { 3371291dcae3SSean Anderson bool changed = 0; 337293eaceb0SRussell King u16 bmcr; 3373291dcae3SSean Anderson int ret, adv; 337493eaceb0SRussell King 3375291dcae3SSean Anderson adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising); 3376291dcae3SSean Anderson if (adv >= 0) { 3377291dcae3SSean Anderson ret = mdiobus_modify_changed(pcs->bus, pcs->addr, 3378291dcae3SSean Anderson MII_ADVERTISE, 0xffff, adv); 337993eaceb0SRussell King if (ret < 0) 338093eaceb0SRussell King return ret; 3381291dcae3SSean Anderson changed = ret; 3382291dcae3SSean Anderson } 338393eaceb0SRussell King 3384cd29296fSRobert Hancock /* Ensure ISOLATE bit is disabled */ 338592817dadSRobert Hancock if (mode == MLO_AN_INBAND && 33866d1ce9c0SRussell King (Oracle) (interface == PHY_INTERFACE_MODE_SGMII || 33876d1ce9c0SRussell King (Oracle) interface == PHY_INTERFACE_MODE_QSGMII || 33886d1ce9c0SRussell King (Oracle) linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising))) 338992817dadSRobert Hancock bmcr = BMCR_ANENABLE; 339092817dadSRobert Hancock else 339192817dadSRobert Hancock bmcr = 0; 339292817dadSRobert Hancock 3393c8fb89a7SSean Anderson ret = mdiodev_modify(pcs, MII_BMCR, BMCR_ANENABLE | BMCR_ISOLATE, bmcr); 339493eaceb0SRussell King if (ret < 0) 339593eaceb0SRussell King return ret; 339693eaceb0SRussell King 3397291dcae3SSean Anderson return changed; 339893eaceb0SRussell King } 339993eaceb0SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config); 340093eaceb0SRussell King 340193eaceb0SRussell King /** 340274db1c18SRussell King * phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation 340374db1c18SRussell King * @pcs: a pointer to a &struct mdio_device. 340474db1c18SRussell King * 340574db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 340674db1c18SRussell King * clause 37 negotiation. 340774db1c18SRussell King * 340874db1c18SRussell King * Restart the clause 37 negotiation with the link partner. This is 340974db1c18SRussell King * suitable to be directly plugged into the mac_pcs_get_state() member 341074db1c18SRussell King * of the struct phylink_mac_ops structure. 341174db1c18SRussell King */ 341274db1c18SRussell King void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs) 341374db1c18SRussell King { 3414c8fb89a7SSean Anderson int val = mdiodev_read(pcs, MII_BMCR); 341574db1c18SRussell King 341674db1c18SRussell King if (val >= 0) { 341774db1c18SRussell King val |= BMCR_ANRESTART; 341874db1c18SRussell King 3419c8fb89a7SSean Anderson mdiodev_write(pcs, MII_BMCR, val); 342074db1c18SRussell King } 342174db1c18SRussell King } 342274db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_an_restart); 342374db1c18SRussell King 3424b8679ef8SRussell King void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, 3425b8679ef8SRussell King struct phylink_link_state *state) 3426b8679ef8SRussell King { 3427b8679ef8SRussell King struct mii_bus *bus = pcs->bus; 3428b8679ef8SRussell King int addr = pcs->addr; 3429b8679ef8SRussell King int stat; 3430b8679ef8SRussell King 343190ce665cSRussell King stat = mdiobus_c45_read(bus, addr, MDIO_MMD_PCS, MDIO_STAT1); 3432b8679ef8SRussell King if (stat < 0) { 3433b8679ef8SRussell King state->link = false; 3434b8679ef8SRussell King return; 3435b8679ef8SRussell King } 3436b8679ef8SRussell King 3437b8679ef8SRussell King state->link = !!(stat & MDIO_STAT1_LSTATUS); 3438b8679ef8SRussell King if (!state->link) 3439b8679ef8SRussell King return; 3440b8679ef8SRussell King 3441b8679ef8SRussell King switch (state->interface) { 3442b8679ef8SRussell King case PHY_INTERFACE_MODE_10GBASER: 3443b8679ef8SRussell King state->speed = SPEED_10000; 3444b8679ef8SRussell King state->duplex = DUPLEX_FULL; 3445b8679ef8SRussell King break; 3446b8679ef8SRussell King 3447b8679ef8SRussell King default: 3448b8679ef8SRussell King break; 3449b8679ef8SRussell King } 3450b8679ef8SRussell King } 3451b8679ef8SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); 3452b8679ef8SRussell King 3453*eca68a3cSMarek Behún static int __init phylink_init(void) 3454*eca68a3cSMarek Behún { 3455*eca68a3cSMarek Behún for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i) 3456*eca68a3cSMarek Behún __set_bit(phylink_sfp_interface_preference[i], 3457*eca68a3cSMarek Behún phylink_sfp_interfaces); 3458*eca68a3cSMarek Behún 3459*eca68a3cSMarek Behún return 0; 3460*eca68a3cSMarek Behún } 3461*eca68a3cSMarek Behún 3462*eca68a3cSMarek Behún module_init(phylink_init); 3463*eca68a3cSMarek Behún 34645f857575SAndrew Lunn MODULE_LICENSE("GPL v2"); 3465