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 */ 89525ae83SRussell King #include <linux/ethtool.h> 99525ae83SRussell King #include <linux/export.h> 109525ae83SRussell King #include <linux/gpio/consumer.h> 119525ae83SRussell King #include <linux/netdevice.h> 129525ae83SRussell King #include <linux/of.h> 139525ae83SRussell King #include <linux/of_mdio.h> 149525ae83SRussell King #include <linux/phy.h> 159525ae83SRussell King #include <linux/phy_fixed.h> 169525ae83SRussell King #include <linux/phylink.h> 179525ae83SRussell King #include <linux/rtnetlink.h> 189525ae83SRussell King #include <linux/spinlock.h> 199cd00a8aSRussell King #include <linux/timer.h> 209525ae83SRussell King #include <linux/workqueue.h> 219525ae83SRussell King 22ce0aa27fSRussell King #include "sfp.h" 239525ae83SRussell King #include "swphy.h" 249525ae83SRussell King 259525ae83SRussell King #define SUPPORTED_INTERFACES \ 269525ae83SRussell King (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_FIBRE | \ 279525ae83SRussell King SUPPORTED_BNC | SUPPORTED_AUI | SUPPORTED_Backplane) 289525ae83SRussell King #define ADVERTISED_INTERFACES \ 299525ae83SRussell King (ADVERTISED_TP | ADVERTISED_MII | ADVERTISED_FIBRE | \ 309525ae83SRussell King ADVERTISED_BNC | ADVERTISED_AUI | ADVERTISED_Backplane) 319525ae83SRussell King 329525ae83SRussell King enum { 339525ae83SRussell King PHYLINK_DISABLE_STOPPED, 34ce0aa27fSRussell King PHYLINK_DISABLE_LINK, 359525ae83SRussell King }; 369525ae83SRussell King 378796c892SRussell King /** 388796c892SRussell King * struct phylink - internal data type for phylink 398796c892SRussell King */ 409525ae83SRussell King struct phylink { 418796c892SRussell King /* private: */ 429525ae83SRussell King struct net_device *netdev; 43e7765d63SRussell King const struct phylink_mac_ops *mac_ops; 444c0d6d3aSRussell King const struct phylink_pcs_ops *pcs_ops; 4544cc27e4SIoana Ciornei struct phylink_config *config; 467137e18fSRussell King struct phylink_pcs *pcs; 4743de6195SIoana Ciornei struct device *dev; 4843de6195SIoana Ciornei unsigned int old_link_state:1; 499525ae83SRussell King 509525ae83SRussell King unsigned long phylink_disable_state; /* bitmask of disables */ 519525ae83SRussell King struct phy_device *phydev; 529525ae83SRussell King phy_interface_t link_interface; /* PHY_INTERFACE_xxx */ 5324cf0e69SRussell King u8 cfg_link_an_mode; /* MLO_AN_xxx */ 5424cf0e69SRussell King u8 cur_link_an_mode; 559525ae83SRussell King u8 link_port; /* The current non-phy ethtool port */ 569525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 579525ae83SRussell King 589525ae83SRussell King /* The link configuration settings */ 599525ae83SRussell King struct phylink_link_state link_config; 60c6787263SRussell King 61c6787263SRussell King /* The current settings */ 62c6787263SRussell King phy_interface_t cur_interface; 63c6787263SRussell King 649525ae83SRussell King struct gpio_desc *link_gpio; 657b3b0e89SRussell King unsigned int link_irq; 669cd00a8aSRussell King struct timer_list link_poll; 671ac63e39SFlorian Fainelli void (*get_fixed_state)(struct net_device *dev, 681ac63e39SFlorian Fainelli struct phylink_link_state *s); 699525ae83SRussell King 709525ae83SRussell King struct mutex state_mutex; 719525ae83SRussell King struct phylink_link_state phy_state; 729525ae83SRussell King struct work_struct resolve; 739525ae83SRussell King 749525ae83SRussell King bool mac_link_dropped; 75ce0aa27fSRussell King 76ce0aa27fSRussell King struct sfp_bus *sfp_bus; 7752c95600SRussell King bool sfp_may_have_phy; 7852c95600SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); 7952c95600SRussell King u8 sfp_port; 809525ae83SRussell King }; 819525ae83SRussell King 8217091180SIoana Ciornei #define phylink_printk(level, pl, fmt, ...) \ 8317091180SIoana Ciornei do { \ 8417091180SIoana Ciornei if ((pl)->config->type == PHYLINK_NETDEV) \ 8517091180SIoana Ciornei netdev_printk(level, (pl)->netdev, fmt, ##__VA_ARGS__); \ 8617091180SIoana Ciornei else if ((pl)->config->type == PHYLINK_DEV) \ 8717091180SIoana Ciornei dev_printk(level, (pl)->dev, fmt, ##__VA_ARGS__); \ 8817091180SIoana Ciornei } while (0) 8917091180SIoana Ciornei 9017091180SIoana Ciornei #define phylink_err(pl, fmt, ...) \ 9117091180SIoana Ciornei phylink_printk(KERN_ERR, pl, fmt, ##__VA_ARGS__) 9217091180SIoana Ciornei #define phylink_warn(pl, fmt, ...) \ 9317091180SIoana Ciornei phylink_printk(KERN_WARNING, pl, fmt, ##__VA_ARGS__) 9417091180SIoana Ciornei #define phylink_info(pl, fmt, ...) \ 9517091180SIoana Ciornei phylink_printk(KERN_INFO, pl, fmt, ##__VA_ARGS__) 969d68db50SFlorian Fainelli #if defined(CONFIG_DYNAMIC_DEBUG) 979d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \ 989d68db50SFlorian Fainelli do { \ 999d68db50SFlorian Fainelli if ((pl)->config->type == PHYLINK_NETDEV) \ 1009d68db50SFlorian Fainelli netdev_dbg((pl)->netdev, fmt, ##__VA_ARGS__); \ 1019d68db50SFlorian Fainelli else if ((pl)->config->type == PHYLINK_DEV) \ 1029d68db50SFlorian Fainelli dev_dbg((pl)->dev, fmt, ##__VA_ARGS__); \ 1039d68db50SFlorian Fainelli } while (0) 1049d68db50SFlorian Fainelli #elif defined(DEBUG) 10517091180SIoana Ciornei #define phylink_dbg(pl, fmt, ...) \ 10617091180SIoana Ciornei phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__) 1079d68db50SFlorian Fainelli #else 1089d68db50SFlorian Fainelli #define phylink_dbg(pl, fmt, ...) \ 1099d68db50SFlorian Fainelli ({ \ 1109d68db50SFlorian Fainelli if (0) \ 1119d68db50SFlorian Fainelli phylink_printk(KERN_DEBUG, pl, fmt, ##__VA_ARGS__); \ 1129d68db50SFlorian Fainelli }) 1139d68db50SFlorian Fainelli #endif 11417091180SIoana Ciornei 1158796c892SRussell King /** 1168796c892SRussell King * phylink_set_port_modes() - set the port type modes in the ethtool mask 1178796c892SRussell King * @mask: ethtool link mode mask 1188796c892SRussell King * 1198796c892SRussell King * Sets all the port type modes in the ethtool mask. MAC drivers should 1208796c892SRussell King * use this in their 'validate' callback. 1218796c892SRussell King */ 1229525ae83SRussell King void phylink_set_port_modes(unsigned long *mask) 1239525ae83SRussell King { 1249525ae83SRussell King phylink_set(mask, TP); 1259525ae83SRussell King phylink_set(mask, AUI); 1269525ae83SRussell King phylink_set(mask, MII); 1279525ae83SRussell King phylink_set(mask, FIBRE); 1289525ae83SRussell King phylink_set(mask, BNC); 1299525ae83SRussell King phylink_set(mask, Backplane); 1309525ae83SRussell King } 1319525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_set_port_modes); 1329525ae83SRussell King 1339525ae83SRussell King static int phylink_is_empty_linkmode(const unsigned long *linkmode) 1349525ae83SRussell King { 1359525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp) = { 0, }; 1369525ae83SRussell King 1379525ae83SRussell King phylink_set_port_modes(tmp); 1389525ae83SRussell King phylink_set(tmp, Autoneg); 1399525ae83SRussell King phylink_set(tmp, Pause); 1409525ae83SRussell King phylink_set(tmp, Asym_Pause); 1419525ae83SRussell King 142554032cdSRussell King return linkmode_subset(linkmode, tmp); 1439525ae83SRussell King } 1449525ae83SRussell King 1459525ae83SRussell King static const char *phylink_an_mode_str(unsigned int mode) 1469525ae83SRussell King { 1479525ae83SRussell King static const char *modestr[] = { 1489525ae83SRussell King [MLO_AN_PHY] = "phy", 1499525ae83SRussell King [MLO_AN_FIXED] = "fixed", 15086a362c4SRussell King [MLO_AN_INBAND] = "inband", 1519525ae83SRussell King }; 1529525ae83SRussell King 1539525ae83SRussell King return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; 1549525ae83SRussell King } 1559525ae83SRussell King 1569525ae83SRussell King static int phylink_validate(struct phylink *pl, unsigned long *supported, 1579525ae83SRussell King struct phylink_link_state *state) 1589525ae83SRussell King { 159e7765d63SRussell King pl->mac_ops->validate(pl->config, supported, state); 1609525ae83SRussell King 1619525ae83SRussell King return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; 1629525ae83SRussell King } 1639525ae83SRussell King 1648fa7b9b6SRussell King static int phylink_parse_fixedlink(struct phylink *pl, 1658fa7b9b6SRussell King struct fwnode_handle *fwnode) 1669525ae83SRussell King { 1678fa7b9b6SRussell King struct fwnode_handle *fixed_node; 1689525ae83SRussell King const struct phy_setting *s; 1699525ae83SRussell King struct gpio_desc *desc; 1709525ae83SRussell King u32 speed; 1718fa7b9b6SRussell King int ret; 1729525ae83SRussell King 1738fa7b9b6SRussell King fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); 1749525ae83SRussell King if (fixed_node) { 1758fa7b9b6SRussell King ret = fwnode_property_read_u32(fixed_node, "speed", &speed); 1769525ae83SRussell King 1779525ae83SRussell King pl->link_config.speed = speed; 1789525ae83SRussell King pl->link_config.duplex = DUPLEX_HALF; 1799525ae83SRussell King 1808fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "full-duplex")) 1819525ae83SRussell King pl->link_config.duplex = DUPLEX_FULL; 1829525ae83SRussell King 1839525ae83SRussell King /* We treat the "pause" and "asym-pause" terminology as 1849525ae83SRussell King * defining the link partner's ability. */ 1858fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "pause")) 1864e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, 1874e5aeb41SRussell King pl->link_config.lp_advertising); 1888fa7b9b6SRussell King if (fwnode_property_read_bool(fixed_node, "asym-pause")) 1894e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 1904e5aeb41SRussell King pl->link_config.lp_advertising); 1919525ae83SRussell King 1929525ae83SRussell King if (ret == 0) { 193b605c9abSDmitry Torokhov desc = fwnode_gpiod_get_index(fixed_node, "link", 0, 194b605c9abSDmitry Torokhov GPIOD_IN, "?"); 1959525ae83SRussell King 1969525ae83SRussell King if (!IS_ERR(desc)) 1979525ae83SRussell King pl->link_gpio = desc; 1989525ae83SRussell King else if (desc == ERR_PTR(-EPROBE_DEFER)) 1999525ae83SRussell King ret = -EPROBE_DEFER; 2009525ae83SRussell King } 2018fa7b9b6SRussell King fwnode_handle_put(fixed_node); 2029525ae83SRussell King 2039525ae83SRussell King if (ret) 2049525ae83SRussell King return ret; 2059525ae83SRussell King } else { 2068fa7b9b6SRussell King u32 prop[5]; 2078fa7b9b6SRussell King 2088fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link", 2098fa7b9b6SRussell King NULL, 0); 2108fa7b9b6SRussell King if (ret != ARRAY_SIZE(prop)) { 21117091180SIoana Ciornei phylink_err(pl, "broken fixed-link?\n"); 2129525ae83SRussell King return -EINVAL; 2139525ae83SRussell King } 2148fa7b9b6SRussell King 2158fa7b9b6SRussell King ret = fwnode_property_read_u32_array(fwnode, "fixed-link", 2168fa7b9b6SRussell King prop, ARRAY_SIZE(prop)); 2178fa7b9b6SRussell King if (!ret) { 2188fa7b9b6SRussell King pl->link_config.duplex = prop[1] ? 2199525ae83SRussell King DUPLEX_FULL : DUPLEX_HALF; 2208fa7b9b6SRussell King pl->link_config.speed = prop[2]; 2218fa7b9b6SRussell King if (prop[3]) 2224e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, 2234e5aeb41SRussell King pl->link_config.lp_advertising); 2248fa7b9b6SRussell King if (prop[4]) 2254e5aeb41SRussell King __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 2264e5aeb41SRussell King pl->link_config.lp_advertising); 2279525ae83SRussell King } 2289525ae83SRussell King } 2299525ae83SRussell King 2309525ae83SRussell King if (pl->link_config.speed > SPEED_1000 && 2319525ae83SRussell King pl->link_config.duplex != DUPLEX_FULL) 23217091180SIoana Ciornei phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n", 2339525ae83SRussell King pl->link_config.speed); 2349525ae83SRussell King 2359525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 2369525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 2379525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config); 2389525ae83SRussell King 2399525ae83SRussell King s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex, 2403c1bcc86SAndrew Lunn pl->supported, true); 2419525ae83SRussell King linkmode_zero(pl->supported); 2429525ae83SRussell King phylink_set(pl->supported, MII); 2438aace4f3SRené van Dorst phylink_set(pl->supported, Pause); 2448aace4f3SRené van Dorst phylink_set(pl->supported, Asym_Pause); 2451ceb7ee7SRussell King phylink_set(pl->supported, Autoneg); 2469525ae83SRussell King if (s) { 2479525ae83SRussell King __set_bit(s->bit, pl->supported); 2481ceb7ee7SRussell King __set_bit(s->bit, pl->link_config.lp_advertising); 2499525ae83SRussell King } else { 25017091180SIoana Ciornei phylink_warn(pl, "fixed link %s duplex %dMbps not recognised\n", 2519525ae83SRussell King pl->link_config.duplex == DUPLEX_FULL ? "full" : "half", 2529525ae83SRussell King pl->link_config.speed); 2539525ae83SRussell King } 2549525ae83SRussell King 2559525ae83SRussell King linkmode_and(pl->link_config.advertising, pl->link_config.advertising, 2569525ae83SRussell King pl->supported); 2579525ae83SRussell King 2589525ae83SRussell King pl->link_config.link = 1; 2599525ae83SRussell King pl->link_config.an_complete = 1; 2609525ae83SRussell King 2619525ae83SRussell King return 0; 2629525ae83SRussell King } 2639525ae83SRussell King 2648fa7b9b6SRussell King static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) 2659525ae83SRussell King { 2668fa7b9b6SRussell King struct fwnode_handle *dn; 2679525ae83SRussell King const char *managed; 2689525ae83SRussell King 2698fa7b9b6SRussell King dn = fwnode_get_named_child_node(fwnode, "fixed-link"); 2708fa7b9b6SRussell King if (dn || fwnode_property_present(fwnode, "fixed-link")) 27124cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_FIXED; 2728fa7b9b6SRussell King fwnode_handle_put(dn); 2739525ae83SRussell King 2748fa7b9b6SRussell King if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 && 2759525ae83SRussell King strcmp(managed, "in-band-status") == 0) { 27624cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) { 27717091180SIoana Ciornei phylink_err(pl, 2789525ae83SRussell King "can't use both fixed-link and in-band-status\n"); 2799525ae83SRussell King return -EINVAL; 2809525ae83SRussell King } 2819525ae83SRussell King 2829525ae83SRussell King linkmode_zero(pl->supported); 2839525ae83SRussell King phylink_set(pl->supported, MII); 2849525ae83SRussell King phylink_set(pl->supported, Autoneg); 2859525ae83SRussell King phylink_set(pl->supported, Asym_Pause); 2869525ae83SRussell King phylink_set(pl->supported, Pause); 2879525ae83SRussell King pl->link_config.an_enabled = true; 28824cf0e69SRussell King pl->cfg_link_an_mode = MLO_AN_INBAND; 2899525ae83SRussell King 2909525ae83SRussell King switch (pl->link_config.interface) { 2919525ae83SRussell King case PHY_INTERFACE_MODE_SGMII: 2923a68ba6fSVladimir Oltean case PHY_INTERFACE_MODE_QSGMII: 2939525ae83SRussell King phylink_set(pl->supported, 10baseT_Half); 2949525ae83SRussell King phylink_set(pl->supported, 10baseT_Full); 2959525ae83SRussell King phylink_set(pl->supported, 100baseT_Half); 2969525ae83SRussell King phylink_set(pl->supported, 100baseT_Full); 2979525ae83SRussell King phylink_set(pl->supported, 1000baseT_Half); 2989525ae83SRussell King phylink_set(pl->supported, 1000baseT_Full); 2999525ae83SRussell King break; 3009525ae83SRussell King 3019525ae83SRussell King case PHY_INTERFACE_MODE_1000BASEX: 3029525ae83SRussell King phylink_set(pl->supported, 1000baseX_Full); 3039525ae83SRussell King break; 3049525ae83SRussell King 3059525ae83SRussell King case PHY_INTERFACE_MODE_2500BASEX: 3069525ae83SRussell King phylink_set(pl->supported, 2500baseX_Full); 3079525ae83SRussell King break; 3089525ae83SRussell King 30904e22463SAlex Marginean case PHY_INTERFACE_MODE_USXGMII: 310da7c1862SRussell King case PHY_INTERFACE_MODE_10GKR: 311e0f909bcSRussell King case PHY_INTERFACE_MODE_10GBASER: 312da7c1862SRussell King phylink_set(pl->supported, 10baseT_Half); 313da7c1862SRussell King phylink_set(pl->supported, 10baseT_Full); 314da7c1862SRussell King phylink_set(pl->supported, 100baseT_Half); 315da7c1862SRussell King phylink_set(pl->supported, 100baseT_Full); 316da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Half); 317da7c1862SRussell King phylink_set(pl->supported, 1000baseT_Full); 318da7c1862SRussell King phylink_set(pl->supported, 1000baseX_Full); 319c580165fSJose Abreu phylink_set(pl->supported, 1000baseKX_Full); 3206cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseT_Full); 3216cbdcf25SVladimir Oltean phylink_set(pl->supported, 2500baseX_Full); 3226cbdcf25SVladimir Oltean phylink_set(pl->supported, 5000baseT_Full); 3236cbdcf25SVladimir Oltean phylink_set(pl->supported, 10000baseT_Full); 324da7c1862SRussell King phylink_set(pl->supported, 10000baseKR_Full); 325c580165fSJose Abreu phylink_set(pl->supported, 10000baseKX4_Full); 326da7c1862SRussell King phylink_set(pl->supported, 10000baseCR_Full); 327da7c1862SRussell King phylink_set(pl->supported, 10000baseSR_Full); 328da7c1862SRussell King phylink_set(pl->supported, 10000baseLR_Full); 329da7c1862SRussell King phylink_set(pl->supported, 10000baseLRM_Full); 330da7c1862SRussell King phylink_set(pl->supported, 10000baseER_Full); 331da7c1862SRussell King break; 332da7c1862SRussell King 3331671c42dSJose Abreu case PHY_INTERFACE_MODE_XLGMII: 3341671c42dSJose Abreu phylink_set(pl->supported, 25000baseCR_Full); 3351671c42dSJose Abreu phylink_set(pl->supported, 25000baseKR_Full); 3361671c42dSJose Abreu phylink_set(pl->supported, 25000baseSR_Full); 3371671c42dSJose Abreu phylink_set(pl->supported, 40000baseKR4_Full); 3381671c42dSJose Abreu phylink_set(pl->supported, 40000baseCR4_Full); 3391671c42dSJose Abreu phylink_set(pl->supported, 40000baseSR4_Full); 3401671c42dSJose Abreu phylink_set(pl->supported, 40000baseLR4_Full); 3411671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR2_Full); 3421671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR2_Full); 3431671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR2_Full); 3441671c42dSJose Abreu phylink_set(pl->supported, 50000baseKR_Full); 3451671c42dSJose Abreu phylink_set(pl->supported, 50000baseSR_Full); 3461671c42dSJose Abreu phylink_set(pl->supported, 50000baseCR_Full); 3471671c42dSJose Abreu phylink_set(pl->supported, 50000baseLR_ER_FR_Full); 3481671c42dSJose Abreu phylink_set(pl->supported, 50000baseDR_Full); 3491671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR4_Full); 3501671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR4_Full); 3511671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR4_Full); 3521671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR4_ER4_Full); 3531671c42dSJose Abreu phylink_set(pl->supported, 100000baseKR2_Full); 3541671c42dSJose Abreu phylink_set(pl->supported, 100000baseSR2_Full); 3551671c42dSJose Abreu phylink_set(pl->supported, 100000baseCR2_Full); 3561671c42dSJose Abreu phylink_set(pl->supported, 100000baseLR2_ER2_FR2_Full); 3571671c42dSJose Abreu phylink_set(pl->supported, 100000baseDR2_Full); 3581671c42dSJose Abreu break; 3591671c42dSJose Abreu 3609525ae83SRussell King default: 36117091180SIoana Ciornei phylink_err(pl, 3629525ae83SRussell King "incorrect link mode %s for in-band status\n", 3639525ae83SRussell King phy_modes(pl->link_config.interface)); 3649525ae83SRussell King return -EINVAL; 3659525ae83SRussell King } 3669525ae83SRussell King 3679525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 3689525ae83SRussell King 3699525ae83SRussell King if (phylink_validate(pl, pl->supported, &pl->link_config)) { 37017091180SIoana Ciornei phylink_err(pl, 3719525ae83SRussell King "failed to validate link configuration for in-band status\n"); 3729525ae83SRussell King return -EINVAL; 3739525ae83SRussell King } 37494148196SJose Abreu 37594148196SJose Abreu /* Check if MAC/PCS also supports Autoneg. */ 37694148196SJose Abreu pl->link_config.an_enabled = phylink_test(pl->supported, Autoneg); 3779525ae83SRussell King } 3789525ae83SRussell King 3799525ae83SRussell King return 0; 3809525ae83SRussell King } 3819525ae83SRussell King 3822d5fbef0SRussell King static void phylink_apply_manual_flow(struct phylink *pl, 3832d5fbef0SRussell King struct phylink_link_state *state) 3842d5fbef0SRussell King { 3852d5fbef0SRussell King /* If autoneg is disabled, pause AN is also disabled */ 3862d5fbef0SRussell King if (!state->an_enabled) 3872d5fbef0SRussell King state->pause &= ~MLO_PAUSE_AN; 3882d5fbef0SRussell King 3892d5fbef0SRussell King /* Manual configuration of pause modes */ 3902d5fbef0SRussell King if (!(pl->link_config.pause & MLO_PAUSE_AN)) 3912d5fbef0SRussell King state->pause = pl->link_config.pause; 3922d5fbef0SRussell King } 3932d5fbef0SRussell King 3944e5aeb41SRussell King static void phylink_resolve_flow(struct phylink_link_state *state) 3954e5aeb41SRussell King { 3964e5aeb41SRussell King bool tx_pause, rx_pause; 3974e5aeb41SRussell King 3984e5aeb41SRussell King state->pause = MLO_PAUSE_NONE; 3994e5aeb41SRussell King if (state->duplex == DUPLEX_FULL) { 4004e5aeb41SRussell King linkmode_resolve_pause(state->advertising, 4014e5aeb41SRussell King state->lp_advertising, 4024e5aeb41SRussell King &tx_pause, &rx_pause); 4034e5aeb41SRussell King if (tx_pause) 4044e5aeb41SRussell King state->pause |= MLO_PAUSE_TX; 4054e5aeb41SRussell King if (rx_pause) 4064e5aeb41SRussell King state->pause |= MLO_PAUSE_RX; 4074e5aeb41SRussell King } 4084e5aeb41SRussell King } 4094e5aeb41SRussell King 4109525ae83SRussell King static void phylink_mac_config(struct phylink *pl, 4119525ae83SRussell King const struct phylink_link_state *state) 4129525ae83SRussell King { 41317091180SIoana Ciornei phylink_dbg(pl, 4149525ae83SRussell King "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", 41524cf0e69SRussell King __func__, phylink_an_mode_str(pl->cur_link_an_mode), 4169525ae83SRussell King phy_modes(state->interface), 4179525ae83SRussell King phy_speed_to_str(state->speed), 4189525ae83SRussell King phy_duplex_to_str(state->duplex), 4199525ae83SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, 4209525ae83SRussell King state->pause, state->link, state->an_enabled); 4219525ae83SRussell King 422e7765d63SRussell King pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state); 4239525ae83SRussell King } 4249525ae83SRussell King 4254c0d6d3aSRussell King static void phylink_mac_pcs_an_restart(struct phylink *pl) 4269525ae83SRussell King { 4279525ae83SRussell King if (pl->link_config.an_enabled && 428575691b3SRussell King phy_interface_mode_is_8023z(pl->link_config.interface) && 429575691b3SRussell King phylink_autoneg_inband(pl->cur_link_an_mode)) { 4304c0d6d3aSRussell King if (pl->pcs_ops) 4317137e18fSRussell King pl->pcs_ops->pcs_an_restart(pl->pcs); 4324c0d6d3aSRussell King else 433e7765d63SRussell King pl->mac_ops->mac_an_restart(pl->config); 4349525ae83SRussell King } 4354c0d6d3aSRussell King } 4364c0d6d3aSRussell King 437b7ad14c2SRussell King static void phylink_major_config(struct phylink *pl, bool restart, 4384c0d6d3aSRussell King const struct phylink_link_state *state) 4394c0d6d3aSRussell King { 440b7ad14c2SRussell King int err; 4414c0d6d3aSRussell King 442b7ad14c2SRussell King phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); 443b7ad14c2SRussell King 444b7ad14c2SRussell King if (pl->mac_ops->mac_prepare) { 445b7ad14c2SRussell King err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, 446b7ad14c2SRussell King state->interface); 447b7ad14c2SRussell King if (err < 0) { 448b7ad14c2SRussell King phylink_err(pl, "mac_prepare failed: %pe\n", 449b7ad14c2SRussell King ERR_PTR(err)); 450b7ad14c2SRussell King return; 451b7ad14c2SRussell King } 452b7ad14c2SRussell King } 4534c0d6d3aSRussell King 4544c0d6d3aSRussell King phylink_mac_config(pl, state); 4554c0d6d3aSRussell King 456b7ad14c2SRussell King if (pl->pcs_ops) { 4577137e18fSRussell King err = pl->pcs_ops->pcs_config(pl->pcs, pl->cur_link_an_mode, 458b7ad14c2SRussell King state->interface, 459b7ad14c2SRussell King state->advertising, 460b7ad14c2SRussell King !!(pl->link_config.pause & 461b7ad14c2SRussell King MLO_PAUSE_AN)); 462b7ad14c2SRussell King if (err < 0) 463b7ad14c2SRussell King phylink_err(pl, "pcs_config failed: %pe\n", 464b7ad14c2SRussell King ERR_PTR(err)); 465b7ad14c2SRussell King if (err > 0) 466b7ad14c2SRussell King restart = true; 467b7ad14c2SRussell King } 4684c0d6d3aSRussell King if (restart) 4694c0d6d3aSRussell King phylink_mac_pcs_an_restart(pl); 470b7ad14c2SRussell King 471b7ad14c2SRussell King if (pl->mac_ops->mac_finish) { 472b7ad14c2SRussell King err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode, 473b7ad14c2SRussell King state->interface); 474b7ad14c2SRussell King if (err < 0) 475b7ad14c2SRussell King phylink_err(pl, "mac_prepare failed: %pe\n", 476b7ad14c2SRussell King ERR_PTR(err)); 477b7ad14c2SRussell King } 4784c0d6d3aSRussell King } 4799525ae83SRussell King 4801571e700SRussell King /* 4811571e700SRussell King * Reconfigure for a change of inband advertisement. 4821571e700SRussell King * If we have a separate PCS, we only need to call its pcs_config() method, 4831571e700SRussell King * and then restart AN if it indicates something changed. Otherwise, we do 4841571e700SRussell King * the full MAC reconfiguration. 4851571e700SRussell King */ 4861571e700SRussell King static int phylink_change_inband_advert(struct phylink *pl) 4871571e700SRussell King { 4881571e700SRussell King int ret; 4891571e700SRussell King 4901571e700SRussell King if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) 4911571e700SRussell King return 0; 4921571e700SRussell King 4931571e700SRussell King if (!pl->pcs_ops) { 4941571e700SRussell King /* Legacy method */ 4951571e700SRussell King phylink_mac_config(pl, &pl->link_config); 4961571e700SRussell King phylink_mac_pcs_an_restart(pl); 4971571e700SRussell King return 0; 4981571e700SRussell King } 4991571e700SRussell King 5001571e700SRussell King phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__, 5011571e700SRussell King phylink_an_mode_str(pl->cur_link_an_mode), 5021571e700SRussell King phy_modes(pl->link_config.interface), 5031571e700SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising, 5041571e700SRussell King pl->link_config.pause); 5051571e700SRussell King 5061571e700SRussell King /* Modern PCS-based method; update the advert at the PCS, and 5071571e700SRussell King * restart negotiation if the pcs_config() helper indicates that 5081571e700SRussell King * the programmed advertisement has changed. 5091571e700SRussell King */ 5107137e18fSRussell King ret = pl->pcs_ops->pcs_config(pl->pcs, pl->cur_link_an_mode, 5111571e700SRussell King pl->link_config.interface, 5121571e700SRussell King pl->link_config.advertising, 5131571e700SRussell King !!(pl->link_config.pause & MLO_PAUSE_AN)); 5141571e700SRussell King if (ret < 0) 5151571e700SRussell King return ret; 5161571e700SRussell King 5171571e700SRussell King if (ret > 0) 5181571e700SRussell King phylink_mac_pcs_an_restart(pl); 5191571e700SRussell King 5201571e700SRussell King return 0; 5211571e700SRussell King } 5221571e700SRussell King 523d46b7e4fSRussell King static void phylink_mac_pcs_get_state(struct phylink *pl, 524d46b7e4fSRussell King struct phylink_link_state *state) 5259525ae83SRussell King { 5269525ae83SRussell King linkmode_copy(state->advertising, pl->link_config.advertising); 5279525ae83SRussell King linkmode_zero(state->lp_advertising); 5289525ae83SRussell King state->interface = pl->link_config.interface; 5299525ae83SRussell King state->an_enabled = pl->link_config.an_enabled; 530d25ed413SHeiner Kallweit state->speed = SPEED_UNKNOWN; 531d25ed413SHeiner Kallweit state->duplex = DUPLEX_UNKNOWN; 532d25ed413SHeiner Kallweit state->pause = MLO_PAUSE_NONE; 533d25ed413SHeiner Kallweit state->an_complete = 0; 5349525ae83SRussell King state->link = 1; 5359525ae83SRussell King 5364c0d6d3aSRussell King if (pl->pcs_ops) 5377137e18fSRussell King pl->pcs_ops->pcs_get_state(pl->pcs, state); 538e859a60aSRussell King else if (pl->mac_ops->mac_pcs_get_state) 539e7765d63SRussell King pl->mac_ops->mac_pcs_get_state(pl->config, state); 540e859a60aSRussell King else 541e859a60aSRussell King state->link = 0; 5429525ae83SRussell King } 5439525ae83SRussell King 5449525ae83SRussell King /* The fixed state is... fixed except for the link state, 5451ac63e39SFlorian Fainelli * which may be determined by a GPIO or a callback. 5469525ae83SRussell King */ 5474e5aeb41SRussell King static void phylink_get_fixed_state(struct phylink *pl, 5484e5aeb41SRussell King struct phylink_link_state *state) 5499525ae83SRussell King { 5509525ae83SRussell King *state = pl->link_config; 5515c05c1dbSRussell King if (pl->config->get_fixed_state) 5525c05c1dbSRussell King pl->config->get_fixed_state(pl->config, state); 5531ac63e39SFlorian Fainelli else if (pl->link_gpio) 554bb322a90SFlorian Fainelli state->link = !!gpiod_get_value_cansleep(pl->link_gpio); 5559525ae83SRussell King 5564e5aeb41SRussell King phylink_resolve_flow(state); 5579525ae83SRussell King } 5589525ae83SRussell King 5594c0d6d3aSRussell King static void phylink_mac_initial_config(struct phylink *pl, bool force_restart) 56097fec51fSRussell King { 56197fec51fSRussell King struct phylink_link_state link_state; 56297fec51fSRussell King 56397fec51fSRussell King switch (pl->cur_link_an_mode) { 56497fec51fSRussell King case MLO_AN_PHY: 56597fec51fSRussell King link_state = pl->phy_state; 56697fec51fSRussell King break; 56797fec51fSRussell King 56897fec51fSRussell King case MLO_AN_FIXED: 56997fec51fSRussell King phylink_get_fixed_state(pl, &link_state); 57097fec51fSRussell King break; 57197fec51fSRussell King 57297fec51fSRussell King case MLO_AN_INBAND: 57397fec51fSRussell King link_state = pl->link_config; 57497fec51fSRussell King if (link_state.interface == PHY_INTERFACE_MODE_SGMII) 57597fec51fSRussell King link_state.pause = MLO_PAUSE_NONE; 57697fec51fSRussell King break; 57797fec51fSRussell King 57897fec51fSRussell King default: /* can't happen */ 57997fec51fSRussell King return; 58097fec51fSRussell King } 58197fec51fSRussell King 58297fec51fSRussell King link_state.link = false; 58397fec51fSRussell King 58497fec51fSRussell King phylink_apply_manual_flow(pl, &link_state); 585b7ad14c2SRussell King phylink_major_config(pl, force_restart, &link_state); 58697fec51fSRussell King } 58797fec51fSRussell King 5889525ae83SRussell King static const char *phylink_pause_to_str(int pause) 5899525ae83SRussell King { 5909525ae83SRussell King switch (pause & MLO_PAUSE_TXRX_MASK) { 5919525ae83SRussell King case MLO_PAUSE_TX | MLO_PAUSE_RX: 5929525ae83SRussell King return "rx/tx"; 5939525ae83SRussell King case MLO_PAUSE_TX: 5949525ae83SRussell King return "tx"; 5959525ae83SRussell King case MLO_PAUSE_RX: 5969525ae83SRussell King return "rx"; 5979525ae83SRussell King default: 5989525ae83SRussell King return "off"; 5999525ae83SRussell King } 6009525ae83SRussell King } 6019525ae83SRussell King 6024c0d6d3aSRussell King static void phylink_link_up(struct phylink *pl, 60327755ff8SIoana Ciornei struct phylink_link_state link_state) 60427755ff8SIoana Ciornei { 60527755ff8SIoana Ciornei struct net_device *ndev = pl->netdev; 60627755ff8SIoana Ciornei 607b4b12b0dSDavid S. Miller pl->cur_interface = link_state.interface; 6084c0d6d3aSRussell King 6094c0d6d3aSRussell King if (pl->pcs_ops && pl->pcs_ops->pcs_link_up) 6107137e18fSRussell King pl->pcs_ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode, 6114c0d6d3aSRussell King pl->cur_interface, 6124c0d6d3aSRussell King link_state.speed, link_state.duplex); 6134c0d6d3aSRussell King 614e7765d63SRussell King pl->mac_ops->mac_link_up(pl->config, pl->phydev, 61591a208f2SRussell King pl->cur_link_an_mode, pl->cur_interface, 61691a208f2SRussell King link_state.speed, link_state.duplex, 61791a208f2SRussell King !!(link_state.pause & MLO_PAUSE_TX), 61891a208f2SRussell King !!(link_state.pause & MLO_PAUSE_RX)); 61927755ff8SIoana Ciornei 62043de6195SIoana Ciornei if (ndev) 62127755ff8SIoana Ciornei netif_carrier_on(ndev); 62227755ff8SIoana Ciornei 62317091180SIoana Ciornei phylink_info(pl, 62427755ff8SIoana Ciornei "Link is Up - %s/%s - flow control %s\n", 62527755ff8SIoana Ciornei phy_speed_to_str(link_state.speed), 62627755ff8SIoana Ciornei phy_duplex_to_str(link_state.duplex), 62727755ff8SIoana Ciornei phylink_pause_to_str(link_state.pause)); 62827755ff8SIoana Ciornei } 62927755ff8SIoana Ciornei 6304c0d6d3aSRussell King static void phylink_link_down(struct phylink *pl) 63127755ff8SIoana Ciornei { 63227755ff8SIoana Ciornei struct net_device *ndev = pl->netdev; 63327755ff8SIoana Ciornei 63443de6195SIoana Ciornei if (ndev) 63527755ff8SIoana Ciornei netif_carrier_off(ndev); 636e7765d63SRussell King pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode, 637b4b12b0dSDavid S. Miller pl->cur_interface); 63817091180SIoana Ciornei phylink_info(pl, "Link is Down\n"); 63927755ff8SIoana Ciornei } 64027755ff8SIoana Ciornei 6419525ae83SRussell King static void phylink_resolve(struct work_struct *w) 6429525ae83SRussell King { 6439525ae83SRussell King struct phylink *pl = container_of(w, struct phylink, resolve); 6449525ae83SRussell King struct phylink_link_state link_state; 6459525ae83SRussell King struct net_device *ndev = pl->netdev; 646319bfafeSRussell King bool mac_config = false; 647b06e5cacSRussell King bool cur_link_state; 6489525ae83SRussell King 6499525ae83SRussell King mutex_lock(&pl->state_mutex); 650b06e5cacSRussell King if (pl->netdev) 651b06e5cacSRussell King cur_link_state = netif_carrier_ok(ndev); 652b06e5cacSRussell King else 653b06e5cacSRussell King cur_link_state = pl->old_link_state; 654b06e5cacSRussell King 6559525ae83SRussell King if (pl->phylink_disable_state) { 6569525ae83SRussell King pl->mac_link_dropped = false; 6579525ae83SRussell King link_state.link = false; 6589525ae83SRussell King } else if (pl->mac_link_dropped) { 6599525ae83SRussell King link_state.link = false; 6609525ae83SRussell King } else { 66124cf0e69SRussell King switch (pl->cur_link_an_mode) { 6629525ae83SRussell King case MLO_AN_PHY: 6639525ae83SRussell King link_state = pl->phy_state; 6642d5fbef0SRussell King phylink_apply_manual_flow(pl, &link_state); 665319bfafeSRussell King mac_config = link_state.link; 6669525ae83SRussell King break; 6679525ae83SRussell King 6689525ae83SRussell King case MLO_AN_FIXED: 6699525ae83SRussell King phylink_get_fixed_state(pl, &link_state); 670319bfafeSRussell King mac_config = link_state.link; 6719525ae83SRussell King break; 6729525ae83SRussell King 67386a362c4SRussell King case MLO_AN_INBAND: 674d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state); 6759525ae83SRussell King 676406cb0c4SRussell King /* If we have a phy, the "up" state is the union of 677406cb0c4SRussell King * both the PHY and the MAC */ 678406cb0c4SRussell King if (pl->phydev) 679406cb0c4SRussell King link_state.link &= pl->phy_state.link; 6809525ae83SRussell King 681406cb0c4SRussell King /* Only update if the PHY link is up */ 682406cb0c4SRussell King if (pl->phydev && pl->phy_state.link) { 6839525ae83SRussell King link_state.interface = pl->phy_state.interface; 6849525ae83SRussell King 685406cb0c4SRussell King /* If we have a PHY, we need to update with 68633faac8eSRussell King * the PHY flow control bits. */ 68733faac8eSRussell King link_state.pause = pl->phy_state.pause; 688319bfafeSRussell King mac_config = true; 6899525ae83SRussell King } 690319bfafeSRussell King phylink_apply_manual_flow(pl, &link_state); 6919525ae83SRussell King break; 6929525ae83SRussell King } 6939525ae83SRussell King } 6949525ae83SRussell King 69516319a7dSRussell King if (mac_config) { 69616319a7dSRussell King if (link_state.interface != pl->link_config.interface) { 69716319a7dSRussell King /* The interface has changed, force the link down and 69816319a7dSRussell King * then reconfigure. 69916319a7dSRussell King */ 70016319a7dSRussell King if (cur_link_state) { 70116319a7dSRussell King phylink_link_down(pl); 70216319a7dSRussell King cur_link_state = false; 70316319a7dSRussell King } 704b7ad14c2SRussell King phylink_major_config(pl, false, &link_state); 7055005b163SRussell King pl->link_config.interface = link_state.interface; 7067cceb599SRussell King } else if (!pl->pcs_ops) { 7075005b163SRussell King /* The interface remains unchanged, only the speed, 7085005b163SRussell King * duplex or pause settings have changed. Call the 7097cceb599SRussell King * old mac_config() method to configure the MAC/PCS 7107cceb599SRussell King * only if we do not have a PCS installed (an 7117cceb599SRussell King * unconverted user.) 7125005b163SRussell King */ 713319bfafeSRussell King phylink_mac_config(pl, &link_state); 71416319a7dSRussell King } 7155005b163SRussell King } 716319bfafeSRussell King 717b06e5cacSRussell King if (link_state.link != cur_link_state) { 71843de6195SIoana Ciornei pl->old_link_state = link_state.link; 71927755ff8SIoana Ciornei if (!link_state.link) 7204c0d6d3aSRussell King phylink_link_down(pl); 72127755ff8SIoana Ciornei else 7224c0d6d3aSRussell King phylink_link_up(pl, link_state); 7239525ae83SRussell King } 7249525ae83SRussell King if (!link_state.link && pl->mac_link_dropped) { 7259525ae83SRussell King pl->mac_link_dropped = false; 7269525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve); 7279525ae83SRussell King } 7289525ae83SRussell King mutex_unlock(&pl->state_mutex); 7299525ae83SRussell King } 7309525ae83SRussell King 7319525ae83SRussell King static void phylink_run_resolve(struct phylink *pl) 7329525ae83SRussell King { 7339525ae83SRussell King if (!pl->phylink_disable_state) 7349525ae83SRussell King queue_work(system_power_efficient_wq, &pl->resolve); 7359525ae83SRussell King } 7369525ae83SRussell King 73787454b6eSRussell King static void phylink_run_resolve_and_disable(struct phylink *pl, int bit) 73887454b6eSRussell King { 73987454b6eSRussell King unsigned long state = pl->phylink_disable_state; 74087454b6eSRussell King 74187454b6eSRussell King set_bit(bit, &pl->phylink_disable_state); 74287454b6eSRussell King if (state == 0) { 74387454b6eSRussell King queue_work(system_power_efficient_wq, &pl->resolve); 74487454b6eSRussell King flush_work(&pl->resolve); 74587454b6eSRussell King } 74687454b6eSRussell King } 74787454b6eSRussell King 7489cd00a8aSRussell King static void phylink_fixed_poll(struct timer_list *t) 7499cd00a8aSRussell King { 7509cd00a8aSRussell King struct phylink *pl = container_of(t, struct phylink, link_poll); 7519cd00a8aSRussell King 7529cd00a8aSRussell King mod_timer(t, jiffies + HZ); 7539cd00a8aSRussell King 7549cd00a8aSRussell King phylink_run_resolve(pl); 7559cd00a8aSRussell King } 7569cd00a8aSRussell King 757ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops; 758ce0aa27fSRussell King 7598fa7b9b6SRussell King static int phylink_register_sfp(struct phylink *pl, 7608fa7b9b6SRussell King struct fwnode_handle *fwnode) 761ce0aa27fSRussell King { 7622203cbf2SRussell King struct sfp_bus *bus; 7638fa7b9b6SRussell King int ret; 764ce0aa27fSRussell King 765eed70fd9SRussell King if (!fwnode) 766eed70fd9SRussell King return 0; 767eed70fd9SRussell King 768727b3668SRussell King bus = sfp_bus_find_fwnode(fwnode); 7692203cbf2SRussell King if (IS_ERR(bus)) { 7702203cbf2SRussell King ret = PTR_ERR(bus); 7712203cbf2SRussell King phylink_err(pl, "unable to attach SFP bus: %d\n", ret); 7728fa7b9b6SRussell King return ret; 7738fa7b9b6SRussell King } 7748fa7b9b6SRussell King 7752203cbf2SRussell King pl->sfp_bus = bus; 776ce0aa27fSRussell King 777727b3668SRussell King ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops); 778727b3668SRussell King sfp_bus_put(bus); 779727b3668SRussell King 780727b3668SRussell King return ret; 781ce0aa27fSRussell King } 782ce0aa27fSRussell King 7838796c892SRussell King /** 7848796c892SRussell King * phylink_create() - create a phylink instance 7859db74e51SRandy Dunlap * @config: a pointer to the target &struct phylink_config 7868fa7b9b6SRussell King * @fwnode: a pointer to a &struct fwnode_handle describing the network 7878fa7b9b6SRussell King * interface 7888796c892SRussell King * @iface: the desired link mode defined by &typedef phy_interface_t 789e7765d63SRussell King * @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC. 7908796c892SRussell King * 7918796c892SRussell King * Create a new phylink instance, and parse the link parameters found in @np. 7928796c892SRussell King * This will parse in-band modes, fixed-link or SFP configuration. 7938796c892SRussell King * 794269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function. 795269a6b5fSRussell King * 7968796c892SRussell King * Returns a pointer to a &struct phylink, or an error-pointer value. Users 7978796c892SRussell King * must use IS_ERR() to check for errors from this function. 7988796c892SRussell King */ 79944cc27e4SIoana Ciornei struct phylink *phylink_create(struct phylink_config *config, 8008fa7b9b6SRussell King struct fwnode_handle *fwnode, 801516b29edSFlorian Fainelli phy_interface_t iface, 802e7765d63SRussell King const struct phylink_mac_ops *mac_ops) 8039525ae83SRussell King { 8049525ae83SRussell King struct phylink *pl; 8059525ae83SRussell King int ret; 8069525ae83SRussell King 8079525ae83SRussell King pl = kzalloc(sizeof(*pl), GFP_KERNEL); 8089525ae83SRussell King if (!pl) 8099525ae83SRussell King return ERR_PTR(-ENOMEM); 8109525ae83SRussell King 8119525ae83SRussell King mutex_init(&pl->state_mutex); 8129525ae83SRussell King INIT_WORK(&pl->resolve, phylink_resolve); 81344cc27e4SIoana Ciornei 81444cc27e4SIoana Ciornei pl->config = config; 81544cc27e4SIoana Ciornei if (config->type == PHYLINK_NETDEV) { 81644cc27e4SIoana Ciornei pl->netdev = to_net_dev(config->dev); 81743de6195SIoana Ciornei } else if (config->type == PHYLINK_DEV) { 81843de6195SIoana Ciornei pl->dev = config->dev; 81944cc27e4SIoana Ciornei } else { 82044cc27e4SIoana Ciornei kfree(pl); 82144cc27e4SIoana Ciornei return ERR_PTR(-EINVAL); 82244cc27e4SIoana Ciornei } 82344cc27e4SIoana Ciornei 8249525ae83SRussell King pl->phy_state.interface = iface; 8259525ae83SRussell King pl->link_interface = iface; 8264be11ef0SFlorian Fainelli if (iface == PHY_INTERFACE_MODE_MOCA) 8274be11ef0SFlorian Fainelli pl->link_port = PORT_BNC; 8284be11ef0SFlorian Fainelli else 8299525ae83SRussell King pl->link_port = PORT_MII; 8309525ae83SRussell King pl->link_config.interface = iface; 8319525ae83SRussell King pl->link_config.pause = MLO_PAUSE_AN; 8329525ae83SRussell King pl->link_config.speed = SPEED_UNKNOWN; 8339525ae83SRussell King pl->link_config.duplex = DUPLEX_UNKNOWN; 83474ee0e8cSRussell King pl->link_config.an_enabled = true; 835e7765d63SRussell King pl->mac_ops = mac_ops; 8369525ae83SRussell King __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); 8379cd00a8aSRussell King timer_setup(&pl->link_poll, phylink_fixed_poll, 0); 8389525ae83SRussell King 8399525ae83SRussell King bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 8409525ae83SRussell King linkmode_copy(pl->link_config.advertising, pl->supported); 8419525ae83SRussell King phylink_validate(pl, pl->supported, &pl->link_config); 8429525ae83SRussell King 8438fa7b9b6SRussell King ret = phylink_parse_mode(pl, fwnode); 8449525ae83SRussell King if (ret < 0) { 8459525ae83SRussell King kfree(pl); 8469525ae83SRussell King return ERR_PTR(ret); 8479525ae83SRussell King } 8489525ae83SRussell King 84924cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED) { 8508fa7b9b6SRussell King ret = phylink_parse_fixedlink(pl, fwnode); 8519525ae83SRussell King if (ret < 0) { 8529525ae83SRussell King kfree(pl); 8539525ae83SRussell King return ERR_PTR(ret); 8549525ae83SRussell King } 8559525ae83SRussell King } 8569525ae83SRussell King 85724cf0e69SRussell King pl->cur_link_an_mode = pl->cfg_link_an_mode; 85824cf0e69SRussell King 8598fa7b9b6SRussell King ret = phylink_register_sfp(pl, fwnode); 860ce0aa27fSRussell King if (ret < 0) { 861ce0aa27fSRussell King kfree(pl); 862ce0aa27fSRussell King return ERR_PTR(ret); 863ce0aa27fSRussell King } 864ce0aa27fSRussell King 8659525ae83SRussell King return pl; 8669525ae83SRussell King } 8679525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_create); 8689525ae83SRussell King 8697137e18fSRussell King /** 8707137e18fSRussell King * phylink_set_pcs() - set the current PCS for phylink to use 8717137e18fSRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 8727137e18fSRussell King * @pcs: a pointer to the &struct phylink_pcs 8737137e18fSRussell King * 8747137e18fSRussell King * Bind the MAC PCS to phylink. This may be called after phylink_create(), 8757137e18fSRussell King * in mac_prepare() or mac_config() methods if it is desired to dynamically 8767137e18fSRussell King * change the PCS. 8777137e18fSRussell King * 8787137e18fSRussell King * Please note that there are behavioural changes with the mac_config() 8797137e18fSRussell King * callback if a PCS is present (denoting a newer setup) so removing a PCS 8807137e18fSRussell King * is not supported, and if a PCS is going to be used, it must be registered 8817137e18fSRussell King * by calling phylink_set_pcs() at the latest in the first mac_config() call. 8827137e18fSRussell King */ 8837137e18fSRussell King void phylink_set_pcs(struct phylink *pl, struct phylink_pcs *pcs) 8844c0d6d3aSRussell King { 8857137e18fSRussell King pl->pcs = pcs; 8867137e18fSRussell King pl->pcs_ops = pcs->ops; 8874c0d6d3aSRussell King } 8887137e18fSRussell King EXPORT_SYMBOL_GPL(phylink_set_pcs); 8894c0d6d3aSRussell King 8908796c892SRussell King /** 8918796c892SRussell King * phylink_destroy() - cleanup and destroy the phylink instance 8928796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 8938796c892SRussell King * 8948796c892SRussell King * Destroy a phylink instance. Any PHY that has been attached must have been 8958796c892SRussell King * cleaned up via phylink_disconnect_phy() prior to calling this function. 896269a6b5fSRussell King * 897269a6b5fSRussell King * Note: the rtnl lock must not be held when calling this function. 8988796c892SRussell King */ 8999525ae83SRussell King void phylink_destroy(struct phylink *pl) 9009525ae83SRussell King { 901727b3668SRussell King sfp_bus_del_upstream(pl->sfp_bus); 9027b3b0e89SRussell King if (pl->link_gpio) 903daab3349SFlorian Fainelli gpiod_put(pl->link_gpio); 904ce0aa27fSRussell King 9059525ae83SRussell King cancel_work_sync(&pl->resolve); 9069525ae83SRussell King kfree(pl); 9079525ae83SRussell King } 9089525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_destroy); 9099525ae83SRussell King 910a307593aSDoug Berger static void phylink_phy_change(struct phy_device *phydev, bool up) 9119525ae83SRussell King { 9129525ae83SRussell King struct phylink *pl = phydev->phylink; 91333faac8eSRussell King bool tx_pause, rx_pause; 91433faac8eSRussell King 91533faac8eSRussell King phy_get_pause(phydev, &tx_pause, &rx_pause); 9169525ae83SRussell King 9179525ae83SRussell King mutex_lock(&pl->state_mutex); 9189525ae83SRussell King pl->phy_state.speed = phydev->speed; 9199525ae83SRussell King pl->phy_state.duplex = phydev->duplex; 9209525ae83SRussell King pl->phy_state.pause = MLO_PAUSE_NONE; 92133faac8eSRussell King if (tx_pause) 92233faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_TX; 92333faac8eSRussell King if (rx_pause) 92433faac8eSRussell King pl->phy_state.pause |= MLO_PAUSE_RX; 9259525ae83SRussell King pl->phy_state.interface = phydev->interface; 9269525ae83SRussell King pl->phy_state.link = up; 9279525ae83SRussell King mutex_unlock(&pl->state_mutex); 9289525ae83SRussell King 9299525ae83SRussell King phylink_run_resolve(pl); 9309525ae83SRussell King 93117091180SIoana Ciornei phylink_dbg(pl, "phy link %s %s/%s/%s\n", up ? "up" : "down", 9329525ae83SRussell King phy_modes(phydev->interface), 9339525ae83SRussell King phy_speed_to_str(phydev->speed), 9349525ae83SRussell King phy_duplex_to_str(phydev->duplex)); 9359525ae83SRussell King } 9369525ae83SRussell King 937e45d1f52SRussell King static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, 938e45d1f52SRussell King phy_interface_t interface) 9399525ae83SRussell King { 9409525ae83SRussell King struct phylink_link_state config; 9419525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); 942e27f1787SFlorian Fainelli char *irq_str; 9439525ae83SRussell King int ret; 9449525ae83SRussell King 9459525ae83SRussell King /* 9469525ae83SRussell King * This is the new way of dealing with flow control for PHYs, 9479525ae83SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy: 9489525ae83SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except 9499525ae83SRussell King * using our validate call to the MAC, we rely upon the MAC 9509525ae83SRussell King * clearing the bits from both supported and advertising fields. 9519525ae83SRussell King */ 952725ea4bfSRussell King phy_support_asym_pause(phy); 953725ea4bfSRussell King 954725ea4bfSRussell King memset(&config, 0, sizeof(config)); 955725ea4bfSRussell King linkmode_copy(supported, phy->supported); 956725ea4bfSRussell King linkmode_copy(config.advertising, phy->advertising); 957df3f57acSRussell King 958df3f57acSRussell King /* Clause 45 PHYs switch their Serdes lane between several different 959df3f57acSRussell King * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G 960df3f57acSRussell King * speeds. We really need to know which interface modes the PHY and 961df3f57acSRussell King * MAC supports to properly work out which linkmodes can be supported. 962df3f57acSRussell King */ 963df3f57acSRussell King if (phy->is_c45 && 964df3f57acSRussell King interface != PHY_INTERFACE_MODE_RXAUI && 965df3f57acSRussell King interface != PHY_INTERFACE_MODE_XAUI && 966df3f57acSRussell King interface != PHY_INTERFACE_MODE_USXGMII) 967df3f57acSRussell King config.interface = PHY_INTERFACE_MODE_NA; 968df3f57acSRussell King else 969e45d1f52SRussell King config.interface = interface; 9709525ae83SRussell King 9719525ae83SRussell King ret = phylink_validate(pl, supported, &config); 97220d8bb0dSHauke Mehrtens if (ret) { 97320d8bb0dSHauke Mehrtens phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %d\n", 97420d8bb0dSHauke Mehrtens phy_modes(config.interface), 97520d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported, 97620d8bb0dSHauke Mehrtens __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising, 97720d8bb0dSHauke Mehrtens ret); 9789525ae83SRussell King return ret; 97920d8bb0dSHauke Mehrtens } 9809525ae83SRussell King 9819525ae83SRussell King phy->phylink = pl; 9829525ae83SRussell King phy->phy_link_change = phylink_phy_change; 9839525ae83SRussell King 984e27f1787SFlorian Fainelli irq_str = phy_attached_info_irq(phy); 98517091180SIoana Ciornei phylink_info(pl, 986e27f1787SFlorian Fainelli "PHY [%s] driver [%s] (irq=%s)\n", 987e27f1787SFlorian Fainelli dev_name(&phy->mdio.dev), phy->drv->name, irq_str); 988e27f1787SFlorian Fainelli kfree(irq_str); 9899525ae83SRussell King 9909525ae83SRussell King mutex_lock(&phy->lock); 9919525ae83SRussell King mutex_lock(&pl->state_mutex); 9929525ae83SRussell King pl->phydev = phy; 993e45d1f52SRussell King pl->phy_state.interface = interface; 99497fec51fSRussell King pl->phy_state.pause = MLO_PAUSE_NONE; 99597fec51fSRussell King pl->phy_state.speed = SPEED_UNKNOWN; 99697fec51fSRussell King pl->phy_state.duplex = DUPLEX_UNKNOWN; 9979525ae83SRussell King linkmode_copy(pl->supported, supported); 9989525ae83SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 9999525ae83SRussell King 1000cc1122b0SColin Ian King /* Restrict the phy advertisement according to the MAC support. */ 10013c1bcc86SAndrew Lunn linkmode_copy(phy->advertising, config.advertising); 10029525ae83SRussell King mutex_unlock(&pl->state_mutex); 10039525ae83SRussell King mutex_unlock(&phy->lock); 10049525ae83SRussell King 100517091180SIoana Ciornei phylink_dbg(pl, 10063c1bcc86SAndrew Lunn "phy: setting supported %*pb advertising %*pb\n", 10079525ae83SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported, 10083c1bcc86SAndrew Lunn __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising); 10099525ae83SRussell King 1010434a4315SHeiner Kallweit if (phy_interrupt_is_valid(phy)) 1011434a4315SHeiner Kallweit phy_request_interrupt(phy); 10129525ae83SRussell King 10139525ae83SRussell King return 0; 10149525ae83SRussell King } 10159525ae83SRussell King 1016938d44c2SRussell King static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, 10177e418375SBaruch Siach phy_interface_t interface) 10187e418375SBaruch Siach { 101924cf0e69SRussell King if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || 102024cf0e69SRussell King (pl->cfg_link_an_mode == MLO_AN_INBAND && 10217e418375SBaruch Siach phy_interface_mode_is_8023z(interface)))) 10227e418375SBaruch Siach return -EINVAL; 10237e418375SBaruch Siach 10247e418375SBaruch Siach if (pl->phydev) 10257e418375SBaruch Siach return -EBUSY; 10267e418375SBaruch Siach 1027938d44c2SRussell King return phy_attach_direct(pl->netdev, phy, 0, interface); 10287e418375SBaruch Siach } 10297e418375SBaruch Siach 10308796c892SRussell King /** 10318796c892SRussell King * phylink_connect_phy() - connect a PHY to the phylink instance 10328796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 10338796c892SRussell King * @phy: a pointer to a &struct phy_device. 10348796c892SRussell King * 10358796c892SRussell King * Connect @phy to the phylink instance specified by @pl by calling 10368796c892SRussell King * phy_attach_direct(). Configure the @phy according to the MAC driver's 10378796c892SRussell King * capabilities, start the PHYLIB state machine and enable any interrupts 10388796c892SRussell King * that the PHY supports. 10398796c892SRussell King * 10408796c892SRussell King * This updates the phylink's ethtool supported and advertising link mode 10418796c892SRussell King * masks. 10428796c892SRussell King * 10438796c892SRussell King * Returns 0 on success or a negative errno. 10448796c892SRussell King */ 10459525ae83SRussell King int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) 10469525ae83SRussell King { 1047938d44c2SRussell King int ret; 1048938d44c2SRussell King 10494904b6eaSFlorian Fainelli /* Use PHY device/driver interface */ 10504904b6eaSFlorian Fainelli if (pl->link_interface == PHY_INTERFACE_MODE_NA) { 10514904b6eaSFlorian Fainelli pl->link_interface = phy->interface; 10524904b6eaSFlorian Fainelli pl->link_config.interface = pl->link_interface; 10534904b6eaSFlorian Fainelli } 10544904b6eaSFlorian Fainelli 1055938d44c2SRussell King ret = phylink_attach_phy(pl, phy, pl->link_interface); 1056938d44c2SRussell King if (ret < 0) 1057938d44c2SRussell King return ret; 1058938d44c2SRussell King 1059e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, pl->link_config.interface); 1060938d44c2SRussell King if (ret) 1061938d44c2SRussell King phy_detach(phy); 1062938d44c2SRussell King 1063938d44c2SRussell King return ret; 10649525ae83SRussell King } 10659525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_connect_phy); 10669525ae83SRussell King 10678796c892SRussell King /** 10688796c892SRussell King * phylink_of_phy_connect() - connect the PHY specified in the DT mode. 10698796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 10708796c892SRussell King * @dn: a pointer to a &struct device_node. 10710a62964cSFlorian Fainelli * @flags: PHY-specific flags to communicate to the PHY device driver 10728796c892SRussell King * 10738796c892SRussell King * Connect the phy specified in the device node @dn to the phylink instance 10748796c892SRussell King * specified by @pl. Actions specified in phylink_connect_phy() will be 10758796c892SRussell King * performed. 10768796c892SRussell King * 10778796c892SRussell King * Returns 0 on success or a negative errno. 10788796c892SRussell King */ 10790a62964cSFlorian Fainelli int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, 10800a62964cSFlorian Fainelli u32 flags) 10819525ae83SRussell King { 10829525ae83SRussell King struct device_node *phy_node; 10839525ae83SRussell King struct phy_device *phy_dev; 10849525ae83SRussell King int ret; 10859525ae83SRussell King 1086cf4f2675SRussell King /* Fixed links and 802.3z are handled without needing a PHY */ 108724cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED || 108824cf0e69SRussell King (pl->cfg_link_an_mode == MLO_AN_INBAND && 108986a362c4SRussell King phy_interface_mode_is_8023z(pl->link_interface))) 10909525ae83SRussell King return 0; 10919525ae83SRussell King 10929525ae83SRussell King phy_node = of_parse_phandle(dn, "phy-handle", 0); 10939525ae83SRussell King if (!phy_node) 10949525ae83SRussell King phy_node = of_parse_phandle(dn, "phy", 0); 10959525ae83SRussell King if (!phy_node) 10969525ae83SRussell King phy_node = of_parse_phandle(dn, "phy-device", 0); 10979525ae83SRussell King 10989525ae83SRussell King if (!phy_node) { 109924cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_PHY) 11009525ae83SRussell King return -ENODEV; 11019525ae83SRussell King return 0; 11029525ae83SRussell King } 11039525ae83SRussell King 1104f5058a27SRussell King phy_dev = of_phy_find_device(phy_node); 11059525ae83SRussell King /* We're done with the phy_node handle */ 11069525ae83SRussell King of_node_put(phy_node); 11079525ae83SRussell King if (!phy_dev) 11089525ae83SRussell King return -ENODEV; 11099525ae83SRussell King 1110f5058a27SRussell King ret = phy_attach_direct(pl->netdev, phy_dev, flags, 1111f5058a27SRussell King pl->link_interface); 1112f5058a27SRussell King if (ret) 1113f5058a27SRussell King return ret; 1114f5058a27SRussell King 1115e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); 11169525ae83SRussell King if (ret) 11179525ae83SRussell King phy_detach(phy_dev); 11189525ae83SRussell King 11199525ae83SRussell King return ret; 11209525ae83SRussell King } 11219525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_of_phy_connect); 11229525ae83SRussell King 11238796c892SRussell King /** 11248796c892SRussell King * phylink_disconnect_phy() - disconnect any PHY attached to the phylink 11258796c892SRussell King * instance. 11268796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 11278796c892SRussell King * 11288796c892SRussell King * Disconnect any current PHY from the phylink instance described by @pl. 11298796c892SRussell King */ 11309525ae83SRussell King void phylink_disconnect_phy(struct phylink *pl) 11319525ae83SRussell King { 11329525ae83SRussell King struct phy_device *phy; 11339525ae83SRussell King 11348b874514SRussell King ASSERT_RTNL(); 11359525ae83SRussell King 11369525ae83SRussell King phy = pl->phydev; 11379525ae83SRussell King if (phy) { 11389525ae83SRussell King mutex_lock(&phy->lock); 11399525ae83SRussell King mutex_lock(&pl->state_mutex); 11409525ae83SRussell King pl->phydev = NULL; 11419525ae83SRussell King mutex_unlock(&pl->state_mutex); 11429525ae83SRussell King mutex_unlock(&phy->lock); 11439525ae83SRussell King flush_work(&pl->resolve); 11449525ae83SRussell King 11459525ae83SRussell King phy_disconnect(phy); 11469525ae83SRussell King } 11479525ae83SRussell King } 11489525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_disconnect_phy); 11499525ae83SRussell King 11508796c892SRussell King /** 11518796c892SRussell King * phylink_mac_change() - notify phylink of a change in MAC state 11528796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 11538796c892SRussell King * @up: indicates whether the link is currently up. 11548796c892SRussell King * 11558796c892SRussell King * The MAC driver should call this driver when the state of its link 11568796c892SRussell King * changes (eg, link failure, new negotiation results, etc.) 11578796c892SRussell King */ 11589525ae83SRussell King void phylink_mac_change(struct phylink *pl, bool up) 11599525ae83SRussell King { 11609525ae83SRussell King if (!up) 11619525ae83SRussell King pl->mac_link_dropped = true; 11629525ae83SRussell King phylink_run_resolve(pl); 116317091180SIoana Ciornei phylink_dbg(pl, "mac link %s\n", up ? "up" : "down"); 11649525ae83SRussell King } 11659525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mac_change); 11669525ae83SRussell King 11677b3b0e89SRussell King static irqreturn_t phylink_link_handler(int irq, void *data) 11687b3b0e89SRussell King { 11697b3b0e89SRussell King struct phylink *pl = data; 11707b3b0e89SRussell King 11717b3b0e89SRussell King phylink_run_resolve(pl); 11727b3b0e89SRussell King 11737b3b0e89SRussell King return IRQ_HANDLED; 11747b3b0e89SRussell King } 11757b3b0e89SRussell King 11768796c892SRussell King /** 11778796c892SRussell King * phylink_start() - start a phylink instance 11788796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 11798796c892SRussell King * 11808796c892SRussell King * Start the phylink instance specified by @pl, configuring the MAC for the 11818796c892SRussell King * desired link mode(s) and negotiation style. This should be called from the 11828796c892SRussell King * network device driver's &struct net_device_ops ndo_open() method. 11838796c892SRussell King */ 11849525ae83SRussell King void phylink_start(struct phylink *pl) 11859525ae83SRussell King { 11865c05c1dbSRussell King bool poll = false; 11875c05c1dbSRussell King 11888b874514SRussell King ASSERT_RTNL(); 11899525ae83SRussell King 119017091180SIoana Ciornei phylink_info(pl, "configuring for %s/%s link mode\n", 119124cf0e69SRussell King phylink_an_mode_str(pl->cur_link_an_mode), 11929525ae83SRussell King phy_modes(pl->link_config.interface)); 11939525ae83SRussell King 1194aeeb2e8fSAntoine Tenart /* Always set the carrier off */ 119543de6195SIoana Ciornei if (pl->netdev) 1196aeeb2e8fSAntoine Tenart netif_carrier_off(pl->netdev); 1197aeeb2e8fSAntoine Tenart 11989525ae83SRussell King /* Apply the link configuration to the MAC when starting. This allows 11999525ae83SRussell King * a fixed-link to start with the correct parameters, and also 1200cc1122b0SColin Ian King * ensures that we set the appropriate advertisement for Serdes links. 12014c0d6d3aSRussell King * 12024c0d6d3aSRussell King * Restart autonegotiation if using 802.3z to ensure that the link 120385b43945SRussell King * parameters are properly negotiated. This is necessary for DSA 120485b43945SRussell King * switches using 802.3z negotiation to ensure they see our modes. 120585b43945SRussell King */ 12064c0d6d3aSRussell King phylink_mac_initial_config(pl, true); 120785b43945SRussell King 12089525ae83SRussell King clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); 12099525ae83SRussell King phylink_run_resolve(pl); 12109525ae83SRussell King 121124cf0e69SRussell King if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) { 12127b3b0e89SRussell King int irq = gpiod_to_irq(pl->link_gpio); 12137b3b0e89SRussell King 12147b3b0e89SRussell King if (irq > 0) { 12157b3b0e89SRussell King if (!request_irq(irq, phylink_link_handler, 12167b3b0e89SRussell King IRQF_TRIGGER_RISING | 12177b3b0e89SRussell King IRQF_TRIGGER_FALLING, 12187b3b0e89SRussell King "netdev link", pl)) 12197b3b0e89SRussell King pl->link_irq = irq; 12207b3b0e89SRussell King else 12217b3b0e89SRussell King irq = 0; 12227b3b0e89SRussell King } 12237b3b0e89SRussell King if (irq <= 0) 12245c05c1dbSRussell King poll = true; 12257b3b0e89SRussell King } 12265c05c1dbSRussell King 12275c05c1dbSRussell King switch (pl->cfg_link_an_mode) { 12285c05c1dbSRussell King case MLO_AN_FIXED: 12295c05c1dbSRussell King poll |= pl->config->poll_fixed_state; 12305c05c1dbSRussell King break; 12315c05c1dbSRussell King case MLO_AN_INBAND: 12325c05c1dbSRussell King poll |= pl->config->pcs_poll; 12337137e18fSRussell King if (pl->pcs) 12347137e18fSRussell King poll |= pl->pcs->poll; 12355c05c1dbSRussell King break; 12365c05c1dbSRussell King } 12375c05c1dbSRussell King if (poll) 12389cd00a8aSRussell King mod_timer(&pl->link_poll, jiffies + HZ); 12399525ae83SRussell King if (pl->phydev) 12409525ae83SRussell King phy_start(pl->phydev); 1241c7fa7f56SArseny Solokha if (pl->sfp_bus) 1242c7fa7f56SArseny Solokha sfp_upstream_start(pl->sfp_bus); 12439525ae83SRussell King } 12449525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_start); 12459525ae83SRussell King 12468796c892SRussell King /** 12478796c892SRussell King * phylink_stop() - stop a phylink instance 12488796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 12498796c892SRussell King * 12508796c892SRussell King * Stop the phylink instance specified by @pl. This should be called from the 12518796c892SRussell King * network device driver's &struct net_device_ops ndo_stop() method. The 12528796c892SRussell King * network device's carrier state should not be changed prior to calling this 12538796c892SRussell King * function. 12548796c892SRussell King */ 12559525ae83SRussell King void phylink_stop(struct phylink *pl) 12569525ae83SRussell King { 12578b874514SRussell King ASSERT_RTNL(); 12589525ae83SRussell King 1259ce0aa27fSRussell King if (pl->sfp_bus) 1260ce0aa27fSRussell King sfp_upstream_stop(pl->sfp_bus); 1261c7fa7f56SArseny Solokha if (pl->phydev) 1262c7fa7f56SArseny Solokha phy_stop(pl->phydev); 12639cd00a8aSRussell King del_timer_sync(&pl->link_poll); 12647b3b0e89SRussell King if (pl->link_irq) { 12657b3b0e89SRussell King free_irq(pl->link_irq, pl); 12667b3b0e89SRussell King pl->link_irq = 0; 12677b3b0e89SRussell King } 12689525ae83SRussell King 126987454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED); 12709525ae83SRussell King } 12719525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_stop); 12729525ae83SRussell King 12738796c892SRussell King /** 12748796c892SRussell King * phylink_ethtool_get_wol() - get the wake on lan parameters for the PHY 12758796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 12768796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo to hold the read parameters 12778796c892SRussell King * 12788796c892SRussell King * Read the wake on lan parameters from the PHY attached to the phylink 12798796c892SRussell King * instance specified by @pl. If no PHY is currently attached, report no 12808796c892SRussell King * support for wake on lan. 12818796c892SRussell King */ 12829525ae83SRussell King void phylink_ethtool_get_wol(struct phylink *pl, struct ethtool_wolinfo *wol) 12839525ae83SRussell King { 12848b874514SRussell King ASSERT_RTNL(); 12859525ae83SRussell King 12869525ae83SRussell King wol->supported = 0; 12879525ae83SRussell King wol->wolopts = 0; 12889525ae83SRussell King 12899525ae83SRussell King if (pl->phydev) 12909525ae83SRussell King phy_ethtool_get_wol(pl->phydev, wol); 12919525ae83SRussell King } 12929525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_wol); 12939525ae83SRussell King 12948796c892SRussell King /** 12958796c892SRussell King * phylink_ethtool_set_wol() - set wake on lan parameters 12968796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 12978796c892SRussell King * @wol: a pointer to &struct ethtool_wolinfo for the desired parameters 12988796c892SRussell King * 12998796c892SRussell King * Set the wake on lan parameters for the PHY attached to the phylink 13008796c892SRussell King * instance specified by @pl. If no PHY is attached, returns %EOPNOTSUPP 13018796c892SRussell King * error. 13028796c892SRussell King * 13038796c892SRussell King * Returns zero on success or negative errno code. 13048796c892SRussell King */ 13059525ae83SRussell King int phylink_ethtool_set_wol(struct phylink *pl, struct ethtool_wolinfo *wol) 13069525ae83SRussell King { 13079525ae83SRussell King int ret = -EOPNOTSUPP; 13089525ae83SRussell King 13098b874514SRussell King ASSERT_RTNL(); 13109525ae83SRussell King 13119525ae83SRussell King if (pl->phydev) 13129525ae83SRussell King ret = phy_ethtool_set_wol(pl->phydev, wol); 13139525ae83SRussell King 13149525ae83SRussell King return ret; 13159525ae83SRussell King } 13169525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_wol); 13179525ae83SRussell King 13189525ae83SRussell King static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b) 13199525ae83SRussell King { 13209525ae83SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(mask); 13219525ae83SRussell King 13229525ae83SRussell King linkmode_zero(mask); 13239525ae83SRussell King phylink_set_port_modes(mask); 13249525ae83SRussell King 13259525ae83SRussell King linkmode_and(dst, dst, mask); 13269525ae83SRussell King linkmode_or(dst, dst, b); 13279525ae83SRussell King } 13289525ae83SRussell King 13299525ae83SRussell King static void phylink_get_ksettings(const struct phylink_link_state *state, 13309525ae83SRussell King struct ethtool_link_ksettings *kset) 13319525ae83SRussell King { 13329525ae83SRussell King phylink_merge_link_mode(kset->link_modes.advertising, state->advertising); 13339525ae83SRussell King linkmode_copy(kset->link_modes.lp_advertising, state->lp_advertising); 13349525ae83SRussell King kset->base.speed = state->speed; 13359525ae83SRussell King kset->base.duplex = state->duplex; 13369525ae83SRussell King kset->base.autoneg = state->an_enabled ? AUTONEG_ENABLE : 13379525ae83SRussell King AUTONEG_DISABLE; 13389525ae83SRussell King } 13399525ae83SRussell King 13408796c892SRussell King /** 13418796c892SRussell King * phylink_ethtool_ksettings_get() - get the current link settings 13428796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 13438796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings to hold link settings 13448796c892SRussell King * 13458796c892SRussell King * Read the current link settings for the phylink instance specified by @pl. 13468796c892SRussell King * This will be the link settings read from the MAC, PHY or fixed link 13478796c892SRussell King * settings depending on the current negotiation mode. 13488796c892SRussell King */ 13499525ae83SRussell King int phylink_ethtool_ksettings_get(struct phylink *pl, 13509525ae83SRussell King struct ethtool_link_ksettings *kset) 13519525ae83SRussell King { 13529525ae83SRussell King struct phylink_link_state link_state; 13539525ae83SRussell King 13548b874514SRussell King ASSERT_RTNL(); 13559525ae83SRussell King 13569525ae83SRussell King if (pl->phydev) { 13579525ae83SRussell King phy_ethtool_ksettings_get(pl->phydev, kset); 13589525ae83SRussell King } else { 13599525ae83SRussell King kset->base.port = pl->link_port; 13609525ae83SRussell King } 13619525ae83SRussell King 13629525ae83SRussell King linkmode_copy(kset->link_modes.supported, pl->supported); 13639525ae83SRussell King 136424cf0e69SRussell King switch (pl->cur_link_an_mode) { 13659525ae83SRussell King case MLO_AN_FIXED: 13669525ae83SRussell King /* We are using fixed settings. Report these as the 13679525ae83SRussell King * current link settings - and note that these also 13689525ae83SRussell King * represent the supported speeds/duplex/pause modes. 13699525ae83SRussell King */ 13709525ae83SRussell King phylink_get_fixed_state(pl, &link_state); 13719525ae83SRussell King phylink_get_ksettings(&link_state, kset); 13729525ae83SRussell King break; 13739525ae83SRussell King 137486a362c4SRussell King case MLO_AN_INBAND: 13759525ae83SRussell King /* If there is a phy attached, then use the reported 13769525ae83SRussell King * settings from the phy with no modification. 13779525ae83SRussell King */ 13789525ae83SRussell King if (pl->phydev) 13799525ae83SRussell King break; 13809525ae83SRussell King 1381d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &link_state); 13829525ae83SRussell King 13839525ae83SRussell King /* The MAC is reporting the link results from its own PCS 13849525ae83SRussell King * layer via in-band status. Report these as the current 13859525ae83SRussell King * link settings. 13869525ae83SRussell King */ 13879525ae83SRussell King phylink_get_ksettings(&link_state, kset); 13889525ae83SRussell King break; 13899525ae83SRussell King } 13909525ae83SRussell King 13919525ae83SRussell King return 0; 13929525ae83SRussell King } 13939525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get); 13949525ae83SRussell King 13958796c892SRussell King /** 13968796c892SRussell King * phylink_ethtool_ksettings_set() - set the link settings 13978796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 13988796c892SRussell King * @kset: a pointer to a &struct ethtool_link_ksettings for the desired modes 13998796c892SRussell King */ 14009525ae83SRussell King int phylink_ethtool_ksettings_set(struct phylink *pl, 14019525ae83SRussell King const struct ethtool_link_ksettings *kset) 14029525ae83SRussell King { 140377316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support); 14049525ae83SRussell King struct phylink_link_state config; 1405c8cab719SRussell King const struct phy_setting *s; 14069525ae83SRussell King 14078b874514SRussell King ASSERT_RTNL(); 14089525ae83SRussell King 1409cbc1bb1eSRussell King if (pl->phydev) { 1410cbc1bb1eSRussell King /* We can rely on phylib for this update; we also do not need 1411cbc1bb1eSRussell King * to update the pl->link_config settings: 1412cbc1bb1eSRussell King * - the configuration returned via ksettings_get() will come 1413cbc1bb1eSRussell King * from phylib whenever a PHY is present. 1414cbc1bb1eSRussell King * - link_config.interface will be updated by the PHY calling 1415cbc1bb1eSRussell King * back via phylink_phy_change() and a subsequent resolve. 1416cbc1bb1eSRussell King * - initial link configuration for PHY mode comes from the 1417cbc1bb1eSRussell King * last phy state updated via phylink_phy_change(). 1418cbc1bb1eSRussell King * - other configuration changes (e.g. pause modes) are 1419cbc1bb1eSRussell King * performed directly via phylib. 1420cbc1bb1eSRussell King * - if in in-band mode with a PHY, the link configuration 1421cbc1bb1eSRussell King * is passed on the link from the PHY, and all of 1422cbc1bb1eSRussell King * link_config.{speed,duplex,an_enabled,pause} are not used. 1423cbc1bb1eSRussell King * - the only possible use would be link_config.advertising 1424cbc1bb1eSRussell King * pause modes when in 1000base-X mode with a PHY, but in 1425cbc1bb1eSRussell King * the presence of a PHY, this should not be changed as that 1426cbc1bb1eSRussell King * should be determined from the media side advertisement. 1427cbc1bb1eSRussell King */ 1428cbc1bb1eSRussell King return phy_ethtool_ksettings_set(pl->phydev, kset); 1429cbc1bb1eSRussell King } 1430cbc1bb1eSRussell King 143177316763SRussell King linkmode_copy(support, pl->supported); 14329525ae83SRussell King config = pl->link_config; 1433c8cab719SRussell King config.an_enabled = kset->base.autoneg == AUTONEG_ENABLE; 14349525ae83SRussell King 1435c8cab719SRussell King /* Mask out unsupported advertisements, and force the autoneg bit */ 14369525ae83SRussell King linkmode_and(config.advertising, kset->link_modes.advertising, 143777316763SRussell King support); 1438c8cab719SRussell King linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising, 1439c8cab719SRussell King config.an_enabled); 14409525ae83SRussell King 14419525ae83SRussell King /* FIXME: should we reject autoneg if phy/mac does not support it? */ 1442c8cab719SRussell King switch (kset->base.autoneg) { 1443c8cab719SRussell King case AUTONEG_DISABLE: 14449525ae83SRussell King /* Autonegotiation disabled, select a suitable speed and 14459525ae83SRussell King * duplex. 14469525ae83SRussell King */ 14479525ae83SRussell King s = phy_lookup_setting(kset->base.speed, kset->base.duplex, 144877316763SRussell King support, false); 14499525ae83SRussell King if (!s) 14509525ae83SRussell King return -EINVAL; 14519525ae83SRussell King 14521e1bf14aSRussell King /* If we have a fixed link, refuse to change link parameters. 14531e1bf14aSRussell King * If the link parameters match, accept them but do nothing. 14549525ae83SRussell King */ 14551e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) { 14561e1bf14aSRussell King if (s->speed != pl->link_config.speed || 14571e1bf14aSRussell King s->duplex != pl->link_config.duplex) 14589525ae83SRussell King return -EINVAL; 14591e1bf14aSRussell King return 0; 14601e1bf14aSRussell King } 14619525ae83SRussell King 14629525ae83SRussell King config.speed = s->speed; 14639525ae83SRussell King config.duplex = s->duplex; 1464c8cab719SRussell King break; 14659525ae83SRussell King 1466c8cab719SRussell King case AUTONEG_ENABLE: 14671e1bf14aSRussell King /* If we have a fixed link, allow autonegotiation (since that 14681e1bf14aSRussell King * is our default case) but do not allow the advertisement to 14691e1bf14aSRussell King * be changed. If the advertisement matches, simply return. 14701e1bf14aSRussell King */ 14711e1bf14aSRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) { 14721e1bf14aSRussell King if (!linkmode_equal(config.advertising, 14731e1bf14aSRussell King pl->link_config.advertising)) 14749525ae83SRussell King return -EINVAL; 14751e1bf14aSRussell King return 0; 14761e1bf14aSRussell King } 14779525ae83SRussell King 14789525ae83SRussell King config.speed = SPEED_UNKNOWN; 14799525ae83SRussell King config.duplex = DUPLEX_UNKNOWN; 1480c8cab719SRussell King break; 14819525ae83SRussell King 1482c8cab719SRussell King default: 1483c8cab719SRussell King return -EINVAL; 14849525ae83SRussell King } 14859525ae83SRussell King 14861e1bf14aSRussell King /* We have ruled out the case with a PHY attached, and the 14871e1bf14aSRussell King * fixed-link cases. All that is left are in-band links. 14885d57c327SRussell King */ 148977316763SRussell King if (phylink_validate(pl, support, &config)) 14909525ae83SRussell King return -EINVAL; 14919525ae83SRussell King 1492cc1122b0SColin Ian King /* If autonegotiation is enabled, we must have an advertisement */ 1493cbc1bb1eSRussell King if (config.an_enabled && phylink_is_empty_linkmode(config.advertising)) 14949525ae83SRussell King return -EINVAL; 14959525ae83SRussell King 14969525ae83SRussell King mutex_lock(&pl->state_mutex); 14975d57c327SRussell King pl->link_config.speed = config.speed; 14985d57c327SRussell King pl->link_config.duplex = config.duplex; 1499a83c8829SRussell King pl->link_config.an_enabled = config.an_enabled; 15009525ae83SRussell King 1501b7ad14c2SRussell King if (pl->link_config.interface != config.interface) { 1502b7ad14c2SRussell King /* The interface changed, e.g. 1000base-X <-> 2500base-X */ 1503b7ad14c2SRussell King /* We need to force the link down, then change the interface */ 1504b7ad14c2SRussell King if (pl->old_link_state) { 1505b7ad14c2SRussell King phylink_link_down(pl); 1506b7ad14c2SRussell King pl->old_link_state = false; 1507b7ad14c2SRussell King } 1508b7ad14c2SRussell King if (!test_bit(PHYLINK_DISABLE_STOPPED, 1509b7ad14c2SRussell King &pl->phylink_disable_state)) 1510b7ad14c2SRussell King phylink_major_config(pl, false, &config); 1511b7ad14c2SRussell King pl->link_config.interface = config.interface; 1512b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 1513b7ad14c2SRussell King } else if (!linkmode_equal(pl->link_config.advertising, 1514b7ad14c2SRussell King config.advertising)) { 1515b7ad14c2SRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 1516b7ad14c2SRussell King phylink_change_inband_advert(pl); 15179525ae83SRussell King } 15189525ae83SRussell King mutex_unlock(&pl->state_mutex); 15199525ae83SRussell King 1520d18c2a1bSDan Carpenter return 0; 15219525ae83SRussell King } 15229525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_set); 15239525ae83SRussell King 15248796c892SRussell King /** 15258796c892SRussell King * phylink_ethtool_nway_reset() - restart negotiation 15268796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 15278796c892SRussell King * 15288796c892SRussell King * Restart negotiation for the phylink instance specified by @pl. This will 15298796c892SRussell King * cause any attached phy to restart negotiation with the link partner, and 15308796c892SRussell King * if the MAC is in a BaseX mode, the MAC will also be requested to restart 15318796c892SRussell King * negotiation. 15328796c892SRussell King * 15338796c892SRussell King * Returns zero on success, or negative error code. 15348796c892SRussell King */ 15359525ae83SRussell King int phylink_ethtool_nway_reset(struct phylink *pl) 15369525ae83SRussell King { 15379525ae83SRussell King int ret = 0; 15389525ae83SRussell King 15398b874514SRussell King ASSERT_RTNL(); 15409525ae83SRussell King 15419525ae83SRussell King if (pl->phydev) 15429525ae83SRussell King ret = phy_restart_aneg(pl->phydev); 15434c0d6d3aSRussell King phylink_mac_pcs_an_restart(pl); 15449525ae83SRussell King 15459525ae83SRussell King return ret; 15469525ae83SRussell King } 15479525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_nway_reset); 15489525ae83SRussell King 15498796c892SRussell King /** 15508796c892SRussell King * phylink_ethtool_get_pauseparam() - get the current pause parameters 15518796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 15528796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam 15538796c892SRussell King */ 15549525ae83SRussell King void phylink_ethtool_get_pauseparam(struct phylink *pl, 15559525ae83SRussell King struct ethtool_pauseparam *pause) 15569525ae83SRussell King { 15578b874514SRussell King ASSERT_RTNL(); 15589525ae83SRussell King 15599525ae83SRussell King pause->autoneg = !!(pl->link_config.pause & MLO_PAUSE_AN); 15609525ae83SRussell King pause->rx_pause = !!(pl->link_config.pause & MLO_PAUSE_RX); 15619525ae83SRussell King pause->tx_pause = !!(pl->link_config.pause & MLO_PAUSE_TX); 15629525ae83SRussell King } 15639525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_pauseparam); 15649525ae83SRussell King 15658796c892SRussell King /** 15668796c892SRussell King * phylink_ethtool_set_pauseparam() - set the current pause parameters 15678796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 15688796c892SRussell King * @pause: a pointer to a &struct ethtool_pauseparam 15698796c892SRussell King */ 15709525ae83SRussell King int phylink_ethtool_set_pauseparam(struct phylink *pl, 15719525ae83SRussell King struct ethtool_pauseparam *pause) 15729525ae83SRussell King { 15739525ae83SRussell King struct phylink_link_state *config = &pl->link_config; 15742e919bc4SRussell King bool manual_changed; 15752e919bc4SRussell King int pause_state; 15769525ae83SRussell King 15778b874514SRussell King ASSERT_RTNL(); 15789525ae83SRussell King 15798cdfa256SRussell King if (pl->cur_link_an_mode == MLO_AN_FIXED) 15808cdfa256SRussell King return -EOPNOTSUPP; 15818cdfa256SRussell King 15829525ae83SRussell King if (!phylink_test(pl->supported, Pause) && 15839525ae83SRussell King !phylink_test(pl->supported, Asym_Pause)) 15849525ae83SRussell King return -EOPNOTSUPP; 15859525ae83SRussell King 15869525ae83SRussell King if (!phylink_test(pl->supported, Asym_Pause) && 15879525ae83SRussell King !pause->autoneg && pause->rx_pause != pause->tx_pause) 15889525ae83SRussell King return -EINVAL; 15899525ae83SRussell King 15902e919bc4SRussell King pause_state = 0; 15919525ae83SRussell King if (pause->autoneg) 15922e919bc4SRussell King pause_state |= MLO_PAUSE_AN; 15939525ae83SRussell King if (pause->rx_pause) 15942e919bc4SRussell King pause_state |= MLO_PAUSE_RX; 15959525ae83SRussell King if (pause->tx_pause) 15962e919bc4SRussell King pause_state |= MLO_PAUSE_TX; 15979525ae83SRussell King 15982e919bc4SRussell King mutex_lock(&pl->state_mutex); 1599f904f15eSRussell King /* 1600f904f15eSRussell King * See the comments for linkmode_set_pause(), wrt the deficiencies 1601f904f15eSRussell King * with the current implementation. A solution to this issue would 1602f904f15eSRussell King * be: 1603f904f15eSRussell King * ethtool Local device 1604f904f15eSRussell King * rx tx Pause AsymDir 1605f904f15eSRussell King * 0 0 0 0 1606f904f15eSRussell King * 1 0 1 1 1607f904f15eSRussell King * 0 1 0 1 1608f904f15eSRussell King * 1 1 1 1 1609f904f15eSRussell King * and then use the ethtool rx/tx enablement status to mask the 1610f904f15eSRussell King * rx/tx pause resolution. 1611f904f15eSRussell King */ 1612f904f15eSRussell King linkmode_set_pause(config->advertising, pause->tx_pause, 1613f904f15eSRussell King pause->rx_pause); 1614f904f15eSRussell King 16152e919bc4SRussell King manual_changed = (config->pause ^ pause_state) & MLO_PAUSE_AN || 16162e919bc4SRussell King (!(pause_state & MLO_PAUSE_AN) && 16172e919bc4SRussell King (config->pause ^ pause_state) & MLO_PAUSE_TXRX_MASK); 16182e919bc4SRussell King 16192e919bc4SRussell King config->pause = pause_state; 16202e919bc4SRussell King 16211571e700SRussell King /* Update our in-band advertisement, triggering a renegotiation if 16221571e700SRussell King * the advertisement changed. 16231571e700SRussell King */ 16241571e700SRussell King if (!pl->phydev) 16251571e700SRussell King phylink_change_inband_advert(pl); 1626c718af2dSRussell King 1627c718af2dSRussell King mutex_unlock(&pl->state_mutex); 1628c718af2dSRussell King 1629c718af2dSRussell King /* If we have a PHY, a change of the pause frame advertisement will 1630c718af2dSRussell King * cause phylib to renegotiate (if AN is enabled) which will in turn 1631c718af2dSRussell King * call our phylink_phy_change() and trigger a resolve. Note that 1632c718af2dSRussell King * we can't hold our state mutex while calling phy_set_asym_pause(). 1633d9922c0eSRussell King */ 1634c718af2dSRussell King if (pl->phydev) 1635d9922c0eSRussell King phy_set_asym_pause(pl->phydev, pause->rx_pause, 1636d9922c0eSRussell King pause->tx_pause); 16379525ae83SRussell King 16382e919bc4SRussell King /* If the manual pause settings changed, make sure we trigger a 16392e919bc4SRussell King * resolve to update their state; we can not guarantee that the 16402e919bc4SRussell King * link will cycle. 16412e919bc4SRussell King */ 16422e919bc4SRussell King if (manual_changed) { 16432e919bc4SRussell King pl->mac_link_dropped = true; 16442e919bc4SRussell King phylink_run_resolve(pl); 16459525ae83SRussell King } 16469525ae83SRussell King 16479525ae83SRussell King return 0; 16489525ae83SRussell King } 16499525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_pauseparam); 16509525ae83SRussell King 16519525ae83SRussell King /** 1652*69280228SMauro Carvalho Chehab * phylink_get_eee_err() - read the energy efficient ethernet error 16539525ae83SRussell King * counter 16549525ae83SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create(). 16559525ae83SRussell King * 16569525ae83SRussell King * Read the Energy Efficient Ethernet error counter from the PHY associated 16579525ae83SRussell King * with the phylink instance specified by @pl. 16589525ae83SRussell King * 16599525ae83SRussell King * Returns positive error counter value, or negative error code. 16609525ae83SRussell King */ 16619525ae83SRussell King int phylink_get_eee_err(struct phylink *pl) 16629525ae83SRussell King { 16639525ae83SRussell King int ret = 0; 16649525ae83SRussell King 16658b874514SRussell King ASSERT_RTNL(); 16669525ae83SRussell King 16679525ae83SRussell King if (pl->phydev) 16689525ae83SRussell King ret = phy_get_eee_err(pl->phydev); 16699525ae83SRussell King 16709525ae83SRussell King return ret; 16719525ae83SRussell King } 16729525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_get_eee_err); 16739525ae83SRussell King 16748796c892SRussell King /** 167586e58135SRussell King * phylink_init_eee() - init and check the EEE features 167686e58135SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 167786e58135SRussell King * @clk_stop_enable: allow PHY to stop receive clock 167886e58135SRussell King * 167986e58135SRussell King * Must be called either with RTNL held or within mac_link_up() 168086e58135SRussell King */ 168186e58135SRussell King int phylink_init_eee(struct phylink *pl, bool clk_stop_enable) 168286e58135SRussell King { 168386e58135SRussell King int ret = -EOPNOTSUPP; 168486e58135SRussell King 168586e58135SRussell King if (pl->phydev) 168686e58135SRussell King ret = phy_init_eee(pl->phydev, clk_stop_enable); 168786e58135SRussell King 168886e58135SRussell King return ret; 168986e58135SRussell King } 169086e58135SRussell King EXPORT_SYMBOL_GPL(phylink_init_eee); 169186e58135SRussell King 169286e58135SRussell King /** 16938796c892SRussell King * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters 16948796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 16958796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the read parameters 16968796c892SRussell King */ 16979525ae83SRussell King int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee) 16989525ae83SRussell King { 16999525ae83SRussell King int ret = -EOPNOTSUPP; 17009525ae83SRussell King 17018b874514SRussell King ASSERT_RTNL(); 17029525ae83SRussell King 17039525ae83SRussell King if (pl->phydev) 17049525ae83SRussell King ret = phy_ethtool_get_eee(pl->phydev, eee); 17059525ae83SRussell King 17069525ae83SRussell King return ret; 17079525ae83SRussell King } 17089525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); 17099525ae83SRussell King 17108796c892SRussell King /** 17118796c892SRussell King * phylink_ethtool_set_eee() - set the energy efficient ethernet parameters 17128796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 17138796c892SRussell King * @eee: a pointer to a &struct ethtool_eee for the desired parameters 17148796c892SRussell King */ 17159525ae83SRussell King int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee) 17169525ae83SRussell King { 17179525ae83SRussell King int ret = -EOPNOTSUPP; 17189525ae83SRussell King 17198b874514SRussell King ASSERT_RTNL(); 17209525ae83SRussell King 17219525ae83SRussell King if (pl->phydev) 17229525ae83SRussell King ret = phy_ethtool_set_eee(pl->phydev, eee); 17239525ae83SRussell King 17249525ae83SRussell King return ret; 17259525ae83SRussell King } 17269525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee); 17279525ae83SRussell King 17289525ae83SRussell King /* This emulates MII registers for a fixed-mode phy operating as per the 17299525ae83SRussell King * passed in state. "aneg" defines if we report negotiation is possible. 17309525ae83SRussell King * 17319525ae83SRussell King * FIXME: should deal with negotiation state too. 17329525ae83SRussell King */ 17337fdc455eSRussell King static int phylink_mii_emul_read(unsigned int reg, 17347fdc455eSRussell King struct phylink_link_state *state) 17359525ae83SRussell King { 17369525ae83SRussell King struct fixed_phy_status fs; 17374e5aeb41SRussell King unsigned long *lpa = state->lp_advertising; 17389525ae83SRussell King int val; 17399525ae83SRussell King 17409525ae83SRussell King fs.link = state->link; 17419525ae83SRussell King fs.speed = state->speed; 17429525ae83SRussell King fs.duplex = state->duplex; 17434e5aeb41SRussell King fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa); 17444e5aeb41SRussell King fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa); 17459525ae83SRussell King 17469525ae83SRussell King val = swphy_read_reg(reg, &fs); 17479525ae83SRussell King if (reg == MII_BMSR) { 17489525ae83SRussell King if (!state->an_complete) 17499525ae83SRussell King val &= ~BMSR_ANEGCOMPLETE; 17509525ae83SRussell King } 17519525ae83SRussell King return val; 17529525ae83SRussell King } 17539525ae83SRussell King 1754ecbd87b8SRussell King static int phylink_phy_read(struct phylink *pl, unsigned int phy_id, 1755ecbd87b8SRussell King unsigned int reg) 1756ecbd87b8SRussell King { 1757ecbd87b8SRussell King struct phy_device *phydev = pl->phydev; 1758ecbd87b8SRussell King int prtad, devad; 1759ecbd87b8SRussell King 1760ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) { 1761ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id); 1762ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id); 176390ce665cSRussell King devad = mdiobus_c45_addr(devad, reg); 1764ecbd87b8SRussell King } else if (phydev->is_c45) { 1765ecbd87b8SRussell King switch (reg) { 1766ecbd87b8SRussell King case MII_BMCR: 1767ecbd87b8SRussell King case MII_BMSR: 1768ecbd87b8SRussell King case MII_PHYSID1: 1769ecbd87b8SRussell King case MII_PHYSID2: 1770320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present); 1771ecbd87b8SRussell King break; 1772ecbd87b8SRussell King case MII_ADVERTISE: 1773ecbd87b8SRussell King case MII_LPA: 1774320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN)) 1775ecbd87b8SRussell King return -EINVAL; 1776ecbd87b8SRussell King devad = MDIO_MMD_AN; 1777ecbd87b8SRussell King if (reg == MII_ADVERTISE) 1778ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE; 1779ecbd87b8SRussell King else 1780ecbd87b8SRussell King reg = MDIO_AN_LPA; 1781ecbd87b8SRussell King break; 1782ecbd87b8SRussell King default: 1783ecbd87b8SRussell King return -EINVAL; 1784ecbd87b8SRussell King } 1785ecbd87b8SRussell King prtad = phy_id; 178690ce665cSRussell King devad = mdiobus_c45_addr(devad, reg); 1787ecbd87b8SRussell King } else { 1788ecbd87b8SRussell King prtad = phy_id; 1789ecbd87b8SRussell King devad = reg; 1790ecbd87b8SRussell King } 1791ecbd87b8SRussell King return mdiobus_read(pl->phydev->mdio.bus, prtad, devad); 1792ecbd87b8SRussell King } 1793ecbd87b8SRussell King 1794ecbd87b8SRussell King static int phylink_phy_write(struct phylink *pl, unsigned int phy_id, 1795ecbd87b8SRussell King unsigned int reg, unsigned int val) 1796ecbd87b8SRussell King { 1797ecbd87b8SRussell King struct phy_device *phydev = pl->phydev; 1798ecbd87b8SRussell King int prtad, devad; 1799ecbd87b8SRussell King 1800ecbd87b8SRussell King if (mdio_phy_id_is_c45(phy_id)) { 1801ecbd87b8SRussell King prtad = mdio_phy_id_prtad(phy_id); 1802ecbd87b8SRussell King devad = mdio_phy_id_devad(phy_id); 180390ce665cSRussell King devad = mdiobus_c45_addr(devad, reg); 1804ecbd87b8SRussell King } else if (phydev->is_c45) { 1805ecbd87b8SRussell King switch (reg) { 1806ecbd87b8SRussell King case MII_BMCR: 1807ecbd87b8SRussell King case MII_BMSR: 1808ecbd87b8SRussell King case MII_PHYSID1: 1809ecbd87b8SRussell King case MII_PHYSID2: 1810320ed3bfSRussell King devad = __ffs(phydev->c45_ids.mmds_present); 1811ecbd87b8SRussell King break; 1812ecbd87b8SRussell King case MII_ADVERTISE: 1813ecbd87b8SRussell King case MII_LPA: 1814320ed3bfSRussell King if (!(phydev->c45_ids.mmds_present & MDIO_DEVS_AN)) 1815ecbd87b8SRussell King return -EINVAL; 1816ecbd87b8SRussell King devad = MDIO_MMD_AN; 1817ecbd87b8SRussell King if (reg == MII_ADVERTISE) 1818ecbd87b8SRussell King reg = MDIO_AN_ADVERTISE; 1819ecbd87b8SRussell King else 1820ecbd87b8SRussell King reg = MDIO_AN_LPA; 1821ecbd87b8SRussell King break; 1822ecbd87b8SRussell King default: 1823ecbd87b8SRussell King return -EINVAL; 1824ecbd87b8SRussell King } 1825ecbd87b8SRussell King prtad = phy_id; 182690ce665cSRussell King devad = mdiobus_c45_addr(devad, reg); 1827ecbd87b8SRussell King } else { 1828ecbd87b8SRussell King prtad = phy_id; 1829ecbd87b8SRussell King devad = reg; 1830ecbd87b8SRussell King } 1831ecbd87b8SRussell King 1832ecbd87b8SRussell King return mdiobus_write(phydev->mdio.bus, prtad, devad, val); 1833ecbd87b8SRussell King } 1834ecbd87b8SRussell King 18359525ae83SRussell King static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, 18369525ae83SRussell King unsigned int reg) 18379525ae83SRussell King { 18389525ae83SRussell King struct phylink_link_state state; 18399525ae83SRussell King int val = 0xffff; 18409525ae83SRussell King 184124cf0e69SRussell King switch (pl->cur_link_an_mode) { 18429525ae83SRussell King case MLO_AN_FIXED: 18439525ae83SRussell King if (phy_id == 0) { 18449525ae83SRussell King phylink_get_fixed_state(pl, &state); 18457fdc455eSRussell King val = phylink_mii_emul_read(reg, &state); 18469525ae83SRussell King } 18479525ae83SRussell King break; 18489525ae83SRussell King 18499525ae83SRussell King case MLO_AN_PHY: 18509525ae83SRussell King return -EOPNOTSUPP; 18519525ae83SRussell King 185286a362c4SRussell King case MLO_AN_INBAND: 18539525ae83SRussell King if (phy_id == 0) { 1854d46b7e4fSRussell King phylink_mac_pcs_get_state(pl, &state); 18557fdc455eSRussell King val = phylink_mii_emul_read(reg, &state); 18569525ae83SRussell King } 18579525ae83SRussell King break; 18589525ae83SRussell King } 18599525ae83SRussell King 18609525ae83SRussell King return val & 0xffff; 18619525ae83SRussell King } 18629525ae83SRussell King 18639525ae83SRussell King static int phylink_mii_write(struct phylink *pl, unsigned int phy_id, 18649525ae83SRussell King unsigned int reg, unsigned int val) 18659525ae83SRussell King { 186624cf0e69SRussell King switch (pl->cur_link_an_mode) { 18679525ae83SRussell King case MLO_AN_FIXED: 18689525ae83SRussell King break; 18699525ae83SRussell King 18709525ae83SRussell King case MLO_AN_PHY: 18719525ae83SRussell King return -EOPNOTSUPP; 18729525ae83SRussell King 187386a362c4SRussell King case MLO_AN_INBAND: 18749525ae83SRussell King break; 18759525ae83SRussell King } 18769525ae83SRussell King 18779525ae83SRussell King return 0; 18789525ae83SRussell King } 18799525ae83SRussell King 18808796c892SRussell King /** 18818796c892SRussell King * phylink_mii_ioctl() - generic mii ioctl interface 18828796c892SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 18838796c892SRussell King * @ifr: a pointer to a &struct ifreq for socket ioctls 18848796c892SRussell King * @cmd: ioctl cmd to execute 18858796c892SRussell King * 18868796c892SRussell King * Perform the specified MII ioctl on the PHY attached to the phylink instance 18878796c892SRussell King * specified by @pl. If no PHY is attached, emulate the presence of the PHY. 18888796c892SRussell King * 18898796c892SRussell King * Returns: zero on success or negative error code. 18908796c892SRussell King * 18918796c892SRussell King * %SIOCGMIIPHY: 18928796c892SRussell King * read register from the current PHY. 18938796c892SRussell King * %SIOCGMIIREG: 18948796c892SRussell King * read register from the specified PHY. 18958796c892SRussell King * %SIOCSMIIREG: 18968796c892SRussell King * set a register on the specified PHY. 18978796c892SRussell King */ 18989525ae83SRussell King int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd) 18999525ae83SRussell King { 1900ecbd87b8SRussell King struct mii_ioctl_data *mii = if_mii(ifr); 1901ecbd87b8SRussell King int ret; 19029525ae83SRussell King 19038b874514SRussell King ASSERT_RTNL(); 19049525ae83SRussell King 1905ecbd87b8SRussell King if (pl->phydev) { 190686a362c4SRussell King /* PHYs only exist for MLO_AN_PHY and SGMII */ 19079525ae83SRussell King switch (cmd) { 19089525ae83SRussell King case SIOCGMIIPHY: 1909ecbd87b8SRussell King mii->phy_id = pl->phydev->mdio.addr; 1910df561f66SGustavo A. R. Silva fallthrough; 19119525ae83SRussell King 19129525ae83SRussell King case SIOCGMIIREG: 1913ecbd87b8SRussell King ret = phylink_phy_read(pl, mii->phy_id, mii->reg_num); 1914ecbd87b8SRussell King if (ret >= 0) { 1915ecbd87b8SRussell King mii->val_out = ret; 19169525ae83SRussell King ret = 0; 19179525ae83SRussell King } 19189525ae83SRussell King break; 19199525ae83SRussell King 19209525ae83SRussell King case SIOCSMIIREG: 1921ecbd87b8SRussell King ret = phylink_phy_write(pl, mii->phy_id, mii->reg_num, 1922ecbd87b8SRussell King mii->val_in); 1923ecbd87b8SRussell King break; 1924ecbd87b8SRussell King 1925ecbd87b8SRussell King default: 1926ecbd87b8SRussell King ret = phy_mii_ioctl(pl->phydev, ifr, cmd); 1927ecbd87b8SRussell King break; 1928ecbd87b8SRussell King } 1929ecbd87b8SRussell King } else { 1930ecbd87b8SRussell King switch (cmd) { 1931ecbd87b8SRussell King case SIOCGMIIPHY: 1932ecbd87b8SRussell King mii->phy_id = 0; 1933df561f66SGustavo A. R. Silva fallthrough; 1934ecbd87b8SRussell King 1935ecbd87b8SRussell King case SIOCGMIIREG: 1936ecbd87b8SRussell King ret = phylink_mii_read(pl, mii->phy_id, mii->reg_num); 1937ecbd87b8SRussell King if (ret >= 0) { 1938ecbd87b8SRussell King mii->val_out = ret; 1939ecbd87b8SRussell King ret = 0; 1940ecbd87b8SRussell King } 1941ecbd87b8SRussell King break; 1942ecbd87b8SRussell King 1943ecbd87b8SRussell King case SIOCSMIIREG: 1944ecbd87b8SRussell King ret = phylink_mii_write(pl, mii->phy_id, mii->reg_num, 1945ecbd87b8SRussell King mii->val_in); 19469525ae83SRussell King break; 19479525ae83SRussell King 19489525ae83SRussell King default: 19499525ae83SRussell King ret = -EOPNOTSUPP; 19509525ae83SRussell King break; 19519525ae83SRussell King } 1952ecbd87b8SRussell King } 19539525ae83SRussell King 19549525ae83SRussell King return ret; 19559525ae83SRussell King } 19569525ae83SRussell King EXPORT_SYMBOL_GPL(phylink_mii_ioctl); 19579525ae83SRussell King 1958c6d5d843SRussell King /** 1959c6d5d843SRussell King * phylink_speed_down() - set the non-SFP PHY to lowest speed supported by both 1960c6d5d843SRussell King * link partners 1961c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 1962c6d5d843SRussell King * @sync: perform action synchronously 1963c6d5d843SRussell King * 1964c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then set the speed 1965c6d5d843SRussell King * as described in the phy_speed_down() function. Please see this function 1966c6d5d843SRussell King * for a description of the @sync parameter. 1967c6d5d843SRussell King * 1968c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_down(). 1969c6d5d843SRussell King */ 1970c6d5d843SRussell King int phylink_speed_down(struct phylink *pl, bool sync) 1971c6d5d843SRussell King { 1972c6d5d843SRussell King int ret = 0; 1973c6d5d843SRussell King 1974c6d5d843SRussell King ASSERT_RTNL(); 1975c6d5d843SRussell King 1976c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev) 1977c6d5d843SRussell King ret = phy_speed_down(pl->phydev, sync); 1978c6d5d843SRussell King 1979c6d5d843SRussell King return ret; 1980c6d5d843SRussell King } 1981c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_down); 1982c6d5d843SRussell King 1983c6d5d843SRussell King /** 1984c6d5d843SRussell King * phylink_speed_up() - restore the advertised speeds prior to the call to 1985c6d5d843SRussell King * phylink_speed_down() 1986c6d5d843SRussell King * @pl: a pointer to a &struct phylink returned from phylink_create() 1987c6d5d843SRussell King * 1988c6d5d843SRussell King * If we have a PHY that is not part of a SFP module, then restore the 1989c6d5d843SRussell King * PHY speeds as per phy_speed_up(). 1990c6d5d843SRussell King * 1991c6d5d843SRussell King * Returns zero if there is no PHY, otherwise as per phy_speed_up(). 1992c6d5d843SRussell King */ 1993c6d5d843SRussell King int phylink_speed_up(struct phylink *pl) 1994c6d5d843SRussell King { 1995c6d5d843SRussell King int ret = 0; 1996c6d5d843SRussell King 1997c6d5d843SRussell King ASSERT_RTNL(); 1998c6d5d843SRussell King 1999c6d5d843SRussell King if (!pl->sfp_bus && pl->phydev) 2000c6d5d843SRussell King ret = phy_speed_up(pl->phydev); 2001c6d5d843SRussell King 2002c6d5d843SRussell King return ret; 2003c6d5d843SRussell King } 2004c6d5d843SRussell King EXPORT_SYMBOL_GPL(phylink_speed_up); 2005c6d5d843SRussell King 2006320587e6SRussell King static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus) 2007320587e6SRussell King { 2008320587e6SRussell King struct phylink *pl = upstream; 2009320587e6SRussell King 2010320587e6SRussell King pl->netdev->sfp_bus = bus; 2011320587e6SRussell King } 2012320587e6SRussell King 2013320587e6SRussell King static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus) 2014320587e6SRussell King { 2015320587e6SRussell King struct phylink *pl = upstream; 2016320587e6SRussell King 2017320587e6SRussell King pl->netdev->sfp_bus = NULL; 2018320587e6SRussell King } 2019320587e6SRussell King 202052c95600SRussell King static int phylink_sfp_config(struct phylink *pl, u8 mode, 2021c0de2f47SRussell King const unsigned long *supported, 2022c0de2f47SRussell King const unsigned long *advertising) 2023ce0aa27fSRussell King { 202477316763SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); 2025c0de2f47SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(support); 2026ce0aa27fSRussell King struct phylink_link_state config; 2027ce0aa27fSRussell King phy_interface_t iface; 2028ce0aa27fSRussell King bool changed; 2029c0de2f47SRussell King int ret; 2030ce0aa27fSRussell King 2031c0de2f47SRussell King linkmode_copy(support, supported); 2032ce0aa27fSRussell King 2033ce0aa27fSRussell King memset(&config, 0, sizeof(config)); 2034c0de2f47SRussell King linkmode_copy(config.advertising, advertising); 2035a9c79364SRussell King config.interface = PHY_INTERFACE_MODE_NA; 2036ce0aa27fSRussell King config.speed = SPEED_UNKNOWN; 2037ce0aa27fSRussell King config.duplex = DUPLEX_UNKNOWN; 2038ce0aa27fSRussell King config.pause = MLO_PAUSE_AN; 2039ce0aa27fSRussell King config.an_enabled = pl->link_config.an_enabled; 2040ce0aa27fSRussell King 2041ce0aa27fSRussell King /* Ignore errors if we're expecting a PHY to attach later */ 2042ce0aa27fSRussell King ret = phylink_validate(pl, support, &config); 2043ce0aa27fSRussell King if (ret) { 204417091180SIoana Ciornei phylink_err(pl, "validation with support %*pb failed: %d\n", 2045a9c79364SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); 2046a9c79364SRussell King return ret; 2047a9c79364SRussell King } 2048a9c79364SRussell King 2049a4516c70SRussell King iface = sfp_select_interface(pl->sfp_bus, config.advertising); 2050a9c79364SRussell King if (iface == PHY_INTERFACE_MODE_NA) { 205117091180SIoana Ciornei phylink_err(pl, 2052cc1122b0SColin Ian King "selection of interface failed, advertisement %*pb\n", 2053a9c79364SRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising); 2054a9c79364SRussell King return -EINVAL; 2055a9c79364SRussell King } 2056a9c79364SRussell King 2057a9c79364SRussell King config.interface = iface; 2058c0de2f47SRussell King linkmode_copy(support1, support); 205977316763SRussell King ret = phylink_validate(pl, support1, &config); 2060a9c79364SRussell King if (ret) { 206117091180SIoana Ciornei phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n", 2062c0de2f47SRussell King phylink_an_mode_str(mode), 2063444d3502SRussell King phy_modes(config.interface), 2064ce0aa27fSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); 2065ce0aa27fSRussell King return ret; 2066ce0aa27fSRussell King } 2067ce0aa27fSRussell King 206817091180SIoana Ciornei phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", 2069c0de2f47SRussell King phylink_an_mode_str(mode), phy_modes(config.interface), 2070ce0aa27fSRussell King __ETHTOOL_LINK_MODE_MASK_NBITS, support); 2071ce0aa27fSRussell King 207286a362c4SRussell King if (phy_interface_mode_is_8023z(iface) && pl->phydev) 2073ce0aa27fSRussell King return -EINVAL; 2074ce0aa27fSRussell King 2075554032cdSRussell King changed = !linkmode_equal(pl->supported, support); 2076ce0aa27fSRussell King if (changed) { 2077ce0aa27fSRussell King linkmode_copy(pl->supported, support); 2078ce0aa27fSRussell King linkmode_copy(pl->link_config.advertising, config.advertising); 2079ce0aa27fSRussell King } 2080ce0aa27fSRussell King 2081c0de2f47SRussell King if (pl->cur_link_an_mode != mode || 2082ce0aa27fSRussell King pl->link_config.interface != config.interface) { 2083ce0aa27fSRussell King pl->link_config.interface = config.interface; 2084c0de2f47SRussell King pl->cur_link_an_mode = mode; 2085ce0aa27fSRussell King 2086ce0aa27fSRussell King changed = true; 2087ce0aa27fSRussell King 208817091180SIoana Ciornei phylink_info(pl, "switched to %s/%s link mode\n", 2089c0de2f47SRussell King phylink_an_mode_str(mode), 2090ce0aa27fSRussell King phy_modes(config.interface)); 2091ce0aa27fSRussell King } 2092ce0aa27fSRussell King 209352c95600SRussell King pl->link_port = pl->sfp_port; 2094ce0aa27fSRussell King 2095ce0aa27fSRussell King if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, 2096ce0aa27fSRussell King &pl->phylink_disable_state)) 20974c0d6d3aSRussell King phylink_mac_initial_config(pl, false); 2098ce0aa27fSRussell King 2099ce0aa27fSRussell King return ret; 2100ce0aa27fSRussell King } 2101ce0aa27fSRussell King 2102c0de2f47SRussell King static int phylink_sfp_module_insert(void *upstream, 2103c0de2f47SRussell King const struct sfp_eeprom_id *id) 2104c0de2f47SRussell King { 2105c0de2f47SRussell King struct phylink *pl = upstream; 210652c95600SRussell King unsigned long *support = pl->sfp_support; 2107c0de2f47SRussell King 2108c0de2f47SRussell King ASSERT_RTNL(); 2109c0de2f47SRussell King 211052c95600SRussell King linkmode_zero(support); 2111c0de2f47SRussell King sfp_parse_support(pl->sfp_bus, id, support); 211252c95600SRussell King pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); 2113c0de2f47SRussell King 211452c95600SRussell King /* If this module may have a PHY connecting later, defer until later */ 211552c95600SRussell King pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); 211652c95600SRussell King if (pl->sfp_may_have_phy) 211752c95600SRussell King return 0; 211852c95600SRussell King 211952c95600SRussell King return phylink_sfp_config(pl, MLO_AN_INBAND, support, support); 2120c0de2f47SRussell King } 2121c0de2f47SRussell King 21224882057aSRussell King static int phylink_sfp_module_start(void *upstream) 21234882057aSRussell King { 21244882057aSRussell King struct phylink *pl = upstream; 21254882057aSRussell King 21264882057aSRussell King /* If this SFP module has a PHY, start the PHY now. */ 212752c95600SRussell King if (pl->phydev) { 21284882057aSRussell King phy_start(pl->phydev); 21294882057aSRussell King return 0; 21304882057aSRussell King } 21314882057aSRussell King 213252c95600SRussell King /* If the module may have a PHY but we didn't detect one we 213352c95600SRussell King * need to configure the MAC here. 213452c95600SRussell King */ 213552c95600SRussell King if (!pl->sfp_may_have_phy) 213652c95600SRussell King return 0; 213752c95600SRussell King 213852c95600SRussell King return phylink_sfp_config(pl, MLO_AN_INBAND, 213952c95600SRussell King pl->sfp_support, pl->sfp_support); 214052c95600SRussell King } 214152c95600SRussell King 21424882057aSRussell King static void phylink_sfp_module_stop(void *upstream) 21434882057aSRussell King { 21444882057aSRussell King struct phylink *pl = upstream; 21454882057aSRussell King 21464882057aSRussell King /* If this SFP module has a PHY, stop it. */ 21474882057aSRussell King if (pl->phydev) 21484882057aSRussell King phy_stop(pl->phydev); 21494882057aSRussell King } 21504882057aSRussell King 2151ce0aa27fSRussell King static void phylink_sfp_link_down(void *upstream) 2152ce0aa27fSRussell King { 2153ce0aa27fSRussell King struct phylink *pl = upstream; 2154ce0aa27fSRussell King 21558b874514SRussell King ASSERT_RTNL(); 2156ce0aa27fSRussell King 215787454b6eSRussell King phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_LINK); 2158ce0aa27fSRussell King } 2159ce0aa27fSRussell King 2160ce0aa27fSRussell King static void phylink_sfp_link_up(void *upstream) 2161ce0aa27fSRussell King { 2162ce0aa27fSRussell King struct phylink *pl = upstream; 2163ce0aa27fSRussell King 21648b874514SRussell King ASSERT_RTNL(); 2165ce0aa27fSRussell King 2166ce0aa27fSRussell King clear_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state); 2167ce0aa27fSRussell King phylink_run_resolve(pl); 2168ce0aa27fSRussell King } 2169ce0aa27fSRussell King 21707adb5b21SRussell King /* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII 21717adb5b21SRussell King * or 802.3z control word, so inband will not work. 21727adb5b21SRussell King */ 21737adb5b21SRussell King static bool phylink_phy_no_inband(struct phy_device *phy) 21747adb5b21SRussell King { 21757adb5b21SRussell King return phy->is_c45 && 21767adb5b21SRussell King (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150; 21777adb5b21SRussell King } 21787adb5b21SRussell King 2179ce0aa27fSRussell King static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) 2180ce0aa27fSRussell King { 21817e418375SBaruch Siach struct phylink *pl = upstream; 218252c95600SRussell King phy_interface_t interface; 21837adb5b21SRussell King u8 mode; 2184938d44c2SRussell King int ret; 21857e418375SBaruch Siach 218652c95600SRussell King /* 218752c95600SRussell King * This is the new way of dealing with flow control for PHYs, 218852c95600SRussell King * as described by Timur Tabi in commit 529ed1275263 ("net: phy: 218952c95600SRussell King * phy drivers should not set SUPPORTED_[Asym_]Pause") except 219052c95600SRussell King * using our validate call to the MAC, we rely upon the MAC 219152c95600SRussell King * clearing the bits from both supported and advertising fields. 219252c95600SRussell King */ 219352c95600SRussell King phy_support_asym_pause(phy); 219452c95600SRussell King 21957adb5b21SRussell King if (phylink_phy_no_inband(phy)) 21967adb5b21SRussell King mode = MLO_AN_PHY; 21977adb5b21SRussell King else 21987adb5b21SRussell King mode = MLO_AN_INBAND; 21997adb5b21SRussell King 220052c95600SRussell King /* Do the initial configuration */ 22017adb5b21SRussell King ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising); 220252c95600SRussell King if (ret < 0) 220352c95600SRussell King return ret; 220452c95600SRussell King 220552c95600SRussell King interface = pl->link_config.interface; 220652c95600SRussell King ret = phylink_attach_phy(pl, phy, interface); 2207938d44c2SRussell King if (ret < 0) 2208938d44c2SRussell King return ret; 2209938d44c2SRussell King 2210e45d1f52SRussell King ret = phylink_bringup_phy(pl, phy, interface); 2211938d44c2SRussell King if (ret) 2212938d44c2SRussell King phy_detach(phy); 2213938d44c2SRussell King 2214938d44c2SRussell King return ret; 2215ce0aa27fSRussell King } 2216ce0aa27fSRussell King 2217ce0aa27fSRussell King static void phylink_sfp_disconnect_phy(void *upstream) 2218ce0aa27fSRussell King { 2219ce0aa27fSRussell King phylink_disconnect_phy(upstream); 2220ce0aa27fSRussell King } 2221ce0aa27fSRussell King 2222ce0aa27fSRussell King static const struct sfp_upstream_ops sfp_phylink_ops = { 2223320587e6SRussell King .attach = phylink_sfp_attach, 2224320587e6SRussell King .detach = phylink_sfp_detach, 2225ce0aa27fSRussell King .module_insert = phylink_sfp_module_insert, 22264882057aSRussell King .module_start = phylink_sfp_module_start, 22274882057aSRussell King .module_stop = phylink_sfp_module_stop, 2228ce0aa27fSRussell King .link_up = phylink_sfp_link_up, 2229ce0aa27fSRussell King .link_down = phylink_sfp_link_down, 2230ce0aa27fSRussell King .connect_phy = phylink_sfp_connect_phy, 2231ce0aa27fSRussell King .disconnect_phy = phylink_sfp_disconnect_phy, 2232ce0aa27fSRussell King }; 2233ce0aa27fSRussell King 2234624c0f02SRussell King /* Helpers for MAC drivers */ 2235624c0f02SRussell King 2236624c0f02SRussell King /** 2237624c0f02SRussell King * phylink_helper_basex_speed() - 1000BaseX/2500BaseX helper 2238624c0f02SRussell King * @state: a pointer to a &struct phylink_link_state 2239624c0f02SRussell King * 2240624c0f02SRussell King * Inspect the interface mode, advertising mask or forced speed and 2241624c0f02SRussell King * decide whether to run at 2.5Gbit or 1Gbit appropriately, switching 2242624c0f02SRussell King * the interface mode to suit. @state->interface is appropriately 2243624c0f02SRussell King * updated, and the advertising mask has the "other" baseX_Full flag 2244624c0f02SRussell King * cleared. 2245624c0f02SRussell King */ 2246624c0f02SRussell King void phylink_helper_basex_speed(struct phylink_link_state *state) 2247624c0f02SRussell King { 2248624c0f02SRussell King if (phy_interface_mode_is_8023z(state->interface)) { 2249624c0f02SRussell King bool want_2500 = state->an_enabled ? 2250624c0f02SRussell King phylink_test(state->advertising, 2500baseX_Full) : 2251624c0f02SRussell King state->speed == SPEED_2500; 2252624c0f02SRussell King 2253624c0f02SRussell King if (want_2500) { 2254624c0f02SRussell King phylink_clear(state->advertising, 1000baseX_Full); 2255624c0f02SRussell King state->interface = PHY_INTERFACE_MODE_2500BASEX; 2256624c0f02SRussell King } else { 2257624c0f02SRussell King phylink_clear(state->advertising, 2500baseX_Full); 2258624c0f02SRussell King state->interface = PHY_INTERFACE_MODE_1000BASEX; 2259624c0f02SRussell King } 2260624c0f02SRussell King } 2261624c0f02SRussell King } 2262624c0f02SRussell King EXPORT_SYMBOL_GPL(phylink_helper_basex_speed); 2263624c0f02SRussell King 226474db1c18SRussell King static void phylink_decode_c37_word(struct phylink_link_state *state, 226574db1c18SRussell King uint16_t config_reg, int speed) 226674db1c18SRussell King { 226774db1c18SRussell King bool tx_pause, rx_pause; 226874db1c18SRussell King int fd_bit; 226974db1c18SRussell King 227074db1c18SRussell King if (speed == SPEED_2500) 227174db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT; 227274db1c18SRussell King else 227374db1c18SRussell King fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT; 227474db1c18SRussell King 227574db1c18SRussell King mii_lpa_mod_linkmode_x(state->lp_advertising, config_reg, fd_bit); 227674db1c18SRussell King 227774db1c18SRussell King if (linkmode_test_bit(fd_bit, state->advertising) && 227874db1c18SRussell King linkmode_test_bit(fd_bit, state->lp_advertising)) { 227974db1c18SRussell King state->speed = speed; 228074db1c18SRussell King state->duplex = DUPLEX_FULL; 228174db1c18SRussell King } else { 228274db1c18SRussell King /* negotiation failure */ 228374db1c18SRussell King state->link = false; 228474db1c18SRussell King } 228574db1c18SRussell King 228674db1c18SRussell King linkmode_resolve_pause(state->advertising, state->lp_advertising, 228774db1c18SRussell King &tx_pause, &rx_pause); 228874db1c18SRussell King 228974db1c18SRussell King if (tx_pause) 229074db1c18SRussell King state->pause |= MLO_PAUSE_TX; 229174db1c18SRussell King if (rx_pause) 229274db1c18SRussell King state->pause |= MLO_PAUSE_RX; 229374db1c18SRussell King } 229474db1c18SRussell King 229574db1c18SRussell King static void phylink_decode_sgmii_word(struct phylink_link_state *state, 229674db1c18SRussell King uint16_t config_reg) 229774db1c18SRussell King { 229874db1c18SRussell King if (!(config_reg & LPA_SGMII_LINK)) { 229974db1c18SRussell King state->link = false; 230074db1c18SRussell King return; 230174db1c18SRussell King } 230274db1c18SRussell King 230374db1c18SRussell King switch (config_reg & LPA_SGMII_SPD_MASK) { 230474db1c18SRussell King case LPA_SGMII_10: 230574db1c18SRussell King state->speed = SPEED_10; 230674db1c18SRussell King break; 230774db1c18SRussell King case LPA_SGMII_100: 230874db1c18SRussell King state->speed = SPEED_100; 230974db1c18SRussell King break; 231074db1c18SRussell King case LPA_SGMII_1000: 231174db1c18SRussell King state->speed = SPEED_1000; 231274db1c18SRussell King break; 231374db1c18SRussell King default: 231474db1c18SRussell King state->link = false; 231574db1c18SRussell King return; 231674db1c18SRussell King } 231774db1c18SRussell King if (config_reg & LPA_SGMII_FULL_DUPLEX) 231874db1c18SRussell King state->duplex = DUPLEX_FULL; 231974db1c18SRussell King else 232074db1c18SRussell King state->duplex = DUPLEX_HALF; 232174db1c18SRussell King } 232274db1c18SRussell King 232374db1c18SRussell King /** 2324afd62209SIoana Ciornei * phylink_decode_usxgmii_word() - decode the USXGMII word from a MAC PCS 2325afd62209SIoana Ciornei * @state: a pointer to a struct phylink_link_state. 2326afd62209SIoana Ciornei * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word 2327afd62209SIoana Ciornei * 2328afd62209SIoana Ciornei * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation 2329afd62209SIoana Ciornei * code word. Decode the USXGMII code word and populate the corresponding fields 2330afd62209SIoana Ciornei * (speed, duplex) into the phylink_link_state structure. 2331afd62209SIoana Ciornei */ 2332afd62209SIoana Ciornei void phylink_decode_usxgmii_word(struct phylink_link_state *state, 2333afd62209SIoana Ciornei uint16_t lpa) 2334afd62209SIoana Ciornei { 2335afd62209SIoana Ciornei switch (lpa & MDIO_USXGMII_SPD_MASK) { 2336afd62209SIoana Ciornei case MDIO_USXGMII_10: 2337afd62209SIoana Ciornei state->speed = SPEED_10; 2338afd62209SIoana Ciornei break; 2339afd62209SIoana Ciornei case MDIO_USXGMII_100: 2340afd62209SIoana Ciornei state->speed = SPEED_100; 2341afd62209SIoana Ciornei break; 2342afd62209SIoana Ciornei case MDIO_USXGMII_1000: 2343afd62209SIoana Ciornei state->speed = SPEED_1000; 2344afd62209SIoana Ciornei break; 2345afd62209SIoana Ciornei case MDIO_USXGMII_2500: 2346afd62209SIoana Ciornei state->speed = SPEED_2500; 2347afd62209SIoana Ciornei break; 2348afd62209SIoana Ciornei case MDIO_USXGMII_5000: 2349afd62209SIoana Ciornei state->speed = SPEED_5000; 2350afd62209SIoana Ciornei break; 2351afd62209SIoana Ciornei case MDIO_USXGMII_10G: 2352afd62209SIoana Ciornei state->speed = SPEED_10000; 2353afd62209SIoana Ciornei break; 2354afd62209SIoana Ciornei default: 2355afd62209SIoana Ciornei state->link = false; 2356afd62209SIoana Ciornei return; 2357afd62209SIoana Ciornei } 2358afd62209SIoana Ciornei 2359afd62209SIoana Ciornei if (lpa & MDIO_USXGMII_FULL_DUPLEX) 2360afd62209SIoana Ciornei state->duplex = DUPLEX_FULL; 2361afd62209SIoana Ciornei else 2362afd62209SIoana Ciornei state->duplex = DUPLEX_HALF; 2363afd62209SIoana Ciornei } 2364afd62209SIoana Ciornei EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word); 2365afd62209SIoana Ciornei 2366afd62209SIoana Ciornei /** 236774db1c18SRussell King * phylink_mii_c22_pcs_get_state() - read the MAC PCS state 236874db1c18SRussell King * @pcs: a pointer to a &struct mdio_device. 236974db1c18SRussell King * @state: a pointer to a &struct phylink_link_state. 237074db1c18SRussell King * 237174db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 237274db1c18SRussell King * clause 37 negotiation and/or SGMII control. 237374db1c18SRussell King * 237474db1c18SRussell King * Read the MAC PCS state from the MII device configured in @config and 237574db1c18SRussell King * parse the Clause 37 or Cisco SGMII link partner negotiation word into 237674db1c18SRussell King * the phylink @state structure. This is suitable to be directly plugged 237774db1c18SRussell King * into the mac_pcs_get_state() member of the struct phylink_mac_ops 237874db1c18SRussell King * structure. 237974db1c18SRussell King */ 238074db1c18SRussell King void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, 238174db1c18SRussell King struct phylink_link_state *state) 238274db1c18SRussell King { 238374db1c18SRussell King struct mii_bus *bus = pcs->bus; 238474db1c18SRussell King int addr = pcs->addr; 238574db1c18SRussell King int bmsr, lpa; 238674db1c18SRussell King 238774db1c18SRussell King bmsr = mdiobus_read(bus, addr, MII_BMSR); 238874db1c18SRussell King lpa = mdiobus_read(bus, addr, MII_LPA); 238974db1c18SRussell King if (bmsr < 0 || lpa < 0) { 239074db1c18SRussell King state->link = false; 239174db1c18SRussell King return; 239274db1c18SRussell King } 239374db1c18SRussell King 239474db1c18SRussell King state->link = !!(bmsr & BMSR_LSTATUS); 239574db1c18SRussell King state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); 239674db1c18SRussell King if (!state->link) 239774db1c18SRussell King return; 239874db1c18SRussell King 239974db1c18SRussell King switch (state->interface) { 240074db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX: 240174db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_1000); 240274db1c18SRussell King break; 240374db1c18SRussell King 240474db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX: 240574db1c18SRussell King phylink_decode_c37_word(state, lpa, SPEED_2500); 240674db1c18SRussell King break; 240774db1c18SRussell King 240874db1c18SRussell King case PHY_INTERFACE_MODE_SGMII: 240929f02ee4SIoana Ciornei case PHY_INTERFACE_MODE_QSGMII: 241074db1c18SRussell King phylink_decode_sgmii_word(state, lpa); 241174db1c18SRussell King break; 241274db1c18SRussell King 241374db1c18SRussell King default: 241474db1c18SRussell King state->link = false; 241574db1c18SRussell King break; 241674db1c18SRussell King } 241774db1c18SRussell King } 241874db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); 241974db1c18SRussell King 242074db1c18SRussell King /** 242174db1c18SRussell King * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS 242274db1c18SRussell King * advertisement 242374db1c18SRussell King * @pcs: a pointer to a &struct mdio_device. 24240bd27406SRussell King * @interface: the PHY interface mode being configured 24250bd27406SRussell King * @advertising: the ethtool advertisement mask 242674db1c18SRussell King * 242774db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 242874db1c18SRussell King * clause 37 negotiation and/or SGMII control. 242974db1c18SRussell King * 243074db1c18SRussell King * Configure the clause 37 PCS advertisement as specified by @state. This 243174db1c18SRussell King * does not trigger a renegotiation; phylink will do that via the 243274db1c18SRussell King * mac_an_restart() method of the struct phylink_mac_ops structure. 243374db1c18SRussell King * 243474db1c18SRussell King * Returns negative error code on failure to configure the advertisement, 243574db1c18SRussell King * zero if no change has been made, or one if the advertisement has changed. 243674db1c18SRussell King */ 243774db1c18SRussell King int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, 24380bd27406SRussell King phy_interface_t interface, 24390bd27406SRussell King const unsigned long *advertising) 244074db1c18SRussell King { 244174db1c18SRussell King struct mii_bus *bus = pcs->bus; 244274db1c18SRussell King int addr = pcs->addr; 244374db1c18SRussell King int val, ret; 244474db1c18SRussell King u16 adv; 244574db1c18SRussell King 24460bd27406SRussell King switch (interface) { 244774db1c18SRussell King case PHY_INTERFACE_MODE_1000BASEX: 244874db1c18SRussell King case PHY_INTERFACE_MODE_2500BASEX: 244974db1c18SRussell King adv = ADVERTISE_1000XFULL; 245074db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, 24510bd27406SRussell King advertising)) 245274db1c18SRussell King adv |= ADVERTISE_1000XPAUSE; 245374db1c18SRussell King if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, 24540bd27406SRussell King advertising)) 245574db1c18SRussell King adv |= ADVERTISE_1000XPSE_ASYM; 245674db1c18SRussell King 245774db1c18SRussell King val = mdiobus_read(bus, addr, MII_ADVERTISE); 245874db1c18SRussell King if (val < 0) 245974db1c18SRussell King return val; 246074db1c18SRussell King 246174db1c18SRussell King if (val == adv) 246274db1c18SRussell King return 0; 246374db1c18SRussell King 246474db1c18SRussell King ret = mdiobus_write(bus, addr, MII_ADVERTISE, adv); 246574db1c18SRussell King if (ret < 0) 246674db1c18SRussell King return ret; 246774db1c18SRussell King 246874db1c18SRussell King return 1; 246974db1c18SRussell King 247074db1c18SRussell King case PHY_INTERFACE_MODE_SGMII: 247174db1c18SRussell King val = mdiobus_read(bus, addr, MII_ADVERTISE); 247274db1c18SRussell King if (val < 0) 247374db1c18SRussell King return val; 247474db1c18SRussell King 247574db1c18SRussell King if (val == 0x0001) 247674db1c18SRussell King return 0; 247774db1c18SRussell King 247874db1c18SRussell King ret = mdiobus_write(bus, addr, MII_ADVERTISE, 0x0001); 247974db1c18SRussell King if (ret < 0) 248074db1c18SRussell King return ret; 248174db1c18SRussell King 248274db1c18SRussell King return 1; 248374db1c18SRussell King 248474db1c18SRussell King default: 248574db1c18SRussell King /* Nothing to do for other modes */ 248674db1c18SRussell King return 0; 248774db1c18SRussell King } 248874db1c18SRussell King } 248974db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); 249074db1c18SRussell King 249174db1c18SRussell King /** 249293eaceb0SRussell King * phylink_mii_c22_pcs_config() - configure clause 22 PCS 249393eaceb0SRussell King * @pcs: a pointer to a &struct mdio_device. 249493eaceb0SRussell King * @mode: link autonegotiation mode 249593eaceb0SRussell King * @interface: the PHY interface mode being configured 249693eaceb0SRussell King * @advertising: the ethtool advertisement mask 249793eaceb0SRussell King * 249893eaceb0SRussell King * Configure a Clause 22 PCS PHY with the appropriate negotiation 249993eaceb0SRussell King * parameters for the @mode, @interface and @advertising parameters. 250093eaceb0SRussell King * Returns negative error number on failure, zero if the advertisement 250193eaceb0SRussell King * has not changed, or positive if there is a change. 250293eaceb0SRussell King */ 250393eaceb0SRussell King int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, 250493eaceb0SRussell King phy_interface_t interface, 250593eaceb0SRussell King const unsigned long *advertising) 250693eaceb0SRussell King { 250793eaceb0SRussell King bool changed; 250893eaceb0SRussell King u16 bmcr; 250993eaceb0SRussell King int ret; 251093eaceb0SRussell King 251193eaceb0SRussell King ret = phylink_mii_c22_pcs_set_advertisement(pcs, interface, 251293eaceb0SRussell King advertising); 251393eaceb0SRussell King if (ret < 0) 251493eaceb0SRussell King return ret; 251593eaceb0SRussell King 251693eaceb0SRussell King changed = ret > 0; 251793eaceb0SRussell King 2518cd29296fSRobert Hancock /* Ensure ISOLATE bit is disabled */ 251993eaceb0SRussell King bmcr = mode == MLO_AN_INBAND ? BMCR_ANENABLE : 0; 252093eaceb0SRussell King ret = mdiobus_modify(pcs->bus, pcs->addr, MII_BMCR, 2521cd29296fSRobert Hancock BMCR_ANENABLE | BMCR_ISOLATE, bmcr); 252293eaceb0SRussell King if (ret < 0) 252393eaceb0SRussell King return ret; 252493eaceb0SRussell King 252593eaceb0SRussell King return changed ? 1 : 0; 252693eaceb0SRussell King } 252793eaceb0SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config); 252893eaceb0SRussell King 252993eaceb0SRussell King /** 253074db1c18SRussell King * phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation 253174db1c18SRussell King * @pcs: a pointer to a &struct mdio_device. 253274db1c18SRussell King * 253374db1c18SRussell King * Helper for MAC PCS supporting the 802.3 clause 22 register set for 253474db1c18SRussell King * clause 37 negotiation. 253574db1c18SRussell King * 253674db1c18SRussell King * Restart the clause 37 negotiation with the link partner. This is 253774db1c18SRussell King * suitable to be directly plugged into the mac_pcs_get_state() member 253874db1c18SRussell King * of the struct phylink_mac_ops structure. 253974db1c18SRussell King */ 254074db1c18SRussell King void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs) 254174db1c18SRussell King { 254274db1c18SRussell King struct mii_bus *bus = pcs->bus; 254374db1c18SRussell King int val, addr = pcs->addr; 254474db1c18SRussell King 254574db1c18SRussell King val = mdiobus_read(bus, addr, MII_BMCR); 254674db1c18SRussell King if (val >= 0) { 254774db1c18SRussell King val |= BMCR_ANRESTART; 254874db1c18SRussell King 254974db1c18SRussell King mdiobus_write(bus, addr, MII_BMCR, val); 255074db1c18SRussell King } 255174db1c18SRussell King } 255274db1c18SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_an_restart); 255374db1c18SRussell King 2554b8679ef8SRussell King void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, 2555b8679ef8SRussell King struct phylink_link_state *state) 2556b8679ef8SRussell King { 2557b8679ef8SRussell King struct mii_bus *bus = pcs->bus; 2558b8679ef8SRussell King int addr = pcs->addr; 2559b8679ef8SRussell King int stat; 2560b8679ef8SRussell King 256190ce665cSRussell King stat = mdiobus_c45_read(bus, addr, MDIO_MMD_PCS, MDIO_STAT1); 2562b8679ef8SRussell King if (stat < 0) { 2563b8679ef8SRussell King state->link = false; 2564b8679ef8SRussell King return; 2565b8679ef8SRussell King } 2566b8679ef8SRussell King 2567b8679ef8SRussell King state->link = !!(stat & MDIO_STAT1_LSTATUS); 2568b8679ef8SRussell King if (!state->link) 2569b8679ef8SRussell King return; 2570b8679ef8SRussell King 2571b8679ef8SRussell King switch (state->interface) { 2572b8679ef8SRussell King case PHY_INTERFACE_MODE_10GBASER: 2573b8679ef8SRussell King state->speed = SPEED_10000; 2574b8679ef8SRussell King state->duplex = DUPLEX_FULL; 2575b8679ef8SRussell King break; 2576b8679ef8SRussell King 2577b8679ef8SRussell King default: 2578b8679ef8SRussell King break; 2579b8679ef8SRussell King } 2580b8679ef8SRussell King } 2581b8679ef8SRussell King EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state); 2582b8679ef8SRussell King 25835f857575SAndrew Lunn MODULE_LICENSE("GPL v2"); 2584