xref: /openbmc/linux/drivers/net/phy/phylink.c (revision eca68a3c7d05b38b4e728cead0c49718f2bc1d5a)
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