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,
3790ef0a7bSRussell King (Oracle)
3890ef0a7bSRussell King (Oracle) PCS_STATE_DOWN = 0,
3990ef0a7bSRussell King (Oracle) PCS_STATE_STARTING,
4090ef0a7bSRussell King (Oracle) PCS_STATE_STARTED,
419525ae83SRussell King };
429525ae83SRussell King
438796c892SRussell King /**
448796c892SRussell King * struct phylink - internal data type for phylink
458796c892SRussell King */
469525ae83SRussell King struct phylink {
478796c892SRussell King /* private: */
489525ae83SRussell King struct net_device *netdev;
49e7765d63SRussell King const struct phylink_mac_ops *mac_ops;
5044cc27e4SIoana Ciornei struct phylink_config *config;
517137e18fSRussell King struct phylink_pcs *pcs;
5243de6195SIoana Ciornei struct device *dev;
5343de6195SIoana Ciornei unsigned int old_link_state:1;
549525ae83SRussell King
559525ae83SRussell King unsigned long phylink_disable_state; /* bitmask of disables */
569525ae83SRussell King struct phy_device *phydev;
579525ae83SRussell King phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
5824cf0e69SRussell King u8 cfg_link_an_mode; /* MLO_AN_xxx */
5924cf0e69SRussell King u8 cur_link_an_mode;
609525ae83SRussell King u8 link_port; /* The current non-phy ethtool port */
619525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
629525ae83SRussell King
639525ae83SRussell King /* The link configuration settings */
649525ae83SRussell King struct phylink_link_state link_config;
65c6787263SRussell King
66c6787263SRussell King /* The current settings */
67c6787263SRussell King phy_interface_t cur_interface;
68c6787263SRussell King
699525ae83SRussell King struct gpio_desc *link_gpio;
707b3b0e89SRussell King unsigned int link_irq;
719cd00a8aSRussell King struct timer_list link_poll;
721ac63e39SFlorian Fainelli void (*get_fixed_state)(struct net_device *dev,
731ac63e39SFlorian Fainelli struct phylink_link_state *s);
749525ae83SRussell King
759525ae83SRussell King struct mutex state_mutex;
769525ae83SRussell King struct phylink_link_state phy_state;
779525ae83SRussell King struct work_struct resolve;
78f99d471aSRussell King (Oracle) unsigned int pcs_neg_mode;
7990ef0a7bSRussell King (Oracle) unsigned int pcs_state;
809525ae83SRussell King
819525ae83SRussell King bool mac_link_dropped;
8210544570SRussell King (Oracle) bool using_mac_select_pcs;
83ce0aa27fSRussell King
84ce0aa27fSRussell King struct sfp_bus *sfp_bus;
8552c95600SRussell King bool sfp_may_have_phy;
86fd580c98SRussell King DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
8752c95600SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
8852c95600SRussell King u8 sfp_port;
899525ae83SRussell King };
909525ae83SRussell King
9117091180SIoana Ciornei #define phylink_printk(level, pl, fmt, ...) \
9217091180SIoana Ciornei do { \
9317091180SIoana Ciornei if ((pl)->config->type == PHYLINK_NETDEV) \
9417091180SIoana Ciornei netdev_printk(level, (pl)->netdev, fmt, ##__VA_ARGS__); \
9517091180SIoana Ciornei else if ((pl)->config->type == PHYLINK_DEV) \
9617091180SIoana Ciornei dev_printk(level, (pl)->dev, fmt, ##__VA_ARGS__); \
9717091180SIoana Ciornei } while (0)
9817091180SIoana Ciornei
9917091180SIoana Ciornei #define phylink_err(pl, fmt, ...) \
10017091180SIoana Ciornei phylink_printk(KERN_ERR, pl, fmt, ##__VA_ARGS__)
10117091180SIoana Ciornei #define phylink_warn(pl, fmt, ...) \
10217091180SIoana Ciornei phylink_printk(KERN_WARNING, pl, fmt, ##__VA_ARGS__)
10317091180SIoana Ciornei #define phylink_info(pl, fmt, ...) \
10417091180SIoana Ciornei phylink_printk(KERN_INFO, pl, fmt, ##__VA_ARGS__)
1059d68db50SFlorian Fainelli #if defined(CONFIG_DYNAMIC_DEBUG)
1069d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \
1079d68db50SFlorian Fainelli do { \
1089d68db50SFlorian Fainelli if ((pl)->config->type == PHYLINK_NETDEV) \
1099d68db50SFlorian Fainelli netdev_dbg((pl)->netdev, fmt, ##__VA_ARGS__); \
1109d68db50SFlorian Fainelli else if ((pl)->config->type == PHYLINK_DEV) \
1119d68db50SFlorian Fainelli dev_dbg((pl)->dev, fmt, ##__VA_ARGS__); \
1129d68db50SFlorian Fainelli } while (0)
1139d68db50SFlorian Fainelli #elif defined(DEBUG)
11417091180SIoana Ciornei #define phylink_dbg(pl, fmt, ...) \
11517091180SIoana Ciornei phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__)
1169d68db50SFlorian Fainelli #else
1179d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \
1189d68db50SFlorian Fainelli ({ \
1199d68db50SFlorian Fainelli if (0) \
1209d68db50SFlorian Fainelli phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__); \
1219d68db50SFlorian Fainelli })
1229d68db50SFlorian Fainelli #endif
12317091180SIoana Ciornei
1248796c892SRussell King /**
1258796c892SRussell King * phylink_set_port_modes() - set the port type modes in the ethtool mask
1268796c892SRussell King * @mask: ethtool link mode mask
1278796c892SRussell King *
1288796c892SRussell King * Sets all the port type modes in the ethtool mask. MAC drivers should
1298796c892SRussell King * use this in their 'validate' callback.
1308796c892SRussell King */
phylink_set_port_modes(unsigned long * mask)1319525ae83SRussell King void phylink_set_port_modes(unsigned long *mask)
1329525ae83SRussell King {
1339525ae83SRussell King phylink_set(mask, TP);
1349525ae83SRussell King phylink_set(mask, AUI);
1359525ae83SRussell King phylink_set(mask, MII);
1369525ae83SRussell King phylink_set(mask, FIBRE);
1379525ae83SRussell King phylink_set(mask, BNC);
1389525ae83SRussell King phylink_set(mask, Backplane);
1399525ae83SRussell King }
1409525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_set_port_modes);
1419525ae83SRussell King
phylink_is_empty_linkmode(const unsigned long * linkmode)1429525ae83SRussell King static int phylink_is_empty_linkmode(const unsigned long *linkmode)
1439525ae83SRussell King {
1449525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = { 0, };
1459525ae83SRussell King
1469525ae83SRussell King phylink_set_port_modes(tmp);
1479525ae83SRussell King phylink_set(tmp, Autoneg);
1489525ae83SRussell King phylink_set(tmp, Pause);
1499525ae83SRussell King phylink_set(tmp, Asym_Pause);
1509525ae83SRussell King
151554032cdSRussell King return linkmode_subset(linkmode, tmp);
1529525ae83SRussell King }
1539525ae83SRussell King
phylink_an_mode_str(unsigned int mode)1549525ae83SRussell King static const char *phylink_an_mode_str(unsigned int mode)
1559525ae83SRussell King {
1569525ae83SRussell King static const char *modestr[] = {
1579525ae83SRussell King [MLO_AN_PHY] = "phy",
1589525ae83SRussell King [MLO_AN_FIXED] = "fixed",
15986a362c4SRussell King [MLO_AN_INBAND] = "inband",
1609525ae83SRussell King };
1619525ae83SRussell King
1629525ae83SRussell King return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
1639525ae83SRussell King }
1649525ae83SRussell King
phylink_interface_signal_rate(phy_interface_t interface)165dc185822SRussell King (Oracle) static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
166dc185822SRussell King (Oracle) {
167dc185822SRussell King (Oracle) switch (interface) {
168dc185822SRussell King (Oracle) case PHY_INTERFACE_MODE_SGMII:
169dc185822SRussell King (Oracle) case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */
170dc185822SRussell King (Oracle) return 1250;
171dc185822SRussell King (Oracle) case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */
172dc185822SRussell King (Oracle) return 3125;
173dc185822SRussell King (Oracle) case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */
174dc185822SRussell King (Oracle) return 5156;
175dc185822SRussell King (Oracle) case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */
176dc185822SRussell King (Oracle) return 10313;
177dc185822SRussell King (Oracle) default:
178dc185822SRussell King (Oracle) return 0;
179dc185822SRussell King (Oracle) }
180dc185822SRussell King (Oracle) }
181dc185822SRussell King (Oracle)
18260611652SSean Anderson /**
183ae0e4bb2SSean Anderson * phylink_interface_max_speed() - get the maximum speed of a phy interface
184ae0e4bb2SSean Anderson * @interface: phy interface mode defined by &typedef phy_interface_t
185ae0e4bb2SSean Anderson *
186ae0e4bb2SSean Anderson * Determine the maximum speed of a phy interface. This is intended to help
187ae0e4bb2SSean Anderson * determine the correct speed to pass to the MAC when the phy is performing
188ae0e4bb2SSean Anderson * rate matching.
189ae0e4bb2SSean Anderson *
190ae0e4bb2SSean Anderson * Return: The maximum speed of @interface
191ae0e4bb2SSean Anderson */
phylink_interface_max_speed(phy_interface_t interface)192ae0e4bb2SSean Anderson static int phylink_interface_max_speed(phy_interface_t interface)
193ae0e4bb2SSean Anderson {
194ae0e4bb2SSean Anderson switch (interface) {
195ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_100BASEX:
196ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_REVRMII:
197ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RMII:
198ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_SMII:
199ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_REVMII:
200ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MII:
201ae0e4bb2SSean Anderson return SPEED_100;
202ae0e4bb2SSean Anderson
203ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_TBI:
204ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MOCA:
205ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RTBI:
206ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_1000BASEX:
207ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_1000BASEKX:
208ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_TRGMII:
209ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_TXID:
210ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_RXID:
211ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII_ID:
212ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RGMII:
21383b5f025SGabor Juhos case PHY_INTERFACE_MODE_PSGMII:
214ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_QSGMII:
215b9dc1046SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII:
216ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_SGMII:
217ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_GMII:
218ae0e4bb2SSean Anderson return SPEED_1000;
219ae0e4bb2SSean Anderson
220ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_2500BASEX:
221ae0e4bb2SSean Anderson return SPEED_2500;
222ae0e4bb2SSean Anderson
223ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_5GBASER:
224ae0e4bb2SSean Anderson return SPEED_5000;
225ae0e4bb2SSean Anderson
226ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XGMII:
227ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_RXAUI:
228ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XAUI:
229ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_10GBASER:
230ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_10GKR:
231ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_USXGMII:
232ae0e4bb2SSean Anderson return SPEED_10000;
233ae0e4bb2SSean Anderson
234ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_25GBASER:
235ae0e4bb2SSean Anderson return SPEED_25000;
236ae0e4bb2SSean Anderson
237ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_XLGMII:
238ae0e4bb2SSean Anderson return SPEED_40000;
239ae0e4bb2SSean Anderson
240ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_INTERNAL:
241ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_NA:
242ae0e4bb2SSean Anderson case PHY_INTERFACE_MODE_MAX:
243ae0e4bb2SSean Anderson /* No idea! Garbage in, unknown out */
244ae0e4bb2SSean Anderson return SPEED_UNKNOWN;
245ae0e4bb2SSean Anderson }
246ae0e4bb2SSean Anderson
247ae0e4bb2SSean Anderson /* If we get here, someone forgot to add an interface mode above */
248ae0e4bb2SSean Anderson WARN_ON_ONCE(1);
249ae0e4bb2SSean Anderson return SPEED_UNKNOWN;
250ae0e4bb2SSean Anderson }
251ae0e4bb2SSean Anderson
252ae0e4bb2SSean Anderson /**
25360611652SSean Anderson * phylink_caps_to_linkmodes() - Convert capabilities to ethtool link modes
25460611652SSean Anderson * @linkmodes: ethtool linkmode mask (must be already initialised)
25560611652SSean Anderson * @caps: bitmask of MAC capabilities
25660611652SSean Anderson *
25760611652SSean Anderson * Set all possible pause, speed and duplex linkmodes in @linkmodes that are
25860611652SSean Anderson * supported by the @caps. @linkmodes must have been initialised previously.
25960611652SSean Anderson */
phylink_caps_to_linkmodes(unsigned long * linkmodes,unsigned long caps)26060611652SSean Anderson void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps)
26134ae2c09SRussell King (Oracle) {
26234ae2c09SRussell King (Oracle) if (caps & MAC_SYM_PAUSE)
26334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes);
26434ae2c09SRussell King (Oracle)
26534ae2c09SRussell King (Oracle) if (caps & MAC_ASYM_PAUSE)
26634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes);
26734ae2c09SRussell King (Oracle)
26816178c8eSPiergiorgio Beruto if (caps & MAC_10HD) {
26934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes);
27016178c8eSPiergiorgio Beruto __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Half_BIT, linkmodes);
27116178c8eSPiergiorgio Beruto __set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, linkmodes);
27216178c8eSPiergiorgio Beruto }
27334ae2c09SRussell King (Oracle)
2743254e0b9SAlexandru Tachici if (caps & MAC_10FD) {
27534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes);
2763254e0b9SAlexandru Tachici __set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, linkmodes);
27716178c8eSPiergiorgio Beruto __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Full_BIT, linkmodes);
2783254e0b9SAlexandru Tachici }
27934ae2c09SRussell King (Oracle)
28034ae2c09SRussell King (Oracle) if (caps & MAC_100HD) {
28134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, linkmodes);
28234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, linkmodes);
28334ae2c09SRussell King (Oracle) }
28434ae2c09SRussell King (Oracle)
28534ae2c09SRussell King (Oracle) if (caps & MAC_100FD) {
28634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, linkmodes);
28734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, linkmodes);
28834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, linkmodes);
28934ae2c09SRussell King (Oracle) }
29034ae2c09SRussell King (Oracle)
29134ae2c09SRussell King (Oracle) if (caps & MAC_1000HD)
29234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, linkmodes);
29334ae2c09SRussell King (Oracle)
29434ae2c09SRussell King (Oracle) if (caps & MAC_1000FD) {
29534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, linkmodes);
296ec574d9eSRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, linkmodes);
29734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, linkmodes);
29834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, linkmodes);
29934ae2c09SRussell King (Oracle) }
30034ae2c09SRussell King (Oracle)
30134ae2c09SRussell King (Oracle) if (caps & MAC_2500FD) {
30234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, linkmodes);
30334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, linkmodes);
30434ae2c09SRussell King (Oracle) }
30534ae2c09SRussell King (Oracle)
30634ae2c09SRussell King (Oracle) if (caps & MAC_5000FD)
30734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, linkmodes);
30834ae2c09SRussell King (Oracle)
30934ae2c09SRussell King (Oracle) if (caps & MAC_10000FD) {
31034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, linkmodes);
31134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, linkmodes);
31234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, linkmodes);
31334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, linkmodes);
31434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, linkmodes);
31534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, linkmodes);
31634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, linkmodes);
31734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, linkmodes);
31834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, linkmodes);
31934ae2c09SRussell King (Oracle) }
32034ae2c09SRussell King (Oracle)
32134ae2c09SRussell King (Oracle) if (caps & MAC_25000FD) {
32234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, linkmodes);
32334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, linkmodes);
32434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, linkmodes);
32534ae2c09SRussell King (Oracle) }
32634ae2c09SRussell King (Oracle)
32734ae2c09SRussell King (Oracle) if (caps & MAC_40000FD) {
32834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, linkmodes);
32934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, linkmodes);
33034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, linkmodes);
33134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, linkmodes);
33234ae2c09SRussell King (Oracle) }
33334ae2c09SRussell King (Oracle)
33434ae2c09SRussell King (Oracle) if (caps & MAC_50000FD) {
33534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, linkmodes);
33634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, linkmodes);
33734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, linkmodes);
33834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, linkmodes);
33934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, linkmodes);
34034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, linkmodes);
34134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
34234ae2c09SRussell King (Oracle) linkmodes);
34334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, linkmodes);
34434ae2c09SRussell King (Oracle) }
34534ae2c09SRussell King (Oracle)
34634ae2c09SRussell King (Oracle) if (caps & MAC_56000FD) {
34734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, linkmodes);
34834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, linkmodes);
34934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, linkmodes);
35034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, linkmodes);
35134ae2c09SRussell King (Oracle) }
35234ae2c09SRussell King (Oracle)
35334ae2c09SRussell King (Oracle) if (caps & MAC_100000FD) {
35434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, linkmodes);
35534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, linkmodes);
35634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, linkmodes);
35734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
35834ae2c09SRussell King (Oracle) linkmodes);
35934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, linkmodes);
36034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, linkmodes);
36134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, linkmodes);
36234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
36334ae2c09SRussell King (Oracle) linkmodes);
36434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, linkmodes);
36534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, linkmodes);
36634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, linkmodes);
36734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
36834ae2c09SRussell King (Oracle) linkmodes);
36934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, linkmodes);
37034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, linkmodes);
37134ae2c09SRussell King (Oracle) }
37234ae2c09SRussell King (Oracle)
37334ae2c09SRussell King (Oracle) if (caps & MAC_200000FD) {
37434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, linkmodes);
37534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, linkmodes);
37634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
37734ae2c09SRussell King (Oracle) linkmodes);
37834ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, linkmodes);
37934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, linkmodes);
38034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, linkmodes);
38134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, linkmodes);
38234ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
38334ae2c09SRussell King (Oracle) linkmodes);
38434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, linkmodes);
38534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, linkmodes);
38634ae2c09SRussell King (Oracle) }
38734ae2c09SRussell King (Oracle)
38834ae2c09SRussell King (Oracle) if (caps & MAC_400000FD) {
38934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, linkmodes);
39034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, linkmodes);
39134ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
39234ae2c09SRussell King (Oracle) linkmodes);
39334ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, linkmodes);
39434ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, linkmodes);
39534ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, linkmodes);
39634ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, linkmodes);
39734ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
39834ae2c09SRussell King (Oracle) linkmodes);
39934ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, linkmodes);
40034ae2c09SRussell King (Oracle) __set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes);
40134ae2c09SRussell King (Oracle) }
40234ae2c09SRussell King (Oracle) }
40360611652SSean Anderson EXPORT_SYMBOL_GPL(phylink_caps_to_linkmodes);
40434ae2c09SRussell King (Oracle)
405b7e92948SSean Anderson static struct {
406b7e92948SSean Anderson unsigned long mask;
407b7e92948SSean Anderson int speed;
408b7e92948SSean Anderson unsigned int duplex;
409b7e92948SSean Anderson } phylink_caps_params[] = {
410b7e92948SSean Anderson { MAC_400000FD, SPEED_400000, DUPLEX_FULL },
411b7e92948SSean Anderson { MAC_200000FD, SPEED_200000, DUPLEX_FULL },
412b7e92948SSean Anderson { MAC_100000FD, SPEED_100000, DUPLEX_FULL },
413b7e92948SSean Anderson { MAC_56000FD, SPEED_56000, DUPLEX_FULL },
414b7e92948SSean Anderson { MAC_50000FD, SPEED_50000, DUPLEX_FULL },
415b7e92948SSean Anderson { MAC_40000FD, SPEED_40000, DUPLEX_FULL },
416b7e92948SSean Anderson { MAC_25000FD, SPEED_25000, DUPLEX_FULL },
417b7e92948SSean Anderson { MAC_20000FD, SPEED_20000, DUPLEX_FULL },
418b7e92948SSean Anderson { MAC_10000FD, SPEED_10000, DUPLEX_FULL },
419b7e92948SSean Anderson { MAC_5000FD, SPEED_5000, DUPLEX_FULL },
420b7e92948SSean Anderson { MAC_2500FD, SPEED_2500, DUPLEX_FULL },
421b7e92948SSean Anderson { MAC_1000FD, SPEED_1000, DUPLEX_FULL },
422b7e92948SSean Anderson { MAC_1000HD, SPEED_1000, DUPLEX_HALF },
423b7e92948SSean Anderson { MAC_100FD, SPEED_100, DUPLEX_FULL },
424b7e92948SSean Anderson { MAC_100HD, SPEED_100, DUPLEX_HALF },
425b7e92948SSean Anderson { MAC_10FD, SPEED_10, DUPLEX_FULL },
426b7e92948SSean Anderson { MAC_10HD, SPEED_10, DUPLEX_HALF },
427b7e92948SSean Anderson };
428b7e92948SSean Anderson
429b7e92948SSean Anderson /**
43070934c7cSRussell King (Oracle) * phylink_limit_mac_speed - limit the phylink_config to a maximum speed
43170934c7cSRussell King (Oracle) * @config: pointer to a &struct phylink_config
43270934c7cSRussell King (Oracle) * @max_speed: maximum speed
43370934c7cSRussell King (Oracle) *
43470934c7cSRussell King (Oracle) * Mask off MAC capabilities for speeds higher than the @max_speed parameter.
43570934c7cSRussell King (Oracle) * Any further motifications of config.mac_capabilities will override this.
43670934c7cSRussell King (Oracle) */
phylink_limit_mac_speed(struct phylink_config * config,u32 max_speed)43770934c7cSRussell King (Oracle) void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed)
43870934c7cSRussell King (Oracle) {
43970934c7cSRussell King (Oracle) int i;
44070934c7cSRussell King (Oracle)
44170934c7cSRussell King (Oracle) for (i = 0; i < ARRAY_SIZE(phylink_caps_params) &&
44270934c7cSRussell King (Oracle) phylink_caps_params[i].speed > max_speed; i++)
44370934c7cSRussell King (Oracle) config->mac_capabilities &= ~phylink_caps_params[i].mask;
44470934c7cSRussell King (Oracle) }
44570934c7cSRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_limit_mac_speed);
44670934c7cSRussell King (Oracle)
44770934c7cSRussell King (Oracle) /**
448b7e92948SSean Anderson * phylink_cap_from_speed_duplex - Get mac capability from speed/duplex
449b7e92948SSean Anderson * @speed: the speed to search for
450b7e92948SSean Anderson * @duplex: the duplex to search for
451b7e92948SSean Anderson *
452b7e92948SSean Anderson * Find the mac capability for a given speed and duplex.
453b7e92948SSean Anderson *
454b7e92948SSean Anderson * Return: A mask with the mac capability patching @speed and @duplex, or 0 if
455b7e92948SSean Anderson * there were no matches.
456b7e92948SSean Anderson */
phylink_cap_from_speed_duplex(int speed,unsigned int duplex)457b7e92948SSean Anderson static unsigned long phylink_cap_from_speed_duplex(int speed,
458b7e92948SSean Anderson unsigned int duplex)
459b7e92948SSean Anderson {
460b7e92948SSean Anderson int i;
461b7e92948SSean Anderson
462b7e92948SSean Anderson for (i = 0; i < ARRAY_SIZE(phylink_caps_params); i++) {
463b7e92948SSean Anderson if (speed == phylink_caps_params[i].speed &&
464b7e92948SSean Anderson duplex == phylink_caps_params[i].duplex)
465b7e92948SSean Anderson return phylink_caps_params[i].mask;
466b7e92948SSean Anderson }
467b7e92948SSean Anderson
468b7e92948SSean Anderson return 0;
469b7e92948SSean Anderson }
470b7e92948SSean Anderson
47134ae2c09SRussell King (Oracle) /**
4723e6eab8fSSean Anderson * phylink_get_capabilities() - get capabilities for a given MAC
47334ae2c09SRussell King (Oracle) * @interface: phy interface mode defined by &typedef phy_interface_t
47434ae2c09SRussell King (Oracle) * @mac_capabilities: bitmask of MAC capabilities
475b7e92948SSean Anderson * @rate_matching: type of rate matching being performed
47634ae2c09SRussell King (Oracle) *
4773e6eab8fSSean Anderson * Get the MAC capabilities that are supported by the @interface mode and
4783e6eab8fSSean Anderson * @mac_capabilities.
47934ae2c09SRussell King (Oracle) */
phylink_get_capabilities(phy_interface_t interface,unsigned long mac_capabilities,int rate_matching)4803e6eab8fSSean Anderson unsigned long phylink_get_capabilities(phy_interface_t interface,
481b7e92948SSean Anderson unsigned long mac_capabilities,
482b7e92948SSean Anderson int rate_matching)
48334ae2c09SRussell King (Oracle) {
484b7e92948SSean Anderson int max_speed = phylink_interface_max_speed(interface);
48534ae2c09SRussell King (Oracle) unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
486b7e92948SSean Anderson unsigned long matched_caps = 0;
48734ae2c09SRussell King (Oracle)
48834ae2c09SRussell King (Oracle) switch (interface) {
48934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_USXGMII:
49034ae2c09SRussell King (Oracle) caps |= MAC_10000FD | MAC_5000FD | MAC_2500FD;
49134ae2c09SRussell King (Oracle) fallthrough;
49234ae2c09SRussell King (Oracle)
49334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_TXID:
49434ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_RXID:
49534ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII_ID:
49634ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RGMII:
49783b5f025SGabor Juhos case PHY_INTERFACE_MODE_PSGMII:
49834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_QSGMII:
4995e61fe15SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII:
50034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_SGMII:
50134ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_GMII:
50234ae2c09SRussell King (Oracle) caps |= MAC_1000HD | MAC_1000FD;
50334ae2c09SRussell King (Oracle) fallthrough;
50434ae2c09SRussell King (Oracle)
50534ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_REVRMII:
50634ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RMII:
507b9241f54SRussell King (Oracle) case PHY_INTERFACE_MODE_SMII:
50834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_REVMII:
50934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MII:
51034ae2c09SRussell King (Oracle) caps |= MAC_10HD | MAC_10FD;
51134ae2c09SRussell King (Oracle) fallthrough;
51234ae2c09SRussell King (Oracle)
51334ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_100BASEX:
51434ae2c09SRussell King (Oracle) caps |= MAC_100HD | MAC_100FD;
51534ae2c09SRussell King (Oracle) break;
51634ae2c09SRussell King (Oracle)
51734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_TBI:
51834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MOCA:
51934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RTBI:
52034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_1000BASEX:
52134ae2c09SRussell King (Oracle) caps |= MAC_1000HD;
52234ae2c09SRussell King (Oracle) fallthrough;
52305ad5d45SSean Anderson case PHY_INTERFACE_MODE_1000BASEKX:
52434ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_TRGMII:
52534ae2c09SRussell King (Oracle) caps |= MAC_1000FD;
52634ae2c09SRussell King (Oracle) break;
52734ae2c09SRussell King (Oracle)
52834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_2500BASEX:
52934ae2c09SRussell King (Oracle) caps |= MAC_2500FD;
53034ae2c09SRussell King (Oracle) break;
53134ae2c09SRussell King (Oracle)
53234ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_5GBASER:
53334ae2c09SRussell King (Oracle) caps |= MAC_5000FD;
53434ae2c09SRussell King (Oracle) break;
53534ae2c09SRussell King (Oracle)
53634ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XGMII:
53734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_RXAUI:
53834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XAUI:
53934ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_10GBASER:
54034ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_10GKR:
54134ae2c09SRussell King (Oracle) caps |= MAC_10000FD;
54234ae2c09SRussell King (Oracle) break;
54334ae2c09SRussell King (Oracle)
54434ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_25GBASER:
54534ae2c09SRussell King (Oracle) caps |= MAC_25000FD;
54634ae2c09SRussell King (Oracle) break;
54734ae2c09SRussell King (Oracle)
54834ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_XLGMII:
54934ae2c09SRussell King (Oracle) caps |= MAC_40000FD;
55034ae2c09SRussell King (Oracle) break;
55134ae2c09SRussell King (Oracle)
55234ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_INTERNAL:
55334ae2c09SRussell King (Oracle) caps |= ~0;
55434ae2c09SRussell King (Oracle) break;
55534ae2c09SRussell King (Oracle)
55634ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_NA:
55734ae2c09SRussell King (Oracle) case PHY_INTERFACE_MODE_MAX:
55834ae2c09SRussell King (Oracle) break;
55934ae2c09SRussell King (Oracle) }
56034ae2c09SRussell King (Oracle)
561b7e92948SSean Anderson switch (rate_matching) {
562b7e92948SSean Anderson case RATE_MATCH_OPEN_LOOP:
563b7e92948SSean Anderson /* TODO */
564b7e92948SSean Anderson fallthrough;
565b7e92948SSean Anderson case RATE_MATCH_NONE:
566b7e92948SSean Anderson matched_caps = 0;
567b7e92948SSean Anderson break;
568b7e92948SSean Anderson case RATE_MATCH_PAUSE: {
569b7e92948SSean Anderson /* The MAC must support asymmetric pause towards the local
570b7e92948SSean Anderson * device for this. We could allow just symmetric pause, but
571b7e92948SSean Anderson * then we might have to renegotiate if the link partner
572b7e92948SSean Anderson * doesn't support pause. This is because there's no way to
573b7e92948SSean Anderson * accept pause frames without transmitting them if we only
574b7e92948SSean Anderson * support symmetric pause.
575b7e92948SSean Anderson */
576b7e92948SSean Anderson if (!(mac_capabilities & MAC_SYM_PAUSE) ||
577b7e92948SSean Anderson !(mac_capabilities & MAC_ASYM_PAUSE))
578b7e92948SSean Anderson break;
579b7e92948SSean Anderson
580b7e92948SSean Anderson /* We can't adapt if the MAC doesn't support the interface's
581b7e92948SSean Anderson * max speed at full duplex.
582b7e92948SSean Anderson */
583b7e92948SSean Anderson if (mac_capabilities &
584b7e92948SSean Anderson phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) {
585b7e92948SSean Anderson /* Although a duplex-matching phy might exist, we
586b7e92948SSean Anderson * conservatively remove these modes because the MAC
587b7e92948SSean Anderson * will not be aware of the half-duplex nature of the
588b7e92948SSean Anderson * link.
589b7e92948SSean Anderson */
590b7e92948SSean Anderson matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD));
591b7e92948SSean Anderson matched_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD);
592b7e92948SSean Anderson }
593b7e92948SSean Anderson break;
594b7e92948SSean Anderson }
595b7e92948SSean Anderson case RATE_MATCH_CRS:
596b7e92948SSean Anderson /* The MAC must support half duplex at the interface's max
597b7e92948SSean Anderson * speed.
598b7e92948SSean Anderson */
599b7e92948SSean Anderson if (mac_capabilities &
600b7e92948SSean Anderson phylink_cap_from_speed_duplex(max_speed, DUPLEX_HALF)) {
601b7e92948SSean Anderson matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD));
602b7e92948SSean Anderson matched_caps &= mac_capabilities;
603b7e92948SSean Anderson }
604b7e92948SSean Anderson break;
605b7e92948SSean Anderson }
606b7e92948SSean Anderson
607b7e92948SSean Anderson return (caps & mac_capabilities) | matched_caps;
60834ae2c09SRussell King (Oracle) }
6093e6eab8fSSean Anderson EXPORT_SYMBOL_GPL(phylink_get_capabilities);
61034ae2c09SRussell King (Oracle)
61134ae2c09SRussell King (Oracle) /**
612f392a184SRussell King (Oracle) * phylink_validate_mask_caps() - Restrict link modes based on caps
613f392a184SRussell King (Oracle) * @supported: ethtool bitmask for supported link modes.
614e0b3ef17SJakub Kicinski * @state: pointer to a &struct phylink_link_state.
615f392a184SRussell King (Oracle) * @mac_capabilities: bitmask of MAC capabilities
616f392a184SRussell King (Oracle) *
617f392a184SRussell King (Oracle) * Calculate the supported link modes based on @mac_capabilities, and restrict
618f392a184SRussell King (Oracle) * @supported and @state based on that. Use this function if your capabiliies
619f392a184SRussell King (Oracle) * aren't constant, such as if they vary depending on the interface.
620f392a184SRussell King (Oracle) */
phylink_validate_mask_caps(unsigned long * supported,struct phylink_link_state * state,unsigned long mac_capabilities)621f392a184SRussell King (Oracle) void phylink_validate_mask_caps(unsigned long *supported,
622f392a184SRussell King (Oracle) struct phylink_link_state *state,
623f392a184SRussell King (Oracle) unsigned long mac_capabilities)
624f392a184SRussell King (Oracle) {
625f392a184SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
626f392a184SRussell King (Oracle) unsigned long caps;
627f392a184SRussell King (Oracle)
628f392a184SRussell King (Oracle) phylink_set_port_modes(mask);
629f392a184SRussell King (Oracle) phylink_set(mask, Autoneg);
630f392a184SRussell King (Oracle) caps = phylink_get_capabilities(state->interface, mac_capabilities,
631f392a184SRussell King (Oracle) state->rate_matching);
632f392a184SRussell King (Oracle) phylink_caps_to_linkmodes(mask, caps);
633f392a184SRussell King (Oracle)
634f392a184SRussell King (Oracle) linkmode_and(supported, supported, mask);
635f392a184SRussell King (Oracle) linkmode_and(state->advertising, state->advertising, mask);
636f392a184SRussell King (Oracle) }
637f392a184SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_validate_mask_caps);
638f392a184SRussell King (Oracle)
639f392a184SRussell King (Oracle) /**
64034ae2c09SRussell King (Oracle) * phylink_generic_validate() - generic validate() callback implementation
64134ae2c09SRussell King (Oracle) * @config: a pointer to a &struct phylink_config.
64234ae2c09SRussell King (Oracle) * @supported: ethtool bitmask for supported link modes.
64334ae2c09SRussell King (Oracle) * @state: a pointer to a &struct phylink_link_state.
64434ae2c09SRussell King (Oracle) *
64534ae2c09SRussell King (Oracle) * Generic implementation of the validate() callback that MAC drivers can
64634ae2c09SRussell King (Oracle) * use when they pass the range of supported interfaces and MAC capabilities.
64734ae2c09SRussell King (Oracle) */
phylink_generic_validate(struct phylink_config * config,unsigned long * supported,struct phylink_link_state * state)64834ae2c09SRussell King (Oracle) void phylink_generic_validate(struct phylink_config *config,
64934ae2c09SRussell King (Oracle) unsigned long *supported,
65034ae2c09SRussell King (Oracle) struct phylink_link_state *state)
65134ae2c09SRussell King (Oracle) {
652f392a184SRussell King (Oracle) phylink_validate_mask_caps(supported, state, config->mac_capabilities);
65334ae2c09SRussell King (Oracle) }
65434ae2c09SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_generic_validate);
65534ae2c09SRussell King (Oracle)
phylink_validate_mac_and_pcs(struct phylink * pl,unsigned long * supported,struct phylink_link_state * state)656d1e86325SRussell King (Oracle) static int phylink_validate_mac_and_pcs(struct phylink *pl,
657d1e86325SRussell King (Oracle) unsigned long *supported,
658d1e86325SRussell King (Oracle) struct phylink_link_state *state)
659d1e86325SRussell King (Oracle) {
660d1e86325SRussell King (Oracle) struct phylink_pcs *pcs;
6610d22d4b6SRussell King (Oracle) int ret;
662d1e86325SRussell King (Oracle)
6630d22d4b6SRussell King (Oracle) /* Get the PCS for this interface mode */
66410544570SRussell King (Oracle) if (pl->using_mac_select_pcs) {
665d1e86325SRussell King (Oracle) pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
666d1e86325SRussell King (Oracle) if (IS_ERR(pcs))
667d1e86325SRussell King (Oracle) return PTR_ERR(pcs);
6680d22d4b6SRussell King (Oracle) } else {
6690d22d4b6SRussell King (Oracle) pcs = pl->pcs;
670d1e86325SRussell King (Oracle) }
671d1e86325SRussell King (Oracle)
6720d22d4b6SRussell King (Oracle) if (pcs) {
6730d22d4b6SRussell King (Oracle) /* The PCS, if present, must be setup before phylink_create()
6740d22d4b6SRussell King (Oracle) * has been called. If the ops is not initialised, print an
6750d22d4b6SRussell King (Oracle) * error and backtrace rather than oopsing the kernel.
6760d22d4b6SRussell King (Oracle) */
6770d22d4b6SRussell King (Oracle) if (!pcs->ops) {
6780d22d4b6SRussell King (Oracle) phylink_err(pl, "interface %s: uninitialised PCS\n",
6790d22d4b6SRussell King (Oracle) phy_modes(state->interface));
6800d22d4b6SRussell King (Oracle) dump_stack();
6810d22d4b6SRussell King (Oracle) return -EINVAL;
6820d22d4b6SRussell King (Oracle) }
6830d22d4b6SRussell King (Oracle)
6840d22d4b6SRussell King (Oracle) /* Validate the link parameters with the PCS */
6850d22d4b6SRussell King (Oracle) if (pcs->ops->pcs_validate) {
6860d22d4b6SRussell King (Oracle) ret = pcs->ops->pcs_validate(pcs, supported, state);
6870d22d4b6SRussell King (Oracle) if (ret < 0 || phylink_is_empty_linkmode(supported))
6880d22d4b6SRussell King (Oracle) return -EINVAL;
6890d22d4b6SRussell King (Oracle)
6900d22d4b6SRussell King (Oracle) /* Ensure the advertising mask is a subset of the
6910d22d4b6SRussell King (Oracle) * supported mask.
6920d22d4b6SRussell King (Oracle) */
6930d22d4b6SRussell King (Oracle) linkmode_and(state->advertising, state->advertising,
6940d22d4b6SRussell King (Oracle) supported);
6950d22d4b6SRussell King (Oracle) }
6960d22d4b6SRussell King (Oracle) }
6970d22d4b6SRussell King (Oracle)
6980d22d4b6SRussell King (Oracle) /* Then validate the link parameters with the MAC */
699e1f4ecabSRussell King (Oracle) if (pl->mac_ops->validate)
700d1e86325SRussell King (Oracle) pl->mac_ops->validate(pl->config, supported, state);
701e1f4ecabSRussell King (Oracle) else
702e1f4ecabSRussell King (Oracle) phylink_generic_validate(pl->config, supported, state);
703d1e86325SRussell King (Oracle)
704d1e86325SRussell King (Oracle) return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
705d1e86325SRussell King (Oracle) }
706d1e86325SRussell King (Oracle)
phylink_validate_mask(struct phylink * pl,unsigned long * supported,struct phylink_link_state * state,const unsigned long * interfaces)7071645f44dSRussell King (Oracle) static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
7081645f44dSRussell King (Oracle) struct phylink_link_state *state,
7091645f44dSRussell King (Oracle) const unsigned long *interfaces)
710d25f3a74SRussell King (Oracle) {
711d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
712d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
713d25f3a74SRussell King (Oracle) __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
714d25f3a74SRussell King (Oracle) struct phylink_link_state t;
715d25f3a74SRussell King (Oracle) int intf;
716d25f3a74SRussell King (Oracle)
717d25f3a74SRussell King (Oracle) for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
7181645f44dSRussell King (Oracle) if (test_bit(intf, interfaces)) {
719d25f3a74SRussell King (Oracle) linkmode_copy(s, supported);
720d25f3a74SRussell King (Oracle)
721d25f3a74SRussell King (Oracle) t = *state;
722d25f3a74SRussell King (Oracle) t.interface = intf;
723d1e86325SRussell King (Oracle) if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
724d25f3a74SRussell King (Oracle) linkmode_or(all_s, all_s, s);
725d25f3a74SRussell King (Oracle) linkmode_or(all_adv, all_adv, t.advertising);
726d25f3a74SRussell King (Oracle) }
727d25f3a74SRussell King (Oracle) }
728d1e86325SRussell King (Oracle) }
729d25f3a74SRussell King (Oracle)
730d25f3a74SRussell King (Oracle) linkmode_copy(supported, all_s);
731d25f3a74SRussell King (Oracle) linkmode_copy(state->advertising, all_adv);
732d25f3a74SRussell King (Oracle)
733d25f3a74SRussell King (Oracle) return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
734d25f3a74SRussell King (Oracle) }
735d25f3a74SRussell King (Oracle)
phylink_validate(struct phylink * pl,unsigned long * supported,struct phylink_link_state * state)7369525ae83SRussell King static int phylink_validate(struct phylink *pl, unsigned long *supported,
7379525ae83SRussell King struct phylink_link_state *state)
7389525ae83SRussell King {
7391645f44dSRussell King (Oracle) const unsigned long *interfaces = pl->config->supported_interfaces;
740d25f3a74SRussell King (Oracle)
7411645f44dSRussell King (Oracle) if (state->interface == PHY_INTERFACE_MODE_NA)
742de5c9bf4SRussell King (Oracle) return phylink_validate_mask(pl, supported, state, interfaces);
7431645f44dSRussell King (Oracle)
7441645f44dSRussell King (Oracle) if (!test_bit(state->interface, interfaces))
745d25f3a74SRussell King (Oracle) return -EINVAL;
746d25f3a74SRussell King (Oracle)
747d1e86325SRussell King (Oracle) return phylink_validate_mac_and_pcs(pl, supported, state);
7489525ae83SRussell King }
7499525ae83SRussell King
phylink_parse_fixedlink(struct phylink * pl,const struct fwnode_handle * fwnode)7508fa7b9b6SRussell King static int phylink_parse_fixedlink(struct phylink *pl,
751a0b79553SRussell King (Oracle) const struct fwnode_handle *fwnode)
7529525ae83SRussell King {
7538fa7b9b6SRussell King struct fwnode_handle *fixed_node;
754894341adSIvan Bornyakov bool pause, asym_pause, autoneg;
7559525ae83SRussell King const struct phy_setting *s;
7569525ae83SRussell King struct gpio_desc *desc;
7579525ae83SRussell King u32 speed;
7588fa7b9b6SRussell King int ret;
7599525ae83SRussell King
7608fa7b9b6SRussell King fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
7619525ae83SRussell King if (fixed_node) {
7628fa7b9b6SRussell King ret = fwnode_property_read_u32(fixed_node, "speed", &speed);
7639525ae83SRussell King
7649525ae83SRussell King pl->link_config.speed = speed;
7659525ae83SRussell King pl->link_config.duplex = DUPLEX_HALF;
7669525ae83SRussell King
7678fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "full-duplex"))
7689525ae83SRussell King pl->link_config.duplex = DUPLEX_FULL;
7699525ae83SRussell King
7709525ae83SRussell King /* We treat the "pause" and "asym-pause" terminology as
7711953feb0SWenpeng Liang * defining the link partner's ability.
7721953feb0SWenpeng Liang */
7738fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "pause"))
7744e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
7754e5aeb41SRussell King pl->link_config.lp_advertising);
7768fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "asym-pause"))
7774e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
7784e5aeb41SRussell King pl->link_config.lp_advertising);
7799525ae83SRussell King
7809525ae83SRussell King if (ret == 0) {
781b605c9abSDmitry Torokhov desc = fwnode_gpiod_get_index(fixed_node, "link", 0,
782b605c9abSDmitry Torokhov GPIOD_IN, "?");
7839525ae83SRussell King
7849525ae83SRussell King if (!IS_ERR(desc))
7859525ae83SRussell King pl->link_gpio = desc;
7869525ae83SRussell King else if (desc == ERR_PTR(-EPROBE_DEFER))
7879525ae83SRussell King ret = -EPROBE_DEFER;
7889525ae83SRussell King }
7898fa7b9b6SRussell King fwnode_handle_put(fixed_node);
7909525ae83SRussell King
7919525ae83SRussell King if (ret)
7929525ae83SRussell King return ret;
7939525ae83SRussell King } else {
7948fa7b9b6SRussell King u32 prop[5];
7958fa7b9b6SRussell King
7968fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link",
7978fa7b9b6SRussell King NULL, 0);
7988fa7b9b6SRussell King if (ret != ARRAY_SIZE(prop)) {
79917091180SIoana Ciornei phylink_err(pl, "broken fixed-link?\n");
8009525ae83SRussell King return -EINVAL;
8019525ae83SRussell King }
8028fa7b9b6SRussell King
8038fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link",
8048fa7b9b6SRussell King prop, ARRAY_SIZE(prop));
8058fa7b9b6SRussell King if (!ret) {
8068fa7b9b6SRussell King pl->link_config.duplex = prop[1] ?
8079525ae83SRussell King DUPLEX_FULL : DUPLEX_HALF;
8088fa7b9b6SRussell King pl->link_config.speed = prop[2];
8098fa7b9b6SRussell King if (prop[3])
8104e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
8114e5aeb41SRussell King pl->link_config.lp_advertising);
8128fa7b9b6SRussell King if (prop[4])
8134e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
8144e5aeb41SRussell King pl->link_config.lp_advertising);
8159525ae83SRussell King }
8169525ae83SRussell King }
8179525ae83SRussell King
8189525ae83SRussell King if (pl->link_config.speed > SPEED_1000 &&
8199525ae83SRussell King pl->link_config.duplex != DUPLEX_FULL)
82017091180SIoana Ciornei phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n",
8219525ae83SRussell King pl->link_config.speed);
8229525ae83SRussell King
8239525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
8249525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported);
8259525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config);
8269525ae83SRussell King
827894341adSIvan Bornyakov pause = phylink_test(pl->supported, Pause);
828894341adSIvan Bornyakov asym_pause = phylink_test(pl->supported, Asym_Pause);
829894341adSIvan Bornyakov autoneg = phylink_test(pl->supported, Autoneg);
8309525ae83SRussell King s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex,
8313c1bcc86SAndrew Lunn pl->supported, true);
8329525ae83SRussell King linkmode_zero(pl->supported);
8339525ae83SRussell King phylink_set(pl->supported, MII);
834894341adSIvan Bornyakov
835894341adSIvan Bornyakov if (pause)
8368aace4f3SRené van Dorst phylink_set(pl->supported, Pause);
837894341adSIvan Bornyakov
838894341adSIvan Bornyakov if (asym_pause)
8398aace4f3SRené van Dorst phylink_set(pl->supported, Asym_Pause);
840894341adSIvan Bornyakov
841894341adSIvan Bornyakov if (autoneg)
8421ceb7ee7SRussell King phylink_set(pl->supported, Autoneg);
843894341adSIvan Bornyakov
8449525ae83SRussell King if (s) {
8459525ae83SRussell King __set_bit(s->bit, pl->supported);
8461ceb7ee7SRussell King __set_bit(s->bit, pl->link_config.lp_advertising);
8479525ae83SRussell King } else {
84817091180SIoana Ciornei phylink_warn(pl, "fixed link %s duplex %dMbps not recognised\n",
8499525ae83SRussell King pl->link_config.duplex == DUPLEX_FULL ? "full" : "half",
8509525ae83SRussell King pl->link_config.speed);
8519525ae83SRussell King }
8529525ae83SRussell King
8539525ae83SRussell King linkmode_and(pl->link_config.advertising, pl->link_config.advertising,
8549525ae83SRussell King pl->supported);
8559525ae83SRussell King
8569525ae83SRussell King pl->link_config.link = 1;
8579525ae83SRussell King pl->link_config.an_complete = 1;
8589525ae83SRussell King
8599525ae83SRussell King return 0;
8609525ae83SRussell King }
8619525ae83SRussell King
phylink_parse_mode(struct phylink * pl,const struct fwnode_handle * fwnode)862a0b79553SRussell King (Oracle) static int phylink_parse_mode(struct phylink *pl,
863a0b79553SRussell King (Oracle) const struct fwnode_handle *fwnode)
8649525ae83SRussell King {
8658fa7b9b6SRussell King struct fwnode_handle *dn;
8669525ae83SRussell King const char *managed;
8679525ae83SRussell King
8688fa7b9b6SRussell King dn = fwnode_get_named_child_node(fwnode, "fixed-link");
8698fa7b9b6SRussell King if (dn || fwnode_property_present(fwnode, "fixed-link"))
87024cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_FIXED;
8718fa7b9b6SRussell King fwnode_handle_put(dn);
8729525ae83SRussell King
873ab393850SOng Boon Leong if ((fwnode_property_read_string(fwnode, "managed", &managed) == 0 &&
874ab393850SOng Boon Leong strcmp(managed, "in-band-status") == 0) ||
875ab393850SOng Boon Leong pl->config->ovr_an_inband) {
87624cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
87717091180SIoana Ciornei phylink_err(pl,
8789525ae83SRussell King "can't use both fixed-link and in-band-status\n");
8799525ae83SRussell King return -EINVAL;
8809525ae83SRussell King }
8819525ae83SRussell King
8829525ae83SRussell King linkmode_zero(pl->supported);
8839525ae83SRussell King phylink_set(pl->supported, MII);
8849525ae83SRussell King phylink_set(pl->supported, Autoneg);
8859525ae83SRussell King phylink_set(pl->supported, Asym_Pause);
8869525ae83SRussell King phylink_set(pl->supported, Pause);
88724cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_INBAND;
8889525ae83SRussell King
8899525ae83SRussell King switch (pl->link_config.interface) {
8909525ae83SRussell King case PHY_INTERFACE_MODE_SGMII:
89183b5f025SGabor Juhos case PHY_INTERFACE_MODE_PSGMII:
8923a68ba6fSVladimir Oltean case PHY_INTERFACE_MODE_QSGMII:
8935e61fe15SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII:
894d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII:
895d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_ID:
896d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_RXID:
897d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RGMII_TXID:
898d73ffc08SQingfang DENG case PHY_INTERFACE_MODE_RTBI:
8999525ae83SRussell King phylink_set(pl->supported, 10baseT_Half);
9009525ae83SRussell King phylink_set(pl->supported, 10baseT_Full);
9019525ae83SRussell King phylink_set(pl->supported, 100baseT_Half);
9029525ae83SRussell King phylink_set(pl->supported, 100baseT_Full);
9039525ae83SRussell King phylink_set(pl->supported, 1000baseT_Half);
9049525ae83SRussell King phylink_set(pl->supported, 1000baseT_Full);
9059525ae83SRussell King break;
9069525ae83SRussell King
9079525ae83SRussell King case PHY_INTERFACE_MODE_1000BASEX:
9089525ae83SRussell King phylink_set(pl->supported, 1000baseX_Full);
9099525ae83SRussell King break;
9109525ae83SRussell King
9119525ae83SRussell King case PHY_INTERFACE_MODE_2500BASEX:
9129525ae83SRussell King phylink_set(pl->supported, 2500baseX_Full);
9139525ae83SRussell King break;
9149525ae83SRussell King
915f6813bdaSMarek Behún case PHY_INTERFACE_MODE_5GBASER:
916f6813bdaSMarek Behún phylink_set(pl->supported, 5000baseT_Full);
917f6813bdaSMarek Behún break;
918f6813bdaSMarek Behún
91921e0c59eSSteen Hegelund case PHY_INTERFACE_MODE_25GBASER:
92021e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseCR_Full);
92121e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseKR_Full);
92221e0c59eSSteen Hegelund phylink_set(pl->supported, 25000baseSR_Full);
92321e0c59eSSteen Hegelund fallthrough;
92404e22463SAlex Marginean case PHY_INTERFACE_MODE_USXGMII:
925da7c1862SRussell King case PHY_INTERFACE_MODE_10GKR:
926e0f909bcSRussell King case PHY_INTERFACE_MODE_10GBASER:
927da7c1862SRussell King phylink_set(pl->supported, 10baseT_Half);
928da7c1862SRussell King phylink_set(pl->supported, 10baseT_Full);
929da7c1862SRussell King phylink_set(pl->supported, 100baseT_Half);
930da7c1862SRussell King phylink_set(pl->supported, 100baseT_Full);
931da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Half);
932da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Full);
933da7c1862SRussell King phylink_set(pl->supported, 1000baseX_Full);
934c580165fSJose Abreu phylink_set(pl->supported, 1000baseKX_Full);
9356cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseT_Full);
9366cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseX_Full);
9376cbdcf25SVladimir Oltean phylink_set(pl->supported, 5000baseT_Full);
9386cbdcf25SVladimir Oltean phylink_set(pl->supported, 10000baseT_Full);
939da7c1862SRussell King phylink_set(pl->supported, 10000baseKR_Full);
940c580165fSJose Abreu phylink_set(pl->supported, 10000baseKX4_Full);
941da7c1862SRussell King phylink_set(pl->supported, 10000baseCR_Full);
942da7c1862SRussell King phylink_set(pl->supported, 10000baseSR_Full);
943da7c1862SRussell King phylink_set(pl->supported, 10000baseLR_Full);
944da7c1862SRussell King phylink_set(pl->supported, 10000baseLRM_Full);
945da7c1862SRussell King phylink_set(pl->supported, 10000baseER_Full);
946da7c1862SRussell King break;
947da7c1862SRussell King
9481671c42dSJose Abreu case PHY_INTERFACE_MODE_XLGMII:
9491671c42dSJose Abreu phylink_set(pl->supported, 25000baseCR_Full);
9501671c42dSJose Abreu phylink_set(pl->supported, 25000baseKR_Full);
9511671c42dSJose Abreu phylink_set(pl->supported, 25000baseSR_Full);
9521671c42dSJose Abreu phylink_set(pl->supported, 40000baseKR4_Full);
9531671c42dSJose Abreu phylink_set(pl->supported, 40000baseCR4_Full);
9541671c42dSJose Abreu phylink_set(pl->supported, 40000baseSR4_Full);
9551671c42dSJose Abreu phylink_set(pl->supported, 40000baseLR4_Full);
9561671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR2_Full);
9571671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR2_Full);
9581671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR2_Full);
9591671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR_Full);
9601671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR_Full);
9611671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR_Full);
9621671c42dSJose Abreu phylink_set(pl->supported, 50000baseLR_ER_FR_Full);
9631671c42dSJose Abreu phylink_set(pl->supported, 50000baseDR_Full);
9641671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR4_Full);
9651671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR4_Full);
9661671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR4_Full);
9671671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR4_ER4_Full);
9681671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR2_Full);
9691671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR2_Full);
9701671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR2_Full);
9711671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR2_ER2_FR2_Full);
9721671c42dSJose Abreu phylink_set(pl->supported, 100000baseDR2_Full);
9731671c42dSJose Abreu break;
9741671c42dSJose Abreu
9759525ae83SRussell King default:
97617091180SIoana Ciornei phylink_err(pl,
9779525ae83SRussell King "incorrect link mode %s for in-band status\n",
9789525ae83SRussell King phy_modes(pl->link_config.interface));
9799525ae83SRussell King return -EINVAL;
9809525ae83SRussell King }
9819525ae83SRussell King
9829525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported);
9839525ae83SRussell King
9849525ae83SRussell King if (phylink_validate(pl, pl->supported, &pl->link_config)) {
98517091180SIoana Ciornei phylink_err(pl,
9869525ae83SRussell King "failed to validate link configuration for in-band status\n");
9879525ae83SRussell King return -EINVAL;
9889525ae83SRussell King }
9899525ae83SRussell King }
9909525ae83SRussell King
9919525ae83SRussell King return 0;
9929525ae83SRussell King }
9939525ae83SRussell King
phylink_apply_manual_flow(struct phylink * pl,struct phylink_link_state * state)9942d5fbef0SRussell King static void phylink_apply_manual_flow(struct phylink *pl,
9952d5fbef0SRussell King struct phylink_link_state *state)
9962d5fbef0SRussell King {
9972d5fbef0SRussell King /* If autoneg is disabled, pause AN is also disabled */
9984ee9b0dcSRussell King (Oracle) if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
9994ee9b0dcSRussell King (Oracle) state->advertising))
10002d5fbef0SRussell King state->pause &= ~MLO_PAUSE_AN;
10012d5fbef0SRussell King
10022d5fbef0SRussell King /* Manual configuration of pause modes */
10032d5fbef0SRussell King if (!(pl->link_config.pause & MLO_PAUSE_AN))
10042d5fbef0SRussell King state->pause = pl->link_config.pause;
10052d5fbef0SRussell King }
10062d5fbef0SRussell King
phylink_resolve_an_pause(struct phylink_link_state * state)1007dc7a5141SRussell King (Oracle) static void phylink_resolve_an_pause(struct phylink_link_state *state)
10084e5aeb41SRussell King {
10094e5aeb41SRussell King bool tx_pause, rx_pause;
10104e5aeb41SRussell King
10114e5aeb41SRussell King if (state->duplex == DUPLEX_FULL) {
10124e5aeb41SRussell King linkmode_resolve_pause(state->advertising,
10134e5aeb41SRussell King state->lp_advertising,
10144e5aeb41SRussell King &tx_pause, &rx_pause);
10154e5aeb41SRussell King if (tx_pause)
10164e5aeb41SRussell King state->pause |= MLO_PAUSE_TX;
10174e5aeb41SRussell King if (rx_pause)
10184e5aeb41SRussell King state->pause |= MLO_PAUSE_RX;
10194e5aeb41SRussell King }
10204e5aeb41SRussell King }
10214e5aeb41SRussell King
phylink_pcs_pre_config(struct phylink_pcs * pcs,phy_interface_t interface)1022aee60988SRussell King (Oracle) static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
1023aee60988SRussell King (Oracle) phy_interface_t interface)
1024aee60988SRussell King (Oracle) {
1025aee60988SRussell King (Oracle) if (pcs && pcs->ops->pcs_pre_config)
1026aee60988SRussell King (Oracle) pcs->ops->pcs_pre_config(pcs, interface);
1027aee60988SRussell King (Oracle) }
1028aee60988SRussell King (Oracle)
phylink_pcs_post_config(struct phylink_pcs * pcs,phy_interface_t interface)1029aee60988SRussell King (Oracle) static int phylink_pcs_post_config(struct phylink_pcs *pcs,
1030aee60988SRussell King (Oracle) phy_interface_t interface)
1031aee60988SRussell King (Oracle) {
1032aee60988SRussell King (Oracle) int err = 0;
1033aee60988SRussell King (Oracle)
1034aee60988SRussell King (Oracle) if (pcs && pcs->ops->pcs_post_config)
1035aee60988SRussell King (Oracle) err = pcs->ops->pcs_post_config(pcs, interface);
1036aee60988SRussell King (Oracle)
1037aee60988SRussell King (Oracle) return err;
1038aee60988SRussell King (Oracle) }
1039aee60988SRussell King (Oracle)
phylink_pcs_disable(struct phylink_pcs * pcs)104090ef0a7bSRussell King (Oracle) static void phylink_pcs_disable(struct phylink_pcs *pcs)
104190ef0a7bSRussell King (Oracle) {
104290ef0a7bSRussell King (Oracle) if (pcs && pcs->ops->pcs_disable)
104390ef0a7bSRussell King (Oracle) pcs->ops->pcs_disable(pcs);
104490ef0a7bSRussell King (Oracle) }
104590ef0a7bSRussell King (Oracle)
phylink_pcs_enable(struct phylink_pcs * pcs)104690ef0a7bSRussell King (Oracle) static int phylink_pcs_enable(struct phylink_pcs *pcs)
104790ef0a7bSRussell King (Oracle) {
104890ef0a7bSRussell King (Oracle) int err = 0;
104990ef0a7bSRussell King (Oracle)
105090ef0a7bSRussell King (Oracle) if (pcs && pcs->ops->pcs_enable)
105190ef0a7bSRussell King (Oracle) err = pcs->ops->pcs_enable(pcs);
105290ef0a7bSRussell King (Oracle)
105390ef0a7bSRussell King (Oracle) return err;
105490ef0a7bSRussell King (Oracle) }
105590ef0a7bSRussell King (Oracle)
phylink_pcs_config(struct phylink_pcs * pcs,unsigned int neg_mode,const struct phylink_link_state * state,bool permit_pause_to_mac)1056f99d471aSRussell King (Oracle) static int phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
1057ae4899bbSRussell King (Oracle) const struct phylink_link_state *state,
1058ae4899bbSRussell King (Oracle) bool permit_pause_to_mac)
1059ae4899bbSRussell King (Oracle) {
1060ae4899bbSRussell King (Oracle) if (!pcs)
1061ae4899bbSRussell King (Oracle) return 0;
1062ae4899bbSRussell King (Oracle)
1063f99d471aSRussell King (Oracle) return pcs->ops->pcs_config(pcs, neg_mode, state->interface,
1064ae4899bbSRussell King (Oracle) state->advertising, permit_pause_to_mac);
1065ae4899bbSRussell King (Oracle) }
1066ae4899bbSRussell King (Oracle)
phylink_pcs_link_up(struct phylink_pcs * pcs,unsigned int neg_mode,phy_interface_t interface,int speed,int duplex)1067f99d471aSRussell King (Oracle) static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
1068ae4899bbSRussell King (Oracle) phy_interface_t interface, int speed,
1069ae4899bbSRussell King (Oracle) int duplex)
1070ae4899bbSRussell King (Oracle) {
1071ae4899bbSRussell King (Oracle) if (pcs && pcs->ops->pcs_link_up)
1072f99d471aSRussell King (Oracle) pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex);
1073ae4899bbSRussell King (Oracle) }
1074ae4899bbSRussell King (Oracle)
phylink_pcs_poll_stop(struct phylink * pl)1075bfac8c49SRussell King (Oracle) static void phylink_pcs_poll_stop(struct phylink *pl)
1076bfac8c49SRussell King (Oracle) {
1077bfac8c49SRussell King (Oracle) if (pl->cfg_link_an_mode == MLO_AN_INBAND)
1078bfac8c49SRussell King (Oracle) del_timer(&pl->link_poll);
1079bfac8c49SRussell King (Oracle) }
1080bfac8c49SRussell King (Oracle)
phylink_pcs_poll_start(struct phylink * pl)1081bfac8c49SRussell King (Oracle) static void phylink_pcs_poll_start(struct phylink *pl)
1082bfac8c49SRussell King (Oracle) {
1083b7d78b46SVladimir Oltean if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND)
1084bfac8c49SRussell King (Oracle) mod_timer(&pl->link_poll, jiffies + HZ);
1085bfac8c49SRussell King (Oracle) }
1086bfac8c49SRussell King (Oracle)
phylink_mac_config(struct phylink * pl,const struct phylink_link_state * state)10879525ae83SRussell King static void phylink_mac_config(struct phylink *pl,
10889525ae83SRussell King const struct phylink_link_state *state)
10899525ae83SRussell King {
1090c5714f68SRussell King (Oracle) struct phylink_link_state st = *state;
10919525ae83SRussell King
1092c5714f68SRussell King (Oracle) /* Stop drivers incorrectly using these */
1093c5714f68SRussell King (Oracle) linkmode_zero(st.lp_advertising);
1094c5714f68SRussell King (Oracle) st.speed = SPEED_UNKNOWN;
1095c5714f68SRussell King (Oracle) st.duplex = DUPLEX_UNKNOWN;
1096c5714f68SRussell King (Oracle) st.an_complete = false;
1097c5714f68SRussell King (Oracle) st.link = false;
1098c5714f68SRussell King (Oracle)
1099c5714f68SRussell King (Oracle) phylink_dbg(pl,
1100c5714f68SRussell King (Oracle) "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
1101c5714f68SRussell King (Oracle) __func__, phylink_an_mode_str(pl->cur_link_an_mode),
1102c5714f68SRussell King (Oracle) phy_modes(st.interface),
1103c5714f68SRussell King (Oracle) phy_rate_matching_to_str(st.rate_matching),
1104c5714f68SRussell King (Oracle) __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
1105c5714f68SRussell King (Oracle) st.pause);
1106c5714f68SRussell King (Oracle)
1107c5714f68SRussell King (Oracle) pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
11089525ae83SRussell King }
11099525ae83SRussell King
phylink_pcs_an_restart(struct phylink * pl)111076226787SRussell King (Oracle) static void phylink_pcs_an_restart(struct phylink *pl)
11119525ae83SRussell King {
111276226787SRussell King (Oracle) if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
11134ee9b0dcSRussell King (Oracle) pl->link_config.advertising) &&
1114575691b3SRussell King phy_interface_mode_is_8023z(pl->link_config.interface) &&
111576226787SRussell King (Oracle) phylink_autoneg_inband(pl->cur_link_an_mode))
11164f1dd48fSRussell King (Oracle) pl->pcs->ops->pcs_an_restart(pl->pcs);
11174c0d6d3aSRussell King }
11184c0d6d3aSRussell King
phylink_major_config(struct phylink * pl,bool restart,const struct phylink_link_state * state)1119b7ad14c2SRussell King static void phylink_major_config(struct phylink *pl, bool restart,
11204c0d6d3aSRussell King const struct phylink_link_state *state)
11214c0d6d3aSRussell King {
1122d1e86325SRussell King (Oracle) struct phylink_pcs *pcs = NULL;
1123bfac8c49SRussell King (Oracle) bool pcs_changed = false;
1124dc185822SRussell King (Oracle) unsigned int rate_kbd;
1125f99d471aSRussell King (Oracle) unsigned int neg_mode;
1126b7ad14c2SRussell King int err;
11274c0d6d3aSRussell King
1128b7ad14c2SRussell King phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
1129b7ad14c2SRussell King
1130f99d471aSRussell King (Oracle) pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
1131f99d471aSRussell King (Oracle) state->interface,
1132f99d471aSRussell King (Oracle) state->advertising);
1133f99d471aSRussell King (Oracle)
113410544570SRussell King (Oracle) if (pl->using_mac_select_pcs) {
1135d1e86325SRussell King (Oracle) pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
1136d1e86325SRussell King (Oracle) if (IS_ERR(pcs)) {
1137d1e86325SRussell King (Oracle) phylink_err(pl,
1138d1e86325SRussell King (Oracle) "mac_select_pcs unexpectedly failed: %pe\n",
1139d1e86325SRussell King (Oracle) pcs);
1140d1e86325SRussell King (Oracle) return;
1141d1e86325SRussell King (Oracle) }
1142bfac8c49SRussell King (Oracle)
1143bfac8c49SRussell King (Oracle) pcs_changed = pcs && pl->pcs != pcs;
1144d1e86325SRussell King (Oracle) }
1145d1e86325SRussell King (Oracle)
1146bfac8c49SRussell King (Oracle) phylink_pcs_poll_stop(pl);
1147bfac8c49SRussell King (Oracle)
1148b7ad14c2SRussell King if (pl->mac_ops->mac_prepare) {
1149b7ad14c2SRussell King err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
1150b7ad14c2SRussell King state->interface);
1151b7ad14c2SRussell King if (err < 0) {
1152b7ad14c2SRussell King phylink_err(pl, "mac_prepare failed: %pe\n",
1153b7ad14c2SRussell King ERR_PTR(err));
1154b7ad14c2SRussell King return;
1155b7ad14c2SRussell King }
1156b7ad14c2SRussell King }
11574c0d6d3aSRussell King
1158d1e86325SRussell King (Oracle) /* If we have a new PCS, switch to the new PCS after preparing the MAC
1159d1e86325SRussell King (Oracle) * for the change.
1160d1e86325SRussell King (Oracle) */
116190ef0a7bSRussell King (Oracle) if (pcs_changed) {
116290ef0a7bSRussell King (Oracle) phylink_pcs_disable(pl->pcs);
116390ef0a7bSRussell King (Oracle)
116424699cc1SRussell King (Oracle) if (pl->pcs)
116524699cc1SRussell King (Oracle) pl->pcs->phylink = NULL;
116624699cc1SRussell King (Oracle)
116724699cc1SRussell King (Oracle) pcs->phylink = pl;
116824699cc1SRussell King (Oracle)
1169a5081badSRussell King (Oracle) pl->pcs = pcs;
117090ef0a7bSRussell King (Oracle) }
1171a5081badSRussell King (Oracle)
1172aee60988SRussell King (Oracle) if (pl->pcs)
1173aee60988SRussell King (Oracle) phylink_pcs_pre_config(pl->pcs, state->interface);
1174aee60988SRussell King (Oracle)
11754c0d6d3aSRussell King phylink_mac_config(pl, state);
11764c0d6d3aSRussell King
1177aee60988SRussell King (Oracle) if (pl->pcs)
1178aee60988SRussell King (Oracle) phylink_pcs_post_config(pl->pcs, state->interface);
1179aee60988SRussell King (Oracle)
118090ef0a7bSRussell King (Oracle) if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
118190ef0a7bSRussell King (Oracle) phylink_pcs_enable(pl->pcs);
118290ef0a7bSRussell King (Oracle)
1183f99d471aSRussell King (Oracle) neg_mode = pl->cur_link_an_mode;
1184f99d471aSRussell King (Oracle) if (pl->pcs && pl->pcs->neg_mode)
1185f99d471aSRussell King (Oracle) neg_mode = pl->pcs_neg_mode;
1186f99d471aSRussell King (Oracle)
1187f99d471aSRussell King (Oracle) err = phylink_pcs_config(pl->pcs, neg_mode, state,
1188f99d471aSRussell King (Oracle) !!(pl->link_config.pause & MLO_PAUSE_AN));
1189b7ad14c2SRussell King if (err < 0)
1190b7ad14c2SRussell King phylink_err(pl, "pcs_config failed: %pe\n",
1191b7ad14c2SRussell King ERR_PTR(err));
1192ae4899bbSRussell King (Oracle) else if (err > 0)
1193b7ad14c2SRussell King restart = true;
1194ae4899bbSRussell King (Oracle)
11954c0d6d3aSRussell King if (restart)
119676226787SRussell King (Oracle) phylink_pcs_an_restart(pl);
1197b7ad14c2SRussell King
1198b7ad14c2SRussell King if (pl->mac_ops->mac_finish) {
1199b7ad14c2SRussell King err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
1200b7ad14c2SRussell King state->interface);
1201b7ad14c2SRussell King if (err < 0)
1202d82c6c1aSOng Boon Leong phylink_err(pl, "mac_finish failed: %pe\n",
1203b7ad14c2SRussell King ERR_PTR(err));
1204b7ad14c2SRussell King }
1205bfac8c49SRussell King (Oracle)
1206dc185822SRussell King (Oracle) if (pl->sfp_bus) {
1207dc185822SRussell King (Oracle) rate_kbd = phylink_interface_signal_rate(state->interface);
1208dc185822SRussell King (Oracle) if (rate_kbd)
1209dc185822SRussell King (Oracle) sfp_upstream_set_signal_rate(pl->sfp_bus, rate_kbd);
1210dc185822SRussell King (Oracle) }
1211dc185822SRussell King (Oracle)
1212bfac8c49SRussell King (Oracle) phylink_pcs_poll_start(pl);
12134c0d6d3aSRussell King }
12149525ae83SRussell King
12151571e700SRussell King /*
12161571e700SRussell King * Reconfigure for a change of inband advertisement.
12171571e700SRussell King * If we have a separate PCS, we only need to call its pcs_config() method,
12181571e700SRussell King * and then restart AN if it indicates something changed. Otherwise, we do
12191571e700SRussell King * the full MAC reconfiguration.
12201571e700SRussell King */
phylink_change_inband_advert(struct phylink * pl)12211571e700SRussell King static int phylink_change_inband_advert(struct phylink *pl)
12221571e700SRussell King {
1223f99d471aSRussell King (Oracle) unsigned int neg_mode;
12241571e700SRussell King int ret;
12251571e700SRussell King
12261571e700SRussell King if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state))
12271571e700SRussell King return 0;
12281571e700SRussell King
12291571e700SRussell King phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
12301571e700SRussell King phylink_an_mode_str(pl->cur_link_an_mode),
12311571e700SRussell King phy_modes(pl->link_config.interface),
12321571e700SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising,
12331571e700SRussell King pl->link_config.pause);
12341571e700SRussell King
1235f99d471aSRussell King (Oracle) /* Recompute the PCS neg mode */
1236f99d471aSRussell King (Oracle) pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode,
1237f99d471aSRussell King (Oracle) pl->link_config.interface,
1238f99d471aSRussell King (Oracle) pl->link_config.advertising);
1239f99d471aSRussell King (Oracle)
1240f99d471aSRussell King (Oracle) neg_mode = pl->cur_link_an_mode;
1241f99d471aSRussell King (Oracle) if (pl->pcs->neg_mode)
1242f99d471aSRussell King (Oracle) neg_mode = pl->pcs_neg_mode;
1243f99d471aSRussell King (Oracle)
12441571e700SRussell King /* Modern PCS-based method; update the advert at the PCS, and
12451571e700SRussell King * restart negotiation if the pcs_config() helper indicates that
12461571e700SRussell King * the programmed advertisement has changed.
12471571e700SRussell King */
1248f99d471aSRussell King (Oracle) ret = phylink_pcs_config(pl->pcs, neg_mode, &pl->link_config,
1249ae4899bbSRussell King (Oracle) !!(pl->link_config.pause & MLO_PAUSE_AN));
12501571e700SRussell King if (ret < 0)
12511571e700SRussell King return ret;
12521571e700SRussell King
12531571e700SRussell King if (ret > 0)
125476226787SRussell King (Oracle) phylink_pcs_an_restart(pl);
12551571e700SRussell King
12561571e700SRussell King return 0;
12571571e700SRussell King }
12581571e700SRussell King
phylink_mac_pcs_get_state(struct phylink * pl,struct phylink_link_state * state)1259d46b7e4fSRussell King static void phylink_mac_pcs_get_state(struct phylink *pl,
1260d46b7e4fSRussell King struct phylink_link_state *state)
12619525ae83SRussell King {
12629525ae83SRussell King linkmode_copy(state->advertising, pl->link_config.advertising);
12639525ae83SRussell King linkmode_zero(state->lp_advertising);
12649525ae83SRussell King state->interface = pl->link_config.interface;
1265ae0e4bb2SSean Anderson state->rate_matching = pl->link_config.rate_matching;
12664ee9b0dcSRussell King (Oracle) if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
12674ee9b0dcSRussell King (Oracle) state->advertising)) {
1268d25ed413SHeiner Kallweit state->speed = SPEED_UNKNOWN;
1269d25ed413SHeiner Kallweit state->duplex = DUPLEX_UNKNOWN;
1270d25ed413SHeiner Kallweit state->pause = MLO_PAUSE_NONE;
127192817dadSRobert Hancock } else {
127292817dadSRobert Hancock state->speed = pl->link_config.speed;
127392817dadSRobert Hancock state->duplex = pl->link_config.duplex;
127492817dadSRobert Hancock state->pause = pl->link_config.pause;
127592817dadSRobert Hancock }
1276d25ed413SHeiner Kallweit state->an_complete = 0;
12779525ae83SRussell King state->link = 1;
12789525ae83SRussell King
12794f1dd48fSRussell King (Oracle) if (pl->pcs)
12804f1dd48fSRussell King (Oracle) pl->pcs->ops->pcs_get_state(pl->pcs, state);
1281e859a60aSRussell King else
1282e859a60aSRussell King state->link = 0;
12839525ae83SRussell King }
12849525ae83SRussell King
12859525ae83SRussell King /* The fixed state is... fixed except for the link state,
12861ac63e39SFlorian Fainelli * which may be determined by a GPIO or a callback.
12879525ae83SRussell King */
phylink_get_fixed_state(struct phylink * pl,struct phylink_link_state * state)12884e5aeb41SRussell King static void phylink_get_fixed_state(struct phylink *pl,
12894e5aeb41SRussell King struct phylink_link_state *state)
12909525ae83SRussell King {
12919525ae83SRussell King *state = pl->link_config;
12925c05c1dbSRussell King if (pl->config->get_fixed_state)
12935c05c1dbSRussell King pl->config->get_fixed_state(pl->config, state);
12941ac63e39SFlorian Fainelli else if (pl->link_gpio)
1295bb322a90SFlorian Fainelli state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
12969525ae83SRussell King
1297dc7a5141SRussell King (Oracle) state->pause = MLO_PAUSE_NONE;
1298dc7a5141SRussell King (Oracle) phylink_resolve_an_pause(state);
12999525ae83SRussell King }
13009525ae83SRussell King
phylink_mac_initial_config(struct phylink * pl,bool force_restart)13014c0d6d3aSRussell King static void phylink_mac_initial_config(struct phylink *pl, bool force_restart)
130297fec51fSRussell King {
130397fec51fSRussell King struct phylink_link_state link_state;
130497fec51fSRussell King
130597fec51fSRussell King switch (pl->cur_link_an_mode) {
130697fec51fSRussell King case MLO_AN_PHY:
130797fec51fSRussell King link_state = pl->phy_state;
130897fec51fSRussell King break;
130997fec51fSRussell King
131097fec51fSRussell King case MLO_AN_FIXED:
131197fec51fSRussell King phylink_get_fixed_state(pl, &link_state);
131297fec51fSRussell King break;
131397fec51fSRussell King
131497fec51fSRussell King case MLO_AN_INBAND:
131597fec51fSRussell King link_state = pl->link_config;
131697fec51fSRussell King if (link_state.interface == PHY_INTERFACE_MODE_SGMII)
131797fec51fSRussell King link_state.pause = MLO_PAUSE_NONE;
131897fec51fSRussell King break;
131997fec51fSRussell King
132097fec51fSRussell King default: /* can't happen */
132197fec51fSRussell King return;
132297fec51fSRussell King }
132397fec51fSRussell King
132497fec51fSRussell King link_state.link = false;
132597fec51fSRussell King
132697fec51fSRussell King phylink_apply_manual_flow(pl, &link_state);
1327b7ad14c2SRussell King phylink_major_config(pl, force_restart, &link_state);
132897fec51fSRussell King }
132997fec51fSRussell King
phylink_pause_to_str(int pause)13309525ae83SRussell King static const char *phylink_pause_to_str(int pause)
13319525ae83SRussell King {
13329525ae83SRussell King switch (pause & MLO_PAUSE_TXRX_MASK) {
13339525ae83SRussell King case MLO_PAUSE_TX | MLO_PAUSE_RX:
13349525ae83SRussell King return "rx/tx";
13359525ae83SRussell King case MLO_PAUSE_TX:
13369525ae83SRussell King return "tx";
13379525ae83SRussell King case MLO_PAUSE_RX:
13389525ae83SRussell King return "rx";
13399525ae83SRussell King default:
13409525ae83SRussell King return "off";
13419525ae83SRussell King }
13429525ae83SRussell King }
13439525ae83SRussell King
phylink_link_up(struct phylink * pl,struct phylink_link_state link_state)13444c0d6d3aSRussell King static void phylink_link_up(struct phylink *pl,
134527755ff8SIoana Ciornei struct phylink_link_state link_state)
134627755ff8SIoana Ciornei {
134727755ff8SIoana Ciornei struct net_device *ndev = pl->netdev;
1348f99d471aSRussell King (Oracle) unsigned int neg_mode;
1349ae0e4bb2SSean Anderson int speed, duplex;
1350ae0e4bb2SSean Anderson bool rx_pause;
1351ae0e4bb2SSean Anderson
1352ae0e4bb2SSean Anderson speed = link_state.speed;
1353ae0e4bb2SSean Anderson duplex = link_state.duplex;
1354ae0e4bb2SSean Anderson rx_pause = !!(link_state.pause & MLO_PAUSE_RX);
1355ae0e4bb2SSean Anderson
1356ae0e4bb2SSean Anderson switch (link_state.rate_matching) {
1357ae0e4bb2SSean Anderson case RATE_MATCH_PAUSE:
1358ae0e4bb2SSean Anderson /* The PHY is doing rate matchion from the media rate (in
1359ae0e4bb2SSean Anderson * the link_state) to the interface speed, and will send
1360ae0e4bb2SSean Anderson * pause frames to the MAC to limit its transmission speed.
1361ae0e4bb2SSean Anderson */
1362ae0e4bb2SSean Anderson speed = phylink_interface_max_speed(link_state.interface);
1363ae0e4bb2SSean Anderson duplex = DUPLEX_FULL;
1364ae0e4bb2SSean Anderson rx_pause = true;
1365ae0e4bb2SSean Anderson break;
1366ae0e4bb2SSean Anderson
1367ae0e4bb2SSean Anderson case RATE_MATCH_CRS:
1368ae0e4bb2SSean Anderson /* The PHY is doing rate matchion from the media rate (in
1369ae0e4bb2SSean Anderson * the link_state) to the interface speed, and will cause
1370ae0e4bb2SSean Anderson * collisions to the MAC to limit its transmission speed.
1371ae0e4bb2SSean Anderson */
1372ae0e4bb2SSean Anderson speed = phylink_interface_max_speed(link_state.interface);
1373ae0e4bb2SSean Anderson duplex = DUPLEX_HALF;
1374ae0e4bb2SSean Anderson break;
1375ae0e4bb2SSean Anderson }
137627755ff8SIoana Ciornei
1377b4b12b0dSDavid S. Miller pl->cur_interface = link_state.interface;
13784c0d6d3aSRussell King
1379f99d471aSRussell King (Oracle) neg_mode = pl->cur_link_an_mode;
1380f99d471aSRussell King (Oracle) if (pl->pcs && pl->pcs->neg_mode)
1381f99d471aSRussell King (Oracle) neg_mode = pl->pcs_neg_mode;
1382f99d471aSRussell King (Oracle)
1383f99d471aSRussell King (Oracle) phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed,
1384f99d471aSRussell King (Oracle) duplex);
13854c0d6d3aSRussell King
1386ae0e4bb2SSean Anderson pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
1387ae0e4bb2SSean Anderson pl->cur_interface, speed, duplex,
1388ae0e4bb2SSean Anderson !!(link_state.pause & MLO_PAUSE_TX), rx_pause);
138927755ff8SIoana Ciornei
139043de6195SIoana Ciornei if (ndev)
139127755ff8SIoana Ciornei netif_carrier_on(ndev);
139227755ff8SIoana Ciornei
139317091180SIoana Ciornei phylink_info(pl,
139427755ff8SIoana Ciornei "Link is Up - %s/%s - flow control %s\n",
139527755ff8SIoana Ciornei phy_speed_to_str(link_state.speed),
139627755ff8SIoana Ciornei phy_duplex_to_str(link_state.duplex),
139727755ff8SIoana Ciornei phylink_pause_to_str(link_state.pause));
139827755ff8SIoana Ciornei }
139927755ff8SIoana Ciornei
phylink_link_down(struct phylink * pl)14004c0d6d3aSRussell King static void phylink_link_down(struct phylink *pl)
140127755ff8SIoana Ciornei {
140227755ff8SIoana Ciornei struct net_device *ndev = pl->netdev;
140327755ff8SIoana Ciornei
140443de6195SIoana Ciornei if (ndev)
140527755ff8SIoana Ciornei netif_carrier_off(ndev);
1406e7765d63SRussell King pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
1407b4b12b0dSDavid S. Miller pl->cur_interface);
140817091180SIoana Ciornei phylink_info(pl, "Link is Down\n");
140927755ff8SIoana Ciornei }
141027755ff8SIoana Ciornei
phylink_resolve(struct work_struct * w)14119525ae83SRussell King static void phylink_resolve(struct work_struct *w)
14129525ae83SRussell King {
14139525ae83SRussell King struct phylink *pl = container_of(w, struct phylink, resolve);
14149525ae83SRussell King struct phylink_link_state link_state;
14159525ae83SRussell King struct net_device *ndev = pl->netdev;
1416319bfafeSRussell King bool mac_config = false;
141780662f4fSRussell King (Oracle) bool retrigger = false;
1418b06e5cacSRussell King bool cur_link_state;
14199525ae83SRussell King
14209525ae83SRussell King mutex_lock(&pl->state_mutex);
1421b06e5cacSRussell King if (pl->netdev)
1422b06e5cacSRussell King cur_link_state = netif_carrier_ok(ndev);
1423b06e5cacSRussell King else
1424b06e5cacSRussell King cur_link_state = pl->old_link_state;
1425b06e5cacSRussell King
14269525ae83SRussell King if (pl->phylink_disable_state) {
14279525ae83SRussell King pl->mac_link_dropped = false;
14289525ae83SRussell King link_state.link = false;
14299525ae83SRussell King } else if (pl->mac_link_dropped) {
14309525ae83SRussell King link_state.link = false;
143180662f4fSRussell King (Oracle) retrigger = true;
14329525ae83SRussell King } else {
143324cf0e69SRussell King switch (pl->cur_link_an_mode) {
14349525ae83SRussell King case MLO_AN_PHY:
14359525ae83SRussell King link_state = pl->phy_state;
14362d5fbef0SRussell King phylink_apply_manual_flow(pl, &link_state);
1437319bfafeSRussell King mac_config = link_state.link;
14389525ae83SRussell King break;
14399525ae83SRussell King
14409525ae83SRussell King case MLO_AN_FIXED:
14419525ae83SRussell King phylink_get_fixed_state(pl, &link_state);
1442319bfafeSRussell King mac_config = link_state.link;
14439525ae83SRussell King break;
14449525ae83SRussell King
144586a362c4SRussell King case MLO_AN_INBAND:
1446d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state);
14479525ae83SRussell King
1448dbae3388SRussell King (Oracle) /* The PCS may have a latching link-fail indicator.
1449dbae3388SRussell King (Oracle) * If the link was up, bring the link down and
1450dbae3388SRussell King (Oracle) * re-trigger the resolve. Otherwise, re-read the
1451dbae3388SRussell King (Oracle) * PCS state to get the current status of the link.
1452dbae3388SRussell King (Oracle) */
1453dbae3388SRussell King (Oracle) if (!link_state.link) {
1454dbae3388SRussell King (Oracle) if (cur_link_state)
1455dbae3388SRussell King (Oracle) retrigger = true;
1456dbae3388SRussell King (Oracle) else
1457dbae3388SRussell King (Oracle) phylink_mac_pcs_get_state(pl,
1458dbae3388SRussell King (Oracle) &link_state);
1459dbae3388SRussell King (Oracle) }
1460dbae3388SRussell King (Oracle)
1461406cb0c4SRussell King /* If we have a phy, the "up" state is the union of
14621953feb0SWenpeng Liang * both the PHY and the MAC
14631953feb0SWenpeng Liang */
1464406cb0c4SRussell King if (pl->phydev)
1465406cb0c4SRussell King link_state.link &= pl->phy_state.link;
14669525ae83SRussell King
1467406cb0c4SRussell King /* Only update if the PHY link is up */
1468406cb0c4SRussell King if (pl->phydev && pl->phy_state.link) {
146980662f4fSRussell King (Oracle) /* If the interface has changed, force a
147080662f4fSRussell King (Oracle) * link down event if the link isn't already
147180662f4fSRussell King (Oracle) * down, and re-resolve.
147280662f4fSRussell King (Oracle) */
147380662f4fSRussell King (Oracle) if (link_state.interface !=
147480662f4fSRussell King (Oracle) pl->phy_state.interface) {
147580662f4fSRussell King (Oracle) retrigger = true;
147680662f4fSRussell King (Oracle) link_state.link = false;
147780662f4fSRussell King (Oracle) }
14789525ae83SRussell King link_state.interface = pl->phy_state.interface;
14799525ae83SRussell King
1480ae0e4bb2SSean Anderson /* If we are doing rate matching, then the
1481ae0e4bb2SSean Anderson * link speed/duplex comes from the PHY
1482ae0e4bb2SSean Anderson */
1483ae0e4bb2SSean Anderson if (pl->phy_state.rate_matching) {
1484ae0e4bb2SSean Anderson link_state.rate_matching =
1485ae0e4bb2SSean Anderson pl->phy_state.rate_matching;
1486ae0e4bb2SSean Anderson link_state.speed = pl->phy_state.speed;
1487ae0e4bb2SSean Anderson link_state.duplex =
1488ae0e4bb2SSean Anderson pl->phy_state.duplex;
1489ae0e4bb2SSean Anderson }
1490ae0e4bb2SSean Anderson
1491406cb0c4SRussell King /* If we have a PHY, we need to update with
14921953feb0SWenpeng Liang * the PHY flow control bits.
14931953feb0SWenpeng Liang */
149433faac8eSRussell King link_state.pause = pl->phy_state.pause;
1495319bfafeSRussell King mac_config = true;
14969525ae83SRussell King }
1497319bfafeSRussell King phylink_apply_manual_flow(pl, &link_state);
14989525ae83SRussell King break;
14999525ae83SRussell King }
15009525ae83SRussell King }
15019525ae83SRussell King
150216319a7dSRussell King if (mac_config) {
150316319a7dSRussell King if (link_state.interface != pl->link_config.interface) {
150416319a7dSRussell King /* The interface has changed, force the link down and
150516319a7dSRussell King * then reconfigure.
150616319a7dSRussell King */
150716319a7dSRussell King if (cur_link_state) {
150816319a7dSRussell King phylink_link_down(pl);
150916319a7dSRussell King cur_link_state = false;
151016319a7dSRussell King }
1511b7ad14c2SRussell King phylink_major_config(pl, false, &link_state);
15125005b163SRussell King pl->link_config.interface = link_state.interface;
151316319a7dSRussell King }
15145005b163SRussell King }
1515319bfafeSRussell King
1516b06e5cacSRussell King if (link_state.link != cur_link_state) {
151743de6195SIoana Ciornei pl->old_link_state = link_state.link;
151827755ff8SIoana Ciornei if (!link_state.link)
15194c0d6d3aSRussell King phylink_link_down(pl);
152027755ff8SIoana Ciornei else
15214c0d6d3aSRussell King phylink_link_up(pl, link_state);
15229525ae83SRussell King }
152380662f4fSRussell King (Oracle) if (!link_state.link && retrigger) {
15249525ae83SRussell King pl->mac_link_dropped = false;
15259525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve);
15269525ae83SRussell King }
15279525ae83SRussell King mutex_unlock(&pl->state_mutex);
15289525ae83SRussell King }
15299525ae83SRussell King
phylink_run_resolve(struct phylink * pl)15309525ae83SRussell King static void phylink_run_resolve(struct phylink *pl)
15319525ae83SRussell King {
15329525ae83SRussell King if (!pl->phylink_disable_state)
15339525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve);
15349525ae83SRussell King }
15359525ae83SRussell King
phylink_run_resolve_and_disable(struct phylink * pl,int bit)153687454b6eSRussell King static void phylink_run_resolve_and_disable(struct phylink *pl, int bit)
153787454b6eSRussell King {
153887454b6eSRussell King unsigned long state = pl->phylink_disable_state;
153987454b6eSRussell King
154087454b6eSRussell King set_bit(bit, &pl->phylink_disable_state);
154187454b6eSRussell King if (state == 0) {
154287454b6eSRussell King queue_work(system_power_efficient_wq, &pl->resolve);
154387454b6eSRussell King flush_work(&pl->resolve);
154487454b6eSRussell King }
154587454b6eSRussell King }
154687454b6eSRussell King
phylink_enable_and_run_resolve(struct phylink * pl,int bit)1547aa729c43SRussell King static void phylink_enable_and_run_resolve(struct phylink *pl, int bit)
1548aa729c43SRussell King {
1549aa729c43SRussell King clear_bit(bit, &pl->phylink_disable_state);
1550aa729c43SRussell King phylink_run_resolve(pl);
1551aa729c43SRussell King }
1552aa729c43SRussell King
phylink_fixed_poll(struct timer_list * t)15539cd00a8aSRussell King static void phylink_fixed_poll(struct timer_list *t)
15549cd00a8aSRussell King {
15559cd00a8aSRussell King struct phylink *pl = container_of(t, struct phylink, link_poll);
15569cd00a8aSRussell King
15579cd00a8aSRussell King mod_timer(t, jiffies + HZ);
15589cd00a8aSRussell King
15599cd00a8aSRussell King phylink_run_resolve(pl);
15609cd00a8aSRussell King }
15619cd00a8aSRussell King
1562ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops;
1563ce0aa27fSRussell King
phylink_register_sfp(struct phylink * pl,const struct fwnode_handle * fwnode)15648fa7b9b6SRussell King static int phylink_register_sfp(struct phylink *pl,
1565a0b79553SRussell King (Oracle) const struct fwnode_handle *fwnode)
1566ce0aa27fSRussell King {
15672203cbf2SRussell King struct sfp_bus *bus;
15688fa7b9b6SRussell King int ret;
1569ce0aa27fSRussell King
1570eed70fd9SRussell King if (!fwnode)
1571eed70fd9SRussell King return 0;
1572eed70fd9SRussell King
1573727b3668SRussell King bus = sfp_bus_find_fwnode(fwnode);
15742203cbf2SRussell King if (IS_ERR(bus)) {
1575ab1198e5SRussell King (Oracle) phylink_err(pl, "unable to attach SFP bus: %pe\n", bus);
1576ab1198e5SRussell King (Oracle) return PTR_ERR(bus);
15778fa7b9b6SRussell King }
15788fa7b9b6SRussell King
15792203cbf2SRussell King pl->sfp_bus = bus;
1580ce0aa27fSRussell King
1581727b3668SRussell King ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
1582727b3668SRussell King sfp_bus_put(bus);
1583727b3668SRussell King
1584727b3668SRussell King return ret;
1585ce0aa27fSRussell King }
1586ce0aa27fSRussell King
15878796c892SRussell King /**
15888796c892SRussell King * phylink_create() - create a phylink instance
15899db74e51SRandy Dunlap * @config: a pointer to the target &struct phylink_config
15908fa7b9b6SRussell King * @fwnode: a pointer to a &struct fwnode_handle describing the network
15918fa7b9b6SRussell King * interface
15928796c892SRussell King * @iface: the desired link mode defined by &typedef phy_interface_t
1593e7765d63SRussell King * @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC.
15948796c892SRussell King *
15958796c892SRussell King * Create a new phylink instance, and parse the link parameters found in @np.
15968796c892SRussell King * This will parse in-band modes, fixed-link or SFP configuration.
15978796c892SRussell King *
1598269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function.
1599269a6b5fSRussell King *
16008796c892SRussell King * Returns a pointer to a &struct phylink, or an error-pointer value. Users
16018796c892SRussell King * must use IS_ERR() to check for errors from this function.
16028796c892SRussell King */
phylink_create(struct phylink_config * config,const struct fwnode_handle * fwnode,phy_interface_t iface,const struct phylink_mac_ops * mac_ops)160344cc27e4SIoana Ciornei struct phylink *phylink_create(struct phylink_config *config,
1604a0b79553SRussell King (Oracle) const struct fwnode_handle *fwnode,
1605516b29edSFlorian Fainelli phy_interface_t iface,
1606e7765d63SRussell King const struct phylink_mac_ops *mac_ops)
16079525ae83SRussell King {
160810544570SRussell King (Oracle) bool using_mac_select_pcs = false;
16099525ae83SRussell King struct phylink *pl;
16109525ae83SRussell King int ret;
16119525ae83SRussell King
1612de5c9bf4SRussell King (Oracle) /* Validate the supplied configuration */
1613de5c9bf4SRussell King (Oracle) if (phy_interface_empty(config->supported_interfaces)) {
1614de5c9bf4SRussell King (Oracle) dev_err(config->dev,
1615de5c9bf4SRussell King (Oracle) "phylink: error: empty supported_interfaces\n");
1616de5c9bf4SRussell King (Oracle) return ERR_PTR(-EINVAL);
1617de5c9bf4SRussell King (Oracle) }
1618de5c9bf4SRussell King (Oracle)
1619d1e86325SRussell King (Oracle) if (mac_ops->mac_select_pcs &&
162010544570SRussell King (Oracle) mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) !=
162110544570SRussell King (Oracle) ERR_PTR(-EOPNOTSUPP))
162210544570SRussell King (Oracle) using_mac_select_pcs = true;
162310544570SRussell King (Oracle)
16249525ae83SRussell King pl = kzalloc(sizeof(*pl), GFP_KERNEL);
16259525ae83SRussell King if (!pl)
16269525ae83SRussell King return ERR_PTR(-ENOMEM);
16279525ae83SRussell King
16289525ae83SRussell King mutex_init(&pl->state_mutex);
16299525ae83SRussell King INIT_WORK(&pl->resolve, phylink_resolve);
163044cc27e4SIoana Ciornei
163144cc27e4SIoana Ciornei pl->config = config;
163244cc27e4SIoana Ciornei if (config->type == PHYLINK_NETDEV) {
163344cc27e4SIoana Ciornei pl->netdev = to_net_dev(config->dev);
1634*6d0bbeafSKlaus Kudielka netif_carrier_off(pl->netdev);
163543de6195SIoana Ciornei } else if (config->type == PHYLINK_DEV) {
163643de6195SIoana Ciornei pl->dev = config->dev;
163744cc27e4SIoana Ciornei } else {
163844cc27e4SIoana Ciornei kfree(pl);
163944cc27e4SIoana Ciornei return ERR_PTR(-EINVAL);
164044cc27e4SIoana Ciornei }
164144cc27e4SIoana Ciornei
164210544570SRussell King (Oracle) pl->using_mac_select_pcs = using_mac_select_pcs;
16439525ae83SRussell King pl->phy_state.interface = iface;
16449525ae83SRussell King pl->link_interface = iface;
16454be11ef0SFlorian Fainelli if (iface == PHY_INTERFACE_MODE_MOCA)
16464be11ef0SFlorian Fainelli pl->link_port = PORT_BNC;
16474be11ef0SFlorian Fainelli else
16489525ae83SRussell King pl->link_port = PORT_MII;
16499525ae83SRussell King pl->link_config.interface = iface;
16509525ae83SRussell King pl->link_config.pause = MLO_PAUSE_AN;
16519525ae83SRussell King pl->link_config.speed = SPEED_UNKNOWN;
16529525ae83SRussell King pl->link_config.duplex = DUPLEX_UNKNOWN;
165390ef0a7bSRussell King (Oracle) pl->pcs_state = PCS_STATE_DOWN;
1654e7765d63SRussell King pl->mac_ops = mac_ops;
16559525ae83SRussell King __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
16569cd00a8aSRussell King timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
16579525ae83SRussell King
16589525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
16599525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported);
16609525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config);
16619525ae83SRussell King
16628fa7b9b6SRussell King ret = phylink_parse_mode(pl, fwnode);
16639525ae83SRussell King if (ret < 0) {
16649525ae83SRussell King kfree(pl);
16659525ae83SRussell King return ERR_PTR(ret);
16669525ae83SRussell King }
16679525ae83SRussell King
166824cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
16698fa7b9b6SRussell King ret = phylink_parse_fixedlink(pl, fwnode);
16709525ae83SRussell King if (ret < 0) {
16719525ae83SRussell King kfree(pl);
16729525ae83SRussell King return ERR_PTR(ret);
16739525ae83SRussell King }
16749525ae83SRussell King }
16759525ae83SRussell King
167624cf0e69SRussell King pl->cur_link_an_mode = pl->cfg_link_an_mode;
167724cf0e69SRussell King
16788fa7b9b6SRussell King ret = phylink_register_sfp(pl, fwnode);
1679ce0aa27fSRussell King if (ret < 0) {
1680ce0aa27fSRussell King kfree(pl);
1681ce0aa27fSRussell King return ERR_PTR(ret);
1682ce0aa27fSRussell King }
1683ce0aa27fSRussell King
16849525ae83SRussell King return pl;
16859525ae83SRussell King }
16869525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_create);
16879525ae83SRussell King
16887137e18fSRussell King /**
16898796c892SRussell King * phylink_destroy() - cleanup and destroy the phylink instance
16908796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
16918796c892SRussell King *
16928796c892SRussell King * Destroy a phylink instance. Any PHY that has been attached must have been
16938796c892SRussell King * cleaned up via phylink_disconnect_phy() prior to calling this function.
1694269a6b5fSRussell King *
1695269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function.
16968796c892SRussell King */
phylink_destroy(struct phylink * pl)16979525ae83SRussell King void phylink_destroy(struct phylink *pl)
16989525ae83SRussell King {
1699727b3668SRussell King sfp_bus_del_upstream(pl->sfp_bus);
17007b3b0e89SRussell King if (pl->link_gpio)
1701daab3349SFlorian Fainelli gpiod_put(pl->link_gpio);
1702ce0aa27fSRussell King
17039525ae83SRussell King cancel_work_sync(&pl->resolve);
17049525ae83SRussell King kfree(pl);
17059525ae83SRussell King }
17069525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_destroy);
17079525ae83SRussell King
1708653a1809SMichael Sit Wei Hong /**
1709653a1809SMichael Sit Wei Hong * phylink_expects_phy() - Determine if phylink expects a phy to be attached
1710653a1809SMichael Sit Wei Hong * @pl: a pointer to a &struct phylink returned from phylink_create()
1711653a1809SMichael Sit Wei Hong *
1712653a1809SMichael Sit Wei Hong * When using fixed-link mode, or in-band mode with 1000base-X or 2500base-X,
1713653a1809SMichael Sit Wei Hong * no PHY is needed.
1714653a1809SMichael Sit Wei Hong *
1715653a1809SMichael Sit Wei Hong * Returns true if phylink will be expecting a PHY.
1716653a1809SMichael Sit Wei Hong */
phylink_expects_phy(struct phylink * pl)1717653a1809SMichael Sit Wei Hong bool phylink_expects_phy(struct phylink *pl)
1718653a1809SMichael Sit Wei Hong {
1719653a1809SMichael Sit Wei Hong if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
1720653a1809SMichael Sit Wei Hong (pl->cfg_link_an_mode == MLO_AN_INBAND &&
1721653a1809SMichael Sit Wei Hong phy_interface_mode_is_8023z(pl->link_config.interface)))
1722653a1809SMichael Sit Wei Hong return false;
1723653a1809SMichael Sit Wei Hong return true;
1724653a1809SMichael Sit Wei Hong }
1725653a1809SMichael Sit Wei Hong EXPORT_SYMBOL_GPL(phylink_expects_phy);
1726653a1809SMichael Sit Wei Hong
phylink_phy_change(struct phy_device * phydev,bool up)1727a307593aSDoug Berger static void phylink_phy_change(struct phy_device *phydev, bool up)
17289525ae83SRussell King {
17299525ae83SRussell King struct phylink *pl = phydev->phylink;
173033faac8eSRussell King bool tx_pause, rx_pause;
173133faac8eSRussell King
173233faac8eSRussell King phy_get_pause(phydev, &tx_pause, &rx_pause);
17339525ae83SRussell King
17349525ae83SRussell King mutex_lock(&pl->state_mutex);
17359525ae83SRussell King pl->phy_state.speed = phydev->speed;
17369525ae83SRussell King pl->phy_state.duplex = phydev->duplex;
1737ae0e4bb2SSean Anderson pl->phy_state.rate_matching = phydev->rate_matching;
17389525ae83SRussell King pl->phy_state.pause = MLO_PAUSE_NONE;
173933faac8eSRussell King if (tx_pause)
174033faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_TX;
174133faac8eSRussell King if (rx_pause)
174233faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_RX;
17439525ae83SRussell King pl->phy_state.interface = phydev->interface;
17449525ae83SRussell King pl->phy_state.link = up;
17459525ae83SRussell King mutex_unlock(&pl->state_mutex);
17469525ae83SRussell King
17479525ae83SRussell King phylink_run_resolve(pl);
17489525ae83SRussell King
1749ae0e4bb2SSean Anderson phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s\n", up ? "up" : "down",
17509525ae83SRussell King phy_modes(phydev->interface),
17519525ae83SRussell King phy_speed_to_str(phydev->speed),
1752d34869b4SRussell King (Oracle) phy_duplex_to_str(phydev->duplex),
1753ae0e4bb2SSean Anderson phy_rate_matching_to_str(phydev->rate_matching),
1754d34869b4SRussell King (Oracle) phylink_pause_to_str(pl->phy_state.pause));
17559525ae83SRussell King }
17569525ae83SRussell King
phylink_bringup_phy(struct phylink * pl,struct phy_device * phy,phy_interface_t interface)1757e45d1f52SRussell King static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
1758e45d1f52SRussell King phy_interface_t interface)
17599525ae83SRussell King {
17609525ae83SRussell King struct phylink_link_state config;
17619525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
1762e27f1787SFlorian Fainelli char *irq_str;
17639525ae83SRussell King int ret;
17649525ae83SRussell King
17659525ae83SRussell King /*
17669525ae83SRussell King * This is the new way of dealing with flow control for PHYs,
17679525ae83SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
17689525ae83SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except
17699525ae83SRussell King * using our validate call to the MAC, we rely upon the MAC
17709525ae83SRussell King * clearing the bits from both supported and advertising fields.
17719525ae83SRussell King */
1772725ea4bfSRussell King phy_support_asym_pause(phy);
1773725ea4bfSRussell King
1774725ea4bfSRussell King memset(&config, 0, sizeof(config));
1775725ea4bfSRussell King linkmode_copy(supported, phy->supported);
1776725ea4bfSRussell King linkmode_copy(config.advertising, phy->advertising);
1777df3f57acSRussell King
17787642cc28SRussell King (Oracle) /* Check whether we would use rate matching for the proposed interface
17797642cc28SRussell King (Oracle) * mode.
1780df3f57acSRussell King */
17817642cc28SRussell King (Oracle) config.rate_matching = phy_get_rate_matching(phy, interface);
17827642cc28SRussell King (Oracle)
17837642cc28SRussell King (Oracle) /* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
17847642cc28SRussell King (Oracle) * 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
17857642cc28SRussell King (Oracle) * For some interface modes (e.g. RXAUI, XAUI and USXGMII) switching
17867642cc28SRussell King (Oracle) * their Serdes is either unnecessary or not reasonable.
17877642cc28SRussell King (Oracle) *
17887642cc28SRussell King (Oracle) * For these which switch interface modes, we really need to know which
17897642cc28SRussell King (Oracle) * interface modes the PHY supports to properly work out which ethtool
17907642cc28SRussell King (Oracle) * linkmodes can be supported. For now, as a work-around, we validate
17917642cc28SRussell King (Oracle) * against all interface modes, which may lead to more ethtool link
17927642cc28SRussell King (Oracle) * modes being advertised than are actually supported.
17937642cc28SRussell King (Oracle) */
17947642cc28SRussell King (Oracle) if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
1795df3f57acSRussell King interface != PHY_INTERFACE_MODE_RXAUI &&
1796df3f57acSRussell King interface != PHY_INTERFACE_MODE_XAUI &&
1797df3f57acSRussell King interface != PHY_INTERFACE_MODE_USXGMII)
1798df3f57acSRussell King config.interface = PHY_INTERFACE_MODE_NA;
1799df3f57acSRussell King else
1800e45d1f52SRussell King config.interface = interface;
18019525ae83SRussell King
18029525ae83SRussell King ret = phylink_validate(pl, supported, &config);
180320d8bb0dSHauke Mehrtens if (ret) {
1804ab1198e5SRussell King (Oracle) phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
180520d8bb0dSHauke Mehrtens phy_modes(config.interface),
180620d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported,
180720d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising,
1808ab1198e5SRussell King (Oracle) ERR_PTR(ret));
18099525ae83SRussell King return ret;
181020d8bb0dSHauke Mehrtens }
18119525ae83SRussell King
18129525ae83SRussell King phy->phylink = pl;
18139525ae83SRussell King phy->phy_link_change = phylink_phy_change;
18149525ae83SRussell King
1815e27f1787SFlorian Fainelli irq_str = phy_attached_info_irq(phy);
181617091180SIoana Ciornei phylink_info(pl,
1817e27f1787SFlorian Fainelli "PHY [%s] driver [%s] (irq=%s)\n",
1818e27f1787SFlorian Fainelli dev_name(&phy->mdio.dev), phy->drv->name, irq_str);
1819e27f1787SFlorian Fainelli kfree(irq_str);
18209525ae83SRussell King
18219525ae83SRussell King mutex_lock(&phy->lock);
18229525ae83SRussell King mutex_lock(&pl->state_mutex);
18239525ae83SRussell King pl->phydev = phy;
1824e45d1f52SRussell King pl->phy_state.interface = interface;
182597fec51fSRussell King pl->phy_state.pause = MLO_PAUSE_NONE;
182697fec51fSRussell King pl->phy_state.speed = SPEED_UNKNOWN;
182797fec51fSRussell King pl->phy_state.duplex = DUPLEX_UNKNOWN;
1828ae0e4bb2SSean Anderson pl->phy_state.rate_matching = RATE_MATCH_NONE;
18299525ae83SRussell King linkmode_copy(pl->supported, supported);
18309525ae83SRussell King linkmode_copy(pl->link_config.advertising, config.advertising);
18319525ae83SRussell King
1832cc1122b0SColin Ian King /* Restrict the phy advertisement according to the MAC support. */
18333c1bcc86SAndrew Lunn linkmode_copy(phy->advertising, config.advertising);
18349525ae83SRussell King mutex_unlock(&pl->state_mutex);
18359525ae83SRussell King mutex_unlock(&phy->lock);
18369525ae83SRussell King
183717091180SIoana Ciornei phylink_dbg(pl,
1838a18e6521SRussell King (Oracle) "phy: %s setting supported %*pb advertising %*pb\n",
1839a18e6521SRussell King (Oracle) phy_modes(interface),
18409525ae83SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported,
18413c1bcc86SAndrew Lunn __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);
18429525ae83SRussell King
1843434a4315SHeiner Kallweit if (phy_interrupt_is_valid(phy))
1844434a4315SHeiner Kallweit phy_request_interrupt(phy);
18459525ae83SRussell King
184696de900aSShenwei Wang if (pl->config->mac_managed_pm)
184796de900aSShenwei Wang phy->mac_managed_pm = true;
184896de900aSShenwei Wang
18499525ae83SRussell King return 0;
18509525ae83SRussell King }
18519525ae83SRussell King
phylink_attach_phy(struct phylink * pl,struct phy_device * phy,phy_interface_t interface)1852938d44c2SRussell King static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
18537e418375SBaruch Siach phy_interface_t interface)
18547e418375SBaruch Siach {
185524cf0e69SRussell King if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
185624cf0e69SRussell King (pl->cfg_link_an_mode == MLO_AN_INBAND &&
185731eb8907SMarek Behún phy_interface_mode_is_8023z(interface) && !pl->sfp_bus)))
18587e418375SBaruch Siach return -EINVAL;
18597e418375SBaruch Siach
18607e418375SBaruch Siach if (pl->phydev)
18617e418375SBaruch Siach return -EBUSY;
18627e418375SBaruch Siach
1863938d44c2SRussell King return phy_attach_direct(pl->netdev, phy, 0, interface);
18647e418375SBaruch Siach }
18657e418375SBaruch Siach
18668796c892SRussell King /**
18678796c892SRussell King * phylink_connect_phy() - connect a PHY to the phylink instance
18688796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
18698796c892SRussell King * @phy: a pointer to a &struct phy_device.
18708796c892SRussell King *
18718796c892SRussell King * Connect @phy to the phylink instance specified by @pl by calling
18728796c892SRussell King * phy_attach_direct(). Configure the @phy according to the MAC driver's
18738796c892SRussell King * capabilities, start the PHYLIB state machine and enable any interrupts
18748796c892SRussell King * that the PHY supports.
18758796c892SRussell King *
18768796c892SRussell King * This updates the phylink's ethtool supported and advertising link mode
18778796c892SRussell King * masks.
18788796c892SRussell King *
18798796c892SRussell King * Returns 0 on success or a negative errno.
18808796c892SRussell King */
phylink_connect_phy(struct phylink * pl,struct phy_device * phy)18819525ae83SRussell King int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
18829525ae83SRussell King {
1883938d44c2SRussell King int ret;
1884938d44c2SRussell King
18854904b6eaSFlorian Fainelli /* Use PHY device/driver interface */
18864904b6eaSFlorian Fainelli if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
18874904b6eaSFlorian Fainelli pl->link_interface = phy->interface;
18884904b6eaSFlorian Fainelli pl->link_config.interface = pl->link_interface;
18894904b6eaSFlorian Fainelli }
18904904b6eaSFlorian Fainelli
1891938d44c2SRussell King ret = phylink_attach_phy(pl, phy, pl->link_interface);
1892938d44c2SRussell King if (ret < 0)
1893938d44c2SRussell King return ret;
1894938d44c2SRussell King
1895e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, pl->link_config.interface);
1896938d44c2SRussell King if (ret)
1897938d44c2SRussell King phy_detach(phy);
1898938d44c2SRussell King
1899938d44c2SRussell King return ret;
19009525ae83SRussell King }
19019525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_connect_phy);
19029525ae83SRussell King
19038796c892SRussell King /**
19048796c892SRussell King * phylink_of_phy_connect() - connect the PHY specified in the DT mode.
19058796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
19068796c892SRussell King * @dn: a pointer to a &struct device_node.
19070a62964cSFlorian Fainelli * @flags: PHY-specific flags to communicate to the PHY device driver
19088796c892SRussell King *
19098796c892SRussell King * Connect the phy specified in the device node @dn to the phylink instance
19108796c892SRussell King * specified by @pl. Actions specified in phylink_connect_phy() will be
19118796c892SRussell King * performed.
19128796c892SRussell King *
19138796c892SRussell King * Returns 0 on success or a negative errno.
19148796c892SRussell King */
phylink_of_phy_connect(struct phylink * pl,struct device_node * dn,u32 flags)19150a62964cSFlorian Fainelli int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn,
19160a62964cSFlorian Fainelli u32 flags)
19179525ae83SRussell King {
1918423e6e89SCalvin Johnson return phylink_fwnode_phy_connect(pl, of_fwnode_handle(dn), flags);
19199525ae83SRussell King }
19209525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_of_phy_connect);
19219525ae83SRussell King
19228796c892SRussell King /**
192325396f68SCalvin Johnson * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode.
192425396f68SCalvin Johnson * @pl: a pointer to a &struct phylink returned from phylink_create()
192525396f68SCalvin Johnson * @fwnode: a pointer to a &struct fwnode_handle.
192625396f68SCalvin Johnson * @flags: PHY-specific flags to communicate to the PHY device driver
192725396f68SCalvin Johnson *
192825396f68SCalvin Johnson * Connect the phy specified @fwnode to the phylink instance specified
192925396f68SCalvin Johnson * by @pl.
193025396f68SCalvin Johnson *
193125396f68SCalvin Johnson * Returns 0 on success or a negative errno.
193225396f68SCalvin Johnson */
phylink_fwnode_phy_connect(struct phylink * pl,const struct fwnode_handle * fwnode,u32 flags)193325396f68SCalvin Johnson int phylink_fwnode_phy_connect(struct phylink *pl,
1934a0b79553SRussell King (Oracle) const struct fwnode_handle *fwnode,
193525396f68SCalvin Johnson u32 flags)
193625396f68SCalvin Johnson {
193725396f68SCalvin Johnson struct fwnode_handle *phy_fwnode;
193825396f68SCalvin Johnson struct phy_device *phy_dev;
193925396f68SCalvin Johnson int ret;
194025396f68SCalvin Johnson
194125396f68SCalvin Johnson /* Fixed links and 802.3z are handled without needing a PHY */
194225396f68SCalvin Johnson if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
194325396f68SCalvin Johnson (pl->cfg_link_an_mode == MLO_AN_INBAND &&
194425396f68SCalvin Johnson phy_interface_mode_is_8023z(pl->link_interface)))
194525396f68SCalvin Johnson return 0;
194625396f68SCalvin Johnson
194725396f68SCalvin Johnson phy_fwnode = fwnode_get_phy_node(fwnode);
194825396f68SCalvin Johnson if (IS_ERR(phy_fwnode)) {
194925396f68SCalvin Johnson if (pl->cfg_link_an_mode == MLO_AN_PHY)
195025396f68SCalvin Johnson return -ENODEV;
195125396f68SCalvin Johnson return 0;
195225396f68SCalvin Johnson }
195325396f68SCalvin Johnson
195425396f68SCalvin Johnson phy_dev = fwnode_phy_find_device(phy_fwnode);
195525396f68SCalvin Johnson /* We're done with the phy_node handle */
195625396f68SCalvin Johnson fwnode_handle_put(phy_fwnode);
195725396f68SCalvin Johnson if (!phy_dev)
195825396f68SCalvin Johnson return -ENODEV;
195925396f68SCalvin Johnson
1960a18e6521SRussell King (Oracle) /* Use PHY device/driver interface */
1961a18e6521SRussell King (Oracle) if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
1962a18e6521SRussell King (Oracle) pl->link_interface = phy_dev->interface;
1963a18e6521SRussell King (Oracle) pl->link_config.interface = pl->link_interface;
1964a18e6521SRussell King (Oracle) }
1965a18e6521SRussell King (Oracle)
196625396f68SCalvin Johnson ret = phy_attach_direct(pl->netdev, phy_dev, flags,
196725396f68SCalvin Johnson pl->link_interface);
196825396f68SCalvin Johnson phy_device_free(phy_dev);
1969ce93fdb5SClément Léger if (ret)
197025396f68SCalvin Johnson return ret;
197125396f68SCalvin Johnson
197225396f68SCalvin Johnson ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
197325396f68SCalvin Johnson if (ret)
197425396f68SCalvin Johnson phy_detach(phy_dev);
197525396f68SCalvin Johnson
197625396f68SCalvin Johnson return ret;
197725396f68SCalvin Johnson }
197825396f68SCalvin Johnson EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect);
197925396f68SCalvin Johnson
198025396f68SCalvin Johnson /**
19818796c892SRussell King * phylink_disconnect_phy() - disconnect any PHY attached to the phylink
19828796c892SRussell King * instance.
19838796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
19848796c892SRussell King *
19858796c892SRussell King * Disconnect any current PHY from the phylink instance described by @pl.
19868796c892SRussell King */
phylink_disconnect_phy(struct phylink * pl)19879525ae83SRussell King void phylink_disconnect_phy(struct phylink *pl)
19889525ae83SRussell King {
19899525ae83SRussell King struct phy_device *phy;
19909525ae83SRussell King
19918b874514SRussell King ASSERT_RTNL();
19929525ae83SRussell King
19939525ae83SRussell King phy = pl->phydev;
19949525ae83SRussell King if (phy) {
19959525ae83SRussell King mutex_lock(&phy->lock);
19969525ae83SRussell King mutex_lock(&pl->state_mutex);
19979525ae83SRussell King pl->phydev = NULL;
19989525ae83SRussell King mutex_unlock(&pl->state_mutex);
19999525ae83SRussell King mutex_unlock(&phy->lock);
20009525ae83SRussell King flush_work(&pl->resolve);
20019525ae83SRussell King
20029525ae83SRussell King phy_disconnect(phy);
20039525ae83SRussell King }
20049525ae83SRussell King }
20059525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
20069525ae83SRussell King
phylink_link_changed(struct phylink * pl,bool up,const char * what)200724699cc1SRussell King (Oracle) static void phylink_link_changed(struct phylink *pl, bool up, const char *what)
200824699cc1SRussell King (Oracle) {
200924699cc1SRussell King (Oracle) if (!up)
201024699cc1SRussell King (Oracle) pl->mac_link_dropped = true;
201124699cc1SRussell King (Oracle) phylink_run_resolve(pl);
201224699cc1SRussell King (Oracle) phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
201324699cc1SRussell King (Oracle) }
201424699cc1SRussell King (Oracle)
20158796c892SRussell King /**
20168796c892SRussell King * phylink_mac_change() - notify phylink of a change in MAC state
20178796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
20188796c892SRussell King * @up: indicates whether the link is currently up.
20198796c892SRussell King *
20208796c892SRussell King * The MAC driver should call this driver when the state of its link
20218796c892SRussell King * changes (eg, link failure, new negotiation results, etc.)
20228796c892SRussell King */
phylink_mac_change(struct phylink * pl,bool up)20239525ae83SRussell King void phylink_mac_change(struct phylink *pl, bool up)
20249525ae83SRussell King {
202524699cc1SRussell King (Oracle) phylink_link_changed(pl, up, "mac");
20269525ae83SRussell King }
20279525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mac_change);
20289525ae83SRussell King
202924699cc1SRussell King (Oracle) /**
203024699cc1SRussell King (Oracle) * phylink_pcs_change() - notify phylink of a change to PCS link state
203124699cc1SRussell King (Oracle) * @pcs: pointer to &struct phylink_pcs
203224699cc1SRussell King (Oracle) * @up: indicates whether the link is currently up.
203324699cc1SRussell King (Oracle) *
203424699cc1SRussell King (Oracle) * The PCS driver should call this when the state of its link changes
203524699cc1SRussell King (Oracle) * (e.g. link failure, new negotiation results, etc.) Note: it should
203624699cc1SRussell King (Oracle) * not determine "up" by reading the BMSR. If in doubt about the link
203724699cc1SRussell King (Oracle) * state at interrupt time, then pass true if pcs_get_state() returns
203824699cc1SRussell King (Oracle) * the latched link-down state, otherwise pass false.
203924699cc1SRussell King (Oracle) */
phylink_pcs_change(struct phylink_pcs * pcs,bool up)204024699cc1SRussell King (Oracle) void phylink_pcs_change(struct phylink_pcs *pcs, bool up)
204124699cc1SRussell King (Oracle) {
204224699cc1SRussell King (Oracle) struct phylink *pl = pcs->phylink;
204324699cc1SRussell King (Oracle)
204424699cc1SRussell King (Oracle) if (pl)
204524699cc1SRussell King (Oracle) phylink_link_changed(pl, up, "pcs");
204624699cc1SRussell King (Oracle) }
204724699cc1SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_pcs_change);
204824699cc1SRussell King (Oracle)
phylink_link_handler(int irq,void * data)20497b3b0e89SRussell King static irqreturn_t phylink_link_handler(int irq, void *data)
20507b3b0e89SRussell King {
20517b3b0e89SRussell King struct phylink *pl = data;
20527b3b0e89SRussell King
20537b3b0e89SRussell King phylink_run_resolve(pl);
20547b3b0e89SRussell King
20557b3b0e89SRussell King return IRQ_HANDLED;
20567b3b0e89SRussell King }
20577b3b0e89SRussell King
20588796c892SRussell King /**
20598796c892SRussell King * phylink_start() - start a phylink instance
20608796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
20618796c892SRussell King *
20628796c892SRussell King * Start the phylink instance specified by @pl, configuring the MAC for the
20638796c892SRussell King * desired link mode(s) and negotiation style. This should be called from the
20648796c892SRussell King * network device driver's &struct net_device_ops ndo_open() method.
20658796c892SRussell King */
phylink_start(struct phylink * pl)20669525ae83SRussell King void phylink_start(struct phylink *pl)
20679525ae83SRussell King {
20685c05c1dbSRussell King bool poll = false;
20695c05c1dbSRussell King
20708b874514SRussell King ASSERT_RTNL();
20719525ae83SRussell King
207217091180SIoana Ciornei phylink_info(pl, "configuring for %s/%s link mode\n",
207324cf0e69SRussell King phylink_an_mode_str(pl->cur_link_an_mode),
20749525ae83SRussell King phy_modes(pl->link_config.interface));
20759525ae83SRussell King
2076aeeb2e8fSAntoine Tenart /* Always set the carrier off */
207743de6195SIoana Ciornei if (pl->netdev)
2078aeeb2e8fSAntoine Tenart netif_carrier_off(pl->netdev);
2079aeeb2e8fSAntoine Tenart
208090ef0a7bSRussell King (Oracle) pl->pcs_state = PCS_STATE_STARTING;
208190ef0a7bSRussell King (Oracle)
20829525ae83SRussell King /* Apply the link configuration to the MAC when starting. This allows
20839525ae83SRussell King * a fixed-link to start with the correct parameters, and also
2084cc1122b0SColin Ian King * ensures that we set the appropriate advertisement for Serdes links.
20854c0d6d3aSRussell King *
20864c0d6d3aSRussell King * Restart autonegotiation if using 802.3z to ensure that the link
208785b43945SRussell King * parameters are properly negotiated. This is necessary for DSA
208885b43945SRussell King * switches using 802.3z negotiation to ensure they see our modes.
208985b43945SRussell King */
20904c0d6d3aSRussell King phylink_mac_initial_config(pl, true);
209185b43945SRussell King
209290ef0a7bSRussell King (Oracle) pl->pcs_state = PCS_STATE_STARTED;
209390ef0a7bSRussell King (Oracle)
2094aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_STOPPED);
20959525ae83SRussell King
209624cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
20977b3b0e89SRussell King int irq = gpiod_to_irq(pl->link_gpio);
20987b3b0e89SRussell King
20997b3b0e89SRussell King if (irq > 0) {
21007b3b0e89SRussell King if (!request_irq(irq, phylink_link_handler,
21017b3b0e89SRussell King IRQF_TRIGGER_RISING |
21027b3b0e89SRussell King IRQF_TRIGGER_FALLING,
21037b3b0e89SRussell King "netdev link", pl))
21047b3b0e89SRussell King pl->link_irq = irq;
21057b3b0e89SRussell King else
21067b3b0e89SRussell King irq = 0;
21077b3b0e89SRussell King }
21087b3b0e89SRussell King if (irq <= 0)
21095c05c1dbSRussell King poll = true;
21107b3b0e89SRussell King }
21115c05c1dbSRussell King
211290ef0a7bSRussell King (Oracle) if (pl->cfg_link_an_mode == MLO_AN_FIXED)
21135c05c1dbSRussell King poll |= pl->config->poll_fixed_state;
211490ef0a7bSRussell King (Oracle)
21155c05c1dbSRussell King if (poll)
21169cd00a8aSRussell King mod_timer(&pl->link_poll, jiffies + HZ);
21179525ae83SRussell King if (pl->phydev)
21189525ae83SRussell King phy_start(pl->phydev);
2119c7fa7f56SArseny Solokha if (pl->sfp_bus)
2120c7fa7f56SArseny Solokha sfp_upstream_start(pl->sfp_bus);
21219525ae83SRussell King }
21229525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_start);
21239525ae83SRussell King
21248796c892SRussell King /**
21258796c892SRussell King * phylink_stop() - stop a phylink instance
21268796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
21278796c892SRussell King *
21288796c892SRussell King * Stop the phylink instance specified by @pl. This should be called from the
21298796c892SRussell King * network device driver's &struct net_device_ops ndo_stop() method. The
21308796c892SRussell King * network device's carrier state should not be changed prior to calling this
21318796c892SRussell King * function.
2132f9749365SRussell King (Oracle) *
2133f9749365SRussell King (Oracle) * This will synchronously bring down the link if the link is not already
2134f9749365SRussell King (Oracle) * down (in other words, it will trigger a mac_link_down() method call.)
21358796c892SRussell King */
phylink_stop(struct phylink * pl)21369525ae83SRussell King void phylink_stop(struct phylink *pl)
21379525ae83SRussell King {
21388b874514SRussell King ASSERT_RTNL();
21399525ae83SRussell King
2140ce0aa27fSRussell King if (pl->sfp_bus)
2141ce0aa27fSRussell King sfp_upstream_stop(pl->sfp_bus);
2142c7fa7f56SArseny Solokha if (pl->phydev)
2143c7fa7f56SArseny Solokha phy_stop(pl->phydev);
21449cd00a8aSRussell King del_timer_sync(&pl->link_poll);
21457b3b0e89SRussell King if (pl->link_irq) {
21467b3b0e89SRussell King free_irq(pl->link_irq, pl);
21477b3b0e89SRussell King pl->link_irq = 0;
21487b3b0e89SRussell King }
21499525ae83SRussell King
215087454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
215190ef0a7bSRussell King (Oracle)
215290ef0a7bSRussell King (Oracle) pl->pcs_state = PCS_STATE_DOWN;
215390ef0a7bSRussell King (Oracle)
215490ef0a7bSRussell King (Oracle) phylink_pcs_disable(pl->pcs);
21559525ae83SRussell King }
21569525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_stop);
21579525ae83SRussell King
21588796c892SRussell King /**
2159f9749365SRussell King (Oracle) * phylink_suspend() - handle a network device suspend event
2160f9749365SRussell King (Oracle) * @pl: a pointer to a &struct phylink returned from phylink_create()
2161f9749365SRussell King (Oracle) * @mac_wol: true if the MAC needs to receive packets for Wake-on-Lan
2162f9749365SRussell King (Oracle) *
2163f9749365SRussell King (Oracle) * Handle a network device suspend event. There are several cases:
2164c35e8de7SYanteng Si *
2165f9749365SRussell King (Oracle) * - If Wake-on-Lan is not active, we can bring down the link between
2166f9749365SRussell King (Oracle) * the MAC and PHY by calling phylink_stop().
2167f9749365SRussell King (Oracle) * - If Wake-on-Lan is active, and being handled only by the PHY, we
2168f9749365SRussell King (Oracle) * can also bring down the link between the MAC and PHY.
2169f9749365SRussell King (Oracle) * - If Wake-on-Lan is active, but being handled by the MAC, the MAC
2170f9749365SRussell King (Oracle) * still needs to receive packets, so we can not bring the link down.
2171f9749365SRussell King (Oracle) */
phylink_suspend(struct phylink * pl,bool mac_wol)2172f9749365SRussell King (Oracle) void phylink_suspend(struct phylink *pl, bool mac_wol)
2173f9749365SRussell King (Oracle) {
2174f9749365SRussell King (Oracle) ASSERT_RTNL();
2175f9749365SRussell King (Oracle)
2176f9749365SRussell King (Oracle) if (mac_wol && (!pl->netdev || pl->netdev->wol_enabled)) {
2177f9749365SRussell King (Oracle) /* Wake-on-Lan enabled, MAC handling */
2178f9749365SRussell King (Oracle) mutex_lock(&pl->state_mutex);
2179f9749365SRussell King (Oracle)
2180f9749365SRussell King (Oracle) /* Stop the resolver bringing the link up */
2181f9749365SRussell King (Oracle) __set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
2182f9749365SRussell King (Oracle)
2183f9749365SRussell King (Oracle) /* Disable the carrier, to prevent transmit timeouts,
2184f9749365SRussell King (Oracle) * but one would hope all packets have been sent. This
2185f9749365SRussell King (Oracle) * also means phylink_resolve() will do nothing.
2186f9749365SRussell King (Oracle) */
2187cbcca2e3SRussell King (Oracle) if (pl->netdev)
2188f9749365SRussell King (Oracle) netif_carrier_off(pl->netdev);
2189cbcca2e3SRussell King (Oracle) else
2190cbcca2e3SRussell King (Oracle) pl->old_link_state = false;
2191f9749365SRussell King (Oracle)
2192f9749365SRussell King (Oracle) /* We do not call mac_link_down() here as we want the
2193f9749365SRussell King (Oracle) * link to remain up to receive the WoL packets.
2194f9749365SRussell King (Oracle) */
2195f9749365SRussell King (Oracle) mutex_unlock(&pl->state_mutex);
2196f9749365SRussell King (Oracle) } else {
2197f9749365SRussell King (Oracle) phylink_stop(pl);
2198f9749365SRussell King (Oracle) }
2199f9749365SRussell King (Oracle) }
2200f9749365SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_suspend);
2201f9749365SRussell King (Oracle)
2202f9749365SRussell King (Oracle) /**
2203f9749365SRussell King (Oracle) * phylink_resume() - handle a network device resume event
2204f9749365SRussell King (Oracle) * @pl: a pointer to a &struct phylink returned from phylink_create()
2205f9749365SRussell King (Oracle) *
2206f9749365SRussell King (Oracle) * Undo the effects of phylink_suspend(), returning the link to an
2207f9749365SRussell King (Oracle) * operational state.
2208f9749365SRussell King (Oracle) */
phylink_resume(struct phylink * pl)2209f9749365SRussell King (Oracle) void phylink_resume(struct phylink *pl)
2210f9749365SRussell King (Oracle) {
2211f9749365SRussell King (Oracle) ASSERT_RTNL();
2212f9749365SRussell King (Oracle)
2213f9749365SRussell King (Oracle) if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) {
2214f9749365SRussell King (Oracle) /* Wake-on-Lan enabled, MAC handling */
2215f9749365SRussell King (Oracle)
2216f9749365SRussell King (Oracle) /* Call mac_link_down() so we keep the overall state balanced.
2217f9749365SRussell King (Oracle) * Do this under the state_mutex lock for consistency. This
2218f9749365SRussell King (Oracle) * will cause a "Link Down" message to be printed during
2219f9749365SRussell King (Oracle) * resume, which is harmless - the true link state will be
2220f9749365SRussell King (Oracle) * printed when we run a resolve.
2221f9749365SRussell King (Oracle) */
2222f9749365SRussell King (Oracle) mutex_lock(&pl->state_mutex);
2223f9749365SRussell King (Oracle) phylink_link_down(pl);
2224f9749365SRussell King (Oracle) mutex_unlock(&pl->state_mutex);
2225f9749365SRussell King (Oracle)
2226f9749365SRussell King (Oracle) /* Re-apply the link parameters so that all the settings get
2227f9749365SRussell King (Oracle) * restored to the MAC.
2228f9749365SRussell King (Oracle) */
2229f9749365SRussell King (Oracle) phylink_mac_initial_config(pl, true);
2230f9749365SRussell King (Oracle)
2231f9749365SRussell King (Oracle) /* Re-enable and re-resolve the link parameters */
2232aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_MAC_WOL);
2233f9749365SRussell King (Oracle) } else {
2234f9749365SRussell King (Oracle) phylink_start(pl);
2235f9749365SRussell King (Oracle) }
2236f9749365SRussell King (Oracle) }
2237f9749365SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_resume);
2238f9749365SRussell King (Oracle)
2239f9749365SRussell King (Oracle) /**
22408796c892SRussell King * phylink_ethtool_get_wol() - get the wake on lan parameters for the PHY
22418796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
22428796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo to hold the read parameters
22438796c892SRussell King *
22448796c892SRussell King * Read the wake on lan parameters from the PHY attached to the phylink
22458796c892SRussell King * instance specified by @pl. If no PHY is currently attached, report no
22468796c892SRussell King * support for wake on lan.
22478796c892SRussell King */
phylink_ethtool_get_wol(struct phylink * pl,struct ethtool_wolinfo * wol)22489525ae83SRussell King void phylink_ethtool_get_wol(struct phylink *pl, struct ethtool_wolinfo *wol)
22499525ae83SRussell King {
22508b874514SRussell King ASSERT_RTNL();
22519525ae83SRussell King
22529525ae83SRussell King wol->supported = 0;
22539525ae83SRussell King wol->wolopts = 0;
22549525ae83SRussell King
22559525ae83SRussell King if (pl->phydev)
22569525ae83SRussell King phy_ethtool_get_wol(pl->phydev, wol);
22579525ae83SRussell King }
22589525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_wol);
22599525ae83SRussell King
22608796c892SRussell King /**
22618796c892SRussell King * phylink_ethtool_set_wol() - set wake on lan parameters
22628796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
22638796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo for the desired parameters
22648796c892SRussell King *
22658796c892SRussell King * Set the wake on lan parameters for the PHY attached to the phylink
22668796c892SRussell King * instance specified by @pl. If no PHY is attached, returns %EOPNOTSUPP
22678796c892SRussell King * error.
22688796c892SRussell King *
22698796c892SRussell King * Returns zero on success or negative errno code.
22708796c892SRussell King */
phylink_ethtool_set_wol(struct phylink * pl,struct ethtool_wolinfo * wol)22719525ae83SRussell King int phylink_ethtool_set_wol(struct phylink *pl, struct ethtool_wolinfo *wol)
22729525ae83SRussell King {
22739525ae83SRussell King int ret = -EOPNOTSUPP;
22749525ae83SRussell King
22758b874514SRussell King ASSERT_RTNL();
22769525ae83SRussell King
22779525ae83SRussell King if (pl->phydev)
22789525ae83SRussell King ret = phy_ethtool_set_wol(pl->phydev, wol);
22799525ae83SRussell King
22809525ae83SRussell King return ret;
22819525ae83SRussell King }
22829525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_wol);
22839525ae83SRussell King
phylink_merge_link_mode(unsigned long * dst,const unsigned long * b)22849525ae83SRussell King static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b)
22859525ae83SRussell King {
22869525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask);
22879525ae83SRussell King
22889525ae83SRussell King linkmode_zero(mask);
22899525ae83SRussell King phylink_set_port_modes(mask);
22909525ae83SRussell King
22919525ae83SRussell King linkmode_and(dst, dst, mask);
22929525ae83SRussell King linkmode_or(dst, dst, b);
22939525ae83SRussell King }
22949525ae83SRussell King
phylink_get_ksettings(const struct phylink_link_state * state,struct ethtool_link_ksettings * kset)22959525ae83SRussell King static void phylink_get_ksettings(const struct phylink_link_state *state,
22969525ae83SRussell King struct ethtool_link_ksettings *kset)
22979525ae83SRussell King {
22989525ae83SRussell King phylink_merge_link_mode(kset->link_modes.advertising, state->advertising);
22999525ae83SRussell King linkmode_copy(kset->link_modes.lp_advertising, state->lp_advertising);
2300ae0e4bb2SSean Anderson if (kset->base.rate_matching == RATE_MATCH_NONE) {
23019525ae83SRussell King kset->base.speed = state->speed;
23029525ae83SRussell King kset->base.duplex = state->duplex;
2303ae0e4bb2SSean Anderson }
23044ee9b0dcSRussell King (Oracle) kset->base.autoneg = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
23054ee9b0dcSRussell King (Oracle) state->advertising) ?
23064ee9b0dcSRussell King (Oracle) AUTONEG_ENABLE : AUTONEG_DISABLE;
23079525ae83SRussell King }
23089525ae83SRussell King
23098796c892SRussell King /**
23108796c892SRussell King * phylink_ethtool_ksettings_get() - get the current link settings
23118796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
23128796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings to hold link settings
23138796c892SRussell King *
23148796c892SRussell King * Read the current link settings for the phylink instance specified by @pl.
23158796c892SRussell King * This will be the link settings read from the MAC, PHY or fixed link
23168796c892SRussell King * settings depending on the current negotiation mode.
23178796c892SRussell King */
phylink_ethtool_ksettings_get(struct phylink * pl,struct ethtool_link_ksettings * kset)23189525ae83SRussell King int phylink_ethtool_ksettings_get(struct phylink *pl,
23199525ae83SRussell King struct ethtool_link_ksettings *kset)
23209525ae83SRussell King {
23219525ae83SRussell King struct phylink_link_state link_state;
23229525ae83SRussell King
23238b874514SRussell King ASSERT_RTNL();
23249525ae83SRussell King
2325169d7a40SWenpeng Liang if (pl->phydev)
23269525ae83SRussell King phy_ethtool_ksettings_get(pl->phydev, kset);
2327169d7a40SWenpeng Liang else
23289525ae83SRussell King kset->base.port = pl->link_port;
23299525ae83SRussell King
23309525ae83SRussell King linkmode_copy(kset->link_modes.supported, pl->supported);
23319525ae83SRussell King
233224cf0e69SRussell King switch (pl->cur_link_an_mode) {
23339525ae83SRussell King case MLO_AN_FIXED:
23349525ae83SRussell King /* We are using fixed settings. Report these as the
23359525ae83SRussell King * current link settings - and note that these also
23369525ae83SRussell King * represent the supported speeds/duplex/pause modes.
23379525ae83SRussell King */
23389525ae83SRussell King phylink_get_fixed_state(pl, &link_state);
23399525ae83SRussell King phylink_get_ksettings(&link_state, kset);
23409525ae83SRussell King break;
23419525ae83SRussell King
234286a362c4SRussell King case MLO_AN_INBAND:
23439525ae83SRussell King /* If there is a phy attached, then use the reported
23449525ae83SRussell King * settings from the phy with no modification.
23459525ae83SRussell King */
23469525ae83SRussell King if (pl->phydev)
23479525ae83SRussell King break;
23489525ae83SRussell King
2349d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state);
23509525ae83SRussell King
23519525ae83SRussell King /* The MAC is reporting the link results from its own PCS
23529525ae83SRussell King * layer via in-band status. Report these as the current
23539525ae83SRussell King * link settings.
23549525ae83SRussell King */
23559525ae83SRussell King phylink_get_ksettings(&link_state, kset);
23569525ae83SRussell King break;
23579525ae83SRussell King }
23589525ae83SRussell King
23599525ae83SRussell King return 0;
23609525ae83SRussell King }
23619525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get);
23629525ae83SRussell King
23638796c892SRussell King /**
23648796c892SRussell King * phylink_ethtool_ksettings_set() - set the link settings
23658796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
23668796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings for the desired modes
23678796c892SRussell King */
phylink_ethtool_ksettings_set(struct phylink * pl,const struct ethtool_link_ksettings * kset)23689525ae83SRussell King int phylink_ethtool_ksettings_set(struct phylink *pl,
23699525ae83SRussell King const struct ethtool_link_ksettings *kset)
23709525ae83SRussell King {
237177316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
23729525ae83SRussell King struct phylink_link_state config;
2373c8cab719SRussell King const struct phy_setting *s;
23749525ae83SRussell King
23758b874514SRussell King ASSERT_RTNL();
23769525ae83SRussell King
237703c44a21SRussell King (Oracle) if (pl->phydev) {
237803c44a21SRussell King (Oracle) struct ethtool_link_ksettings phy_kset = *kset;
237903c44a21SRussell King (Oracle)
238003c44a21SRussell King (Oracle) linkmode_and(phy_kset.link_modes.advertising,
238103c44a21SRussell King (Oracle) phy_kset.link_modes.advertising,
2382df0acdc5SRussell King (Oracle) pl->supported);
2383df0acdc5SRussell King (Oracle)
2384cbc1bb1eSRussell King /* We can rely on phylib for this update; we also do not need
2385cbc1bb1eSRussell King * to update the pl->link_config settings:
2386cbc1bb1eSRussell King * - the configuration returned via ksettings_get() will come
2387cbc1bb1eSRussell King * from phylib whenever a PHY is present.
2388cbc1bb1eSRussell King * - link_config.interface will be updated by the PHY calling
2389cbc1bb1eSRussell King * back via phylink_phy_change() and a subsequent resolve.
2390cbc1bb1eSRussell King * - initial link configuration for PHY mode comes from the
2391cbc1bb1eSRussell King * last phy state updated via phylink_phy_change().
2392cbc1bb1eSRussell King * - other configuration changes (e.g. pause modes) are
2393cbc1bb1eSRussell King * performed directly via phylib.
2394cbc1bb1eSRussell King * - if in in-band mode with a PHY, the link configuration
2395cbc1bb1eSRussell King * is passed on the link from the PHY, and all of
2396cbc1bb1eSRussell King * link_config.{speed,duplex,an_enabled,pause} are not used.
2397cbc1bb1eSRussell King * - the only possible use would be link_config.advertising
2398cbc1bb1eSRussell King * pause modes when in 1000base-X mode with a PHY, but in
2399cbc1bb1eSRussell King * the presence of a PHY, this should not be changed as that
2400cbc1bb1eSRussell King * should be determined from the media side advertisement.
2401cbc1bb1eSRussell King */
240203c44a21SRussell King (Oracle) return phy_ethtool_ksettings_set(pl->phydev, &phy_kset);
2403cbc1bb1eSRussell King }
2404cbc1bb1eSRussell King
24059525ae83SRussell King config = pl->link_config;
240603c44a21SRussell King (Oracle) /* Mask out unsupported advertisements */
240703c44a21SRussell King (Oracle) linkmode_and(config.advertising, kset->link_modes.advertising,
240803c44a21SRussell King (Oracle) pl->supported);
24099525ae83SRussell King
24109525ae83SRussell King /* FIXME: should we reject autoneg if phy/mac does not support it? */
2411c8cab719SRussell King switch (kset->base.autoneg) {
2412c8cab719SRussell King case AUTONEG_DISABLE:
24139525ae83SRussell King /* Autonegotiation disabled, select a suitable speed and
24149525ae83SRussell King * duplex.
24159525ae83SRussell King */
24169525ae83SRussell King s = phy_lookup_setting(kset->base.speed, kset->base.duplex,
24177cefb0b0SRussell King (Oracle) pl->supported, false);
24189525ae83SRussell King if (!s)
24199525ae83SRussell King return -EINVAL;
24209525ae83SRussell King
24211e1bf14aSRussell King /* If we have a fixed link, refuse to change link parameters.
24221e1bf14aSRussell King * If the link parameters match, accept them but do nothing.
24239525ae83SRussell King */
24241e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) {
24251e1bf14aSRussell King if (s->speed != pl->link_config.speed ||
24261e1bf14aSRussell King s->duplex != pl->link_config.duplex)
24279525ae83SRussell King return -EINVAL;
24281e1bf14aSRussell King return 0;
24291e1bf14aSRussell King }
24309525ae83SRussell King
24319525ae83SRussell King config.speed = s->speed;
24329525ae83SRussell King config.duplex = s->duplex;
2433c8cab719SRussell King break;
24349525ae83SRussell King
2435c8cab719SRussell King case AUTONEG_ENABLE:
24361e1bf14aSRussell King /* If we have a fixed link, allow autonegotiation (since that
24371e1bf14aSRussell King * is our default case) but do not allow the advertisement to
24381e1bf14aSRussell King * be changed. If the advertisement matches, simply return.
24391e1bf14aSRussell King */
24401e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) {
24411e1bf14aSRussell King if (!linkmode_equal(config.advertising,
24421e1bf14aSRussell King pl->link_config.advertising))
24439525ae83SRussell King return -EINVAL;
24441e1bf14aSRussell King return 0;
24451e1bf14aSRussell King }
24469525ae83SRussell King
24479525ae83SRussell King config.speed = SPEED_UNKNOWN;
24489525ae83SRussell King config.duplex = DUPLEX_UNKNOWN;
2449c8cab719SRussell King break;
24509525ae83SRussell King
2451c8cab719SRussell King default:
2452c8cab719SRussell King return -EINVAL;
24539525ae83SRussell King }
24549525ae83SRussell King
24551e1bf14aSRussell King /* We have ruled out the case with a PHY attached, and the
24561e1bf14aSRussell King * fixed-link cases. All that is left are in-band links.
24575d57c327SRussell King */
24587cefb0b0SRussell King (Oracle) linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising,
24594ee9b0dcSRussell King (Oracle) kset->base.autoneg == AUTONEG_ENABLE);
24607cefb0b0SRussell King (Oracle)
2461ea269a6fSNathan Rossi /* If this link is with an SFP, ensure that changes to advertised modes
2462ea269a6fSNathan Rossi * also cause the associated interface to be selected such that the
2463ea269a6fSNathan Rossi * link can be configured correctly.
2464ea269a6fSNathan Rossi */
2465dc90604bSRussell King (Oracle) if (pl->sfp_bus) {
2466ea269a6fSNathan Rossi config.interface = sfp_select_interface(pl->sfp_bus,
2467ea269a6fSNathan Rossi config.advertising);
2468ea269a6fSNathan Rossi if (config.interface == PHY_INTERFACE_MODE_NA) {
2469ea269a6fSNathan Rossi phylink_err(pl,
2470ea269a6fSNathan Rossi "selection of interface failed, advertisement %*pb\n",
2471ea269a6fSNathan Rossi __ETHTOOL_LINK_MODE_MASK_NBITS,
2472ea269a6fSNathan Rossi config.advertising);
2473ea269a6fSNathan Rossi return -EINVAL;
2474ea269a6fSNathan Rossi }
2475ea269a6fSNathan Rossi
2476ea269a6fSNathan Rossi /* Revalidate with the selected interface */
2477ea269a6fSNathan Rossi linkmode_copy(support, pl->supported);
2478ea269a6fSNathan Rossi if (phylink_validate(pl, support, &config)) {
2479ea269a6fSNathan Rossi phylink_err(pl, "validation of %s/%s with support %*pb failed\n",
2480ea269a6fSNathan Rossi phylink_an_mode_str(pl->cur_link_an_mode),
2481ea269a6fSNathan Rossi phy_modes(config.interface),
2482ea269a6fSNathan Rossi __ETHTOOL_LINK_MODE_MASK_NBITS, support);
2483ea269a6fSNathan Rossi return -EINVAL;
2484ea269a6fSNathan Rossi }
2485dc90604bSRussell King (Oracle) } else {
2486dc90604bSRussell King (Oracle) /* Validate without changing the current supported mask. */
2487dc90604bSRussell King (Oracle) linkmode_copy(support, pl->supported);
2488dc90604bSRussell King (Oracle) if (phylink_validate(pl, support, &config))
2489dc90604bSRussell King (Oracle) return -EINVAL;
2490ea269a6fSNathan Rossi }
2491ea269a6fSNathan Rossi
2492dc90604bSRussell King (Oracle) /* If autonegotiation is enabled, we must have an advertisement */
24934ee9b0dcSRussell King (Oracle) if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
24944ee9b0dcSRussell King (Oracle) config.advertising) &&
24954ee9b0dcSRussell King (Oracle) phylink_is_empty_linkmode(config.advertising))
2496dc90604bSRussell King (Oracle) return -EINVAL;
2497dc90604bSRussell King (Oracle)
24989525ae83SRussell King mutex_lock(&pl->state_mutex);
24995d57c327SRussell King pl->link_config.speed = config.speed;
25005d57c327SRussell King pl->link_config.duplex = config.duplex;
25019525ae83SRussell King
2502b7ad14c2SRussell King if (pl->link_config.interface != config.interface) {
2503b7ad14c2SRussell King /* The interface changed, e.g. 1000base-X <-> 2500base-X */
2504b7ad14c2SRussell King /* We need to force the link down, then change the interface */
2505b7ad14c2SRussell King if (pl->old_link_state) {
2506b7ad14c2SRussell King phylink_link_down(pl);
2507b7ad14c2SRussell King pl->old_link_state = false;
2508b7ad14c2SRussell King }
2509b7ad14c2SRussell King if (!test_bit(PHYLINK_DISABLE_STOPPED,
2510b7ad14c2SRussell King &pl->phylink_disable_state))
2511b7ad14c2SRussell King phylink_major_config(pl, false, &config);
2512b7ad14c2SRussell King pl->link_config.interface = config.interface;
2513b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising);
2514b7ad14c2SRussell King } else if (!linkmode_equal(pl->link_config.advertising,
2515b7ad14c2SRussell King config.advertising)) {
2516b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising);
2517b7ad14c2SRussell King phylink_change_inband_advert(pl);
25189525ae83SRussell King }
25199525ae83SRussell King mutex_unlock(&pl->state_mutex);
25209525ae83SRussell King
2521d18c2a1bSDan Carpenter return 0;
25229525ae83SRussell King }
25239525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_set);
25249525ae83SRussell King
25258796c892SRussell King /**
25268796c892SRussell King * phylink_ethtool_nway_reset() - restart negotiation
25278796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
25288796c892SRussell King *
25298796c892SRussell King * Restart negotiation for the phylink instance specified by @pl. This will
25308796c892SRussell King * cause any attached phy to restart negotiation with the link partner, and
25318796c892SRussell King * if the MAC is in a BaseX mode, the MAC will also be requested to restart
25328796c892SRussell King * negotiation.
25338796c892SRussell King *
25348796c892SRussell King * Returns zero on success, or negative error code.
25358796c892SRussell King */
phylink_ethtool_nway_reset(struct phylink * pl)25369525ae83SRussell King int phylink_ethtool_nway_reset(struct phylink *pl)
25379525ae83SRussell King {
25389525ae83SRussell King int ret = 0;
25399525ae83SRussell King
25408b874514SRussell King ASSERT_RTNL();
25419525ae83SRussell King
25429525ae83SRussell King if (pl->phydev)
25439525ae83SRussell King ret = phy_restart_aneg(pl->phydev);
254476226787SRussell King (Oracle) phylink_pcs_an_restart(pl);
25459525ae83SRussell King
25469525ae83SRussell King return ret;
25479525ae83SRussell King }
25489525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_nway_reset);
25499525ae83SRussell King
25508796c892SRussell King /**
25518796c892SRussell King * phylink_ethtool_get_pauseparam() - get the current pause parameters
25528796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
25538796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam
25548796c892SRussell King */
phylink_ethtool_get_pauseparam(struct phylink * pl,struct ethtool_pauseparam * pause)25559525ae83SRussell King void phylink_ethtool_get_pauseparam(struct phylink *pl,
25569525ae83SRussell King struct ethtool_pauseparam *pause)
25579525ae83SRussell King {
25588b874514SRussell King ASSERT_RTNL();
25599525ae83SRussell King
25609525ae83SRussell King pause->autoneg = !!(pl->link_config.pause & MLO_PAUSE_AN);
25619525ae83SRussell King pause->rx_pause = !!(pl->link_config.pause & MLO_PAUSE_RX);
25629525ae83SRussell King pause->tx_pause = !!(pl->link_config.pause & MLO_PAUSE_TX);
25639525ae83SRussell King }
25649525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_pauseparam);
25659525ae83SRussell King
25668796c892SRussell King /**
25678796c892SRussell King * phylink_ethtool_set_pauseparam() - set the current pause parameters
25688796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
25698796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam
25708796c892SRussell King */
phylink_ethtool_set_pauseparam(struct phylink * pl,struct ethtool_pauseparam * pause)25719525ae83SRussell King int phylink_ethtool_set_pauseparam(struct phylink *pl,
25729525ae83SRussell King struct ethtool_pauseparam *pause)
25739525ae83SRussell King {
25749525ae83SRussell King struct phylink_link_state *config = &pl->link_config;
25752e919bc4SRussell King bool manual_changed;
25762e919bc4SRussell King int pause_state;
25779525ae83SRussell King
25788b874514SRussell King ASSERT_RTNL();
25799525ae83SRussell King
25808cdfa256SRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED)
25818cdfa256SRussell King return -EOPNOTSUPP;
25828cdfa256SRussell King
25839525ae83SRussell King if (!phylink_test(pl->supported, Pause) &&
25849525ae83SRussell King !phylink_test(pl->supported, Asym_Pause))
25859525ae83SRussell King return -EOPNOTSUPP;
25869525ae83SRussell King
25879525ae83SRussell King if (!phylink_test(pl->supported, Asym_Pause) &&
2588fd8d9731SRussell King (Oracle) pause->rx_pause != pause->tx_pause)
25899525ae83SRussell King return -EINVAL;
25909525ae83SRussell King
25912e919bc4SRussell King pause_state = 0;
25929525ae83SRussell King if (pause->autoneg)
25932e919bc4SRussell King pause_state |= MLO_PAUSE_AN;
25949525ae83SRussell King if (pause->rx_pause)
25952e919bc4SRussell King pause_state |= MLO_PAUSE_RX;
25969525ae83SRussell King if (pause->tx_pause)
25972e919bc4SRussell King pause_state |= MLO_PAUSE_TX;
25989525ae83SRussell King
25992e919bc4SRussell King mutex_lock(&pl->state_mutex);
2600f904f15eSRussell King /*
2601f904f15eSRussell King * See the comments for linkmode_set_pause(), wrt the deficiencies
2602f904f15eSRussell King * with the current implementation. A solution to this issue would
2603f904f15eSRussell King * be:
2604f904f15eSRussell King * ethtool Local device
2605f904f15eSRussell King * rx tx Pause AsymDir
2606f904f15eSRussell King * 0 0 0 0
2607f904f15eSRussell King * 1 0 1 1
2608f904f15eSRussell King * 0 1 0 1
2609f904f15eSRussell King * 1 1 1 1
2610f904f15eSRussell King * and then use the ethtool rx/tx enablement status to mask the
2611f904f15eSRussell King * rx/tx pause resolution.
2612f904f15eSRussell King */
2613f904f15eSRussell King linkmode_set_pause(config->advertising, pause->tx_pause,
2614f904f15eSRussell King pause->rx_pause);
2615f904f15eSRussell King
26162e919bc4SRussell King manual_changed = (config->pause ^ pause_state) & MLO_PAUSE_AN ||
26172e919bc4SRussell King (!(pause_state & MLO_PAUSE_AN) &&
26182e919bc4SRussell King (config->pause ^ pause_state) & MLO_PAUSE_TXRX_MASK);
26192e919bc4SRussell King
26202e919bc4SRussell King config->pause = pause_state;
26212e919bc4SRussell King
26221571e700SRussell King /* Update our in-band advertisement, triggering a renegotiation if
26231571e700SRussell King * the advertisement changed.
26241571e700SRussell King */
26251571e700SRussell King if (!pl->phydev)
26261571e700SRussell King phylink_change_inband_advert(pl);
2627c718af2dSRussell King
2628c718af2dSRussell King mutex_unlock(&pl->state_mutex);
2629c718af2dSRussell King
2630c718af2dSRussell King /* If we have a PHY, a change of the pause frame advertisement will
2631c718af2dSRussell King * cause phylib to renegotiate (if AN is enabled) which will in turn
2632c718af2dSRussell King * call our phylink_phy_change() and trigger a resolve. Note that
2633c718af2dSRussell King * we can't hold our state mutex while calling phy_set_asym_pause().
2634d9922c0eSRussell King */
2635c718af2dSRussell King if (pl->phydev)
2636d9922c0eSRussell King phy_set_asym_pause(pl->phydev, pause->rx_pause,
2637d9922c0eSRussell King pause->tx_pause);
26389525ae83SRussell King
26392e919bc4SRussell King /* If the manual pause settings changed, make sure we trigger a
26402e919bc4SRussell King * resolve to update their state; we can not guarantee that the
26412e919bc4SRussell King * link will cycle.
26422e919bc4SRussell King */
26432e919bc4SRussell King if (manual_changed) {
26442e919bc4SRussell King pl->mac_link_dropped = true;
26452e919bc4SRussell King phylink_run_resolve(pl);
26469525ae83SRussell King }
26479525ae83SRussell King
26489525ae83SRussell King return 0;
26499525ae83SRussell King }
26509525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam);
26519525ae83SRussell King
26529525ae83SRussell King /**
265369280228SMauro Carvalho Chehab * phylink_get_eee_err() - read the energy efficient ethernet error
26549525ae83SRussell King * counter
26559525ae83SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create().
26569525ae83SRussell King *
26579525ae83SRussell King * Read the Energy Efficient Ethernet error counter from the PHY associated
26589525ae83SRussell King * with the phylink instance specified by @pl.
26599525ae83SRussell King *
26609525ae83SRussell King * Returns positive error counter value, or negative error code.
26619525ae83SRussell King */
phylink_get_eee_err(struct phylink * pl)26629525ae83SRussell King int phylink_get_eee_err(struct phylink *pl)
26639525ae83SRussell King {
26649525ae83SRussell King int ret = 0;
26659525ae83SRussell King
26668b874514SRussell King ASSERT_RTNL();
26679525ae83SRussell King
26689525ae83SRussell King if (pl->phydev)
26699525ae83SRussell King ret = phy_get_eee_err(pl->phydev);
26709525ae83SRussell King
26719525ae83SRussell King return ret;
26729525ae83SRussell King }
26739525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_get_eee_err);
26749525ae83SRussell King
26758796c892SRussell King /**
267686e58135SRussell King * phylink_init_eee() - init and check the EEE features
267786e58135SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
267886e58135SRussell King * @clk_stop_enable: allow PHY to stop receive clock
267986e58135SRussell King *
268086e58135SRussell King * Must be called either with RTNL held or within mac_link_up()
268186e58135SRussell King */
phylink_init_eee(struct phylink * pl,bool clk_stop_enable)268286e58135SRussell King int phylink_init_eee(struct phylink *pl, bool clk_stop_enable)
268386e58135SRussell King {
268486e58135SRussell King int ret = -EOPNOTSUPP;
268586e58135SRussell King
268686e58135SRussell King if (pl->phydev)
268786e58135SRussell King ret = phy_init_eee(pl->phydev, clk_stop_enable);
268886e58135SRussell King
268986e58135SRussell King return ret;
269086e58135SRussell King }
269186e58135SRussell King EXPORT_SYMBOL_GPL(phylink_init_eee);
269286e58135SRussell King
269386e58135SRussell King /**
26948796c892SRussell King * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters
26958796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
26968796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the read parameters
26978796c892SRussell King */
phylink_ethtool_get_eee(struct phylink * pl,struct ethtool_eee * eee)26989525ae83SRussell King int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee)
26999525ae83SRussell King {
27009525ae83SRussell King int ret = -EOPNOTSUPP;
27019525ae83SRussell King
27028b874514SRussell King ASSERT_RTNL();
27039525ae83SRussell King
27049525ae83SRussell King if (pl->phydev)
27059525ae83SRussell King ret = phy_ethtool_get_eee(pl->phydev, eee);
27069525ae83SRussell King
27079525ae83SRussell King return ret;
27089525ae83SRussell King }
27099525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee);
27109525ae83SRussell King
27118796c892SRussell King /**
27128796c892SRussell King * phylink_ethtool_set_eee() - set the energy efficient ethernet parameters
27138796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
27148796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the desired parameters
27158796c892SRussell King */
phylink_ethtool_set_eee(struct phylink * pl,struct ethtool_eee * eee)27169525ae83SRussell King int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee)
27179525ae83SRussell King {
27189525ae83SRussell King int ret = -EOPNOTSUPP;
27199525ae83SRussell King
27208b874514SRussell King ASSERT_RTNL();
27219525ae83SRussell King
27229525ae83SRussell King if (pl->phydev)
27239525ae83SRussell King ret = phy_ethtool_set_eee(pl->phydev, eee);
27249525ae83SRussell King
27259525ae83SRussell King return ret;
27269525ae83SRussell King }
27279525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee);
27289525ae83SRussell King
27299525ae83SRussell King /* This emulates MII registers for a fixed-mode phy operating as per the
27309525ae83SRussell King * passed in state. "aneg" defines if we report negotiation is possible.
27319525ae83SRussell King *
27329525ae83SRussell King * FIXME: should deal with negotiation state too.
27339525ae83SRussell King */
phylink_mii_emul_read(unsigned int reg,struct phylink_link_state * state)27347fdc455eSRussell King static int phylink_mii_emul_read(unsigned int reg,
27357fdc455eSRussell King struct phylink_link_state *state)
27369525ae83SRussell King {
27379525ae83SRussell King struct fixed_phy_status fs;
27384e5aeb41SRussell King unsigned long *lpa = state->lp_advertising;
27399525ae83SRussell King int val;
27409525ae83SRussell King
27419525ae83SRussell King fs.link = state->link;
27429525ae83SRussell King fs.speed = state->speed;
27439525ae83SRussell King fs.duplex = state->duplex;
27444e5aeb41SRussell King fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa);
27454e5aeb41SRussell King fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa);
27469525ae83SRussell King
27479525ae83SRussell King val = swphy_read_reg(reg, &fs);
27489525ae83SRussell King if (reg == MII_BMSR) {
27499525ae83SRussell King if (!state->an_complete)
27509525ae83SRussell King val &= ~BMSR_ANEGCOMPLETE;
27519525ae83SRussell King }
27529525ae83SRussell King return val;
27539525ae83SRussell King }
27549525ae83SRussell King
phylink_phy_read(struct phylink * pl,unsigned int phy_id,unsigned int reg)2755ecbd87b8SRussell King static int phylink_phy_read(struct phylink *pl, unsigned int phy_id,
2756ecbd87b8SRussell King unsigned int reg)
2757ecbd87b8SRussell King {
2758ecbd87b8SRussell King struct phy_device *phydev = pl->phydev;
2759ecbd87b8SRussell King int prtad, devad;
2760ecbd87b8SRussell King
2761ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) {
2762ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id);
2763ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id);
276470dcf3cdSAndrew Lunn return mdiobus_c45_read(pl->phydev->mdio.bus, prtad, devad,
276570dcf3cdSAndrew Lunn reg);
276670dcf3cdSAndrew Lunn }
276770dcf3cdSAndrew Lunn
276870dcf3cdSAndrew Lunn if (phydev->is_c45) {
2769ecbd87b8SRussell King switch (reg) {
2770ecbd87b8SRussell King case MII_BMCR:
2771ecbd87b8SRussell King case MII_BMSR:
2772ecbd87b8SRussell King case MII_PHYSID1:
2773ecbd87b8SRussell King case MII_PHYSID2:
2774320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present);
2775ecbd87b8SRussell King break;
2776ecbd87b8SRussell King case MII_ADVERTISE:
2777ecbd87b8SRussell King case MII_LPA:
2778320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN))
2779ecbd87b8SRussell King return -EINVAL;
2780ecbd87b8SRussell King devad = MDIO_MMD_AN;
2781ecbd87b8SRussell King if (reg == MII_ADVERTISE)
2782ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE;
2783ecbd87b8SRussell King else
2784ecbd87b8SRussell King reg = MDIO_AN_LPA;
2785ecbd87b8SRussell King break;
2786ecbd87b8SRussell King default:
2787ecbd87b8SRussell King return -EINVAL;
2788ecbd87b8SRussell King }
2789ecbd87b8SRussell King prtad = phy_id;
279070dcf3cdSAndrew Lunn return mdiobus_c45_read(pl->phydev->mdio.bus, prtad, devad,
279170dcf3cdSAndrew Lunn reg);
2792ecbd87b8SRussell King }
279370dcf3cdSAndrew Lunn
279470dcf3cdSAndrew Lunn return mdiobus_read(pl->phydev->mdio.bus, phy_id, reg);
2795ecbd87b8SRussell King }
2796ecbd87b8SRussell King
phylink_phy_write(struct phylink * pl,unsigned int phy_id,unsigned int reg,unsigned int val)2797ecbd87b8SRussell King static int phylink_phy_write(struct phylink *pl, unsigned int phy_id,
2798ecbd87b8SRussell King unsigned int reg, unsigned int val)
2799ecbd87b8SRussell King {
2800ecbd87b8SRussell King struct phy_device *phydev = pl->phydev;
2801ecbd87b8SRussell King int prtad, devad;
2802ecbd87b8SRussell King
2803ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) {
2804ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id);
2805ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id);
280670dcf3cdSAndrew Lunn return mdiobus_c45_write(pl->phydev->mdio.bus, prtad, devad,
280770dcf3cdSAndrew Lunn reg, val);
280870dcf3cdSAndrew Lunn }
280970dcf3cdSAndrew Lunn
281070dcf3cdSAndrew Lunn if (phydev->is_c45) {
2811ecbd87b8SRussell King switch (reg) {
2812ecbd87b8SRussell King case MII_BMCR:
2813ecbd87b8SRussell King case MII_BMSR:
2814ecbd87b8SRussell King case MII_PHYSID1:
2815ecbd87b8SRussell King case MII_PHYSID2:
2816320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present);
2817ecbd87b8SRussell King break;
2818ecbd87b8SRussell King case MII_ADVERTISE:
2819ecbd87b8SRussell King case MII_LPA:
2820320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN))
2821ecbd87b8SRussell King return -EINVAL;
2822ecbd87b8SRussell King devad = MDIO_MMD_AN;
2823ecbd87b8SRussell King if (reg == MII_ADVERTISE)
2824ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE;
2825ecbd87b8SRussell King else
2826ecbd87b8SRussell King reg = MDIO_AN_LPA;
2827ecbd87b8SRussell King break;
2828ecbd87b8SRussell King default:
2829ecbd87b8SRussell King return -EINVAL;
2830ecbd87b8SRussell King }
283170dcf3cdSAndrew Lunn return mdiobus_c45_write(pl->phydev->mdio.bus, phy_id, devad,
283270dcf3cdSAndrew Lunn reg, val);
2833ecbd87b8SRussell King }
2834ecbd87b8SRussell King
283570dcf3cdSAndrew Lunn return mdiobus_write(phydev->mdio.bus, phy_id, reg, val);
2836ecbd87b8SRussell King }
2837ecbd87b8SRussell King
phylink_mii_read(struct phylink * pl,unsigned int phy_id,unsigned int reg)28389525ae83SRussell King static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
28399525ae83SRussell King unsigned int reg)
28409525ae83SRussell King {
28419525ae83SRussell King struct phylink_link_state state;
28429525ae83SRussell King int val = 0xffff;
28439525ae83SRussell King
284424cf0e69SRussell King switch (pl->cur_link_an_mode) {
28459525ae83SRussell King case MLO_AN_FIXED:
28469525ae83SRussell King if (phy_id == 0) {
28479525ae83SRussell King phylink_get_fixed_state(pl, &state);
28487fdc455eSRussell King val = phylink_mii_emul_read(reg, &state);
28499525ae83SRussell King }
28509525ae83SRussell King break;
28519525ae83SRussell King
28529525ae83SRussell King case MLO_AN_PHY:
28539525ae83SRussell King return -EOPNOTSUPP;
28549525ae83SRussell King
285586a362c4SRussell King case MLO_AN_INBAND:
28569525ae83SRussell King if (phy_id == 0) {
2857d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &state);
28587fdc455eSRussell King val = phylink_mii_emul_read(reg, &state);
28599525ae83SRussell King }
28609525ae83SRussell King break;
28619525ae83SRussell King }
28629525ae83SRussell King
28639525ae83SRussell King return val & 0xffff;
28649525ae83SRussell King }
28659525ae83SRussell King
phylink_mii_write(struct phylink * pl,unsigned int phy_id,unsigned int reg,unsigned int val)28669525ae83SRussell King static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
28679525ae83SRussell King unsigned int reg, unsigned int val)
28689525ae83SRussell King {
286924cf0e69SRussell King switch (pl->cur_link_an_mode) {
28709525ae83SRussell King case MLO_AN_FIXED:
28719525ae83SRussell King break;
28729525ae83SRussell King
28739525ae83SRussell King case MLO_AN_PHY:
28749525ae83SRussell King return -EOPNOTSUPP;
28759525ae83SRussell King
287686a362c4SRussell King case MLO_AN_INBAND:
28779525ae83SRussell King break;
28789525ae83SRussell King }
28799525ae83SRussell King
28809525ae83SRussell King return 0;
28819525ae83SRussell King }
28829525ae83SRussell King
28838796c892SRussell King /**
28848796c892SRussell King * phylink_mii_ioctl() - generic mii ioctl interface
28858796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
28868796c892SRussell King * @ifr: a pointer to a &struct ifreq for socket ioctls
28878796c892SRussell King * @cmd: ioctl cmd to execute
28888796c892SRussell King *
28898796c892SRussell King * Perform the specified MII ioctl on the PHY attached to the phylink instance
28908796c892SRussell King * specified by @pl. If no PHY is attached, emulate the presence of the PHY.
28918796c892SRussell King *
28928796c892SRussell King * Returns: zero on success or negative error code.
28938796c892SRussell King *
28948796c892SRussell King * %SIOCGMIIPHY:
28958796c892SRussell King * read register from the current PHY.
28968796c892SRussell King * %SIOCGMIIREG:
28978796c892SRussell King * read register from the specified PHY.
28988796c892SRussell King * %SIOCSMIIREG:
28998796c892SRussell King * set a register on the specified PHY.
29008796c892SRussell King */
phylink_mii_ioctl(struct phylink * pl,struct ifreq * ifr,int cmd)29019525ae83SRussell King int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
29029525ae83SRussell King {
2903ecbd87b8SRussell King struct mii_ioctl_data *mii = if_mii(ifr);
2904ecbd87b8SRussell King int ret;
29059525ae83SRussell King
29068b874514SRussell King ASSERT_RTNL();
29079525ae83SRussell King
2908ecbd87b8SRussell King if (pl->phydev) {
290986a362c4SRussell King /* PHYs only exist for MLO_AN_PHY and SGMII */
29109525ae83SRussell King switch (cmd) {
29119525ae83SRussell King case SIOCGMIIPHY:
2912ecbd87b8SRussell King mii->phy_id = pl->phydev->mdio.addr;
2913df561f66SGustavo A. R. Silva fallthrough;
29149525ae83SRussell King
29159525ae83SRussell King case SIOCGMIIREG:
2916ecbd87b8SRussell King ret = phylink_phy_read(pl, mii->phy_id, mii->reg_num);
2917ecbd87b8SRussell King if (ret >= 0) {
2918ecbd87b8SRussell King mii->val_out = ret;
29199525ae83SRussell King ret = 0;
29209525ae83SRussell King }
29219525ae83SRussell King break;
29229525ae83SRussell King
29239525ae83SRussell King case SIOCSMIIREG:
2924ecbd87b8SRussell King ret = phylink_phy_write(pl, mii->phy_id, mii->reg_num,
2925ecbd87b8SRussell King mii->val_in);
2926ecbd87b8SRussell King break;
2927ecbd87b8SRussell King
2928ecbd87b8SRussell King default:
2929ecbd87b8SRussell King ret = phy_mii_ioctl(pl->phydev, ifr, cmd);
2930ecbd87b8SRussell King break;
2931ecbd87b8SRussell King }
2932ecbd87b8SRussell King } else {
2933ecbd87b8SRussell King switch (cmd) {
2934ecbd87b8SRussell King case SIOCGMIIPHY:
2935ecbd87b8SRussell King mii->phy_id = 0;
2936df561f66SGustavo A. R. Silva fallthrough;
2937ecbd87b8SRussell King
2938ecbd87b8SRussell King case SIOCGMIIREG:
2939ecbd87b8SRussell King ret = phylink_mii_read(pl, mii->phy_id, mii->reg_num);
2940ecbd87b8SRussell King if (ret >= 0) {
2941ecbd87b8SRussell King mii->val_out = ret;
2942ecbd87b8SRussell King ret = 0;
2943ecbd87b8SRussell King }
2944ecbd87b8SRussell King break;
2945ecbd87b8SRussell King
2946ecbd87b8SRussell King case SIOCSMIIREG:
2947ecbd87b8SRussell King ret = phylink_mii_write(pl, mii->phy_id, mii->reg_num,
2948ecbd87b8SRussell King mii->val_in);
29499525ae83SRussell King break;
29509525ae83SRussell King
29519525ae83SRussell King default:
29529525ae83SRussell King ret = -EOPNOTSUPP;
29539525ae83SRussell King break;
29549525ae83SRussell King }
2955ecbd87b8SRussell King }
29569525ae83SRussell King
29579525ae83SRussell King return ret;
29589525ae83SRussell King }
29599525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
29609525ae83SRussell King
2961c6d5d843SRussell King /**
2962c6d5d843SRussell King * phylink_speed_down() - set the non-SFP PHY to lowest speed supported by both
2963c6d5d843SRussell King * link partners
2964c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
2965c6d5d843SRussell King * @sync: perform action synchronously
2966c6d5d843SRussell King *
2967c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then set the speed
2968c6d5d843SRussell King * as described in the phy_speed_down() function. Please see this function
2969c6d5d843SRussell King * for a description of the @sync parameter.
2970c6d5d843SRussell King *
2971c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_down().
2972c6d5d843SRussell King */
phylink_speed_down(struct phylink * pl,bool sync)2973c6d5d843SRussell King int phylink_speed_down(struct phylink *pl, bool sync)
2974c6d5d843SRussell King {
2975c6d5d843SRussell King int ret = 0;
2976c6d5d843SRussell King
2977c6d5d843SRussell King ASSERT_RTNL();
2978c6d5d843SRussell King
2979c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev)
2980c6d5d843SRussell King ret = phy_speed_down(pl->phydev, sync);
2981c6d5d843SRussell King
2982c6d5d843SRussell King return ret;
2983c6d5d843SRussell King }
2984c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_down);
2985c6d5d843SRussell King
2986c6d5d843SRussell King /**
2987c6d5d843SRussell King * phylink_speed_up() - restore the advertised speeds prior to the call to
2988c6d5d843SRussell King * phylink_speed_down()
2989c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create()
2990c6d5d843SRussell King *
2991c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then restore the
2992c6d5d843SRussell King * PHY speeds as per phy_speed_up().
2993c6d5d843SRussell King *
2994c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_up().
2995c6d5d843SRussell King */
phylink_speed_up(struct phylink * pl)2996c6d5d843SRussell King int phylink_speed_up(struct phylink *pl)
2997c6d5d843SRussell King {
2998c6d5d843SRussell King int ret = 0;
2999c6d5d843SRussell King
3000c6d5d843SRussell King ASSERT_RTNL();
3001c6d5d843SRussell King
3002c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev)
3003c6d5d843SRussell King ret = phy_speed_up(pl->phydev);
3004c6d5d843SRussell King
3005c6d5d843SRussell King return ret;
3006c6d5d843SRussell King }
3007c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_up);
3008c6d5d843SRussell King
phylink_sfp_attach(void * upstream,struct sfp_bus * bus)3009320587e6SRussell King static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus)
3010320587e6SRussell King {
3011320587e6SRussell King struct phylink *pl = upstream;
3012320587e6SRussell King
3013320587e6SRussell King pl->netdev->sfp_bus = bus;
3014320587e6SRussell King }
3015320587e6SRussell King
phylink_sfp_detach(void * upstream,struct sfp_bus * bus)3016320587e6SRussell King static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
3017320587e6SRussell King {
3018320587e6SRussell King struct phylink *pl = upstream;
3019320587e6SRussell King
3020320587e6SRussell King pl->netdev->sfp_bus = NULL;
3021320587e6SRussell King }
3022320587e6SRussell King
3023f81fa96dSRussell King static const phy_interface_t phylink_sfp_interface_preference[] = {
3024f81fa96dSRussell King PHY_INTERFACE_MODE_25GBASER,
3025f81fa96dSRussell King PHY_INTERFACE_MODE_USXGMII,
3026f81fa96dSRussell King PHY_INTERFACE_MODE_10GBASER,
3027f81fa96dSRussell King PHY_INTERFACE_MODE_5GBASER,
3028f81fa96dSRussell King PHY_INTERFACE_MODE_2500BASEX,
3029f81fa96dSRussell King PHY_INTERFACE_MODE_SGMII,
3030f81fa96dSRussell King PHY_INTERFACE_MODE_1000BASEX,
3031f81fa96dSRussell King PHY_INTERFACE_MODE_100BASEX,
3032f81fa96dSRussell King };
3033f81fa96dSRussell King
3034eca68a3cSMarek Behún static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
3035eca68a3cSMarek Behún
phylink_choose_sfp_interface(struct phylink * pl,const unsigned long * intf)3036f81fa96dSRussell King static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
3037f81fa96dSRussell King const unsigned long *intf)
3038f81fa96dSRussell King {
3039f81fa96dSRussell King phy_interface_t interface;
3040f81fa96dSRussell King size_t i;
3041f81fa96dSRussell King
3042f81fa96dSRussell King interface = PHY_INTERFACE_MODE_NA;
3043f81fa96dSRussell King for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++)
3044f81fa96dSRussell King if (test_bit(phylink_sfp_interface_preference[i], intf)) {
3045f81fa96dSRussell King interface = phylink_sfp_interface_preference[i];
3046f81fa96dSRussell King break;
3047f81fa96dSRussell King }
3048f81fa96dSRussell King
3049f81fa96dSRussell King return interface;
3050f81fa96dSRussell King }
3051f81fa96dSRussell King
phylink_sfp_set_config(struct phylink * pl,u8 mode,unsigned long * supported,struct phylink_link_state * state)3052f81fa96dSRussell King static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
3053f81fa96dSRussell King unsigned long *supported,
3054f81fa96dSRussell King struct phylink_link_state *state)
3055f81fa96dSRussell King {
3056f81fa96dSRussell King bool changed = false;
3057f81fa96dSRussell King
3058f81fa96dSRussell King phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
3059f81fa96dSRussell King phylink_an_mode_str(mode), phy_modes(state->interface),
3060f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
3061f81fa96dSRussell King
3062f81fa96dSRussell King if (!linkmode_equal(pl->supported, supported)) {
3063f81fa96dSRussell King linkmode_copy(pl->supported, supported);
3064f81fa96dSRussell King changed = true;
3065f81fa96dSRussell King }
3066f81fa96dSRussell King
3067f81fa96dSRussell King if (!linkmode_equal(pl->link_config.advertising, state->advertising)) {
3068f81fa96dSRussell King linkmode_copy(pl->link_config.advertising, state->advertising);
3069f81fa96dSRussell King changed = true;
3070f81fa96dSRussell King }
3071f81fa96dSRussell King
3072f81fa96dSRussell King if (pl->cur_link_an_mode != mode ||
3073f81fa96dSRussell King pl->link_config.interface != state->interface) {
3074f81fa96dSRussell King pl->cur_link_an_mode = mode;
3075f81fa96dSRussell King pl->link_config.interface = state->interface;
3076f81fa96dSRussell King
3077f81fa96dSRussell King changed = true;
3078f81fa96dSRussell King
3079f81fa96dSRussell King phylink_info(pl, "switched to %s/%s link mode\n",
3080f81fa96dSRussell King phylink_an_mode_str(mode),
3081f81fa96dSRussell King phy_modes(state->interface));
3082f81fa96dSRussell King }
3083f81fa96dSRussell King
3084f81fa96dSRussell King if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
3085f81fa96dSRussell King &pl->phylink_disable_state))
3086f81fa96dSRussell King phylink_mac_initial_config(pl, false);
3087f81fa96dSRussell King }
3088f81fa96dSRussell King
phylink_sfp_config_phy(struct phylink * pl,u8 mode,struct phy_device * phy)3089e6084637SRussell King (Oracle) static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
3090e6084637SRussell King (Oracle) struct phy_device *phy)
3091ce0aa27fSRussell King {
309277316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
3093c0de2f47SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
3094ce0aa27fSRussell King struct phylink_link_state config;
3095ce0aa27fSRussell King phy_interface_t iface;
3096c0de2f47SRussell King int ret;
3097ce0aa27fSRussell King
3098e6084637SRussell King (Oracle) linkmode_copy(support, phy->supported);
3099ce0aa27fSRussell King
3100ce0aa27fSRussell King memset(&config, 0, sizeof(config));
3101e6084637SRussell King (Oracle) linkmode_copy(config.advertising, phy->advertising);
3102a9c79364SRussell King config.interface = PHY_INTERFACE_MODE_NA;
3103ce0aa27fSRussell King config.speed = SPEED_UNKNOWN;
3104ce0aa27fSRussell King config.duplex = DUPLEX_UNKNOWN;
3105ce0aa27fSRussell King config.pause = MLO_PAUSE_AN;
3106ce0aa27fSRussell King
3107ce0aa27fSRussell King /* Ignore errors if we're expecting a PHY to attach later */
3108ce0aa27fSRussell King ret = phylink_validate(pl, support, &config);
3109ce0aa27fSRussell King if (ret) {
3110ab1198e5SRussell King (Oracle) phylink_err(pl, "validation with support %*pb failed: %pe\n",
3111ab1198e5SRussell King (Oracle) __ETHTOOL_LINK_MODE_MASK_NBITS, support,
3112ab1198e5SRussell King (Oracle) ERR_PTR(ret));
3113a9c79364SRussell King return ret;
3114a9c79364SRussell King }
3115a9c79364SRussell King
3116a4516c70SRussell King iface = sfp_select_interface(pl->sfp_bus, config.advertising);
3117a9c79364SRussell King if (iface == PHY_INTERFACE_MODE_NA) {
311817091180SIoana Ciornei phylink_err(pl,
3119cc1122b0SColin Ian King "selection of interface failed, advertisement %*pb\n",
3120a9c79364SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising);
3121a9c79364SRussell King return -EINVAL;
3122a9c79364SRussell King }
3123a9c79364SRussell King
3124a9c79364SRussell King config.interface = iface;
3125c0de2f47SRussell King linkmode_copy(support1, support);
312677316763SRussell King ret = phylink_validate(pl, support1, &config);
3127a9c79364SRussell King if (ret) {
3128ab1198e5SRussell King (Oracle) phylink_err(pl,
3129ab1198e5SRussell King (Oracle) "validation of %s/%s with support %*pb failed: %pe\n",
3130c0de2f47SRussell King phylink_an_mode_str(mode),
3131444d3502SRussell King phy_modes(config.interface),
3132ab1198e5SRussell King (Oracle) __ETHTOOL_LINK_MODE_MASK_NBITS, support,
3133ab1198e5SRussell King (Oracle) ERR_PTR(ret));
3134ce0aa27fSRussell King return ret;
3135ce0aa27fSRussell King }
3136ce0aa27fSRussell King
3137f81fa96dSRussell King pl->link_port = pl->sfp_port;
3138f81fa96dSRussell King
3139f81fa96dSRussell King phylink_sfp_set_config(pl, mode, support, &config);
3140f81fa96dSRussell King
3141f81fa96dSRussell King return 0;
3142ce0aa27fSRussell King }
3143ce0aa27fSRussell King
phylink_sfp_config_optical(struct phylink * pl)3144f81fa96dSRussell King static int phylink_sfp_config_optical(struct phylink *pl)
3145f81fa96dSRussell King {
3146f81fa96dSRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
3147f81fa96dSRussell King DECLARE_PHY_INTERFACE_MASK(interfaces);
3148f81fa96dSRussell King struct phylink_link_state config;
3149f81fa96dSRussell King phy_interface_t interface;
3150f81fa96dSRussell King int ret;
3151ce0aa27fSRussell King
3152f81fa96dSRussell King phylink_dbg(pl, "optical SFP: interfaces=[mac=%*pbl, sfp=%*pbl]\n",
3153f81fa96dSRussell King (int)PHY_INTERFACE_MODE_MAX,
3154f81fa96dSRussell King pl->config->supported_interfaces,
3155f81fa96dSRussell King (int)PHY_INTERFACE_MODE_MAX,
3156f81fa96dSRussell King pl->sfp_interfaces);
3157ce0aa27fSRussell King
3158f81fa96dSRussell King /* Find the union of the supported interfaces by the PCS/MAC and
3159f81fa96dSRussell King * the SFP module.
3160f81fa96dSRussell King */
3161f81fa96dSRussell King phy_interface_and(interfaces, pl->config->supported_interfaces,
3162f81fa96dSRussell King pl->sfp_interfaces);
3163f81fa96dSRussell King if (phy_interface_empty(interfaces)) {
3164f81fa96dSRussell King phylink_err(pl, "unsupported SFP module: no common interface modes\n");
3165f81fa96dSRussell King return -EINVAL;
3166f81fa96dSRussell King }
3167f81fa96dSRussell King
3168f81fa96dSRussell King memset(&config, 0, sizeof(config));
3169f81fa96dSRussell King linkmode_copy(support, pl->sfp_support);
3170f81fa96dSRussell King linkmode_copy(config.advertising, pl->sfp_support);
3171f81fa96dSRussell King config.speed = SPEED_UNKNOWN;
3172f81fa96dSRussell King config.duplex = DUPLEX_UNKNOWN;
3173f81fa96dSRussell King config.pause = MLO_PAUSE_AN;
3174f81fa96dSRussell King
3175f81fa96dSRussell King /* For all the interfaces that are supported, reduce the sfp_support
3176f81fa96dSRussell King * mask to only those link modes that can be supported.
3177f81fa96dSRussell King */
3178f81fa96dSRussell King ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
3179f81fa96dSRussell King if (ret) {
3180f81fa96dSRussell King phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
3181f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support);
3182f81fa96dSRussell King return ret;
3183f81fa96dSRussell King }
3184f81fa96dSRussell King
3185f81fa96dSRussell King interface = phylink_choose_sfp_interface(pl, interfaces);
3186f81fa96dSRussell King if (interface == PHY_INTERFACE_MODE_NA) {
3187f81fa96dSRussell King phylink_err(pl, "failed to select SFP interface\n");
3188f81fa96dSRussell King return -EINVAL;
3189f81fa96dSRussell King }
3190f81fa96dSRussell King
3191f81fa96dSRussell King phylink_dbg(pl, "optical SFP: chosen %s interface\n",
3192f81fa96dSRussell King phy_modes(interface));
3193f81fa96dSRussell King
3194f81fa96dSRussell King config.interface = interface;
3195f81fa96dSRussell King
3196f81fa96dSRussell King /* Ignore errors if we're expecting a PHY to attach later */
3197f81fa96dSRussell King ret = phylink_validate(pl, support, &config);
3198f81fa96dSRussell King if (ret) {
3199f81fa96dSRussell King phylink_err(pl, "validation with support %*pb failed: %pe\n",
3200f81fa96dSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support,
3201f81fa96dSRussell King ERR_PTR(ret));
3202f81fa96dSRussell King return ret;
3203ce0aa27fSRussell King }
3204ce0aa27fSRussell King
320552c95600SRussell King pl->link_port = pl->sfp_port;
3206ce0aa27fSRussell King
3207f81fa96dSRussell King phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config);
3208ce0aa27fSRussell King
3209f81fa96dSRussell King return 0;
3210ce0aa27fSRussell King }
3211ce0aa27fSRussell King
phylink_sfp_module_insert(void * upstream,const struct sfp_eeprom_id * id)3212c0de2f47SRussell King static int phylink_sfp_module_insert(void *upstream,
3213c0de2f47SRussell King const struct sfp_eeprom_id *id)
3214c0de2f47SRussell King {
3215c0de2f47SRussell King struct phylink *pl = upstream;
3216c0de2f47SRussell King
3217c0de2f47SRussell King ASSERT_RTNL();
3218c0de2f47SRussell King
3219f81fa96dSRussell King linkmode_zero(pl->sfp_support);
3220fd580c98SRussell King phy_interface_zero(pl->sfp_interfaces);
3221f81fa96dSRussell King sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces);
3222f81fa96dSRussell King pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support);
3223c0de2f47SRussell King
322452c95600SRussell King /* If this module may have a PHY connecting later, defer until later */
322552c95600SRussell King pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
322652c95600SRussell King if (pl->sfp_may_have_phy)
322752c95600SRussell King return 0;
322852c95600SRussell King
3229f81fa96dSRussell King return phylink_sfp_config_optical(pl);
3230c0de2f47SRussell King }
3231c0de2f47SRussell King
phylink_sfp_module_start(void * upstream)32324882057aSRussell King static int phylink_sfp_module_start(void *upstream)
32334882057aSRussell King {
32344882057aSRussell King struct phylink *pl = upstream;
32354882057aSRussell King
32364882057aSRussell King /* If this SFP module has a PHY, start the PHY now. */
323752c95600SRussell King if (pl->phydev) {
32384882057aSRussell King phy_start(pl->phydev);
32394882057aSRussell King return 0;
32404882057aSRussell King }
32414882057aSRussell King
324252c95600SRussell King /* If the module may have a PHY but we didn't detect one we
324352c95600SRussell King * need to configure the MAC here.
324452c95600SRussell King */
324552c95600SRussell King if (!pl->sfp_may_have_phy)
324652c95600SRussell King return 0;
324752c95600SRussell King
3248f81fa96dSRussell King return phylink_sfp_config_optical(pl);
324952c95600SRussell King }
325052c95600SRussell King
phylink_sfp_module_stop(void * upstream)32514882057aSRussell King static void phylink_sfp_module_stop(void *upstream)
32524882057aSRussell King {
32534882057aSRussell King struct phylink *pl = upstream;
32544882057aSRussell King
32554882057aSRussell King /* If this SFP module has a PHY, stop it. */
32564882057aSRussell King if (pl->phydev)
32574882057aSRussell King phy_stop(pl->phydev);
32584882057aSRussell King }
32594882057aSRussell King
phylink_sfp_link_down(void * upstream)3260ce0aa27fSRussell King static void phylink_sfp_link_down(void *upstream)
3261ce0aa27fSRussell King {
3262ce0aa27fSRussell King struct phylink *pl = upstream;
3263ce0aa27fSRussell King
32648b874514SRussell King ASSERT_RTNL();
3265ce0aa27fSRussell King
326687454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_LINK);
3267ce0aa27fSRussell King }
3268ce0aa27fSRussell King
phylink_sfp_link_up(void * upstream)3269ce0aa27fSRussell King static void phylink_sfp_link_up(void *upstream)
3270ce0aa27fSRussell King {
3271ce0aa27fSRussell King struct phylink *pl = upstream;
3272ce0aa27fSRussell King
32738b874514SRussell King ASSERT_RTNL();
3274ce0aa27fSRussell King
3275aa729c43SRussell King phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK);
3276ce0aa27fSRussell King }
3277ce0aa27fSRussell King
32787adb5b21SRussell King /* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
32797adb5b21SRussell King * or 802.3z control word, so inband will not work.
32807adb5b21SRussell King */
phylink_phy_no_inband(struct phy_device * phy)32817adb5b21SRussell King static bool phylink_phy_no_inband(struct phy_device *phy)
32827adb5b21SRussell King {
32834b159f50SRussell King return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1],
32844b159f50SRussell King 0xae025150, 0xfffffff0);
32857adb5b21SRussell King }
32867adb5b21SRussell King
phylink_sfp_connect_phy(void * upstream,struct phy_device * phy)3287ce0aa27fSRussell King static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
3288ce0aa27fSRussell King {
32897e418375SBaruch Siach struct phylink *pl = upstream;
329052c95600SRussell King phy_interface_t interface;
32917adb5b21SRussell King u8 mode;
3292938d44c2SRussell King int ret;
32937e418375SBaruch Siach
329452c95600SRussell King /*
329552c95600SRussell King * This is the new way of dealing with flow control for PHYs,
329652c95600SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
329752c95600SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except
329852c95600SRussell King * using our validate call to the MAC, we rely upon the MAC
329952c95600SRussell King * clearing the bits from both supported and advertising fields.
330052c95600SRussell King */
330152c95600SRussell King phy_support_asym_pause(phy);
330252c95600SRussell King
33037adb5b21SRussell King if (phylink_phy_no_inband(phy))
33047adb5b21SRussell King mode = MLO_AN_PHY;
33057adb5b21SRussell King else
33067adb5b21SRussell King mode = MLO_AN_INBAND;
33077adb5b21SRussell King
3308eca68a3cSMarek Behún /* Set the PHY's host supported interfaces */
3309eca68a3cSMarek Behún phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
3310eca68a3cSMarek Behún pl->config->supported_interfaces);
3311eca68a3cSMarek Behún
331252c95600SRussell King /* Do the initial configuration */
3313e6084637SRussell King (Oracle) ret = phylink_sfp_config_phy(pl, mode, phy);
331452c95600SRussell King if (ret < 0)
331552c95600SRussell King return ret;
331652c95600SRussell King
331752c95600SRussell King interface = pl->link_config.interface;
331852c95600SRussell King ret = phylink_attach_phy(pl, phy, interface);
3319938d44c2SRussell King if (ret < 0)
3320938d44c2SRussell King return ret;
3321938d44c2SRussell King
3322e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, interface);
3323938d44c2SRussell King if (ret)
3324938d44c2SRussell King phy_detach(phy);
3325938d44c2SRussell King
3326938d44c2SRussell King return ret;
3327ce0aa27fSRussell King }
3328ce0aa27fSRussell King
phylink_sfp_disconnect_phy(void * upstream)3329ce0aa27fSRussell King static void phylink_sfp_disconnect_phy(void *upstream)
3330ce0aa27fSRussell King {
3331ce0aa27fSRussell King phylink_disconnect_phy(upstream);
3332ce0aa27fSRussell King }
3333ce0aa27fSRussell King
3334ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops = {
3335320587e6SRussell King .attach = phylink_sfp_attach,
3336320587e6SRussell King .detach = phylink_sfp_detach,
3337ce0aa27fSRussell King .module_insert = phylink_sfp_module_insert,
33384882057aSRussell King .module_start = phylink_sfp_module_start,
33394882057aSRussell King .module_stop = phylink_sfp_module_stop,
3340ce0aa27fSRussell King .link_up = phylink_sfp_link_up,
3341ce0aa27fSRussell King .link_down = phylink_sfp_link_down,
3342ce0aa27fSRussell King .connect_phy = phylink_sfp_connect_phy,
3343ce0aa27fSRussell King .disconnect_phy = phylink_sfp_disconnect_phy,
3344ce0aa27fSRussell King };
3345ce0aa27fSRussell King
3346624c0f02SRussell King /* Helpers for MAC drivers */
3347624c0f02SRussell King
3348dad98748SRussell King (Oracle) static struct {
3349dad98748SRussell King (Oracle) int bit;
3350dad98748SRussell King (Oracle) int speed;
3351dad98748SRussell King (Oracle) } phylink_c73_priority_resolution[] = {
3352dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, SPEED_100000 },
3353dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, SPEED_100000 },
3354dad98748SRussell King (Oracle) /* 100GBASE-KP4 and 100GBASE-CR10 not supported */
3355dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, SPEED_40000 },
3356dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, SPEED_40000 },
3357dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, SPEED_10000 },
3358dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, SPEED_10000 },
3359dad98748SRussell King (Oracle) /* 5GBASE-KR not supported */
3360dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_2500baseX_Full_BIT, SPEED_2500 },
3361dad98748SRussell King (Oracle) { ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, SPEED_1000 },
3362dad98748SRussell King (Oracle) };
3363dad98748SRussell King (Oracle)
phylink_resolve_c73(struct phylink_link_state * state)3364dad98748SRussell King (Oracle) void phylink_resolve_c73(struct phylink_link_state *state)
3365dad98748SRussell King (Oracle) {
3366dad98748SRussell King (Oracle) int i;
3367dad98748SRussell King (Oracle)
3368dad98748SRussell King (Oracle) for (i = 0; i < ARRAY_SIZE(phylink_c73_priority_resolution); i++) {
3369dad98748SRussell King (Oracle) int bit = phylink_c73_priority_resolution[i].bit;
3370dad98748SRussell King (Oracle) if (linkmode_test_bit(bit, state->advertising) &&
3371dad98748SRussell King (Oracle) linkmode_test_bit(bit, state->lp_advertising))
3372dad98748SRussell King (Oracle) break;
3373dad98748SRussell King (Oracle) }
3374dad98748SRussell King (Oracle)
3375dad98748SRussell King (Oracle) if (i < ARRAY_SIZE(phylink_c73_priority_resolution)) {
3376dad98748SRussell King (Oracle) state->speed = phylink_c73_priority_resolution[i].speed;
3377dad98748SRussell King (Oracle) state->duplex = DUPLEX_FULL;
3378dad98748SRussell King (Oracle) } else {
3379dad98748SRussell King (Oracle) /* negotiation failure */
3380dad98748SRussell King (Oracle) state->link = false;
3381dad98748SRussell King (Oracle) }
3382dad98748SRussell King (Oracle)
3383dad98748SRussell King (Oracle) phylink_resolve_an_pause(state);
3384dad98748SRussell King (Oracle) }
3385dad98748SRussell King (Oracle) EXPORT_SYMBOL_GPL(phylink_resolve_c73);
3386dad98748SRussell King (Oracle)
phylink_decode_c37_word(struct phylink_link_state * state,uint16_t config_reg,int speed)338774db1c18SRussell King static void phylink_decode_c37_word(struct phylink_link_state *state,
338874db1c18SRussell King uint16_t config_reg, int speed)
338974db1c18SRussell King {
339074db1c18SRussell King int fd_bit;
339174db1c18SRussell King
339274db1c18SRussell King if (speed == SPEED_2500)
339374db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
339474db1c18SRussell King else
339574db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT;
339674db1c18SRussell King
339774db1c18SRussell King mii_lpa_mod_linkmode_x(state->lp_advertising, config_reg, fd_bit);
339874db1c18SRussell King
339974db1c18SRussell King if (linkmode_test_bit(fd_bit, state->advertising) &&
340074db1c18SRussell King linkmode_test_bit(fd_bit, state->lp_advertising)) {
340174db1c18SRussell King state->speed = speed;
340274db1c18SRussell King state->duplex = DUPLEX_FULL;
340374db1c18SRussell King } else {
340474db1c18SRussell King /* negotiation failure */
340574db1c18SRussell King state->link = false;
340674db1c18SRussell King }
340774db1c18SRussell King
3408dc7a5141SRussell King (Oracle) phylink_resolve_an_pause(state);
340974db1c18SRussell King }
341074db1c18SRussell King
phylink_decode_sgmii_word(struct phylink_link_state * state,uint16_t config_reg)341174db1c18SRussell King static void phylink_decode_sgmii_word(struct phylink_link_state *state,
341274db1c18SRussell King uint16_t config_reg)
341374db1c18SRussell King {
341474db1c18SRussell King if (!(config_reg & LPA_SGMII_LINK)) {
341574db1c18SRussell King state->link = false;
341674db1c18SRussell King return;
341774db1c18SRussell King }
341874db1c18SRussell King
341974db1c18SRussell King switch (config_reg & LPA_SGMII_SPD_MASK) {
342074db1c18SRussell King case LPA_SGMII_10:
342174db1c18SRussell King state->speed = SPEED_10;
342274db1c18SRussell King break;
342374db1c18SRussell King case LPA_SGMII_100:
342474db1c18SRussell King state->speed = SPEED_100;
342574db1c18SRussell King break;
342674db1c18SRussell King case LPA_SGMII_1000:
342774db1c18SRussell King state->speed = SPEED_1000;
342874db1c18SRussell King break;
342974db1c18SRussell King default:
343074db1c18SRussell King state->link = false;
343174db1c18SRussell King return;
343274db1c18SRussell King }
343374db1c18SRussell King if (config_reg & LPA_SGMII_FULL_DUPLEX)
343474db1c18SRussell King state->duplex = DUPLEX_FULL;
343574db1c18SRussell King else
343674db1c18SRussell King state->duplex = DUPLEX_HALF;
343774db1c18SRussell King }
343874db1c18SRussell King
343974db1c18SRussell King /**
3440afd62209SIoana Ciornei * phylink_decode_usxgmii_word() - decode the USXGMII word from a MAC PCS
3441afd62209SIoana Ciornei * @state: a pointer to a struct phylink_link_state.
3442afd62209SIoana Ciornei * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word
3443afd62209SIoana Ciornei *
3444afd62209SIoana Ciornei * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation
3445afd62209SIoana Ciornei * code word. Decode the USXGMII code word and populate the corresponding fields
3446afd62209SIoana Ciornei * (speed, duplex) into the phylink_link_state structure.
3447afd62209SIoana Ciornei */
phylink_decode_usxgmii_word(struct phylink_link_state * state,uint16_t lpa)3448afd62209SIoana Ciornei void phylink_decode_usxgmii_word(struct phylink_link_state *state,
3449afd62209SIoana Ciornei uint16_t lpa)
3450afd62209SIoana Ciornei {
3451afd62209SIoana Ciornei switch (lpa & MDIO_USXGMII_SPD_MASK) {
3452afd62209SIoana Ciornei case MDIO_USXGMII_10:
3453afd62209SIoana Ciornei state->speed = SPEED_10;
3454afd62209SIoana Ciornei break;
3455afd62209SIoana Ciornei case MDIO_USXGMII_100:
3456afd62209SIoana Ciornei state->speed = SPEED_100;
3457afd62209SIoana Ciornei break;
3458afd62209SIoana Ciornei case MDIO_USXGMII_1000:
3459afd62209SIoana Ciornei state->speed = SPEED_1000;
3460afd62209SIoana Ciornei break;
3461afd62209SIoana Ciornei case MDIO_USXGMII_2500:
3462afd62209SIoana Ciornei state->speed = SPEED_2500;
3463afd62209SIoana Ciornei break;
3464afd62209SIoana Ciornei case MDIO_USXGMII_5000:
3465afd62209SIoana Ciornei state->speed = SPEED_5000;
3466afd62209SIoana Ciornei break;
3467afd62209SIoana Ciornei case MDIO_USXGMII_10G:
3468afd62209SIoana Ciornei state->speed = SPEED_10000;
3469afd62209SIoana Ciornei break;
3470afd62209SIoana Ciornei default:
3471afd62209SIoana Ciornei state->link = false;
3472afd62209SIoana Ciornei return;
3473afd62209SIoana Ciornei }
3474afd62209SIoana Ciornei
3475afd62209SIoana Ciornei if (lpa & MDIO_USXGMII_FULL_DUPLEX)
3476afd62209SIoana Ciornei state->duplex = DUPLEX_FULL;
3477afd62209SIoana Ciornei else
3478afd62209SIoana Ciornei state->duplex = DUPLEX_HALF;
3479afd62209SIoana Ciornei }
3480afd62209SIoana Ciornei EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word);
3481afd62209SIoana Ciornei
3482afd62209SIoana Ciornei /**
3483923454c0SMaxime Chevallier * phylink_decode_usgmii_word() - decode the USGMII word from a MAC PCS
3484923454c0SMaxime Chevallier * @state: a pointer to a struct phylink_link_state.
3485923454c0SMaxime Chevallier * @lpa: a 16 bit value which stores the USGMII auto-negotiation word
3486923454c0SMaxime Chevallier *
3487923454c0SMaxime Chevallier * Helper for MAC PCS supporting the USGMII protocol and the auto-negotiation
3488923454c0SMaxime Chevallier * code word. Decode the USGMII code word and populate the corresponding fields
3489923454c0SMaxime Chevallier * (speed, duplex) into the phylink_link_state structure. The structure for this
3490923454c0SMaxime Chevallier * word is the same as the USXGMII word, except it only supports speeds up to
3491923454c0SMaxime Chevallier * 1Gbps.
3492923454c0SMaxime Chevallier */
phylink_decode_usgmii_word(struct phylink_link_state * state,uint16_t lpa)3493923454c0SMaxime Chevallier static void phylink_decode_usgmii_word(struct phylink_link_state *state,
3494923454c0SMaxime Chevallier uint16_t lpa)
3495923454c0SMaxime Chevallier {
3496923454c0SMaxime Chevallier switch (lpa & MDIO_USXGMII_SPD_MASK) {
3497923454c0SMaxime Chevallier case MDIO_USXGMII_10:
3498923454c0SMaxime Chevallier state->speed = SPEED_10;
3499923454c0SMaxime Chevallier break;
3500923454c0SMaxime Chevallier case MDIO_USXGMII_100:
3501923454c0SMaxime Chevallier state->speed = SPEED_100;
3502923454c0SMaxime Chevallier break;
3503923454c0SMaxime Chevallier case MDIO_USXGMII_1000:
3504923454c0SMaxime Chevallier state->speed = SPEED_1000;
3505923454c0SMaxime Chevallier break;
3506923454c0SMaxime Chevallier default:
3507923454c0SMaxime Chevallier state->link = false;
3508923454c0SMaxime Chevallier return;
3509923454c0SMaxime Chevallier }
3510923454c0SMaxime Chevallier
3511923454c0SMaxime Chevallier if (lpa & MDIO_USXGMII_FULL_DUPLEX)
3512923454c0SMaxime Chevallier state->duplex = DUPLEX_FULL;
3513923454c0SMaxime Chevallier else
3514923454c0SMaxime Chevallier state->duplex = DUPLEX_HALF;
3515923454c0SMaxime Chevallier }
3516923454c0SMaxime Chevallier
3517923454c0SMaxime Chevallier /**
3518291dcae3SSean Anderson * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers
351974db1c18SRussell King * @state: a pointer to a &struct phylink_link_state.
3520291dcae3SSean Anderson * @bmsr: The value of the %MII_BMSR register
3521291dcae3SSean Anderson * @lpa: The value of the %MII_LPA register
352274db1c18SRussell King *
352374db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for
352474db1c18SRussell King * clause 37 negotiation and/or SGMII control.
352574db1c18SRussell King *
3526291dcae3SSean Anderson * Parse the Clause 37 or Cisco SGMII link partner negotiation word into
3527291dcae3SSean Anderson * the phylink @state structure. This is suitable to be used for implementing
35284d72c3bbSRussell King (Oracle) * the pcs_get_state() member of the struct phylink_pcs_ops structure if
3529291dcae3SSean Anderson * accessing @bmsr and @lpa cannot be done with MDIO directly.
353074db1c18SRussell King */
phylink_mii_c22_pcs_decode_state(struct phylink_link_state * state,u16 bmsr,u16 lpa)3531291dcae3SSean Anderson void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
3532291dcae3SSean Anderson u16 bmsr, u16 lpa)
353374db1c18SRussell King {
353474db1c18SRussell King state->link = !!(bmsr & BMSR_LSTATUS);
353574db1c18SRussell King state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
353692817dadSRobert Hancock /* If there is no link or autonegotiation is disabled, the LP advertisement
353792817dadSRobert Hancock * data is not meaningful, so don't go any further.
353892817dadSRobert Hancock */
35394ee9b0dcSRussell King (Oracle) if (!state->link || !linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
35404ee9b0dcSRussell King (Oracle) state->advertising))
354174db1c18SRussell King return;
354274db1c18SRussell King
354374db1c18SRussell King switch (state->interface) {
354474db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX:
354574db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_1000);
354674db1c18SRussell King break;
354774db1c18SRussell King
354874db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX:
354974db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_2500);
355074db1c18SRussell King break;
355174db1c18SRussell King
355274db1c18SRussell King case PHY_INTERFACE_MODE_SGMII:
355329f02ee4SIoana Ciornei case PHY_INTERFACE_MODE_QSGMII:
355474db1c18SRussell King phylink_decode_sgmii_word(state, lpa);
355574db1c18SRussell King break;
3556923454c0SMaxime Chevallier case PHY_INTERFACE_MODE_QUSGMII:
3557923454c0SMaxime Chevallier phylink_decode_usgmii_word(state, lpa);
3558923454c0SMaxime Chevallier break;
355974db1c18SRussell King
356074db1c18SRussell King default:
356174db1c18SRussell King state->link = false;
356274db1c18SRussell King break;
356374db1c18SRussell King }
356474db1c18SRussell King }
3565291dcae3SSean Anderson EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state);
3566291dcae3SSean Anderson
3567291dcae3SSean Anderson /**
3568291dcae3SSean Anderson * phylink_mii_c22_pcs_get_state() - read the MAC PCS state
3569291dcae3SSean Anderson * @pcs: a pointer to a &struct mdio_device.
3570291dcae3SSean Anderson * @state: a pointer to a &struct phylink_link_state.
3571291dcae3SSean Anderson *
3572291dcae3SSean Anderson * Helper for MAC PCS supporting the 802.3 clause 22 register set for
3573291dcae3SSean Anderson * clause 37 negotiation and/or SGMII control.
3574291dcae3SSean Anderson *
3575291dcae3SSean Anderson * Read the MAC PCS state from the MII device configured in @config and
3576291dcae3SSean Anderson * parse the Clause 37 or Cisco SGMII link partner negotiation word into
3577291dcae3SSean Anderson * the phylink @state structure. This is suitable to be directly plugged
35784d72c3bbSRussell King (Oracle) * into the pcs_get_state() member of the struct phylink_pcs_ops
3579291dcae3SSean Anderson * structure.
3580291dcae3SSean Anderson */
phylink_mii_c22_pcs_get_state(struct mdio_device * pcs,struct phylink_link_state * state)3581291dcae3SSean Anderson void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
3582291dcae3SSean Anderson struct phylink_link_state *state)
3583291dcae3SSean Anderson {
3584291dcae3SSean Anderson int bmsr, lpa;
3585291dcae3SSean Anderson
3586291dcae3SSean Anderson bmsr = mdiodev_read(pcs, MII_BMSR);
3587291dcae3SSean Anderson lpa = mdiodev_read(pcs, MII_LPA);
3588291dcae3SSean Anderson if (bmsr < 0 || lpa < 0) {
3589291dcae3SSean Anderson state->link = false;
3590291dcae3SSean Anderson return;
3591291dcae3SSean Anderson }
3592291dcae3SSean Anderson
3593291dcae3SSean Anderson phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
3594291dcae3SSean Anderson }
359574db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state);
359674db1c18SRussell King
359774db1c18SRussell King /**
3598291dcae3SSean Anderson * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS
359974db1c18SRussell King * advertisement
36000bd27406SRussell King * @interface: the PHY interface mode being configured
36010bd27406SRussell King * @advertising: the ethtool advertisement mask
360274db1c18SRussell King *
360374db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for
360474db1c18SRussell King * clause 37 negotiation and/or SGMII control.
360574db1c18SRussell King *
3606291dcae3SSean Anderson * Encode the clause 37 PCS advertisement as specified by @interface and
3607291dcae3SSean Anderson * @advertising.
360874db1c18SRussell King *
3609291dcae3SSean Anderson * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed.
361074db1c18SRussell King */
phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface,const unsigned long * advertising)3611291dcae3SSean Anderson int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface,
36120bd27406SRussell King const unsigned long *advertising)
361374db1c18SRussell King {
361474db1c18SRussell King u16 adv;
361574db1c18SRussell King
36160bd27406SRussell King switch (interface) {
361774db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX:
361874db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX:
361974db1c18SRussell King adv = ADVERTISE_1000XFULL;
362074db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
36210bd27406SRussell King advertising))
362274db1c18SRussell King adv |= ADVERTISE_1000XPAUSE;
362374db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
36240bd27406SRussell King advertising))
362574db1c18SRussell King adv |= ADVERTISE_1000XPSE_ASYM;
3626291dcae3SSean Anderson return adv;
362774db1c18SRussell King case PHY_INTERFACE_MODE_SGMII:
3628f56866c4SRussell King (Oracle) case PHY_INTERFACE_MODE_QSGMII:
3629291dcae3SSean Anderson return 0x0001;
363074db1c18SRussell King default:
363174db1c18SRussell King /* Nothing to do for other modes */
3632291dcae3SSean Anderson return -EINVAL;
363374db1c18SRussell King }
363474db1c18SRussell King }
3635291dcae3SSean Anderson EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement);
363674db1c18SRussell King
363774db1c18SRussell King /**
363893eaceb0SRussell King * phylink_mii_c22_pcs_config() - configure clause 22 PCS
363993eaceb0SRussell King * @pcs: a pointer to a &struct mdio_device.
364093eaceb0SRussell King * @interface: the PHY interface mode being configured
364193eaceb0SRussell King * @advertising: the ethtool advertisement mask
3642febf2aafSRussell King (Oracle) * @neg_mode: PCS negotiation mode
364393eaceb0SRussell King *
364493eaceb0SRussell King * Configure a Clause 22 PCS PHY with the appropriate negotiation
364593eaceb0SRussell King * parameters for the @mode, @interface and @advertising parameters.
364693eaceb0SRussell King * Returns negative error number on failure, zero if the advertisement
364793eaceb0SRussell King * has not changed, or positive if there is a change.
364893eaceb0SRussell King */
phylink_mii_c22_pcs_config(struct mdio_device * pcs,phy_interface_t interface,const unsigned long * advertising,unsigned int neg_mode)3649febf2aafSRussell King (Oracle) int phylink_mii_c22_pcs_config(struct mdio_device *pcs,
365093eaceb0SRussell King phy_interface_t interface,
3651febf2aafSRussell King (Oracle) const unsigned long *advertising,
3652febf2aafSRussell King (Oracle) unsigned int neg_mode)
365393eaceb0SRussell King {
3654291dcae3SSean Anderson bool changed = 0;
365593eaceb0SRussell King u16 bmcr;
3656291dcae3SSean Anderson int ret, adv;
365793eaceb0SRussell King
3658291dcae3SSean Anderson adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
3659291dcae3SSean Anderson if (adv >= 0) {
3660291dcae3SSean Anderson ret = mdiobus_modify_changed(pcs->bus, pcs->addr,
3661291dcae3SSean Anderson MII_ADVERTISE, 0xffff, adv);
366293eaceb0SRussell King if (ret < 0)
366393eaceb0SRussell King return ret;
3664291dcae3SSean Anderson changed = ret;
3665291dcae3SSean Anderson }
366693eaceb0SRussell King
3667cdb08aa0SRussell King (Oracle) if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
366892817dadSRobert Hancock bmcr = BMCR_ANENABLE;
366992817dadSRobert Hancock else
367092817dadSRobert Hancock bmcr = 0;
367192817dadSRobert Hancock
3672cdb08aa0SRussell King (Oracle) /* Configure the inband state. Ensure ISOLATE bit is disabled */
3673c8fb89a7SSean Anderson ret = mdiodev_modify(pcs, MII_BMCR, BMCR_ANENABLE | BMCR_ISOLATE, bmcr);
367493eaceb0SRussell King if (ret < 0)
367593eaceb0SRussell King return ret;
367693eaceb0SRussell King
3677291dcae3SSean Anderson return changed;
367893eaceb0SRussell King }
367993eaceb0SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config);
368093eaceb0SRussell King
368193eaceb0SRussell King /**
368274db1c18SRussell King * phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation
368374db1c18SRussell King * @pcs: a pointer to a &struct mdio_device.
368474db1c18SRussell King *
368574db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for
368674db1c18SRussell King * clause 37 negotiation.
368774db1c18SRussell King *
368874db1c18SRussell King * Restart the clause 37 negotiation with the link partner. This is
36894d72c3bbSRussell King (Oracle) * suitable to be directly plugged into the pcs_get_state() member
36904d72c3bbSRussell King (Oracle) * of the struct phylink_pcs_ops structure.
369174db1c18SRussell King */
phylink_mii_c22_pcs_an_restart(struct mdio_device * pcs)369274db1c18SRussell King void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs)
369374db1c18SRussell King {
3694c8fb89a7SSean Anderson int val = mdiodev_read(pcs, MII_BMCR);
369574db1c18SRussell King
369674db1c18SRussell King if (val >= 0) {
369774db1c18SRussell King val |= BMCR_ANRESTART;
369874db1c18SRussell King
3699c8fb89a7SSean Anderson mdiodev_write(pcs, MII_BMCR, val);
370074db1c18SRussell King }
370174db1c18SRussell King }
370274db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_an_restart);
370374db1c18SRussell King
phylink_mii_c45_pcs_get_state(struct mdio_device * pcs,struct phylink_link_state * state)3704b8679ef8SRussell King void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs,
3705b8679ef8SRussell King struct phylink_link_state *state)
3706b8679ef8SRussell King {
3707b8679ef8SRussell King struct mii_bus *bus = pcs->bus;
3708b8679ef8SRussell King int addr = pcs->addr;
3709b8679ef8SRussell King int stat;
3710b8679ef8SRussell King
371190ce665cSRussell King stat = mdiobus_c45_read(bus, addr, MDIO_MMD_PCS, MDIO_STAT1);
3712b8679ef8SRussell King if (stat < 0) {
3713b8679ef8SRussell King state->link = false;
3714b8679ef8SRussell King return;
3715b8679ef8SRussell King }
3716b8679ef8SRussell King
3717b8679ef8SRussell King state->link = !!(stat & MDIO_STAT1_LSTATUS);
3718b8679ef8SRussell King if (!state->link)
3719b8679ef8SRussell King return;
3720b8679ef8SRussell King
3721b8679ef8SRussell King switch (state->interface) {
3722b8679ef8SRussell King case PHY_INTERFACE_MODE_10GBASER:
3723b8679ef8SRussell King state->speed = SPEED_10000;
3724b8679ef8SRussell King state->duplex = DUPLEX_FULL;
3725b8679ef8SRussell King break;
3726b8679ef8SRussell King
3727b8679ef8SRussell King default:
3728b8679ef8SRussell King break;
3729b8679ef8SRussell King }
3730b8679ef8SRussell King }
3731b8679ef8SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
3732b8679ef8SRussell King
phylink_init(void)3733eca68a3cSMarek Behún static int __init phylink_init(void)
3734eca68a3cSMarek Behún {
3735eca68a3cSMarek Behún for (int i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); ++i)
3736eca68a3cSMarek Behún __set_bit(phylink_sfp_interface_preference[i],
3737eca68a3cSMarek Behún phylink_sfp_interfaces);
3738eca68a3cSMarek Behún
3739eca68a3cSMarek Behún return 0;
3740eca68a3cSMarek Behún }
3741eca68a3cSMarek Behún
3742eca68a3cSMarek Behún module_init(phylink_init);
3743eca68a3cSMarek Behún
37445f857575SAndrew Lunn MODULE_LICENSE("GPL v2");
3745