# Base git commit: e8f897f4afef # (Linux 6.8) # # Author: Russell King (Oracle) (Thu 8 Feb 19:39:42 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:17 BST 2024) # # net: mvpp2: add support for querying PCS inband properties # # Report the PCS inband properties to phylink for Marvell PP2 interfaces. # # Signed-off-by: Russell King (Oracle) # # cc34099db06c0d4cff7098141427edb2e7f2f519 # drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 25 ++++++++++++++++--------- # 1 file changed, 16 insertions(+), 9 deletions(-) # # Author: Russell King (Oracle) (Thu 8 Feb 16:41:31 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:17 BST 2024) # # net: mvneta: add support for querying PCS inband properties # # Report the PCS inband properties to phylink for Marvell NETA # interfaces. # # Signed-off-by: Russell King (Oracle) # # 0a2ec7ae357f2d54a90523b2322b490ed6360786 # drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++---------- # 1 file changed, 17 insertions(+), 10 deletions(-) # # Author: Russell King (Oracle) (Wed 3 Apr 20:20:12 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:17 BST 2024) # # net: txgbe: use phylink_pcs_change() to report PCS link change events # # Use phylink_pcs_change() when reporting changes in PCS link state to # phylink. # # Signed-off-by: Russell King (Oracle) # # 34ce531c76a0a58a184648184173e8d0fe56269c # drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 3 ++- # 1 file changed, 2 insertions(+), 1 deletion(-) # # Author: Russell King (Oracle) (Mon 26 Feb 11:29:49 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:16 BST 2024) # # net: prestera: use phylink_pcs_change() to report PCS link change events # # Use phylink_pcs_change() when reporting changes in PCS link state to # phylink. # # Signed-off-by: Russell King (Oracle) # # 48ef4df0d9ad29bcb5033406bca12d207778e0ba # drivers/net/ethernet/marvell/prestera/prestera_main.c | 4 ++-- # 1 file changed, 2 insertions(+), 2 deletions(-) # # Author: Russell King (Oracle) (Mon 26 Feb 11:27:33 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:16 BST 2024) # # net: mvneta: use phylink_pcs_change() to report PCS link change events # # Use phylink_pcs_change() when reporting changes in PCS link state to # phylink. # # Signed-off-by: Russell King (Oracle) # # 164a15af1e122c0bd0622d41f459caad553d605b # drivers/net/ethernet/marvell/mvneta.c | 3 ++- # 1 file changed, 2 insertions(+), 1 deletion(-) # # Author: Russell King (Oracle) (Mon 26 Feb 11:25:04 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:16 BST 2024) # # net: mvpp2: use phylink_pcs_change() to report PCS link change events # # Use phylink_pcs_change() when reporting changes in PCS link state to # phylink. # # Signed-off-by: Russell King (Oracle) # # e137a513e2e8e055c3fba1f34c1580c5566488d1 # drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 9 +++++---- # 1 file changed, 5 insertions(+), 4 deletions(-) # # Author: Russell King (Oracle) (Thu 8 Feb 12:53:59 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:16 BST 2024) # # net: phylink: switch to use phy_query_inband() for copper SFP modules # # Use phy_query_inband() with the initial mode when configuring copper # SFP modules to determine whether we should use inband or PHY mode. This # allows us to remove the BCM84881 specific detection from phylink, and # instead rely on the PHY driver giving us this detail. # # We can use a simple check here - if the PHY reports that the inband # information is valid, but sets no other bits, then inband is definitely # not supported. # # Signed-off-by: Russell King (Oracle) # # 06b4e230547f21d5501a435ddf1efb7f3499f93e # drivers/net/phy/phylink.c | 20 +++++++++----------- # 1 file changed, 9 insertions(+), 11 deletions(-) # # Author: Russell King (Oracle) (Thu 8 Feb 12:44:26 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:15 BST 2024) # # net: phylink: move phylink_phy_no_inband() # # Since the BCM84881 driver always provides phy->supported_interfaces, # and the driver is required for this PHY, move phylink_phy_no_inband() # to the case where this is non-empty. # # Signed-off-by: Russell King (Oracle) # # 9246d6c69080a7547924edebd7aa870a0c8aa91c # drivers/net/phy/phylink.c | 6 +++--- # 1 file changed, 3 insertions(+), 3 deletions(-) # # Author: Russell King (Oracle) (Wed 22 Sep 15:23:05 BST 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:15 BST 2024) # # net: phylink: move the sfp autoneg mode into struct phylink # # Move the SFP autoneg mode into struct phylink rather than passing it # into phylink_sfp_config(). This is generally MLO_AN_INBAND except when # we have a copper SFP with a Broadcom 84881 PHY. # # Signed-off-by: Russell King (Oracle) # # 02a537c4fcc953c144ff4c9d89b1729dfb17bc28 # drivers/net/phy/phylink.c | 26 ++++++++++++-------------- # 1 file changed, 12 insertions(+), 14 deletions(-) # # Author: Russell King (Oracle) (Thu 17 Aug 21:56:27 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:15 BST 2024) # # net: dsa: mv88e6xxx: add 6352 family EEE support # # Signed-off-by: Russell King (Oracle) # # 5bb8123b0b784b1457071e10621579403c559436 # drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++++++ # 1 file changed, 8 insertions(+) # # Author: Russell King (Oracle) (Sat 4 Dec 20:13:11 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:14 BST 2024) # # net: phy: generate PHY mdio modalias # # The modalias string provided in the uevent sysfs file does not conform # to the format used in PHY driver modules. One of the reasons is that # udev loading of PHY driver modules has not been an expected use case. # # This patch changes the MODALIAS entry for only PHY devices from: # MODALIAS=of:Nethernet-phyT(null) # to: # MODALIAS=mdio:00000000001000100001010100010011 # # Other MDIO devices (such as DSA) remain as before. # # However, having udev automatically load the module has the advantage # of making use of existing functionality to have the module loaded # before the device is bound to the driver, thus taking advantage of # multithreaded boot systems, potentially decreasing the boot time. # # However, this patch will not solve any issues with the driver module # not being loaded prior to the network device needing to use the PHY. # This is something that is completely out of control of any patch to # change the uevent mechanism. # # Reported-by: Yinbo Zhu # Signed-off-by: Russell King (Oracle) # # 7a9f0d4216585f93f2a69fff76546ae9130d3aef # drivers/net/phy/mdio_bus.c | 8 ++++++++ # drivers/net/phy/phy_device.c | 14 ++++++++++++++ # include/linux/mdio.h | 2 ++ # 3 files changed, 24 insertions(+) # # Author: Russell King (Oracle) (Sat 27 Nov 16:34:13 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:14 BST 2024) # # net: all drivers update # # Signed-off-by: Russell King (Oracle) # # e807574f7881d9ac3ab13bce7b41677d2ab7a4d7 # drivers/net/dsa/mt7530.c | 2 +- # drivers/net/ethernet/marvell/mvneta.c | 2 +- # drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 2 +- # drivers/net/pcs/pcs-rzn1-miic.c | 3 ++- # drivers/net/pcs/pcs-xpcs.c | 3 ++- # 5 files changed, 7 insertions(+), 5 deletions(-) # # Author: Russell King (Oracle) (Sat 27 Nov 16:28:48 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:14 BST 2024) # # net: phylink: pass mode into pcs_validate() # # Signed-off-by: Russell King (Oracle) # # 3fbe8a68eb009866166574820b3e05c5ad12b5e6 # drivers/net/phy/phylink.c | 3 ++- # include/linux/phylink.h | 8 +++++--- # 2 files changed, 7 insertions(+), 4 deletions(-) # # Author: Russell King (Oracle) (Sun 21 Nov 12:52:30 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:13 BST 2024) # # net: phylink: pass mode into phylink_validate() # # Signed-off-by: Russell King (Oracle) # # 2d84339bad1a19ac4b8c2f617e2e964d28fa2d35 # drivers/net/phy/phylink.c | 49 ++++++++++++++++++++++++++++++----------------- # 1 file changed, 31 insertions(+), 18 deletions(-) # # Author: Russell King (Oracle) (Sat 27 Nov 16:05:36 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:13 BST 2024) # # net: use phylink_mode_*() helpers # # Use the phylink_mode_*() helpers in all drivers so we can change the # definition of the "mode" argument. # # Signed-off-by: Russell King (Oracle) # # 8ef4949784193b2869568da22352650350dd439b # drivers/net/dsa/b53/b53_common.c | 8 ++++---- # drivers/net/dsa/bcm_sf2.c | 2 +- # drivers/net/dsa/mv88e6xxx/chip.c | 13 +++++++------ # drivers/net/dsa/mv88e6xxx/port.c | 2 +- # drivers/net/ethernet/cadence/macb_main.c | 2 +- # drivers/net/phy/phylink.c | 27 ++++++++++++++------------- # 6 files changed, 28 insertions(+), 26 deletions(-) # # Author: Russell King (Oracle) (Sat 27 Nov 14:15:19 GMT 2021) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:13 BST 2024) # # net: phylink: add helpers for decoding mode # # Add helpers to decode the mode argument passed to the various MAC and # PCS functions. # # Signed-off-by: Russell King (Oracle) # # 9de268b50927ac3fc2f5ac5db20a415c1da3ab12 # include/linux/phylink.h | 17 ++++++++++++++++- # 1 file changed, 16 insertions(+), 1 deletion(-) # # Author: Russell King (Tue 3 Mar 12:12:43 GMT 2020) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:12 BST 2024) # # net: phylink: use phy interface mode bitmaps # # Use the phy interface mode bitmaps for SFP modules and PHYs to select # the operating interface for SFPs and PHYs with SFPs. # # Signed-off-by: Russell King # # d51a722e1ae1a31836f37be6127477b8414b7f08 # drivers/net/phy/phylink.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- # 1 file changed, 42 insertions(+), 4 deletions(-) # # Author: Russell King (Oracle) (Sat 5 Aug 14:30:51 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:12 BST 2024) # # net: phy: add supported_interfaces to Aquantia AQR113C # # Signed-off-by: Russell King (Oracle) # # ee7a8c0634bd7ba95f618cd13a9d5e298bc0e0a2 # drivers/net/phy/aquantia/aquantia_main.c | 15 ++++++++++++++- # 1 file changed, 14 insertions(+), 1 deletion(-) # # Author: Russell King (Mon 23 Dec 23:26:04 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:10 BST 2024) # # net: phy: add supported_interfaces to marvell10g PHYs # # Signed-off-by: Russell King # # 564b1517abdae0456c99faf91177245f3ded6d20 # drivers/net/phy/marvell10g.c | 5 ++--- # 1 file changed, 2 insertions(+), 3 deletions(-) # # Author: Russell King (Mon 23 Dec 23:25:49 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:10 BST 2024) # # net: phy: add supported_interfaces to marvell PHYs # # Signed-off-by: Russell King # # 0abedeb2133b6c0e8e31f0e5fb6feaf5e92a53c6 # drivers/net/phy/marvell.c | 9 +++++++++ # 1 file changed, 9 insertions(+) # # Author: Russell King (Mon 23 Dec 23:25:35 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:10 BST 2024) # # net: phy: add supported_interfaces to bcm84881 # # Signed-off-by: Russell King # # 6b78de6f5bd2c4323b022aa85f3db50ef64f0c74 # drivers/net/phy/bcm84881.c | 4 ++++ # 1 file changed, 4 insertions(+) # # Author: Russell King (Mon 23 Dec 23:24:17 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:09 BST 2024) # # net: phy: add supported_interfaces to phylib # # Add a supported_interfaces member to phylib so we know which # interfaces a PHY supports. Currently, set any unconverted driver # to indicate all interfaces are supported. # # Signed-off-by: Russell King # # 3fae7784f530c1e2d14cf33db2b028d76baec49b # include/linux/phy.h | 3 +++ # 1 file changed, 3 insertions(+) # # Author: Russell King (Sun 13 Sep 01:06:31 BST 2015) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:09 BST 2024) # # net: sfp: display SFP module information [*not for mainline*] # # Display SFP module information verbosely, splitting the generic parts # into a separate file. # # Signed-off-by: Russell King # # 863ef898359453f24ade28b4f59a952dd59d6093 # drivers/net/phy/Makefile | 2 +- # drivers/net/phy/sff.c | 114 +++++++++++++++++++++++ # drivers/net/phy/sff.h | 16 ++++ # drivers/net/phy/sfp.c | 229 ++++++++++++++++++++++++++++++++++++++++++++--- # 4 files changed, 350 insertions(+), 11 deletions(-) # create mode 100644 drivers/net/phy/sff.c # create mode 100644 drivers/net/phy/sff.h # # Author: Russell King (Fri 14 Apr 20:17:13 BST 2017) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:09 BST 2024) # # net: sfp: add sfp+ compatible [*not for mainline*] # # Add a compatible for SFP+ cages. SFP+ cages are backwards compatible, # but the ethernet device behind them may not support the slower speeds # of SFP modules. # # Signed-off-by: Russell King # # 9983f82f9d5eb2c26e5d8443862bb31d83f2cb31 # drivers/net/phy/sfp.c | 1 + # 1 file changed, 1 insertion(+) # # Author: Russell King (Fri 18 Oct 10:37:44 BST 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:08 BST 2024) # # net: sfp: add support for cooled SFP+ transceivers # # Cooled SFP+ transceivers need a longer initialisation (startup) time. # Select the initialisation time depending on the cooled option bit. # # Signed-off-by: Russell King # # f31d4a24d674f6a37ae5c99e91582fb1da1e8778 # drivers/net/phy/sfp.c | 18 +++++++++++------- # 1 file changed, 11 insertions(+), 7 deletions(-) # # Author: Russell King (Tue 5 Nov 10:34:39 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:08 BST 2024) # # net: phy: make phy_error() report which PHY has failed # # phy_error() is called from phy_interrupt() or phy_state_machine(), and # uses WARN_ON() to print a backtrace. The backtrace is not useful when # reporting a PHY error. # # However, a system may contain multiple ethernet PHYs, and phy_error() # gives no clue which one caused the problem. # # Replace WARN_ON() with a call to phydev_err() so that we can see which # PHY had an error, and also inform the user that we are halting the PHY. # # Signed-off-by: Russell King # # 93840becb709b4ac7f26e558995468d9a63c3eaa # drivers/net/phy/phy.c | 3 ++- # 1 file changed, 2 insertions(+), 1 deletion(-) # # Author: Russell King (Wed 5 Jun 11:44:55 BST 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:08 BST 2024) # # net: phy: marvell10g: allow PHY to probe without firmware # # Allow the PHY to probe when there is no firmware, but do not allow the # link to come up by forcing the PHY state to PHY_HALTED in a similar way # to phy_error(). # # Signed-off-by: Russell King # # adfbd07b515a9d82781e405183de6e4282bd623b # drivers/net/phy/marvell10g.c | 18 +++++++++++++++++- # 1 file changed, 17 insertions(+), 1 deletion(-) # # Author: Russell King (Mon 26 Aug 12:19:35 BST 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:07 BST 2024) # # net: phy: provide phy driver start/stop hooks # # Provide phy driver start/stop hooks so that the PHY driver knows when # the network driver is starting or stopping. This will be used for the # Marvell 10G driver so that we can sanely refuse to start if the PHYs # firmware is not present, and also so that we can sanely support SFPs # behind the PHY. # # Signed-off-by: Russell King # # 9e70d679f42d1d345e14196892edb080bfab10d2 # drivers/net/phy/phy.c | 7 +++++++ # include/linux/phy.h | 3 +++ # 2 files changed, 10 insertions(+) # # Author: Russell King (Sat 4 Jan 00:41:35 GMT 2020) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:07 BST 2024) # # net: phy: marvell*: add support for hw resolved pause modes # # Support reporting the hardware resolved pause enablement states via # phylib, overriding our software implementation. # # Signed-off-by: Russell King # # 41852d657d05e069bbaae3175522519bb7a2a888 # drivers/net/phy/marvell.c | 40 ++++++++++++++++++++++++++++++++++------ # drivers/net/phy/marvell10g.c | 6 ++++++ # 2 files changed, 40 insertions(+), 6 deletions(-) # # Author: Russell King (Fri 3 Jan 23:13:28 GMT 2020) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:07 BST 2024) # # net: phy: add resolved pause support [*not for mainline*] # # Allow phylib drivers to pass the hardware-resolved pause state to MAC # drivers, rather than using the software-based pause resolution code. # # Signed-off-by: Russell King # # 01b334d14db0242a727fbb553e829c9ebadbe332 # drivers/net/phy/phy_device.c | 6 ++++++ # include/linux/phy.h | 9 +++++++++ # 2 files changed, 15 insertions(+) # # Author: Russell King (Oracle) (Fri 2 Jun 11:51:53 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:06 BST 2024) # # net: phylink: handle MDIO_USXGMII_LINK when decoding USXGMII # # If MDIO_USXGMII_LINK is not set, it means that the PHYs media side # link is down. Indicate back to phylink that the link as a whole is # down. # # Signed-off-by: Russell King (Oracle) # # 6d6cca431056e024189977126f34db76ae131c81 # drivers/net/phy/phylink.c | 10 ++++++++-- # 1 file changed, 8 insertions(+), 2 deletions(-) # # Author: Russell King (Sun 1 Dec 15:35:08 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:06 BST 2024) # # arm64: dts: configure Macchiatobin 10G PHY LED modes # # Configure the Macchiatobin 10G PHY LED modes to correct their polarity. # We keep the existing LED behaviours, but switch their polarity to # reflect how they are connected. Tweak the LED modes as well to be: # # left: off = no link # solid green = RJ45 link up (not SFP+ cage) # flash green = traffic # right: off = no link # solid green = 10G # solid yellow = 1G # flash green = 100M # flash yellow = 10M # # Signed-off-by: Russell King # # b44fede9099fbbdfffa1a9a20d51bd679117ce73 # arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts | 2 ++ # 1 file changed, 2 insertions(+) # # Author: Russell King (Sun 1 Dec 15:33:39 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:06 BST 2024) # # net: phy: marvell10g: add support for configuring LEDs # # Add support for configuring the LEDs. Macchiatobin has an oddity in # that the left LED goes out when the cable is connected, and flashes # when there's link activity. This is because the reset default for # the LED outputs assume that the LED is connected to supply, not to # ground. Add support for configuring the LED modes and polarities. # # Signed-off-by: Russell King # # 772f58ad70501b4c55f31116170a97acde39d078 # drivers/net/phy/marvell10g.c | 62 +++++++++++++++++++++++++++++++++++++++----- # 1 file changed, 55 insertions(+), 7 deletions(-) # # Author: Russell King (Tue 17 Dec 15:21:50 GMT 2019) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:05 BST 2024) # # dt-bindings: net: add dt bindings for marvell10g driver # # Add a DT bindings document for the Marvell 10G driver, which will # augment the generic ethernet PHY binding by having LED mode # configuration. # # Signed-off-by: Russell King # # 5f514915f30efdd53aa24351163c2488934c967c # .../devicetree/bindings/net/marvell,10g.yaml | 36 ++++++++++++++++++++++ # 1 file changed, 36 insertions(+) # create mode 100644 Documentation/devicetree/bindings/net/marvell,10g.yaml # # Author: Russell King (Oracle) (Thu 8 Feb 15:54:46 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:05 BST 2024) # # net: phy: marvell: provide phy_query_inband() implementation # # Provide an implementation for phy_query_inband() for Marvell PHYs used # on SFP modules. # # Signed-off-by: Russell King (Oracle) # # 0c2fb62db211312ad2f5695997694908b54e9a17 # drivers/net/phy/marvell.c | 16 ++++++++++++++++ # 1 file changed, 16 insertions(+) # # Author: Russell King (Oracle) (Tue 30 Jan 14:38:27 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:05 BST 2024) # # net: phy: bcm84881: provide phy_query_inband() implementation # # BCM84881 has no support for inband signalling, so this is a trivial # implementation that returns no support for inband. # # Signed-off-by: Russell King (Oracle) # # 41a3a2c51cf7cb7b985925fa2dc96fb4396fc7ed # drivers/net/phy/bcm84881.c | 10 ++++++++++ # 1 file changed, 10 insertions(+) # # Author: Russell King (Oracle) (Thu 8 Feb 16:12:43 GMT 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:04 BST 2024) # # net: phylink: add pcs_query_inband() # # Add a pcs_query_inband() interface which reflects phy_query_inband() # for PHYs. This can be used to determine for the specified interface # mode whether in-band signalling is supported by the PCS, and whether # the PCS requires in-band signalling. # # This is used to determine whether we should use inband autonegotiation # in inband mode, which may be required or may be unsupported in various # interface modes. # # Signed-off-by: Russell King (Oracle) # # 7cb3771a782bb7db06169b98d15f4f20bb40ecbc # drivers/net/phy/phylink.c | 180 ++++++++++++++++++++++++++++++++++++++++------ # include/linux/phylink.h | 17 +++++ # 2 files changed, 176 insertions(+), 21 deletions(-) # # Author: Russell King (Oracle) (Mon 21 Aug 13:04:32 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:04 BST 2024) # # net: phy: add phy_query_inband() # # Add a method to query the PHY's in-band capabilities for a PHY # interface mode. This can be used to determine for the specified # interface mode whether in-band signalling is supported, and whether # the PHY requires in-band signalling. # # When not implemented, or the PHY driver doesn't report any modes # for the interface, LINK_INBAND_VALID will not be set. When set, the # remainder of the flags can be interpreted. # # LINK_INBAND_POSSIBLE means that the device can be configured to use # or not use in-band signalling. Later patches may add support to # configure this at the PHY. # # LINK_INBAND_REQUIRED means that the device uses in-band signalling # which can not be disabled. # # When only LINK_INBAND_VALID has been set, this means that the device # does not support any in-band signalling, and can't be configured to # do so. # # "Bypass" mode (where the device may be configured for in-band, but # may still bring the link up if there is no in-band received from the # link partner) is not considered in this patch. # # Signed-off-by: Russell King (Oracle) # # 2c621b33b510f6b9adbadcf1eec01cdf62fa9bd6 # drivers/net/phy/phy.c | 21 +++++++++++++++++++++ # include/linux/phy.h | 28 ++++++++++++++++++++++++++++ # 2 files changed, 49 insertions(+) # # Author: Russell King (Oracle) (Thu 1 Jun 09:48:20 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:04 BST 2024) # # net: phylink allow EEE management for SFPs without PHYs # # Allow EEE management for SFPs without accessible PHYs. # # Signed-off-by: Russell King (Oracle) # # 5de9ed47abfe7547ff008e97992ba2650e47a20d # drivers/net/phy/phylink.c | 11 ++++++++++- # 1 file changed, 10 insertions(+), 1 deletion(-) # # Author: Russell King (Oracle) (Wed 16 Aug 20:48:48 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:03 BST 2024) # # net: dsa: mt7530: convert to phylink managed EEE # # Fixme: doesn't bit 25 and 26 also need to be set in the PMCR for # PMCR_FORCE_EEE100 and PMCR_FORCE_EEE1G to take effect? # # Signed-off-by: Russell King (Oracle) # # 1a853040b7a762b0dab068ba736d1ae6b1adae85 # drivers/net/dsa/mt7530.c | 95 ++++++++++++++++++++++++++---------------------- # drivers/net/dsa/mt7530.h | 6 +-- # 2 files changed, 52 insertions(+), 49 deletions(-) # # Author: Russell King (Oracle) (Wed 16 Aug 14:02:11 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:03 BST 2024) # # net: dsa: add support for phylink managed EEE # # Add support to allow DSA drivers to use phylink managed EEE, with only # needing support for controlling the LPI state. # # Signed-off-by: Russell King (Oracle) # # 6c0aad491228a975f59dc65daad55e272f663d70 # include/net/dsa.h | 3 +++ # net/dsa/port.c | 22 ++++++++++++++++++++++ # net/dsa/user.c | 42 ++++++++++++++++++++++++++---------------- # 3 files changed, 51 insertions(+), 16 deletions(-) # # Author: Russell King (Oracle) (Thu 17 Aug 16:32:32 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:03 BST 2024) # # net: dsa: mv88e6xxx: add EEE controls # # Add phylink EEE control methods to allow EEE to be configured. When # LPI is to be disabled, we force the port to have EEE disabled, but # when enabling EEE, if the port is under the control of the PPU, we # stop forcing it, otherwise we force-enable EEE. # # Signed-off-by: Russell King (Oracle) # # c716326e24fce4592ad6265ceeb1a1cee392d136 # drivers/net/dsa/mv88e6xxx/chip.c | 45 ++++++++++++++++++++++++++++++++++++++++ # 1 file changed, 45 insertions(+) # # Author: Russell King (Oracle) (Thu 17 Aug 15:36:22 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:02 BST 2024) # # net: dsa: mv88e6xxx: add support for EEE forcing # # Add support for EEE forcing using the MAC control register. Replace # the 88e6393x errata 4.5 EEE disable code with a call to the new EEE # forcing code. # # Signed-off-by: Russell King (Oracle) # # e3d7e533dbf1c1482990c1a0e134f34673a82f13 # drivers/net/dsa/mv88e6xxx/port.c | 39 +++++++++++++++++++++++++++++++-------- # drivers/net/dsa/mv88e6xxx/port.h | 1 + # 2 files changed, 32 insertions(+), 8 deletions(-) # # Author: Russell King (Oracle) (Thu 17 Aug 16:32:32 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:02 BST 2024) # # net: dsa: mv88e6xxx: add port_set_eee() method # # Add a port_set_eee() method to allow the EEE settings for a port to be # configured. # # Signed-off-by: Russell King (Oracle) # # 68c5eb934481c6816ee6ad172bcee7c3b54e1553 # drivers/net/dsa/mv88e6xxx/chip.h | 10 ++++++++++ # 1 file changed, 10 insertions(+) # # Author: Russell King (Oracle) (Wed 31 May 17:17:11 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:02 BST 2024) # # net: mvpp2: add EEE implementation # # Add EEE support for mvpp2, using phylink's EEE implementation, which # means we just need to implement the two methods for LPI control, and # with the initial configuration. Only the GMAC is supported, so only # 100M, 1G and 2.5G speeds. # # Disabling LPI requires clearing a single bit. Enabling LPI needs a full # configuration of several values, as the timer values are dependent on # the MAC operating speed. # # Signed-off-by: Russell King (Oracle) # # 75422754ca42d76e398285c50d5182c6a9c2bad2 # drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 5 ++ # drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 85 +++++++++++++++++++++++++ # 2 files changed, 90 insertions(+) # # Author: Russell King (Oracle) (Wed 31 May 15:17:24 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:01 BST 2024) # # net: mvneta: convert to phylink EEE implementation # # Convert mvneta to use phylink's EEE implementation, which means we just # need to implement the two methods for LPI control, and adding the # initial configuration. # # Disabling LPI requires clearing a single bit. Enabling LPI needs a full # configuration of several values, as the timer values are dependent on # the MAC operating speed. # # Signed-off-by: Russell King (Oracle) # # 3c340a0c24c8a106e03ac5f3d87b30b9cb2adc22 # drivers/net/ethernet/marvell/mvneta.c | 107 +++++++++++++++++++--------------- # 1 file changed, 60 insertions(+), 47 deletions(-) # # Author: Russell King (Oracle) (Wed 31 May 10:02:35 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:01 BST 2024) # # net: phylink: add EEE management # # Add EEE management to phylink. # # Signed-off-by: Russell King (Oracle) # # 053c755c22c33613f89047a8f16d41d3fe5a39c0 # drivers/net/phy/phylink.c | 144 ++++++++++++++++++++++++++++++++++++++++++++-- # include/linux/phylink.h | 36 ++++++++++++ # 2 files changed, 175 insertions(+), 5 deletions(-) # # Author: Russell King (Oracle) (Wed 31 May 15:15:03 BST 2023) # Committer: Russell King (Oracle) (Tue 16 Apr 16:51:01 BST 2024) # # net: add helpers for EEE configuration # # Add helpers that phylib and phylink can use to manage EEE configuration # and determine whether the MAC should be permitted to use LPI based on # that configuration. # # Signed-off-by: Russell King (Oracle) # # e2a4546624bbd9be547bc70ae2a1fb779c117517 # include/net/eee.h | 38 ++++++++++++++++++++++++++++++++++++++ # 1 file changed, 38 insertions(+) # create mode 100644 include/net/eee.h # # Author: Russell King (Oracle) (Fri 5 Apr 10:59:17 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:22:32 BST 2024) # # net: dsa: felix: provide own phylink MAC operations # # Convert felix to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. # # Signed-off-by: Russell King (Oracle) # # 87dd8a827061e83a6f4fdbe7f20326663d26566f # drivers/net/dsa/ocelot/felix.c | 54 ++++++++++++++++++++++++------------- # drivers/net/dsa/ocelot/felix.h | 1 + # drivers/net/dsa/ocelot/ocelot_ext.c | 1 + # 3 files changed, 38 insertions(+), 18 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 13:00:55 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:21:46 BST 2024) # # net: dsa: rzn1_a5psw: provide own phylink MAC operations # # Convert rzn1_a5psw to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. We need to provide a stub for # the mac_config() method which is mandatory. # # Signed-off-by: Russell King (Oracle) # # f16d35764c2cf3d4725c136bf830d7172accac84 # drivers/net/dsa/rzn1_a5psw.c | 47 +++++++++++++++++++++++++++++--------------- # 1 file changed, 31 insertions(+), 16 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 13:00:55 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:21:45 BST 2024) # # net: dsa: lan9303: provide own phylink MAC operations # # Convert lan9303 to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. We need to provide stubs for # the mac_link_down() and mac_config() methods which are mandatory. # # Signed-off-by: Russell King (Oracle) # # 9f9bc1df39a1e72987efbb2a863cb56e6f6969d0 # drivers/net/dsa/lan9303-core.c | 31 ++++++++++++++++++++++++++----- # 1 file changed, 26 insertions(+), 5 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 10:59:17 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:21:45 BST 2024) # # net: dsa: xrs700x: provide own phylink MAC operations # # Convert xrs700x to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. We need to provide stubs for # the mac_link_down() and mac_config() methods which are mandatory. # # Signed-off-by: Russell King (Oracle) # # 055235891082f2adc943a9f7abfdd4931b6a1911 # drivers/net/dsa/xrs700x/xrs700x.c | 25 +++++++++++++++++++++---- # 1 file changed, 21 insertions(+), 4 deletions(-) # # Author: Russell King (Oracle) (Fri 12 Apr 18:00:41 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:21:45 BST 2024) # # net: dsa: bcm_sf2: provide own phylink MAC operations # # Convert bcm_sf2 to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c # # Signed-off-by: Russell King (Oracle) # # a1c15a8521d95aae454702876e60838bf35fa6bc # drivers/net/dsa/bcm_sf2.c | 49 +++++++++++++++++++++++++++++++---------------- # 1 file changed, 32 insertions(+), 17 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 10:59:17 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:20:00 BST 2024) # # net: dsa: lantiq_gswip: provide own phylink MAC operations # # Convert lantiq_gswip to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. For lantiq_gswip, it means # we end up with a common instance of phylink MAC operations that are # shared between the different variants, rather than having duplicated # initialisers in dsa_switch_ops. # # Signed-off-by: Russell King (Oracle) # # 91f106839ad5af0eed043cf5ffe52b9f3e3f85f4 # drivers/net/dsa/lantiq_gswip.c | 39 +++++++++++++++++++++++---------------- # 1 file changed, 23 insertions(+), 16 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 10:59:17 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:20:00 BST 2024) # # net: dsa: qca8k: provide own phylink MAC operations # # Convert qca8k to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. # # Signed-off-by: Russell King (Oracle) # # bfbd05a8769e42fc29a7d5de9fd4cd5e9a6895c8 # drivers/net/dsa/qca/qca8k-8xxx.c | 49 ++++++++++++++++++++++++++-------------- # 1 file changed, 32 insertions(+), 17 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 10:59:17 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:19:59 BST 2024) # # net: dsa: ar9331: provide own phylink MAC operations # # Convert ar9331 to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c. # # Signed-off-by: Russell King (Oracle) # # 712c761cbe006b85393a07e38ff1201fe8cf94a1 # drivers/net/dsa/qca/ar9331.c | 37 ++++++++++++++++++++++--------------- # 1 file changed, 22 insertions(+), 15 deletions(-) # # Author: Russell King (Oracle) (Fri 5 Apr 13:00:55 BST 2024) # Committer: Russell King (Oracle) (Tue 16 Apr 11:19:59 BST 2024) # # net: dsa: sja1105: provide own phylink MAC operations # # Convert sja1105 to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c # # Signed-off-by: Russell King (Oracle) # # 4e14bc871c1d482436e8648de85863f142f8eb0a # drivers/net/dsa/sja1105/sja1105_main.c | 38 ++++++++++++++++++++++++---------- # 1 file changed, 27 insertions(+), 11 deletions(-) # # Author: Russell King (Oracle) (Fri 12 Apr 16:05:05 BST 2024) # Committer: Russell King (Oracle) (Fri 12 Apr 17:05:53 BST 2024) # # net: dsa: convert dsa_user_phylink_fixed_state() to use dsa_phylink_to_port() # # Convert dsa_user_phylink_fixed_state() to use the newly introduced # dsa_phylink_to_port() helper. # # Suggested-by: Vladimir Oltean # Signed-off-by: Russell King (Oracle) # # 788c428eeb8660ee3f89b19c9398948b4c9e854f # net/dsa/user.c | 2 +- # 1 file changed, 1 insertion(+), 1 deletion(-) # # Author: Russell King (Oracle) (Thu 1 Feb 12:10:57 GMT 2024) # Committer: Russell King (Oracle) (Wed 10 Apr 20:26:55 BST 2024) # # net: dsa: mv88e6xxx: provide own phylink MAC operations # # Convert mv88e6xxx to provide its own phylink MAC operations, thus # avoiding the shim layer in DSA's port.c # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # 392b4781f4875701982c8cc15082aedb8a3aac3e # drivers/net/dsa/mv88e6xxx/chip.c | 63 +++++++++++++++++++++++++--------------- # 1 file changed, 39 insertions(+), 24 deletions(-) # # Author: Russell King (Oracle) (Thu 1 Feb 11:55:42 GMT 2024) # Committer: Russell King (Oracle) (Wed 10 Apr 20:26:03 BST 2024) # # net: dsa: allow DSA switch drivers to provide their own phylink mac ops # # Rather than having a shim for each and every phylink MAC operation, # allow DSA switch drivers to provide their own ops structure. When a # DSA driver provides the phylink MAC operations, the shimmed ops must # not be provided, so fail an attempt to register a switch with both # the phylink_mac_ops in struct dsa_switch and the phylink_mac_* # operations populated in dsa_switch_ops populated. # # Signed-off-by: Russell King (Oracle) # # fdb34a579b1177a17745f8bac419476c9f156300 # include/net/dsa.h | 5 +++++ # net/dsa/dsa.c | 11 +++++++++++ # net/dsa/port.c | 26 ++++++++++++++++++++------ # 3 files changed, 36 insertions(+), 6 deletions(-) # # Author: Russell King (Oracle) (Thu 1 Feb 11:38:04 GMT 2024) # Committer: Russell King (Oracle) (Wed 10 Apr 20:25:35 BST 2024) # # net: dsa: introduce dsa_phylink_to_port() # # We convert from a phylink_config struct to a dsa_port struct in many # places, let's provide a helper for this. # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # d3de3c9c35be06f6f2b13a6229836c2c06d537af # include/net/dsa.h | 6 ++++++ # net/dsa/port.c | 12 ++++++------ # 2 files changed, 12 insertions(+), 6 deletions(-) # # Author: Russell King (Oracle) (Tue 30 Jan 17:18:43 GMT 2024) # Committer: Russell King (Oracle) (Thu 4 Apr 16:53:36 BST 2024) # # net: pcs: rzn1-miic: update PCS driver to use neg_mode # # Update the RZN1-MIIC PCS driver to use neg_mode rather than the mode # argument to match the other updated PCS drivers. # # Signed-off-by: Russell King (Oracle) # # fae957127a5a06fdd990dfc9b57ac7bff246a138 # drivers/net/pcs/pcs-rzn1-miic.c | 5 +++-- # 1 file changed, 3 insertions(+), 2 deletions(-) # # Author: Russell King (Oracle) (Tue 30 Jan 17:21:03 GMT 2024) # Committer: Russell King (Oracle) (Wed 3 Apr 10:49:01 BST 2024) # # net: dsa: mv88e6xxx: update 88e6185 PCS driver to use neg_mode # # Update the Marvell 88e6185 PCS driver to use neg_mode rather than the # mode argument to match the other updated PCS drivers. # # Signed-off-by: Russell King (Oracle) # # b13b1949f1a66e2781b338f869277e095cc462c1 # drivers/net/dsa/mv88e6xxx/pcs-6185.c | 3 ++- # 1 file changed, 2 insertions(+), 1 deletion(-) # # Author: Russell King (Oracle) (Thu 8 Feb 21:41:51 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:38 GMT 2024) # # net: phy: marvell: add comment about m88e1111_config_init_1000basex() # # The comment in m88e1111_config_init_1000basex() is wrong - it claims # that Autoneg will be enabled, but this doesn't actually happen. # # Signed-off-by: Russell King (Oracle) # # 781509a503e9c44548cf07d9407be0f6afbd5148 # drivers/net/phy/marvell.c | 5 ++++- # 1 file changed, 4 insertions(+), 1 deletion(-) # # Author: Russell King (Oracle) (Wed 16 Aug 12:40:52 BST 2023) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:14 GMT 2024) # # net: dsa: b53: remove eee_enabled/eee_active in b53_get_mac_eee() # # b53_get_mac_eee() sets both eee_enabled and eee_active, and then # returns zero. # # dsa_user_get_eee(), which calls this function, will then continue to # call phylink_ethtool_get_eee(), which will return -EOPNOTSUPP if there # is no PHY present, otherwise calling phy_ethtool_get_eee() which in # turn will call genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Thus, when there is no PHY, dsa_user_get_eee() will fail with # -EOPNOTSUPP, meaning eee_enabled and eee_active will not be returned to # userspace. When there is a PHY, eee_enabled and eee_active will be # overwritten by phylib, making the setting of these members in # b53_get_mac_eee() entirely unnecessary. # # Remove this code, thus simplifying b53_get_mac_eee(). # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # d6061b71fd98ac34a2eb2b786157910004534d0f # drivers/net/dsa/b53/b53_common.c | 6 ------ # 1 file changed, 6 deletions(-) # # Author: Russell King (Oracle) (Thu 4 Jan 16:57:28 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:13 GMT 2024) # # net: bcmasp: remove eee_enabled/eee_active in bcmasp_get_eee() # # bcmasp_get_eee() sets edata->eee_active and edata->eee_enabled from # its own copy, and then calls phy_ethtool_get_eee() which in turn will # call genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Therefore, setting these members in bcmasp_get_eee() is redundant, and # can be removed. This also makes intf->eee.eee_active unnecessary, so # remove this and use a local variable where appropriate. # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # ea6b10f892683feab138a1f33f1139f3d7743730 # drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c | 4 ---- # drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 5 +++-- # 2 files changed, 3 insertions(+), 6 deletions(-) # # Author: Russell King (Oracle) (Thu 4 Jan 16:52:43 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:12 GMT 2024) # # net: bcmgenet: remove eee_enabled/eee_active in bcmgenet_get_eee() # # bcmgenet_get_eee() sets edata->eee_active and edata->eee_enabled from # its own copy, and then calls phy_ethtool_get_eee() which in turn will # call genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Therefore, setting these members in bcmgenet_get_eee() is redundant, # and can be removed. This also makes priv->eee.eee_active unnecessary, # so remove this and use a local variable where appropriate. # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # 96bff05380e2445a746f333becab4c65881248f3 # drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 +++----- # drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++-- # 2 files changed, 6 insertions(+), 7 deletions(-) # # Author: Russell King (Oracle) (Thu 4 Jan 16:34:25 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:10 GMT 2024) # # net: fec: remove eee_enabled/eee_active in fec_enet_get_eee() # # fec_enet_get_eee() sets edata->eee_active and edata->eee_enabled from # its own copy, and then calls phy_ethtool_get_eee() which in turn will # call genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Therefore, setting these members in fec_enet_get_eee() is redundant. # Remove this, and remove the setting of fep->eee.eee_active member which # becomes a write-only variable. # # Signed-off-by: Russell King (Oracle) # # 4d12437d3775febf3d32eb1010c53ceed546f459 # drivers/net/ethernet/freescale/fec_main.c | 4 ---- # 1 file changed, 4 deletions(-) # # Author: Russell King (Oracle) (Thu 4 Jan 16:34:25 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:09 GMT 2024) # # net: sxgbe: remove eee_enabled/eee_active in sxgbe_get_eee() # # sxgbe_get_eee() sets edata->eee_active and edata->eee_enabled from its # own copy, and then calls phy_ethtool_get_eee() which in turn will call # genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Therefore, setting these members in sxgbe_get_eee() is redundant. # Remove this, and remove the priv->eee_active member which then becomes # a write-only variable. # # Reviewed-by: Andrew Lunn # Signed-off-by: Russell King (Oracle) # # 999200e1920fd7c20cd11965356d7710e4dddf0d # drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h | 1 - # drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c | 2 -- # drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 1 - # 3 files changed, 4 deletions(-) # # Author: Russell King (Oracle) (Thu 17 Aug 15:10:52 BST 2023) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:08 GMT 2024) # # net: stmmac: remove eee_enabled/eee_active in stmmac_ethtool_op_get_eee() # # stmmac_ethtool_op_get_eee() sets both eee_enabled and eee_active, and # then goes on to call phylink_ethtool_get_eee(). # # phylink_ethtool_get_eee() will return -EOPNOTSUPP if there is no PHY # present, otherwise calling phy_ethtool_get_eee() which in turn will call # genphy_c45_ethtool_get_eee(). # # genphy_c45_ethtool_get_eee() will overwrite eee_enabled and eee_active # with its own interpretation from the PHYs settings and negotiation # result. # # Thus, when there is no PHY, stmmac_ethtool_op_get_eee() will fail with # -EOPNOTSUPP, meaning eee_enabled and eee_active will not be returned to # userspace. When there is a PHY, eee_enabled and eee_active will be # overwritten by phylib, making the setting of these members in # stmmac_ethtool_op_get_eee() entirely unnecessary. # # Remove this code, thus simplifying stmmac_ethtool_op_get_eee(). # # Reviewed-by: Andrew Lunn # Reviewed-by: Florian Fainelli # Signed-off-by: Russell King (Oracle) # # c9de8c6fa9f5e36272ac7df8d1eef519f6909e61 # drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 -- # 1 file changed, 2 deletions(-) # # Author: Russell King (Oracle) (Fri 2 Feb 17:04:44 GMT 2024) # Committer: Russell King (Oracle) (Tue 26 Mar 11:59:07 GMT 2024) # # net: phy: constify phydev->drv # # Device driver structures are shared between all devices that they # match, and thus nothing should never write to the device driver # structure through the phydev->drv pointer. Let's make this pointer # const to catch code that attempts to do so. # # Suggested-by: Christian Marangi # Signed-off-by: Russell King (Oracle) # # a9f1e576d0c081dbc55fb412a3f7d432c832b682 # drivers/net/phy/phy.c | 3 +-- # drivers/net/phy/phy_device.c | 6 +++--- # drivers/net/phy/xilinx_gmii2rgmii.c | 2 +- # include/linux/phy.h | 2 +- # 4 files changed, 6 insertions(+), 7 deletions(-) # diff --git a/Documentation/devicetree/bindings/net/marvell,10g.yaml b/Documentation/devicetree/bindings/net/marvell,10g.yaml new file mode 100644 index 000000000000..9ec85333f4a4 --- /dev/null +++ b/Documentation/devicetree/bindings/net/marvell,10g.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/marvell,10g.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Alaska X family Ethernet PHYs + +maintainers: + - Russell King + +allOf: + - $ref: ethernet-phy.yaml# + +properties: + marvell,led-mode: + description: + An array of one to four 16-bit integers to write to the PHY LED + configuration registers. + $ref: /schemas/types.yaml#/definitions/uint16-array + minItems: 1 + maxItems: 4 + +additionalProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + ethernet-phy@0 { + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c45"; + marvell,led-mode = /bits/ 16 <0x0129 0x095d 0x0855>; + }; + }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts index 1766cf58101b..68c27f22ff57 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts @@ -21,12 +21,14 @@ phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; sfp = <&sfp_eth0>; + marvell,led-mode = /bits/ 16 <0x0129 0x095d 0x0855>; }; phy8: ethernet-phy@8 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <8>; sfp = <&sfp_eth1>; + marvell,led-mode = /bits/ 16 <0x0129 0x095d 0x0855>; }; }; diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0d628b35fd5c..f0bd9efc24dc 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1420,10 +1420,10 @@ void b53_phylink_mac_link_down(struct dsa_switch *ds, int port, { struct b53_device *dev = ds->priv; - if (mode == MLO_AN_PHY) + if (phylink_mode_phy(mode)) return; - if (mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(mode)) { b53_force_link(dev, port, false); return; } @@ -1446,10 +1446,10 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port, if (is63xx(dev) && port >= B53_63XX_RGMII0) b53_adjust_63xx_rgmii(ds, port, interface); - if (mode == MLO_AN_PHY) + if (phylink_mode_phy(mode)) return; - if (mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(mode)) { b53_force_port_config(dev, port, speed, duplex, tx_pause, rx_pause); b53_force_link(dev, port, true); @@ -2227,16 +2227,10 @@ EXPORT_SYMBOL(b53_eee_init); int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; - u16 reg; if (is5325(dev) || is5365(dev)) return -EOPNOTSUPP; - b53_read16(dev, B53_EEE_PAGE, B53_EEE_LPI_INDICATE, ®); - e->eee_enabled = p->eee_enabled; - e->eee_active = !!(reg & BIT(port)); - return 0; } EXPORT_SYMBOL(b53_get_mac_eee); diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 4a52ccbe393f..0736b894c926 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -740,16 +740,19 @@ static void bcm_sf2_sw_get_caps(struct dsa_switch *ds, int port, MAC_10 | MAC_100 | MAC_1000; } -static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, +static void bcm_sf2_sw_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); + struct dsa_port *dp = dsa_phylink_to_port(config); u32 id_mode_dis = 0, port_mode; + struct bcm_sf2_priv *priv; u32 reg_rgmii_ctrl; u32 reg; - if (port == core_readl(priv, CORE_IMP0_PRT_ID)) + priv = bcm_sf2_to_priv(dp->ds); + + if (dp->index == core_readl(priv, CORE_IMP0_PRT_ID)) return; switch (state->interface) { @@ -770,7 +773,7 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, return; } - reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port); + reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, dp->index); /* Clear id_mode_dis bit, and the existing port mode, let * RGMII_MODE_EN bet set by mac_link_{up,down} @@ -809,13 +812,16 @@ static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port, reg_writel(priv, reg, reg_rgmii_ctrl); } -static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port, +static void bcm_sf2_sw_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); + struct dsa_port *dp = dsa_phylink_to_port(config); + struct bcm_sf2_priv *priv; + int port = dp->index; u32 reg, offset; + priv = bcm_sf2_to_priv(dp->ds); if (priv->wol_ports_mask & BIT(port)) return; @@ -824,23 +830,26 @@ static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port, reg &= ~LINK_STS; core_writel(priv, reg, offset); - bcm_sf2_sw_mac_link_set(ds, port, interface, false); + bcm_sf2_sw_mac_link_set(dp->ds, port, interface, false); } -static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, +static void bcm_sf2_sw_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - struct ethtool_eee *p = &priv->dev->ports[port].eee; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct bcm_sf2_priv *priv; u32 reg_rgmii_ctrl = 0; + struct ethtool_eee *p; + int port = dp->index; u32 reg, offset; - bcm_sf2_sw_mac_link_set(ds, port, interface, true); + bcm_sf2_sw_mac_link_set(dp->ds, port, interface, true); + priv = bcm_sf2_to_priv(dp->ds); offset = bcm_sf2_port_override_offset(priv, port); if (phy_interface_mode_is_rgmii(interface) || @@ -886,8 +895,10 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, core_writel(priv, reg, offset); - if (mode == MLO_AN_PHY && phydev) - p->eee_enabled = b53_eee_init(ds, port, phydev); + if (phylink_mode_phy(mode) && phydev) { + p = &priv->dev->ports[port].eee; + p->eee_enabled = b53_eee_init(dp->ds, port, phydev); + } } static void bcm_sf2_sw_fixed_state(struct dsa_switch *ds, int port, @@ -1196,6 +1207,12 @@ static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds, int port, return cnt; } +static const struct phylink_mac_ops bcm_sf2_phylink_mac_ops = { + .mac_config = bcm_sf2_sw_mac_config, + .mac_link_down = bcm_sf2_sw_mac_link_down, + .mac_link_up = bcm_sf2_sw_mac_link_up, +}; + static const struct dsa_switch_ops bcm_sf2_ops = { .get_tag_protocol = b53_get_tag_protocol, .setup = bcm_sf2_sw_setup, @@ -1206,9 +1223,6 @@ static const struct dsa_switch_ops bcm_sf2_ops = { .get_ethtool_phy_stats = b53_get_ethtool_phy_stats, .get_phy_flags = bcm_sf2_sw_get_phy_flags, .phylink_get_caps = bcm_sf2_sw_get_caps, - .phylink_mac_config = bcm_sf2_sw_mac_config, - .phylink_mac_link_down = bcm_sf2_sw_mac_link_down, - .phylink_mac_link_up = bcm_sf2_sw_mac_link_up, .phylink_fixed_state = bcm_sf2_sw_fixed_state, .suspend = bcm_sf2_sw_suspend, .resume = bcm_sf2_sw_resume, @@ -1399,6 +1413,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) priv->dev = dev; ds = dev->ds; ds->ops = &bcm_sf2_ops; + ds->phylink_mac_ops = &bcm_sf2_phylink_mac_ops; /* Advertise the 8 egress queues */ ds->num_tx_queues = SF2_NUM_EGRESS_QUEUES; diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index fcb20eac332a..666b4d766c00 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1293,14 +1293,29 @@ static void lan9303_phylink_get_caps(struct dsa_switch *ds, int port, } } -static void lan9303_phylink_mac_link_up(struct dsa_switch *ds, int port, +static void lan9303_phylink_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void lan9303_phylink_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ +} + +static void lan9303_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, - int duplex, bool tx_pause, + int speed, int duplex, bool tx_pause, bool rx_pause) { - struct lan9303 *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct lan9303 *chip = dp->ds->priv; + struct dsa_switch *ds = dp->ds; + int port = dp->index; u32 ctl; u32 reg; @@ -1330,6 +1345,12 @@ static void lan9303_phylink_mac_link_up(struct dsa_switch *ds, int port, regmap_write(chip->regmap, flow_ctl_reg[port], reg); } +static const struct phylink_mac_ops lan9303_phylink_mac_ops = { + .mac_config = lan9303_phylink_mac_config, + .mac_link_down = lan9303_phylink_mac_link_down, + .mac_link_up = lan9303_phylink_mac_link_up, +}; + static const struct dsa_switch_ops lan9303_switch_ops = { .get_tag_protocol = lan9303_get_tag_protocol, .setup = lan9303_setup, @@ -1337,7 +1358,6 @@ static const struct dsa_switch_ops lan9303_switch_ops = { .phy_read = lan9303_phy_read, .phy_write = lan9303_phy_write, .phylink_get_caps = lan9303_phylink_get_caps, - .phylink_mac_link_up = lan9303_phylink_mac_link_up, .get_ethtool_stats = lan9303_get_ethtool_stats, .get_sset_count = lan9303_get_sset_count, .port_enable = lan9303_port_enable, @@ -1365,6 +1385,7 @@ static int lan9303_register_switch(struct lan9303 *chip) chip->ds->num_ports = LAN9303_NUM_PORTS; chip->ds->priv = chip; chip->ds->ops = &lan9303_switch_ops; + chip->ds->phylink_mac_ops = &lan9303_phylink_mac_ops; base = chip->phy_addr_base; chip->ds->phys_mii_mask = GENMASK(LAN9303_NUM_PORTS - 1 + base, base); diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index de48b194048f..a557049e34f5 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1670,11 +1670,13 @@ static void gswip_port_set_pause(struct gswip_priv *priv, int port, mdio_phy, GSWIP_MDIO_PHYp(port)); } -static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, +static void gswip_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct gswip_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct gswip_priv *priv = dp->ds->priv; + int port = dp->index; u32 miicfg = 0; miicfg |= GSWIP_MII_CFG_LDCLKDIS; @@ -1700,7 +1702,7 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, miicfg |= GSWIP_MII_CFG_MODE_GMII; break; default: - dev_err(ds->dev, + dev_err(dp->ds->dev, "Unsupported interface: %d\n", state->interface); return; } @@ -1726,28 +1728,32 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, } } -static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port, +static void gswip_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct gswip_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct gswip_priv *priv = dp->ds->priv; + int port = dp->index; gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port); - if (!dsa_is_cpu_port(ds, port)) + if (!dsa_port_is_cpu(dp)) gswip_port_set_link(priv, port, false); } -static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port, +static void gswip_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct gswip_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct gswip_priv *priv = dp->ds->priv; + int port = dp->index; - if (!dsa_is_cpu_port(ds, port)) { + if (!dsa_port_is_cpu(dp)) { gswip_port_set_link(priv, port, true); gswip_port_set_speed(priv, port, speed, interface); gswip_port_set_duplex(priv, port, duplex); @@ -1824,6 +1830,12 @@ static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset) return ARRAY_SIZE(gswip_rmon_cnt); } +static const struct phylink_mac_ops gswip_phylink_mac_ops = { + .mac_config = gswip_phylink_mac_config, + .mac_link_down = gswip_phylink_mac_link_down, + .mac_link_up = gswip_phylink_mac_link_up, +}; + static const struct dsa_switch_ops gswip_xrx200_switch_ops = { .get_tag_protocol = gswip_get_tag_protocol, .setup = gswip_setup, @@ -1842,9 +1854,6 @@ static const struct dsa_switch_ops gswip_xrx200_switch_ops = { .port_change_mtu = gswip_port_change_mtu, .port_max_mtu = gswip_port_max_mtu, .phylink_get_caps = gswip_xrx200_phylink_get_caps, - .phylink_mac_config = gswip_phylink_mac_config, - .phylink_mac_link_down = gswip_phylink_mac_link_down, - .phylink_mac_link_up = gswip_phylink_mac_link_up, .get_strings = gswip_get_strings, .get_ethtool_stats = gswip_get_ethtool_stats, .get_sset_count = gswip_get_sset_count, @@ -1868,9 +1877,6 @@ static const struct dsa_switch_ops gswip_xrx300_switch_ops = { .port_change_mtu = gswip_port_change_mtu, .port_max_mtu = gswip_port_max_mtu, .phylink_get_caps = gswip_xrx300_phylink_get_caps, - .phylink_mac_config = gswip_phylink_mac_config, - .phylink_mac_link_down = gswip_phylink_mac_link_down, - .phylink_mac_link_up = gswip_phylink_mac_link_up, .get_strings = gswip_get_strings, .get_ethtool_stats = gswip_get_ethtool_stats, .get_sset_count = gswip_get_sset_count, @@ -2136,6 +2142,7 @@ static int gswip_probe(struct platform_device *pdev) priv->ds->num_ports = priv->hw_info->max_ports; priv->ds->priv = priv; priv->ds->ops = priv->hw_info->ops; + priv->ds->phylink_mac_ops = &gswip_phylink_mac_ops; priv->dev = dev; mutex_init(&priv->pce_table_lock); version = gswip_switch_r(priv, GSWIP_VERSION); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 3c1f657593a8..6985e1bf94f3 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1080,7 +1080,8 @@ mt7530_port_enable(struct dsa_switch *ds, int port, priv->ports[port].enable = true; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, priv->ports[port].pm); - mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); + mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK | + PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100); mutex_unlock(&priv->reg_mutex); @@ -2860,20 +2861,45 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, mcr |= PMCR_RX_FC_EN; } - if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) { - switch (speed) { - case SPEED_1000: - mcr |= PMCR_FORCE_EEE1G; - break; - case SPEED_100: - mcr |= PMCR_FORCE_EEE100; - break; - } - } - mt7530_set(priv, MT7530_PMCR_P(port), mcr); } +static void mt753x_phylink_mac_disable_tx_lpi(struct dsa_switch *ds, int port) +{ + struct mt7530_priv *priv = ds->priv; + + mt7530_clear(priv, MT7530_PMCR_P(port), + PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100); +} + +static void mt753x_phylink_mac_enable_tx_lpi(struct dsa_switch *ds, int port, + u32 timer) +{ + struct mt7530_priv *priv = ds->priv; + u32 val; + + /* If the timer is zero, then set LPI_MODE_EN, which allows the + * system to enter LPI mode immediately rather than waiting for + * the LPI threshold. + */ + if (!timer) + val = LPI_MODE_EN; + else if (FIELD_FIT(LPI_THRESH_MASK, timer)) + val = FIELD_PREP(LPI_THRESH_MASK, timer); + else + val = LPI_THRESH_MASK; + + mt7530_rmw(priv, MT7530_PMEEECR_P(port), + LPI_THRESH_MASK | LPI_MODE_EN, val); + + /* FIXME: mt7531 docs say that bits 26 and 25 need to be set to + * enable EEE forcing. The PMCR_FORCE_EEE* bits just determine + * whether we force-enable or force-disable these modes. + */ + mt7530_set(priv, MT7530_PMCR_P(port), + PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100); +} + static int mt7531_cpu_port_config(struct dsa_switch *ds, int port) { @@ -2935,15 +2961,26 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { struct mt7530_priv *priv = ds->priv; + u32 eeecr; /* This switch only supports full-duplex at 1Gbps */ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + config->lpi_capabilities = MAC_100FD | MAC_1000FD; + config->lpi_timer_limit_us = FIELD_GET(LPI_THRESH_MASK, + LPI_THRESH_MASK); + + eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); + /* tx_lpi_timer should be in microseconds. The time units for + * LPI threshold are unspecified. + */ + config->eee.tx_lpi_timer = FIELD_GET(LPI_THRESH_MASK, eeecr); + priv->info->mac_port_get_caps(ds, port, config); } -static int mt753x_pcs_validate(struct phylink_pcs *pcs, +static int mt753x_pcs_validate(struct phylink_pcs *pcs, unsigned int mode, unsigned long *supported, const struct phylink_link_state *state) { @@ -3044,36 +3081,6 @@ mt753x_setup(struct dsa_switch *ds) return ret; } -static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) -{ - struct mt7530_priv *priv = ds->priv; - u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); - - e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN); - e->tx_lpi_timer = GET_LPI_THRESH(eeecr); - - return 0; -} - -static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) -{ - struct mt7530_priv *priv = ds->priv; - u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN; - - if (e->tx_lpi_timer > 0xFFF) - return -EINVAL; - - set = SET_LPI_THRESH(e->tx_lpi_timer); - if (!e->tx_lpi_enabled) - /* Force LPI Mode without a delay */ - set |= LPI_MODE_EN; - mt7530_rmw(priv, MT7530_PMEEECR_P(port), mask, set); - - return 0; -} - static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { return 0; @@ -3127,8 +3134,8 @@ const struct dsa_switch_ops mt7530_switch_ops = { .phylink_mac_config = mt753x_phylink_mac_config, .phylink_mac_link_down = mt753x_phylink_mac_link_down, .phylink_mac_link_up = mt753x_phylink_mac_link_up, - .get_mac_eee = mt753x_get_mac_eee, - .set_mac_eee = mt753x_set_mac_eee, + .phylink_mac_disable_tx_lpi = mt753x_phylink_mac_disable_tx_lpi, + .phylink_mac_enable_tx_lpi = mt753x_phylink_mac_enable_tx_lpi, }; EXPORT_SYMBOL_GPL(mt7530_switch_ops); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 17e42d30fff4..cdab7ea79294 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -309,8 +309,7 @@ enum mt7530_vlan_port_acc_frm { #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \ PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \ PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ - PMCR_FORCE_FDX | PMCR_FORCE_LNK | \ - PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100) + PMCR_FORCE_FDX | PMCR_FORCE_LNK) #define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \ PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ @@ -323,9 +322,6 @@ enum mt7530_vlan_port_acc_frm { #define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24) #define WAKEUP_TIME_100(x) (((x) & 0xFF) << 16) #define LPI_THRESH_MASK GENMASK(15, 4) -#define LPI_THRESH_SHT 4 -#define SET_LPI_THRESH(x) (((x) << LPI_THRESH_SHT) & LPI_THRESH_MASK) -#define GET_LPI_THRESH(x) (((x) & LPI_THRESH_MASK) >> LPI_THRESH_SHT) #define LPI_MODE_EN BIT(0) #define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 614cabb5c1b0..fa60a7b19d12 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -630,6 +630,9 @@ static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; + config->lpi_capabilities = MAC_1000FD | MAC_100FD; + config->eee.eee_enabled = true; + config->eee.tx_lpi_enabled = true; /* Port 4 supports automedia if the serdes is associated with it. */ if (port == 4) { @@ -790,31 +793,34 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, } } -static struct phylink_pcs *mv88e6xxx_mac_select_pcs(struct dsa_switch *ds, - int port, - phy_interface_t interface) +static struct phylink_pcs * +mv88e6xxx_mac_select_pcs(struct phylink_config *config, + phy_interface_t interface) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); if (chip->info->ops->pcs_ops) - pcs = chip->info->ops->pcs_ops->pcs_select(chip, port, + pcs = chip->info->ops->pcs_ops->pcs_select(chip, dp->index, interface); return pcs; } -static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port, +static int mv88e6xxx_mac_prepare(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; + int port = dp->index; int err = 0; /* In inband mode, the link may come up at any time while the link * is not forced down. Force the link down while we reconfigure the * interface mode. */ - if (mode == MLO_AN_INBAND && + if (phylink_mode_inband(mode) && chip->ports[port].interface != interface && chip->info->ops->port_set_link) { mv88e6xxx_reg_lock(chip); @@ -826,16 +832,18 @@ static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port, return err; } -static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, +static void mv88e6xxx_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; + int port = dp->index; int err = 0; mv88e6xxx_reg_lock(chip); - if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(chip, port)) { + if (!phylink_mode_phy(mode) || !mv88e6xxx_phy_is_internal(chip, port)) { err = mv88e6xxx_port_config_interface(chip, port, state->interface); if (err && err != -EOPNOTSUPP) @@ -846,13 +854,15 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, mv88e6xxx_reg_unlock(chip); if (err && err != -EOPNOTSUPP) - dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); + dev_err(chip->dev, "p%d: failed to configure MAC/PCS\n", port); } -static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port, +static int mv88e6xxx_mac_finish(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; + int port = dp->index; int err = 0; /* Undo the forced down state above after completing configuration @@ -864,9 +874,10 @@ static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port, mv88e6xxx_reg_lock(chip); if (chip->info->ops->port_set_link && - ((mode == MLO_AN_INBAND && + ((phylink_mode_inband(mode) && chip->ports[port].interface != interface) || - (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port)))) + (phylink_mode_phy(mode) && + mv88e6xxx_port_ppu_updates(chip, port)))) err = chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); mv88e6xxx_reg_unlock(chip); @@ -876,12 +887,14 @@ static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port, return err; } -static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, +static void mv88e6xxx_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; const struct mv88e6xxx_ops *ops; + int port = dp->index; int err = 0; ops = chip->info->ops; @@ -891,7 +904,7 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, * updated by the switch or if we are using fixed-link mode. */ if ((!mv88e6xxx_port_ppu_updates(chip, port) || - mode == MLO_AN_FIXED) && ops->port_sync_link) + phylink_mode_fixed(mode)) && ops->port_sync_link) err = ops->port_sync_link(chip, port, mode, false); if (!err && ops->port_set_speed_duplex) @@ -904,14 +917,16 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, "p%d: failed to force MAC link down\n", port); } -static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, - unsigned int mode, phy_interface_t interface, +static void mv88e6xxx_mac_link_up(struct phylink_config *config, struct phy_device *phydev, + unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct mv88e6xxx_chip *chip = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; const struct mv88e6xxx_ops *ops; + int port = dp->index; int err = 0; ops = chip->info->ops; @@ -922,7 +937,7 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, * mode. */ if (!mv88e6xxx_port_ppu_updates(chip, port) || - mode == MLO_AN_FIXED) { + phylink_mode_fixed(mode)) { if (ops->port_set_speed_duplex) { err = ops->port_set_speed_duplex(chip, port, speed, duplex); @@ -937,10 +952,53 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, mv88e6xxx_reg_unlock(chip); if (err && err != -EOPNOTSUPP) - dev_err(ds->dev, + dev_err(chip->dev, "p%d: failed to configure MAC link up\n", port); } +static void mv88e6xxx_mac_disable_tx_lpi(struct phylink_config *config) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; + int port = dp->index; + int err; + + if (!chip->info->ops->port_set_eee) + return; + + mv88e6xxx_reg_lock(chip); + err = chip->info->ops->port_set_eee(chip, port, EEE_FORCE_DISABLE); + mv88e6xxx_reg_unlock(chip); + + if (err) + dev_err(chip->dev, "p%d: failed to set EEE mode: %pe\n", port, + ERR_PTR(err)); +} + +static void mv88e6xxx_mac_enable_tx_lpi(struct phylink_config *config, + u32 timer) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct mv88e6xxx_chip *chip = dp->ds->priv; + int port = dp->index; + int eee, err; + + if (!chip->info->ops->port_set_eee) + return; + + mv88e6xxx_reg_lock(chip); + if (mv88e6xxx_port_ppu_updates(chip, port)) + eee = EEE_UNFORCED; + else + eee = EEE_FORCE_DISABLE; + err = chip->info->ops->port_set_eee(chip, port, eee); + mv88e6xxx_reg_unlock(chip); + + if (err) + dev_err(chip->dev, "p%d: failed to set EEE mode: %pe\n", port, + ERR_PTR(err)); +} + static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) { int err; @@ -4484,6 +4542,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, .port_set_link = mv88e6xxx_port_set_link, + .port_set_eee = mv88e6xxx_port_set_eee, .port_sync_link = mv88e6xxx_port_sync_link, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, @@ -4584,6 +4643,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, .port_set_link = mv88e6xxx_port_set_link, + .port_set_eee = mv88e6xxx_port_set_eee, .port_sync_link = mv88e6xxx_port_sync_link, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, @@ -4851,6 +4911,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, .port_set_link = mv88e6xxx_port_set_link, + .port_set_eee = mv88e6xxx_port_set_eee, .port_sync_link = mv88e6xxx_port_sync_link, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, @@ -5261,6 +5322,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, .port_set_link = mv88e6xxx_port_set_link, + .port_set_eee = mv88e6xxx_port_set_eee, .port_sync_link = mv88e6xxx_port_sync_link, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, @@ -5444,6 +5506,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { .phy_read_c45 = mv88e6xxx_g2_smi_phy_read_c45, .phy_write_c45 = mv88e6xxx_g2_smi_phy_write_c45, .port_set_link = mv88e6xxx_port_set_link, + /* no port_set_eee due to mv88e6393x errata 4.5 */ .port_sync_link = mv88e6xxx_port_sync_link, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex, @@ -6915,6 +6978,17 @@ static int mv88e6xxx_crosschip_lag_leave(struct dsa_switch *ds, int sw_index, return err_sync ? : err_pvt; } +static const struct phylink_mac_ops mv88e6xxx_phylink_mac_ops = { + .mac_select_pcs = mv88e6xxx_mac_select_pcs, + .mac_prepare = mv88e6xxx_mac_prepare, + .mac_config = mv88e6xxx_mac_config, + .mac_finish = mv88e6xxx_mac_finish, + .mac_link_down = mv88e6xxx_mac_link_down, + .mac_link_up = mv88e6xxx_mac_link_up, + .mac_disable_tx_lpi = mv88e6xxx_mac_disable_tx_lpi, + .mac_enable_tx_lpi = mv88e6xxx_mac_enable_tx_lpi, +}; + static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_tag_protocol = mv88e6xxx_get_tag_protocol, .change_tag_protocol = mv88e6xxx_change_tag_protocol, @@ -6923,12 +6997,6 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .port_setup = mv88e6xxx_port_setup, .port_teardown = mv88e6xxx_port_teardown, .phylink_get_caps = mv88e6xxx_get_caps, - .phylink_mac_select_pcs = mv88e6xxx_mac_select_pcs, - .phylink_mac_prepare = mv88e6xxx_mac_prepare, - .phylink_mac_config = mv88e6xxx_mac_config, - .phylink_mac_finish = mv88e6xxx_mac_finish, - .phylink_mac_link_down = mv88e6xxx_mac_link_down, - .phylink_mac_link_up = mv88e6xxx_mac_link_up, .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats, @@ -6997,6 +7065,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) ds->priv = chip; ds->dev = dev; ds->ops = &mv88e6xxx_switch_ops; + ds->phylink_mac_ops = &mv88e6xxx_phylink_mac_ops; ds->ageing_time_min = chip->info->age_time_coeff; ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 85eb293381a7..549592a9764d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -506,6 +506,16 @@ struct mv88e6xxx_ops { */ int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); +#define EEE_FORCE_DISABLE 0 +#define EEE_FORCE_ENABLE 1 +#define EEE_UNFORCED -1 + + /* Port's EEE state + * Use EEE_FORCE_ENABLE or EEE_FORCE_DISABLE to force EEE to be enabled + * or disabled, or EEE_UNFORCED for normal EEE. + */ + int (*port_set_eee)(struct mv88e6xxx_chip *chip, int port, int eee); + /* Synchronise the port link state with that of the SERDES */ int (*port_sync_link)(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup); diff --git a/drivers/net/dsa/mv88e6xxx/pcs-6185.c b/drivers/net/dsa/mv88e6xxx/pcs-6185.c index 4d677f836807..5a27d047a38e 100644 --- a/drivers/net/dsa/mv88e6xxx/pcs-6185.c +++ b/drivers/net/dsa/mv88e6xxx/pcs-6185.c @@ -95,7 +95,7 @@ static void mv88e6185_pcs_get_state(struct phylink_pcs *pcs, } } -static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -137,6 +137,7 @@ static int mv88e6185_pcs_init(struct mv88e6xxx_chip *chip, int port) mpcs->chip = chip; mpcs->port = port; mpcs->phylink_pcs.ops = &mv88e6185_phylink_pcs_ops; + mpcs->phylink_pcs.neg_mode = true; irq = mv88e6xxx_serdes_irq_mapping(chip, port); if (irq) { diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 5394a8cf7bf1..ef9bb3974f33 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -203,7 +203,7 @@ int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int int err = 0; int link; - if (mode == MLO_AN_INBAND) + if (phylink_mode_inband(mode)) link = LINK_UNFORCED; else if (isup) link = LINK_FORCED_UP; @@ -520,6 +520,36 @@ phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip, return PHY_INTERFACE_MODE_10GBASER; } +int mv88e6xxx_port_set_eee(struct mv88e6xxx_chip *chip, int port, int eee) +{ + u16 reg, val = 0; + int err; + + switch (eee) { + case EEE_FORCE_ENABLE: + val = MV88E6XXX_PORT_MAC_CTL_EEE; + fallthrough; + case EEE_FORCE_DISABLE: + val |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE; + break; + default: + break; + } + + dev_dbg(chip->dev, "p%d: %s eee %sable\n", port, + val & MV88E6XXX_PORT_MAC_CTL_FORCE_EEE ? "Force" : "Unforce", + val & MV88E6XXX_PORT_MAC_CTL_EEE ? "en" : "dis"); + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); + if (err < 0) + return err; + + reg &= ~(MV88E6XXX_PORT_MAC_CTL_EEE | MV88E6XXX_PORT_MAC_CTL_FORCE_EEE); + reg |= val; + + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); +} + static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode, bool force) { @@ -629,7 +659,6 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode) { int err; - u16 reg; if (port != 0 && port != 9 && port != 10) return -EOPNOTSUPP; @@ -648,13 +677,7 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, } /* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */ - err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); - if (err) - return err; - - reg &= ~MV88E6XXX_PORT_MAC_CTL_EEE; - reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE; - err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); + err = mv88e6xxx_port_set_eee(chip, port, EEE_FORCE_DISABLE); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 86deeb347cbc..1410677c415a 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -432,6 +432,7 @@ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, u8 out); int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, u8 out); +int mv88e6xxx_port_set_eee(struct mv88e6xxx_chip *chip, int port, int eee); int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 61e95487732d..3aa66bf9eafc 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1050,24 +1050,32 @@ static void felix_phylink_get_caps(struct dsa_switch *ds, int port, config->supported_interfaces); } -static void felix_phylink_mac_config(struct dsa_switch *ds, int port, +static void felix_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ocelot *ocelot = dp->ds->priv; + int port = dp->index; + struct felix *felix; + + felix = ocelot_to_felix(ocelot); if (felix->info->phylink_mac_config) felix->info->phylink_mac_config(ocelot, port, mode, state); } -static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, - int port, - phy_interface_t iface) +static struct phylink_pcs * +felix_phylink_mac_select_pcs(struct phylink_config *config, + phy_interface_t iface) { - struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ocelot *ocelot = dp->ds->priv; struct phylink_pcs *pcs = NULL; + int port = dp->index; + struct felix *felix; + + felix = ocelot_to_felix(ocelot); if (felix->pcs && felix->pcs[port]) pcs = felix->pcs[port]; @@ -1075,11 +1083,13 @@ static struct phylink_pcs *felix_phylink_mac_select_pcs(struct dsa_switch *ds, return pcs; } -static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, +static void felix_phylink_mac_link_down(struct phylink_config *config, unsigned int link_an_mode, phy_interface_t interface) { - struct ocelot *ocelot = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ocelot *ocelot = dp->ds->priv; + int port = dp->index; struct felix *felix; felix = ocelot_to_felix(ocelot); @@ -1088,15 +1098,19 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, felix->info->quirks); } -static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, +static void felix_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int link_an_mode, phy_interface_t interface, - struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ocelot *ocelot = dp->ds->priv; + int port = dp->index; + struct felix *felix; + + felix = ocelot_to_felix(ocelot); ocelot_phylink_mac_link_up(ocelot, port, phydev, link_an_mode, interface, speed, duplex, tx_pause, rx_pause, @@ -2083,6 +2097,14 @@ static void felix_get_mm_stats(struct dsa_switch *ds, int port, ocelot_port_get_mm_stats(ocelot, port, stats); } +const struct phylink_mac_ops felix_phylink_mac_ops = { + .mac_select_pcs = felix_phylink_mac_select_pcs, + .mac_config = felix_phylink_mac_config, + .mac_link_down = felix_phylink_mac_link_down, + .mac_link_up = felix_phylink_mac_link_up, +}; +EXPORT_SYMBOL_GPL(felix_phylink_mac_ops); + const struct dsa_switch_ops felix_switch_ops = { .get_tag_protocol = felix_get_tag_protocol, .change_tag_protocol = felix_change_tag_protocol, @@ -2104,10 +2126,6 @@ const struct dsa_switch_ops felix_switch_ops = { .get_sset_count = felix_get_sset_count, .get_ts_info = felix_get_ts_info, .phylink_get_caps = felix_phylink_get_caps, - .phylink_mac_config = felix_phylink_mac_config, - .phylink_mac_select_pcs = felix_phylink_mac_select_pcs, - .phylink_mac_link_down = felix_phylink_mac_link_down, - .phylink_mac_link_up = felix_phylink_mac_link_up, .port_enable = felix_port_enable, .port_fast_age = felix_port_fast_age, .port_fdb_dump = felix_fdb_dump, diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index dbf5872fe367..4d3489aaa659 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -82,6 +82,7 @@ struct felix_tag_proto_ops { struct netlink_ext_ack *extack); }; +extern const struct phylink_mac_ops felix_phylink_mac_ops; extern const struct dsa_switch_ops felix_switch_ops; /* DSA glue / front-end for struct ocelot */ diff --git a/drivers/net/dsa/ocelot/ocelot_ext.c b/drivers/net/dsa/ocelot/ocelot_ext.c index 22187d831c4b..a8927dc7aca4 100644 --- a/drivers/net/dsa/ocelot/ocelot_ext.c +++ b/drivers/net/dsa/ocelot/ocelot_ext.c @@ -96,6 +96,7 @@ static int ocelot_ext_probe(struct platform_device *pdev) ds->num_tx_queues = felix->info->num_tx_queues; ds->ops = &felix_switch_ops; + ds->phylink_mac_ops = &felix_phylink_mac_ops; ds->priv = ocelot; felix->ds = ds; felix->tag_proto = DSA_TAG_PROTO_OCELOT; diff --git a/drivers/net/dsa/qca/ar9331.c b/drivers/net/dsa/qca/ar9331.c index 8d9d271ac3af..968cb81088bf 100644 --- a/drivers/net/dsa/qca/ar9331.c +++ b/drivers/net/dsa/qca/ar9331.c @@ -523,28 +523,30 @@ static void ar9331_sw_phylink_get_caps(struct dsa_switch *ds, int port, } } -static void ar9331_sw_phylink_mac_config(struct dsa_switch *ds, int port, +static void ar9331_sw_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct ar9331_sw_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ar9331_sw_priv *priv = dp->ds->priv; struct regmap *regmap = priv->regmap; int ret; - ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port), + ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(dp->index), AR9331_SW_PORT_STATUS_LINK_EN | AR9331_SW_PORT_STATUS_FLOW_LINK_EN, 0); if (ret) dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); } -static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, +static void ar9331_sw_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct ar9331_sw_priv *priv = ds->priv; - struct ar9331_sw_port *p = &priv->port[port]; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ar9331_sw_priv *priv = dp->ds->priv; struct regmap *regmap = priv->regmap; + int port = dp->index; int ret; ret = regmap_update_bits(regmap, AR9331_SW_REG_PORT_STATUS(port), @@ -552,23 +554,24 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, if (ret) dev_err_ratelimited(priv->dev, "%s: %i\n", __func__, ret); - cancel_delayed_work_sync(&p->mib_read); + cancel_delayed_work_sync(&priv->port[port].mib_read); } -static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, +static void ar9331_sw_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct ar9331_sw_priv *priv = ds->priv; - struct ar9331_sw_port *p = &priv->port[port]; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ar9331_sw_priv *priv = dp->ds->priv; struct regmap *regmap = priv->regmap; + int port = dp->index; u32 val; int ret; - schedule_delayed_work(&p->mib_read, 0); + schedule_delayed_work(&priv->port[port].mib_read, 0); val = AR9331_SW_PORT_STATUS_MAC_MASK; switch (speed) { @@ -684,14 +687,17 @@ static void ar9331_get_pause_stats(struct dsa_switch *ds, int port, spin_unlock(&p->stats_lock); } +static const struct phylink_mac_ops ar9331_phylink_mac_ops = { + .mac_config = ar9331_sw_phylink_mac_config, + .mac_link_down = ar9331_sw_phylink_mac_link_down, + .mac_link_up = ar9331_sw_phylink_mac_link_up, +}; + static const struct dsa_switch_ops ar9331_sw_ops = { .get_tag_protocol = ar9331_sw_get_tag_protocol, .setup = ar9331_sw_setup, .port_disable = ar9331_sw_port_disable, .phylink_get_caps = ar9331_sw_phylink_get_caps, - .phylink_mac_config = ar9331_sw_phylink_mac_config, - .phylink_mac_link_down = ar9331_sw_phylink_mac_link_down, - .phylink_mac_link_up = ar9331_sw_phylink_mac_link_up, .get_stats64 = ar9331_get_stats64, .get_pause_stats = ar9331_get_pause_stats, }; @@ -1059,6 +1065,7 @@ static int ar9331_sw_probe(struct mdio_device *mdiodev) ds->priv = priv; priv->ops = ar9331_sw_ops; ds->ops = &priv->ops; + ds->phylink_mac_ops = &ar9331_phylink_mac_ops; dev_set_drvdata(&mdiodev->dev, priv); for (i = 0; i < ARRAY_SIZE(priv->port); i++) { diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 7a864329cb72..e82b84f6bcd3 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1284,11 +1284,13 @@ qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_inde } static struct phylink_pcs * -qca8k_phylink_mac_select_pcs(struct dsa_switch *ds, int port, +qca8k_phylink_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) { - struct qca8k_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct qca8k_priv *priv = dp->ds->priv; struct phylink_pcs *pcs = NULL; + int port = dp->index; switch (interface) { case PHY_INTERFACE_MODE_SGMII: @@ -1312,13 +1314,18 @@ qca8k_phylink_mac_select_pcs(struct dsa_switch *ds, int port, } static void -qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, +qca8k_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct qca8k_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct dsa_switch *ds = dp->ds; + struct qca8k_priv *priv; + int port = dp->index; int cpu_port_index; u32 reg; + priv = ds->priv; + switch (port) { case 0: /* 1st CPU port */ if (state->interface != PHY_INTERFACE_MODE_RGMII && @@ -1427,20 +1434,24 @@ static void qca8k_phylink_get_caps(struct dsa_switch *ds, int port, } static void -qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, +qca8k_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct qca8k_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct qca8k_priv *priv = dp->ds->priv; - qca8k_port_set_status(priv, port, 0); + qca8k_port_set_status(priv, dp->index, 0); } static void -qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, - phy_interface_t interface, struct phy_device *phydev, - int speed, int duplex, bool tx_pause, bool rx_pause) +qca8k_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, + phy_interface_t interface, int speed, int duplex, + bool tx_pause, bool rx_pause) { - struct qca8k_priv *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct qca8k_priv *priv = dp->ds->priv; + int port = dp->index; u32 reg; if (phylink_autoneg_inband(mode)) { @@ -1464,10 +1475,10 @@ qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, if (duplex == DUPLEX_FULL) reg |= QCA8K_PORT_STATUS_DUPLEX; - if (rx_pause || dsa_is_cpu_port(ds, port)) + if (rx_pause || dsa_port_is_cpu(dp)) reg |= QCA8K_PORT_STATUS_RXFLOW; - if (tx_pause || dsa_is_cpu_port(ds, port)) + if (tx_pause || dsa_port_is_cpu(dp)) reg |= QCA8K_PORT_STATUS_TXFLOW; } @@ -1992,6 +2003,13 @@ qca8k_setup(struct dsa_switch *ds) return 0; } +static const struct phylink_mac_ops qca8k_phylink_mac_ops = { + .mac_select_pcs = qca8k_phylink_mac_select_pcs, + .mac_config = qca8k_phylink_mac_config, + .mac_link_down = qca8k_phylink_mac_link_down, + .mac_link_up = qca8k_phylink_mac_link_up, +}; + static const struct dsa_switch_ops qca8k_switch_ops = { .get_tag_protocol = qca8k_get_tag_protocol, .setup = qca8k_setup, @@ -2022,10 +2040,6 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .port_vlan_add = qca8k_port_vlan_add, .port_vlan_del = qca8k_port_vlan_del, .phylink_get_caps = qca8k_phylink_get_caps, - .phylink_mac_select_pcs = qca8k_phylink_mac_select_pcs, - .phylink_mac_config = qca8k_phylink_mac_config, - .phylink_mac_link_down = qca8k_phylink_mac_link_down, - .phylink_mac_link_up = qca8k_phylink_mac_link_up, .get_phy_flags = qca8k_get_phy_flags, .port_lag_join = qca8k_port_lag_join, .port_lag_leave = qca8k_port_lag_leave, @@ -2092,6 +2106,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) priv->ds->num_ports = QCA8K_NUM_PORTS; priv->ds->priv = priv; priv->ds->ops = &qca8k_switch_ops; + priv->ds->phylink_mac_ops = &qca8k_phylink_mac_ops; mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c index 10092ea85e46..92e032972b34 100644 --- a/drivers/net/dsa/rzn1_a5psw.c +++ b/drivers/net/dsa/rzn1_a5psw.c @@ -239,23 +239,31 @@ static void a5psw_phylink_get_caps(struct dsa_switch *ds, int port, } static struct phylink_pcs * -a5psw_phylink_mac_select_pcs(struct dsa_switch *ds, int port, +a5psw_phylink_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) { - struct dsa_port *dp = dsa_to_port(ds, port); - struct a5psw *a5psw = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct a5psw *a5psw = dp->ds->priv; - if (!dsa_port_is_cpu(dp) && a5psw->pcs[port]) - return a5psw->pcs[port]; + if (dsa_port_is_cpu(dp)) + return NULL; - return NULL; + return a5psw->pcs[dp->index]; +} + +static void a5psw_phylink_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +{ } -static void a5psw_phylink_mac_link_down(struct dsa_switch *ds, int port, +static void a5psw_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct a5psw *a5psw = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct a5psw *a5psw = dp->ds->priv; + int port = dp->index; u32 cmd_cfg; cmd_cfg = a5psw_reg_readl(a5psw, A5PSW_CMD_CFG(port)); @@ -263,15 +271,17 @@ static void a5psw_phylink_mac_link_down(struct dsa_switch *ds, int port, a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg); } -static void a5psw_phylink_mac_link_up(struct dsa_switch *ds, int port, +static void a5psw_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, - int duplex, bool tx_pause, bool rx_pause) + int speed, int duplex, bool tx_pause, + bool rx_pause) { u32 cmd_cfg = A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA | A5PSW_CMD_CFG_TX_CRC_APPEND; - struct a5psw *a5psw = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct a5psw *a5psw = dp->ds->priv; if (speed == SPEED_1000) cmd_cfg |= A5PSW_CMD_CFG_ETH_SPEED; @@ -284,7 +294,7 @@ static void a5psw_phylink_mac_link_up(struct dsa_switch *ds, int port, if (!rx_pause) cmd_cfg &= ~A5PSW_CMD_CFG_PAUSE_IGNORE; - a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg); + a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(dp->index), cmd_cfg); } static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) @@ -992,15 +1002,19 @@ static int a5psw_setup(struct dsa_switch *ds) return 0; } +static const struct phylink_mac_ops a5psw_phylink_mac_ops = { + .mac_select_pcs = a5psw_phylink_mac_select_pcs, + .mac_config = a5psw_phylink_mac_config, + .mac_link_down = a5psw_phylink_mac_link_down, + .mac_link_up = a5psw_phylink_mac_link_up, +}; + static const struct dsa_switch_ops a5psw_switch_ops = { .get_tag_protocol = a5psw_get_tag_protocol, .setup = a5psw_setup, .port_disable = a5psw_port_disable, .port_enable = a5psw_port_enable, .phylink_get_caps = a5psw_phylink_get_caps, - .phylink_mac_select_pcs = a5psw_phylink_mac_select_pcs, - .phylink_mac_link_down = a5psw_phylink_mac_link_down, - .phylink_mac_link_up = a5psw_phylink_mac_link_up, .port_change_mtu = a5psw_port_change_mtu, .port_max_mtu = a5psw_port_max_mtu, .get_sset_count = a5psw_get_sset_count, @@ -1252,6 +1266,7 @@ static int a5psw_probe(struct platform_device *pdev) ds->dev = dev; ds->num_ports = A5PSW_PORTS_NUM; ds->ops = &a5psw_switch_ops; + ds->phylink_mac_ops = &a5psw_phylink_mac_ops; ds->priv = a5psw; ret = dsa_register_switch(ds); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 6646f7fb0f90..9591dab7e991 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1358,10 +1358,11 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, } static struct phylink_pcs * -sja1105_mac_select_pcs(struct dsa_switch *ds, int port, phy_interface_t iface) +sja1105_mac_select_pcs(struct phylink_config *config, phy_interface_t iface) { - struct sja1105_private *priv = ds->priv; - struct dw_xpcs *xpcs = priv->xpcs[port]; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct sja1105_private *priv = dp->ds->priv; + struct dw_xpcs *xpcs = priv->xpcs[dp->index]; if (xpcs) return &xpcs->pcs; @@ -1369,21 +1370,31 @@ sja1105_mac_select_pcs(struct dsa_switch *ds, int port, phy_interface_t iface) return NULL; } -static void sja1105_mac_link_down(struct dsa_switch *ds, int port, +static void sja1105_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void sja1105_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - sja1105_inhibit_tx(ds->priv, BIT(port), true); + struct dsa_port *dp = dsa_phylink_to_port(config); + + sja1105_inhibit_tx(dp->ds->priv, BIT(dp->index), true); } -static void sja1105_mac_link_up(struct dsa_switch *ds, int port, +static void sja1105_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, phy_interface_t interface, - struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct sja1105_private *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct sja1105_private *priv = dp->ds->priv; + int port = dp->index; sja1105_adjust_port_config(priv, port, speed); @@ -3198,6 +3209,13 @@ static void sja1105_teardown(struct dsa_switch *ds) sja1105_static_config_free(&priv->static_config); } +static const struct phylink_mac_ops sja1105_phylink_mac_ops = { + .mac_select_pcs = sja1105_mac_select_pcs, + .mac_config = sja1105_mac_config, + .mac_link_up = sja1105_mac_link_up, + .mac_link_down = sja1105_mac_link_down, +}; + static const struct dsa_switch_ops sja1105_switch_ops = { .get_tag_protocol = sja1105_get_tag_protocol, .connect_tag_protocol = sja1105_connect_tag_protocol, @@ -3207,9 +3225,6 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_change_mtu = sja1105_change_mtu, .port_max_mtu = sja1105_get_max_mtu, .phylink_get_caps = sja1105_phylink_get_caps, - .phylink_mac_select_pcs = sja1105_mac_select_pcs, - .phylink_mac_link_up = sja1105_mac_link_up, - .phylink_mac_link_down = sja1105_mac_link_down, .get_strings = sja1105_get_strings, .get_ethtool_stats = sja1105_get_ethtool_stats, .get_sset_count = sja1105_get_sset_count, @@ -3375,6 +3390,7 @@ static int sja1105_probe(struct spi_device *spi) ds->dev = dev; ds->num_ports = priv->info->num_ports; ds->ops = &sja1105_switch_ops; + ds->phylink_mac_ops = &sja1105_phylink_mac_ops; ds->priv = priv; priv->ds = ds; diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index 96db032b478f..6605fa44bcf0 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -466,13 +466,25 @@ static void xrs700x_phylink_get_caps(struct dsa_switch *ds, int port, } } -static void xrs700x_mac_link_up(struct dsa_switch *ds, int port, - unsigned int mode, phy_interface_t interface, +static void xrs700x_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void xrs700x_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ +} + +static void xrs700x_mac_link_up(struct phylink_config *config, struct phy_device *phydev, + unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct xrs700x *priv = ds->priv; + struct dsa_port *dp = dsa_phylink_to_port(config); + struct xrs700x *priv = dp->ds->priv; + int port = dp->index; unsigned int val; switch (speed) { @@ -699,13 +711,18 @@ static int xrs700x_hsr_leave(struct dsa_switch *ds, int port, return 0; } +static const struct phylink_mac_ops xrs700x_phylink_mac_ops = { + .mac_config = xrs700x_mac_config, + .mac_link_down = xrs700x_mac_link_down, + .mac_link_up = xrs700x_mac_link_up, +}; + static const struct dsa_switch_ops xrs700x_ops = { .get_tag_protocol = xrs700x_get_tag_protocol, .setup = xrs700x_setup, .teardown = xrs700x_teardown, .port_stp_state_set = xrs700x_port_stp_state_set, .phylink_get_caps = xrs700x_phylink_get_caps, - .phylink_mac_link_up = xrs700x_mac_link_up, .get_strings = xrs700x_get_strings, .get_sset_count = xrs700x_get_sset_count, .get_ethtool_stats = xrs700x_get_ethtool_stats, diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index ce6a3d56fb23..3188ece72092 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -360,7 +360,6 @@ void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable) umac_wl(intf, reg, UMC_EEE_CTRL); intf->eee.eee_enabled = enable; - intf->eee.eee_active = enable; } static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) @@ -371,8 +370,6 @@ static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) if (!dev->phydev) return -ENODEV; - e->eee_enabled = p->eee_enabled; - e->eee_active = p->eee_active; e->tx_lpi_enabled = p->tx_lpi_enabled; e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER); @@ -399,7 +396,6 @@ static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e) } umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER); - intf->eee.eee_active = ret >= 0; intf->eee.tx_lpi_enabled = e->tx_lpi_enabled; bcmasp_eee_enable_set(intf, true); } diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 6ad1366270f7..e429876c7291 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -607,6 +607,7 @@ static void bcmasp_adj_link(struct net_device *dev) struct phy_device *phydev = dev->phydev; u32 cmd_bits = 0, reg; int changed = 0; + bool active; if (intf->old_link != phydev->link) { changed = 1; @@ -658,8 +659,8 @@ static void bcmasp_adj_link(struct net_device *dev) reg |= cmd_bits; umac_wl(intf, reg, UMC_CMD); - intf->eee.eee_active = phy_init_eee(phydev, 0) >= 0; - bcmasp_eee_enable_set(intf, intf->eee.eee_active); + active = phy_init_eee(phydev, 0) >= 0; + bcmasp_eee_enable_set(intf, active); } reg = rgmii_rl(intf, RGMII_OOB_CNTRL); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 2d7ae71287b1..fef1d2f53489 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1313,7 +1313,6 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable, } priv->eee.eee_enabled = enable; - priv->eee.eee_active = enable; priv->eee.tx_lpi_enabled = tx_lpi_enabled; } @@ -1328,8 +1327,6 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e) if (!dev->phydev) return -ENODEV; - e->eee_enabled = p->eee_enabled; - e->eee_active = p->eee_active; e->tx_lpi_enabled = p->tx_lpi_enabled; e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER); @@ -1340,6 +1337,7 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); struct ethtool_eee *p = &priv->eee; + bool active; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; @@ -1352,9 +1350,9 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e) if (!p->eee_enabled) { bcmgenet_eee_enable_set(dev, false, false); } else { - p->eee_active = phy_init_eee(dev->phydev, false) >= 0; + active = phy_init_eee(dev->phydev, false) >= 0; bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER); - bcmgenet_eee_enable_set(dev, p->eee_active, e->tx_lpi_enabled); + bcmgenet_eee_enable_set(dev, active, e->tx_lpi_enabled); } return phy_ethtool_set_eee(dev->phydev, e); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 97ea76d443ab..cbbe004621bc 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -30,6 +30,7 @@ static void bcmgenet_mac_config(struct net_device *dev) struct bcmgenet_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; u32 reg, cmd_bits = 0; + bool active; /* speed */ if (phydev->speed == SPEED_1000) @@ -88,9 +89,9 @@ static void bcmgenet_mac_config(struct net_device *dev) } bcmgenet_umac_writel(priv, reg, UMAC_CMD); - priv->eee.eee_active = phy_init_eee(phydev, 0) >= 0; + active = phy_init_eee(phydev, 0) >= 0; bcmgenet_eee_enable_set(dev, - priv->eee.eee_enabled && priv->eee.eee_active, + priv->eee.eee_enabled && active, priv->eee.tx_lpi_enabled); } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 898debfd4db3..decfbf91e83d 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -687,7 +687,7 @@ static void macb_mac_config(struct phylink_config *config, unsigned int mode, u32 pcsctrl, old_pcsctrl; old_pcsctrl = gem_readl(bp, PCSCNTRL); - if (mode == MLO_AN_FIXED) + if (phylink_mode_fixed(mode)) pcsctrl = old_pcsctrl & ~GEM_BIT(PCSAUTONEG); else pcsctrl = old_pcsctrl | GEM_BIT(PCSAUTONEG); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 432523b2c789..51828d060c13 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3139,8 +3139,6 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) } p->tx_lpi_enabled = enable; - p->eee_enabled = enable; - p->eee_active = enable; writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP); writel(wake_cycle, fep->hwp + FEC_LPI_WAKE); @@ -3160,8 +3158,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) if (!netif_running(ndev)) return -ENETDOWN; - edata->eee_enabled = p->eee_enabled; - edata->eee_active = p->eee_active; edata->tx_lpi_timer = p->tx_lpi_timer; edata->tx_lpi_enabled = p->tx_lpi_enabled; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a641b3534ca3..00402c252325 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -284,8 +284,10 @@ MVNETA_TXQ_BUCKET_REFILL_PERIOD)) #define MVNETA_LPI_CTRL_0 0x2cc0 +#define MVNETA_LPI_CTRL_0_TS (0xff << 8) #define MVNETA_LPI_CTRL_1 0x2cc4 #define MVNETA_LPI_REQUEST_ENABLE BIT(0) +#define MVNETA_LPI_CTRL_1_TW (0xfff << 4) #define MVNETA_LPI_CTRL_2 0x2cc8 #define MVNETA_LPI_STATUS 0x2ccc @@ -541,10 +543,6 @@ struct mvneta_port { struct mvneta_bm_pool *pool_short; int bm_win_id; - bool eee_enabled; - bool eee_active; - bool tx_lpi_enabled; - u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)]; u32 indir[MVNETA_RSS_LU_TABLE_SIZE]; @@ -3259,7 +3257,8 @@ static void mvneta_link_change(struct mvneta_port *pp) { u32 gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); - phylink_mac_change(pp->phylink, !!(gmac_stat & MVNETA_GMAC_LINK_UP)); + phylink_pcs_change(&pp->phylink_pcs, + !!(gmac_stat & MVNETA_GMAC_LINK_UP)); } /* NAPI handler @@ -3959,20 +3958,27 @@ static struct mvneta_port *mvneta_pcs_to_port(struct phylink_pcs *pcs) return container_of(pcs, struct mvneta_port, phylink_pcs); } -static int mvneta_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) +static unsigned int mvneta_pcs_query_inband(struct phylink_pcs *pcs, + phy_interface_t interface) { - /* We only support QSGMII, SGMII, 802.3z and RGMII modes. - * When in 802.3z mode, we must have AN enabled: + /* When operating in an 802.3z mode, we must have AN enabled: * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... * When = 1 (1000BASE-X) this field must be set to 1." + * Therefore, inband is "required". */ - if (phy_interface_mode_is_8023z(state->interface) && - !phylink_test(state->advertising, Autoneg)) - return -EINVAL; + if (phy_interface_mode_is_8023z(interface)) + return LINK_INBAND_VALID | LINK_INBAND_REQUIRED; - return 0; + /* QSGMII, SGMII and RGMII can be configured to use inband + * signalling of the AN result. Indicate these as "possible". + */ + if (interface == PHY_INTERFACE_MODE_SGMII || + interface == PHY_INTERFACE_MODE_QSGMII || + phy_interface_mode_is_rgmii(interface)) + return LINK_INBAND_VALID | LINK_INBAND_POSSIBLE; + + /* For any other modes, indicate that inband is not supported. */ + return LINK_INBAND_VALID; } static void mvneta_pcs_get_state(struct phylink_pcs *pcs, @@ -4070,7 +4076,7 @@ static void mvneta_pcs_an_restart(struct phylink_pcs *pcs) } static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = { - .pcs_validate = mvneta_pcs_validate, + .pcs_query_inband = mvneta_pcs_query_inband, .pcs_get_state = mvneta_pcs_get_state, .pcs_config = mvneta_pcs_config, .pcs_an_restart = mvneta_pcs_an_restart, @@ -4205,18 +4211,6 @@ static int mvneta_mac_finish(struct phylink_config *config, unsigned int mode, return 0; } -static void mvneta_set_eee(struct mvneta_port *pp, bool enable) -{ - u32 lpi_ctl1; - - lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1); - if (enable) - lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE; - else - lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE; - mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1); -} - static void mvneta_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { @@ -4232,9 +4226,6 @@ static void mvneta_mac_link_down(struct phylink_config *config, val |= MVNETA_GMAC_FORCE_LINK_DOWN; mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); } - - pp->eee_active = false; - mvneta_set_eee(pp, false); } static void mvneta_mac_link_up(struct phylink_config *config, @@ -4283,11 +4274,57 @@ static void mvneta_mac_link_up(struct phylink_config *config, } mvneta_port_up(pp); +} + +static void mvneta_mac_disable_tx_lpi(struct phylink_config *config) +{ + struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev)); + u32 lpi1; + + lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1); + lpi1 &= ~MVNETA_LPI_REQUEST_ENABLE; + mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1); +} + +static void mvneta_mac_enable_tx_lpi(struct phylink_config *config, u32 timer) +{ + struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev)); + u32 ts, tw, lpi0, lpi1, status; - if (phy && pp->eee_enabled) { - pp->eee_active = phy_init_eee(phy, false) >= 0; - mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled); + status = mvreg_read(pp, MVNETA_GMAC_STATUS); + + if (status & MVNETA_GMAC_SPEED_1000) { + /* At 1G speeds, the timer resolution are 1us, and + * 802.3 says tw is 16.5us. Round up to 17us. + */ + tw = 17; + ts = timer; + } else { + /* At 100M speeds, the timer resolutions are 10us, and + * 802.3 says tw is 30us. + */ + tw = 3; + ts = DIV_ROUND_UP(timer, 10); } + + if (ts > 255) + ts = 255; + + /* Ensure LPI generation is disabled */ + lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1); + mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1 & ~MVNETA_LPI_REQUEST_ENABLE); + + /* Configure ts */ + lpi0 = mvreg_read(pp, MVNETA_LPI_CTRL_0) & ~MVNETA_LPI_CTRL_0_TS; + lpi0 |= FIELD_PREP(MVNETA_LPI_CTRL_0_TS, ts); + mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi0); + + /* Configure tw */ + lpi1 &= ~MVNETA_LPI_CTRL_1_TW; + lpi1 |= FIELD_PREP(MVNETA_LPI_CTRL_1_TW, tw); + + /* Enable LPI generation */ + mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1 | MVNETA_LPI_REQUEST_ENABLE); } static const struct phylink_mac_ops mvneta_phylink_ops = { @@ -4297,6 +4334,8 @@ static const struct phylink_mac_ops mvneta_phylink_ops = { .mac_finish = mvneta_mac_finish, .mac_link_down = mvneta_mac_link_down, .mac_link_up = mvneta_mac_link_up, + .mac_disable_tx_lpi = mvneta_mac_disable_tx_lpi, + .mac_enable_tx_lpi = mvneta_mac_enable_tx_lpi, }; static int mvneta_mdio_probe(struct mvneta_port *pp) @@ -5100,14 +5139,6 @@ static int mvneta_ethtool_get_eee(struct net_device *dev, struct ethtool_eee *eee) { struct mvneta_port *pp = netdev_priv(dev); - u32 lpi_ctl0; - - lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); - - eee->eee_enabled = pp->eee_enabled; - eee->eee_active = pp->eee_active; - eee->tx_lpi_enabled = pp->tx_lpi_enabled; - eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale; return phylink_ethtool_get_eee(pp->phylink, eee); } @@ -5116,23 +5147,6 @@ static int mvneta_ethtool_set_eee(struct net_device *dev, struct ethtool_eee *eee) { struct mvneta_port *pp = netdev_priv(dev); - u32 lpi_ctl0; - - /* The Armada 37x documents do not give limits for this other than - * it being an 8-bit register. - */ - if (eee->tx_lpi_enabled && eee->tx_lpi_timer > 255) - return -EINVAL; - - lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); - lpi_ctl0 &= ~(0xff << 8); - lpi_ctl0 |= eee->tx_lpi_timer << 8; - mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0); - - pp->eee_enabled = eee->eee_enabled; - pp->tx_lpi_enabled = eee->tx_lpi_enabled; - - mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled); return phylink_ethtool_set_eee(pp->phylink, eee); } @@ -5537,6 +5551,8 @@ static int mvneta_probe(struct platform_device *pdev) pp->phylink_config.type = PHYLINK_NETDEV; pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; + pp->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD; + pp->phylink_config.lpi_timer_limit_us = 255; phy_interface_set_rgmii(pp->phylink_config.supported_interfaces); __set_bit(PHY_INTERFACE_MODE_QSGMII, @@ -5564,6 +5580,11 @@ static int mvneta_probe(struct platform_device *pdev) pp->phylink_config.supported_interfaces); } + /* Setup EEE. Choose 250us idle. */ + pp->phylink_config.eee.eee_enabled = true; + pp->phylink_config.eee.tx_lpi_enabled = true; + pp->phylink_config.eee.tx_lpi_timer = 250; + phylink = phylink_create(&pp->phylink_config, pdev->dev.fwnode, phy_mode, &mvneta_phylink_ops); if (IS_ERR(phylink)) { diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index e809f91c08fb..299b996ac5df 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -481,6 +481,11 @@ #define MVPP22_GMAC_INT_SUM_MASK 0xa4 #define MVPP22_GMAC_INT_SUM_MASK_LINK_STAT BIT(1) #define MVPP22_GMAC_INT_SUM_MASK_PTP BIT(2) +#define MVPP2_GMAC_LPI_CTRL0 0xc0 +#define MVPP2_GMAC_LPI_CTRL0_TS_MASK GENMASK(8, 8) +#define MVPP2_GMAC_LPI_CTRL1 0xc4 +#define MVPP2_GMAC_LPI_CTRL1_REQ_EN BIT(0) +#define MVPP2_GMAC_LPI_CTRL1_TW_MASK GENMASK(15, 4) /* Per-port XGMAC registers. PPv2.2 and PPv2.3, only for GOP port 0, * relative to port->base. diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 23adf53c2aa1..97e38f61ac65 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -3434,12 +3434,13 @@ static void mvpp2_isr_handle_ptp(struct mvpp2_port *port) mvpp2_isr_handle_ptp_queue(port, 1); } -static void mvpp2_isr_handle_link(struct mvpp2_port *port, bool link) +static void mvpp2_isr_handle_link(struct mvpp2_port *port, + struct phylink_pcs *pcs, bool link) { struct net_device *dev = port->dev; if (port->phylink) { - phylink_mac_change(port->phylink, link); + phylink_pcs_change(pcs, link); return; } @@ -3472,7 +3473,7 @@ static void mvpp2_isr_handle_xlg(struct mvpp2_port *port) if (val & MVPP22_XLG_INT_STAT_LINK) { val = readl(port->base + MVPP22_XLG_STATUS); link = (val & MVPP22_XLG_STATUS_LINK_UP); - mvpp2_isr_handle_link(port, link); + mvpp2_isr_handle_link(port, &port->pcs_xlg, link); } } @@ -3488,7 +3489,7 @@ static void mvpp2_isr_handle_gmac_internal(struct mvpp2_port *port) if (val & MVPP22_GMAC_INT_STAT_LINK) { val = readl(port->base + MVPP2_GMAC_STATUS0); link = (val & MVPP2_GMAC_STATUS0_LINK_UP); - mvpp2_isr_handle_link(port, link); + mvpp2_isr_handle_link(port, &port->pcs_gmac, link); } } } @@ -5726,6 +5727,28 @@ static int mvpp2_ethtool_set_rxfh(struct net_device *dev, return ret; } +static int mvpp2_ethtool_get_eee(struct net_device *dev, + struct ethtool_eee *eee) +{ + struct mvpp2_port *port = netdev_priv(dev); + + if (!port->phylink) + return -EOPNOTSUPP; + + return phylink_ethtool_get_eee(port->phylink, eee); +} + +static int mvpp2_ethtool_set_eee(struct net_device *dev, + struct ethtool_eee *eee) +{ + struct mvpp2_port *port = netdev_priv(dev); + + if (!port->phylink) + return -EOPNOTSUPP; + + return phylink_ethtool_set_eee(port->phylink, eee); +} + /* Device ops */ static const struct net_device_ops mvpp2_netdev_ops = { @@ -5768,6 +5791,8 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = { .get_rxfh_indir_size = mvpp2_ethtool_get_rxfh_indir_size, .get_rxfh = mvpp2_ethtool_get_rxfh, .set_rxfh = mvpp2_ethtool_set_rxfh, + .get_eee = mvpp2_ethtool_get_eee, + .set_eee = mvpp2_ethtool_set_eee, }; /* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that @@ -6190,19 +6215,26 @@ static const struct phylink_pcs_ops mvpp2_phylink_xlg_pcs_ops = { .pcs_config = mvpp2_xlg_pcs_config, }; -static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) +static unsigned int mvpp2_gmac_pcs_query_inband(struct phylink_pcs *pcs, + phy_interface_t interface) { - /* When in 802.3z mode, we must have AN enabled: + /* When operating in an 802.3z mode, we must have AN enabled: * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... * When = 1 (1000BASE-X) this field must be set to 1. + * Therefore, inband is "required". */ - if (phy_interface_mode_is_8023z(state->interface) && - !phylink_test(state->advertising, Autoneg)) - return -EINVAL; + if (phy_interface_mode_is_8023z(interface)) + return LINK_INBAND_VALID | LINK_INBAND_REQUIRED; - return 0; + /* SGMII and RGMII can be configured to use inband signalling of the + * AN result. Indicate these as "possible". + */ + if (interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_rgmii(interface)) + return LINK_INBAND_VALID | LINK_INBAND_POSSIBLE; + + /* For any other modes, indicate that inband is not supported. */ + return LINK_INBAND_VALID; } static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs, @@ -6309,7 +6341,7 @@ static void mvpp2_gmac_pcs_an_restart(struct phylink_pcs *pcs) } static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = { - .pcs_validate = mvpp2_gmac_pcs_validate, + .pcs_query_inband = mvpp2_gmac_pcs_query_inband, .pcs_get_state = mvpp2_gmac_pcs_get_state, .pcs_config = mvpp2_gmac_pcs_config, .pcs_an_restart = mvpp2_gmac_pcs_an_restart, @@ -6631,6 +6663,57 @@ static void mvpp2_mac_link_down(struct phylink_config *config, mvpp2_port_disable(port); } +static void mvpp2_mac_disable_tx_lpi(struct phylink_config *config) +{ + struct mvpp2_port *port = mvpp2_phylink_to_port(config); + + mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL1, + MVPP2_GMAC_LPI_CTRL1_REQ_EN, 0); +} + +static void mvpp2_mac_enable_tx_lpi(struct phylink_config *config, u32 timer) +{ + struct mvpp2_port *port = mvpp2_phylink_to_port(config); + u32 ts, tw, lpi0, lpi1, status; + + status = readl(port->base + MVPP2_GMAC_STATUS0); + if (status & MVPP2_GMAC_STATUS0_GMII_SPEED) { + /* At 1G speeds, the timer resolution are 1us, and + * 802.3 says tw is 16.5us. Round up to 17us. + */ + tw = 17; + ts = timer; + } else { + /* At 100M speeds, the timer resolutions are 10us, and + * 802.3 says tw is 30us. + */ + tw = 3; + ts = DIV_ROUND_UP(timer, 10); + } + + if (ts > 255) + ts = 255; + + /* Ensure LPI generation is disabled */ + lpi1 = readl(port->base + MVPP2_GMAC_LPI_CTRL1); + writel(lpi1 & ~MVPP2_GMAC_LPI_CTRL1_REQ_EN, + port->base + MVPP2_GMAC_LPI_CTRL1); + + /* Configure ts */ + lpi0 = readl(port->base + MVPP2_GMAC_LPI_CTRL0); + lpi0 &= ~MVPP2_GMAC_LPI_CTRL0_TS_MASK; + lpi0 |= FIELD_PREP(MVPP2_GMAC_LPI_CTRL0_TS_MASK, ts); + writel(lpi0, port->base + MVPP2_GMAC_LPI_CTRL0); + + /* Configure tw */ + lpi1 &= ~MVPP2_GMAC_LPI_CTRL1_TW_MASK; + lpi1 |= FIELD_PREP(MVPP2_GMAC_LPI_CTRL1_TW_MASK, tw); + + /* Enable LPI generation */ + writel(lpi1 | MVPP2_GMAC_LPI_CTRL1_REQ_EN, + port->base + MVPP2_GMAC_LPI_CTRL1); +} + static const struct phylink_mac_ops mvpp2_phylink_ops = { .mac_select_pcs = mvpp2_select_pcs, .mac_prepare = mvpp2_mac_prepare, @@ -6638,6 +6721,8 @@ static const struct phylink_mac_ops mvpp2_phylink_ops = { .mac_finish = mvpp2_mac_finish, .mac_link_up = mvpp2_mac_link_up, .mac_link_down = mvpp2_mac_link_down, + .mac_enable_tx_lpi = mvpp2_mac_enable_tx_lpi, + .mac_disable_tx_lpi = mvpp2_mac_disable_tx_lpi, }; /* Work-around for ACPI */ @@ -6914,6 +6999,9 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->phylink_config.type = PHYLINK_NETDEV; port->phylink_config.mac_capabilities = MAC_2500FD | MAC_1000FD | MAC_100 | MAC_10; + port->phylink_config.lpi_capabilities = + MAC_2500FD | MAC_1000FD | MAC_100FD; + port->phylink_config.lpi_timer_limit_us = 255; if (port->priv->global_tx_fc) port->phylink_config.mac_capabilities |= @@ -6982,6 +7070,11 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->phylink_config.supported_interfaces); } + /* Setup EEE. Choose 250us idle. */ + port->phylink_config.eee.eee_enabled = true; + port->phylink_config.eee.tx_lpi_enabled = true; + port->phylink_config.eee.tx_lpi_timer = 250; + phylink = phylink_create(&port->phylink_config, port_fwnode, phy_mode, &mvpp2_phylink_ops); if (IS_ERR(phylink)) { diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c index 4fb886c57cd7..ba6d53ac7f55 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_main.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c @@ -821,7 +821,7 @@ static void prestera_port_handle_event(struct prestera_switch *sw, if (port->state_mac.oper) { if (port->phy_link) - phylink_mac_change(port->phy_link, true); + phylink_pcs_change(&port->phylink_pcs, true); else netif_carrier_on(port->dev); @@ -829,7 +829,7 @@ static void prestera_port_handle_event(struct prestera_switch *sw, queue_delayed_work(prestera_wq, caching_dw, 0); } else { if (port->phy_link) - phylink_mac_change(port->phy_link, false); + phylink_pcs_change(&port->phylink_pcs, false); else if (netif_running(port->dev) && netif_carrier_ok(port->dev)) netif_carrier_off(port->dev); diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h index d14e0cfc3a6b..1458939c3bf5 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -503,7 +503,6 @@ struct sxgbe_priv_data { bool tx_path_in_lpi_mode; int lpi_irq; int eee_enabled; - int eee_active; int tx_lpi_timer; }; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index 8ba017ec9849..52650968bfa5 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -140,8 +140,6 @@ static int sxgbe_get_eee(struct net_device *dev, if (!priv->hw_cap.eee) return -EOPNOTSUPP; - edata->eee_enabled = priv->eee_enabled; - edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; return phy_ethtool_get_eee(dev->phydev, edata); diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 71439825ea4e..ecbe3994f2b1 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -130,7 +130,6 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) if (phy_init_eee(ndev->phydev, true)) return false; - priv->eee_active = 1; timer_setup(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer, 0); priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer); add_timer(&priv->eee_ctrl_timer); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index ec44becf0e2d..1471fbdcc6c8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -904,8 +904,6 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, if (!priv->dma_cap.eee) return -EOPNOTSUPP; - edata->eee_enabled = priv->eee_enabled; - edata->eee_active = priv->eee_active; edata->tx_lpi_timer = priv->tx_lpi_timer; edata->tx_lpi_enabled = priv->tx_lpi_enabled; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 1b84d495d14e..b942926e3b69 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -483,7 +483,8 @@ static void txgbe_irq_handler(struct irq_desc *desc) TXGBE_PX_MISC_ETH_AN)) { u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); - phylink_mac_change(wx->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); + phylink_pcs_change(&txgbe->xpcs->pcs, + !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); } /* unmask interrupt */ diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c index d93f84fbb1fd..f2da79591119 100644 --- a/drivers/net/pcs/pcs-rzn1-miic.c +++ b/drivers/net/pcs/pcs-rzn1-miic.c @@ -183,7 +183,7 @@ static void miic_converter_enable(struct miic *miic, int port, int enable) miic_reg_rmw(miic, MIIC_CONVRST, MIIC_CONVRST_PHYIF_RST(port), val); } -static int miic_config(struct phylink_pcs *pcs, unsigned int mode, +static int miic_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit) { @@ -234,7 +234,7 @@ static int miic_config(struct phylink_pcs *pcs, unsigned int mode, return 0; } -static void miic_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void miic_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { struct miic_port *miic_port = phylink_pcs_to_miic_port(pcs); @@ -268,7 +268,8 @@ static void miic_link_up(struct phylink_pcs *pcs, unsigned int mode, (MIIC_CONVCTRL_CONV_SPEED | MIIC_CONVCTRL_FULLD), val); } -static int miic_validate(struct phylink_pcs *pcs, unsigned long *supported, +static int miic_validate(struct phylink_pcs *pcs, unsigned int mode, + unsigned long *supported, const struct phylink_link_state *state) { if (phy_interface_mode_is_rgmii(state->interface) || @@ -333,6 +334,7 @@ struct phylink_pcs *miic_create(struct device *dev, struct device_node *np) miic_port->miic = miic; miic_port->port = port - 1; miic_port->pcs.ops = &miic_phylink_ops; + miic_port->pcs.neg_mode = true; return &miic_port->pcs; } diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 31f0beba638a..f3cccb459ecb 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -604,7 +604,8 @@ static void xpcs_resolve_pma(struct dw_xpcs *xpcs, } } -static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, +static int xpcs_validate(struct phylink_pcs *pcs, unsigned int mode, + unsigned long *supported, const struct phylink_link_state *state) { __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, }; diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6097afd44392..dc4c583f7e00 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_PHYLIB) += libphy.o obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o -obj-$(CONFIG_SFP) += sfp.o +obj-$(CONFIG_SFP) += sff.o sfp.o sfp-obj-$(CONFIG_SFP) += sfp-bus.o obj-y += $(sfp-obj-y) $(sfp-obj-m) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 97a2fafa15ca..43886d2995e7 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -746,6 +746,19 @@ static int aqr107_probe(struct phy_device *phydev) return aqr_hwmon_probe(phydev); } +static int aqr113c_probe(struct phy_device *phydev) +{ + unsigned long *supported = phydev->supported_interfaces; + + __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); + __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); + __set_bit(PHY_INTERFACE_MODE_SGMII, supported); + + return aqr107_probe(phydev); +} + static struct phy_driver aqr_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202), @@ -866,7 +879,7 @@ static struct phy_driver aqr_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), .name = "Aquantia AQR113C", - .probe = aqr107_probe, + .probe = aqr113c_probe, .get_rate_matching = aqr107_get_rate_matching, .config_init = aqr113c_config_init, .config_aneg = aqr_config_aneg, diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c index f1d47c264058..a72b693be846 100644 --- a/drivers/net/phy/bcm84881.c +++ b/drivers/net/phy/bcm84881.c @@ -63,6 +63,10 @@ static int bcm84881_probe(struct phy_device *phydev) (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) return -ENODEV; + __set_bit(PHY_INTERFACE_MODE_SGMII, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_10GBASER, phydev->supported_interfaces); + return 0; } @@ -235,11 +239,21 @@ static int bcm84881_read_status(struct phy_device *phydev) return genphy_c45_read_mdix(phydev); } +/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII + * or 802.3z control word, so inband will not work. + */ +static unsigned int bcm84881_query_inband(struct phy_device *phydev, + phy_interface_t interface) +{ + return LINK_INBAND_VALID; +} + static struct phy_driver bcm84881_drivers[] = { { .phy_id = 0xae025150, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM84881", + .query_inband = bcm84881_query_inband, .config_init = bcm84881_config_init, .probe = bcm84881_probe, .get_features = bcm84881_get_features, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index eba652a4c1d8..6a6bcda8796d 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -176,6 +176,10 @@ #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 #define MII_M1011_PHY_STATUS_LINK 0x0400 +#define MII_M1111_PHY_STATUS_TX_PAUSE 0x0008 +#define MII_M1111_PHY_STATUS_RX_PAUSE 0x0004 +#define MII_88E151X_PHY_STATUS_TX_PAUSE 0x0200 +#define MII_88E151X_PHY_STATUS_RX_PAUSE 0x0100 #define MII_88E3016_PHY_SPEC_CTRL 0x10 #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 @@ -310,6 +314,8 @@ struct marvell_priv { u32 last; u32 step; s8 pair; + u16 tx_pause_mask; + u16 rx_pause_mask; }; static int marvell_read_page(struct phy_device *phydev) @@ -673,6 +679,19 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev) return genphy_check_and_restart_aneg(phydev, changed); } +static unsigned int m88e1111_query_inband(struct phy_device *phydev, + phy_interface_t interface) +{ + /* In 1000base-X and SGMII modes, the inband mode can be changed + * through the Fibre page BMCR ANENABLE bit. + */ + if (interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_SGMII) + return LINK_INBAND_VALID | LINK_INBAND_POSSIBLE; + + return 0; +} + static int m88e1111_config_aneg(struct phy_device *phydev) { int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); @@ -919,7 +938,10 @@ static int m88e1111_config_init_1000basex(struct phy_device *phydev) if (extsr < 0) return extsr; - /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */ + /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled. + * FIXME: this does not actually enable 1000BaseX auto-negotiation if + * it was previously disabled in the Fiber BMCR! + */ mode = extsr & MII_M1111_HWCFG_MODE_MASK; if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) { err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, @@ -1577,6 +1599,7 @@ static void fiber_lpa_mod_linkmode_lpa_t(unsigned long *advertising, u32 lpa) static int marvell_read_status_page_an(struct phy_device *phydev, int fiber, int status) { + struct marvell_priv *priv = phydev->priv; int lpa; int err; @@ -1632,6 +1655,11 @@ static int marvell_read_status_page_an(struct phy_device *phydev, } } + phydev->resolved_tx_pause = !!(status & priv->tx_pause_mask); + phydev->resolved_rx_pause = !!(status & priv->rx_pause_mask); + phydev->resolved_pause_valid = !fiber && priv->tx_pause_mask && + priv->rx_pause_mask; + return 0; } @@ -1675,6 +1703,7 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) phydev->speed = SPEED_UNKNOWN; phydev->duplex = DUPLEX_UNKNOWN; phydev->port = fiber ? PORT_FIBRE : PORT_TP; + phydev->resolved_pause_valid = false; if (phydev->autoneg == AUTONEG_ENABLE) err = marvell_read_status_page_an(phydev, fiber, status); @@ -3159,14 +3188,26 @@ static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index, return marvell_get_led_rules(index, rules, mode); } -static int marvell_probe(struct phy_device *phydev) +static int marvell_probe_pause(struct phy_device *phydev, u16 tx_pause_mask, + u16 rx_pause_mask) { struct marvell_priv *priv; + __set_bit(PHY_INTERFACE_MODE_GMII, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_TBI, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RGMII, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RGMII_ID, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, phydev->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_RTBI, phydev->supported_interfaces); + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->tx_pause_mask = tx_pause_mask; + priv->rx_pause_mask = rx_pause_mask; phydev->priv = priv; return marvell_hwmon_probe(phydev); @@ -3256,11 +3297,23 @@ static const struct sfp_upstream_ops m88e1510_sfp_ops = { .detach = phy_sfp_detach, }; +static int marvell_probe(struct phy_device *phydev) +{ + return marvell_probe_pause(phydev, 0, 0); +} + +static int m88e1111_probe(struct phy_device *phydev) +{ + return marvell_probe_pause(phydev, MII_M1111_PHY_STATUS_TX_PAUSE, + MII_M1111_PHY_STATUS_RX_PAUSE); +} + static int m88e1510_probe(struct phy_device *phydev) { int err; - err = marvell_probe(phydev); + err = marvell_probe_pause(phydev, MII_88E151X_PHY_STATUS_TX_PAUSE, + MII_88E151X_PHY_STATUS_RX_PAUSE); if (err) return err; @@ -3292,6 +3345,7 @@ static struct phy_driver marvell_drivers[] = { .name = "Marvell 88E1112", /* PHY_GBIT_FEATURES */ .probe = marvell_probe, + .query_inband = m88e1111_query_inband, .config_init = m88e1112_config_init, .config_aneg = marvell_config_aneg, .config_intr = marvell_config_intr, @@ -3311,7 +3365,8 @@ static struct phy_driver marvell_drivers[] = { .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1111", /* PHY_GBIT_FEATURES */ - .probe = marvell_probe, + .probe = m88e1111_probe, + .query_inband = m88e1111_query_inband, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, @@ -3333,6 +3388,7 @@ static struct phy_driver marvell_drivers[] = { .name = "Marvell 88E1111 (Finisar)", /* PHY_GBIT_FEATURES */ .probe = marvell_probe, + .query_inband = m88e1111_query_inband, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, @@ -3532,7 +3588,7 @@ static struct phy_driver marvell_drivers[] = { .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), /* PHY_GBIT_FEATURES */ .flags = PHY_POLL_CABLE_TEST, - .probe = marvell_probe, + .probe = m88e1510_probe, .config_init = marvell_1011gbe_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, @@ -3561,7 +3617,7 @@ static struct phy_driver marvell_drivers[] = { .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1545", .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), - .probe = marvell_probe, + .probe = m88e1510_probe, /* PHY_GBIT_FEATURES */ .flags = PHY_POLL_CABLE_TEST, .config_init = marvell_1011gbe_config_init, @@ -3613,7 +3669,7 @@ static struct phy_driver marvell_drivers[] = { .driver_data = DEF_MARVELL_HWMON_OPS(m88e1510_hwmon_ops), /* PHY_GBIT_FEATURES */ .flags = PHY_POLL_CABLE_TEST, - .probe = marvell_probe, + .probe = m88e1510_probe, .config_init = marvell_1011gbe_config_init, .config_aneg = m88e6390_config_aneg, .read_status = marvell_read_status, diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index ad43e280930c..eb05a578dbd7 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,8 @@ enum { MV_PCS_CSSR1_SPD1_10 = 0x0000, MV_PCS_CSSR1_DUPLEX_FULL= BIT(13), MV_PCS_CSSR1_RESOLVED = BIT(11), + MV_PCS_CSSR1_TX_PAUSE = BIT(9), + MV_PCS_CSSR1_RX_PAUSE = BIT(8), MV_PCS_CSSR1_MDIX = BIT(6), MV_PCS_CSSR1_SPD2_MASK = 0x000c, MV_PCS_CSSR1_SPD2_5000 = 0x0008, @@ -163,14 +166,16 @@ struct mv3310_chip { }; struct mv3310_priv { - DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX); const struct mv3310_mactype *mactype; u32 firmware_ver; bool has_downshift; + bool firmware_failed; struct device *hwmon_dev; char *hwmon_name; + u8 num_leds; + u16 led_mode[4]; }; static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev) @@ -506,6 +511,43 @@ static const struct sfp_upstream_ops mv3310_sfp_ops = { .module_insert = mv3310_sfp_insert, }; +static int mv3310_leds_write(struct phy_device *phydev) +{ + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); + int i, ret; + + for (i = 0; i < priv->num_leds; i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xf020 + i, + priv->led_mode[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int mv3310_fw_config(struct phy_device *phydev) +{ + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); + struct device_node *node; + int ret; + + node = phydev->mdio.dev.of_node; + if (!node) + return 0; + + ret = of_property_read_variable_u16_array(node, "marvell,led-mode", + priv->led_mode, 1, ARRAY_SIZE(priv->led_mode)); + if (ret == -EINVAL) + ret = 0; + if (ret < 0) + return ret; + + priv->num_leds = ret; + + return 0; +} + static int mv3310_probe(struct phy_device *phydev) { const struct mv3310_chip *chip = to_mv3310_chip(phydev); @@ -517,6 +559,20 @@ static int mv3310_probe(struct phy_device *phydev) (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) return -ENODEV; + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(&phydev->mdio.dev, priv); + + ret = mv3310_fw_config(phydev); + if (ret < 0) + return ret; + + ret = mv3310_leds_write(phydev); + if (ret < 0) + return ret; + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT); if (ret < 0) return ret; @@ -524,15 +580,9 @@ static int mv3310_probe(struct phy_device *phydev) if (ret & MV_PMA_BOOT_FATAL) { dev_warn(&phydev->mdio.dev, "PHY failed to boot firmware, status=%04x\n", ret); - return -ENODEV; + priv->firmware_failed = true; } - priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev_set_drvdata(&phydev->mdio.dev, priv); - ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_FW_VER0); if (ret < 0) return ret; @@ -561,7 +611,7 @@ static int mv3310_probe(struct phy_device *phydev) if (ret) return ret; - chip->init_supported_interfaces(priv->supported_interfaces); + chip->init_supported_interfaces(phydev->supported_interfaces); return phy_sfp_probe(phydev, &mv3310_sfp_ops); } @@ -587,6 +637,19 @@ static int mv3310_resume(struct phy_device *phydev) return mv3310_hwmon_config(phydev, true); } +static int mv3310_start(struct phy_device *phydev) +{ + struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); + + if (priv->firmware_failed) { + dev_warn(&phydev->mdio.dev, + "PHY firmware failure: PHY not starting"); + return -EINVAL; + } + + return 0; +} + /* Some PHYs in the Alaska family such as the 88X3310 and the 88E2010 * don't set bit 14 in PMA Extended Abilities (1.11), although they do * support 2.5GBASET and 5GBASET. For these models, we can still read their @@ -826,7 +889,7 @@ static int mv3310_config_init(struct phy_device *phydev) int err, mactype; /* Check that the PHY interface type is compatible */ - if (!test_bit(phydev->interface, priv->supported_interfaces)) + if (!test_bit(phydev->interface, phydev->supported_interfaces)) return -ENODEV; phydev->mdix_ctrl = ETH_TP_MDI_AUTO; @@ -873,7 +936,7 @@ static int mv3310_config_init(struct phy_device *phydev) if (err && err != -EOPNOTSUPP) return err; - return 0; + return mv3310_leds_write(phydev); } static int mv3310_get_features(struct phy_device *phydev) @@ -1090,6 +1153,10 @@ static int mv3310_read_status_copper(struct phy_device *phydev) phydev->mdix = cssr1 & MV_PCS_CSSR1_MDIX ? ETH_TP_MDI_X : ETH_TP_MDI; + phydev->resolved_tx_pause = !!(cssr1 & MV_PCS_CSSR1_TX_PAUSE); + phydev->resolved_rx_pause = !!(cssr1 & MV_PCS_CSSR1_RX_PAUSE); + phydev->resolved_pause_valid = true; + if (val & MDIO_AN_STAT1_COMPLETE) { val = genphy_c45_read_lpa(phydev); if (val < 0) @@ -1432,6 +1499,7 @@ static struct phy_driver mv3310_drivers[] = { .probe = mv3310_probe, .suspend = mv3310_suspend, .resume = mv3310_resume, + .start = mv3310_start, .config_aneg = mv3310_config_aneg, .aneg_done = mv3310_aneg_done, .read_status = mv3310_read_status, @@ -1469,6 +1537,7 @@ static struct phy_driver mv3310_drivers[] = { .probe = mv3310_probe, .suspend = mv3310_suspend, .resume = mv3310_resume, + .start = mv3310_start, .config_init = mv3310_config_init, .config_aneg = mv3310_config_aneg, .aneg_done = mv3310_aneg_done, diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index afbad1ad8683..836a52d147ef 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -1370,8 +1370,16 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) static int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env) { + struct mdio_device *mdio = to_mdio_device(dev); int rc; + /* Use the device-specific uevent if specified */ + if (mdio->bus_uevent) { + rc = mdio->bus_uevent(mdio, env); + if (rc != -ENODEV) + return rc; + } + /* Some devices have extra OF data and an OF-style MODALIAS */ rc = of_device_uevent_modalias(dev, env); if (rc != -ENODEV) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3376e58e2b88..ae1916861986 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -992,6 +992,27 @@ static int phy_check_link_status(struct phy_device *phydev) return 0; } +/** + * phy_query_inband - query which in-band signalling modes are supported + * @phydev: a pointer to a &struct phy_device + * @interface: the interface mode for the PHY + * + * Returns zero if it is unknown what in-band signalling is supported by the + * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, + * returns a bit mask of the LINK_INBAND_* values from + * &enum link_inband_signalling to describe which inband modes are supported + * for this interface mode. + */ +unsigned int phy_query_inband(struct phy_device *phydev, + phy_interface_t interface) +{ + if (phydev->drv && phydev->drv->query_inband) + return phydev->drv->query_inband(phydev, interface); + + return 0; +} +EXPORT_SYMBOL_GPL(phy_query_inband); + /** * _phy_start_aneg - start auto-negotiation for this PHY device * @phydev: the phy_device struct @@ -1239,6 +1260,8 @@ void phy_stop_machine(struct phy_device *phydev) static void phy_process_error(struct phy_device *phydev) { + phydev_err(phydev, "Error detected, halting PHY\n"); + /* phydev->lock must be held for the state change to be safe */ if (!mutex_is_locked(&phydev->lock)) phydev_err(phydev, "PHY-device data unsafe context\n"); @@ -1265,7 +1288,6 @@ static void phy_error_precise(struct phy_device *phydev, */ void phy_error(struct phy_device *phydev) { - WARN_ON(1); phy_process_error(phydev); } EXPORT_SYMBOL(phy_error); @@ -1290,7 +1312,6 @@ int phy_disable_interrupts(struct phy_device *phydev) static irqreturn_t phy_interrupt(int irq, void *phy_dat) { struct phy_device *phydev = phy_dat; - struct phy_driver *drv = phydev->drv; irqreturn_t ret; /* Wakeup interrupts may occur during a system sleep transition. @@ -1316,7 +1337,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) } mutex_lock(&phydev->lock); - ret = drv->handle_interrupt(phydev); + ret = phydev->drv->handle_interrupt(phydev); mutex_unlock(&phydev->lock); return ret; @@ -1513,6 +1534,10 @@ void phy_stop(struct phy_device *phydev) phy_process_state_change(phydev, old_state); state_work = _phy_state_machine(phydev); + + if (phydev->drv->stop) + phydev->drv->stop(phydev); + mutex_unlock(&phydev->lock); _phy_state_machine_post_work(phydev, state_work); @@ -1545,6 +1570,9 @@ void phy_start(struct phy_device *phydev) goto out; } + if (phydev->drv->start && phydev->drv->start(phydev)) + goto out; + if (phydev->sfp_bus) sfp_upstream_start(phydev->sfp_bus); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3611ea64875e..d42b89334116 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -631,6 +631,19 @@ static int phy_request_driver_module(struct phy_device *dev, u32 phy_id) return 0; } +static int phy_bus_uevent(struct mdio_device *mdiodev, + struct kobj_uevent_env *env) +{ + struct phy_device *phydev; + + phydev = container_of(mdiodev, struct phy_device, mdio); + + add_uevent_var(env, "MODALIAS=" MDIO_MODULE_PREFIX MDIO_ID_FMT, + MDIO_ID_ARGS(phydev->phy_id)); + + return 0; +} + struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids) @@ -650,6 +663,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, mdiodev->dev.type = &mdio_bus_phy_type; mdiodev->bus = bus; mdiodev->bus_match = phy_bus_match; + mdiodev->bus_uevent = phy_bus_uevent; mdiodev->addr = addr; mdiodev->flags = MDIO_DEVICE_FLAG_PHY; mdiodev->device_free = phy_mdio_device_free; @@ -1859,7 +1873,7 @@ int phy_suspend(struct phy_device *phydev) { struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; struct net_device *netdev = phydev->attached_dev; - struct phy_driver *phydrv = phydev->drv; + const struct phy_driver *phydrv = phydev->drv; int ret; if (phydev->suspended) @@ -1884,7 +1898,7 @@ EXPORT_SYMBOL(phy_suspend); int __phy_resume(struct phy_device *phydev) { - struct phy_driver *phydrv = phydev->drv; + const struct phy_driver *phydrv = phydev->drv; int ret; lockdep_assert_held(&phydev->lock); @@ -2888,6 +2902,12 @@ void phy_get_pause(struct phy_device *phydev, bool *tx_pause, bool *rx_pause) return; } + if (phydev->resolved_pause_valid) { + *tx_pause = phydev->resolved_tx_pause; + *rx_pause = phydev->resolved_rx_pause; + return; + } + return linkmode_resolve_pause(phydev->advertising, phydev->lp_advertising, tx_pause, rx_pause); @@ -2992,7 +3012,7 @@ s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev, } EXPORT_SYMBOL(phy_get_internal_delay); -static bool phy_drv_supports_irq(struct phy_driver *phydrv) +static bool phy_drv_supports_irq(const struct phy_driver *phydrv) { return phydrv->config_intr && phydrv->handle_interrupt; } diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ed0b4ccaa6a6..8a3728d423e7 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -85,7 +85,11 @@ struct phylink { bool sfp_may_have_phy; DECLARE_PHY_INTERFACE_MASK(sfp_interfaces); __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); + u8 sfp_link_an_mode; u8 sfp_port; + + struct eee_config eee_cfg; + bool eee_active; }; #define phylink_printk(level, pl, fmt, ...) \ @@ -647,7 +651,7 @@ static void phylink_validate_mask_caps(unsigned long *supported, linkmode_and(state->advertising, state->advertising, mask); } -static int phylink_validate_mac_and_pcs(struct phylink *pl, +static int phylink_validate_mac_and_pcs(struct phylink *pl, unsigned int mode, unsigned long *supported, struct phylink_link_state *state) { @@ -678,7 +682,8 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, /* Validate the link parameters with the PCS */ if (pcs->ops->pcs_validate) { - ret = pcs->ops->pcs_validate(pcs, supported, state); + ret = pcs->ops->pcs_validate(pcs, mode, supported, + state); if (ret < 0 || phylink_is_empty_linkmode(supported)) return -EINVAL; @@ -703,6 +708,7 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, } static void phylink_validate_one(struct phylink *pl, struct phy_device *phy, + unsigned int mode, const unsigned long *supported, const struct phylink_link_state *state, phy_interface_t interface, @@ -720,7 +726,8 @@ static void phylink_validate_one(struct phylink *pl, struct phy_device *phy, if (phy) tmp_state.rate_matching = phy_get_rate_matching(phy, interface); - if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) { + if (!phylink_validate_mac_and_pcs(pl, mode, tmp_supported, + &tmp_state)) { phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n", interface, phy_modes(interface), phy_rate_matching_to_str(tmp_state.rate_matching), @@ -733,6 +740,7 @@ static void phylink_validate_one(struct phylink *pl, struct phy_device *phy, } static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy, + unsigned int mode, unsigned long *supported, struct phylink_link_state *state, const unsigned long *interfaces) @@ -742,7 +750,7 @@ static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy, int interface; for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX) - phylink_validate_one(pl, phy, supported, state, interface, + phylink_validate_one(pl, phy, mode, supported, state, interface, all_s, all_adv); linkmode_copy(supported, all_s); @@ -751,19 +759,20 @@ static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy, return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; } -static int phylink_validate(struct phylink *pl, unsigned long *supported, +static int phylink_validate(struct phylink *pl, unsigned int mode, + unsigned long *supported, struct phylink_link_state *state) { const unsigned long *interfaces = pl->config->supported_interfaces; if (state->interface == PHY_INTERFACE_MODE_NA) - return phylink_validate_mask(pl, NULL, supported, state, + return phylink_validate_mask(pl, NULL, mode, supported, state, interfaces); if (!test_bit(state->interface, interfaces)) return -EINVAL; - return phylink_validate_mac_and_pcs(pl, supported, state); + return phylink_validate_mac_and_pcs(pl, mode, supported, state); } static int phylink_parse_fixedlink(struct phylink *pl, @@ -841,7 +850,7 @@ static int phylink_parse_fixedlink(struct phylink *pl, linkmode_fill(pl->supported); linkmode_copy(pl->link_config.advertising, pl->supported); - phylink_validate(pl, pl->supported, &pl->link_config); + phylink_validate(pl, MLO_AN_FIXED, pl->supported, &pl->link_config); pause = phylink_test(pl->supported, Pause); asym_pause = phylink_test(pl->supported, Asym_Pause); @@ -893,7 +902,7 @@ static int phylink_parse_mode(struct phylink *pl, if ((fwnode_property_read_string(fwnode, "managed", &managed) == 0 && strcmp(managed, "in-band-status") == 0) || pl->config->ovr_an_inband) { - if (pl->cfg_link_an_mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(pl->cfg_link_an_mode)) { phylink_err(pl, "can't use both fixed-link and in-band-status\n"); return -EINVAL; @@ -939,7 +948,8 @@ static int phylink_parse_mode(struct phylink *pl, linkmode_copy(pl->link_config.advertising, pl->supported); - if (phylink_validate(pl, pl->supported, &pl->link_config)) { + if (phylink_validate(pl, pl->cfg_link_an_mode, pl->supported, + &pl->link_config)) { phylink_err(pl, "failed to validate link configuration for in-band status\n"); return -EINVAL; @@ -977,6 +987,15 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state) } } +static unsigned int phylink_pcs_query_inband(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + if (pcs && pcs->ops->pcs_query_inband) + return pcs->ops->pcs_query_inband(pcs, interface); + + return 0; +} + static void phylink_pcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) { @@ -1032,13 +1051,14 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, static void phylink_pcs_poll_stop(struct phylink *pl) { - if (pl->cfg_link_an_mode == MLO_AN_INBAND) + if (phylink_mode_inband(pl->cfg_link_an_mode)) del_timer(&pl->link_poll); } static void phylink_pcs_poll_start(struct phylink *pl) { - if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND) + if (pl->pcs && pl->pcs->poll && + phylink_mode_inband(pl->cfg_link_an_mode)) mod_timer(&pl->link_poll, jiffies + HZ); } @@ -1076,6 +1096,8 @@ static void phylink_pcs_an_restart(struct phylink *pl) /** * phylink_pcs_neg_mode() - helper to determine PCS inband mode + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @pcs: a pointer to &struct phylink_pcs * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND. * @interface: interface mode to be used * @advertising: adertisement ethtool link mode mask @@ -1093,11 +1115,19 @@ static void phylink_pcs_an_restart(struct phylink *pl) * Note: this is for cases where the PCS itself is involved in negotiation * (e.g. Clause 37, SGMII and similar) not Clause 73. */ -static unsigned int phylink_pcs_neg_mode(unsigned int mode, +static unsigned int phylink_pcs_neg_mode(struct phylink *pl, + struct phylink_pcs *pcs, + unsigned int mode, phy_interface_t interface, const unsigned long *advertising) { + unsigned int phy_link_mode = 0; + unsigned int pcs_link_mode; unsigned int neg_mode; + enum { + INBAND_CISCO_SGMII, + INBAND_8023Z, + } type; switch (interface) { case PHY_INTERFACE_MODE_SGMII: @@ -1109,10 +1139,7 @@ static unsigned int phylink_pcs_neg_mode(unsigned int mode, * inband communication. Note: there exist PHYs that run * with SGMII but do not send the inband data. */ - if (!phylink_autoneg_inband(mode)) - neg_mode = PHYLINK_PCS_NEG_OUTBAND; - else - neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + type = INBAND_CISCO_SGMII; break; case PHY_INTERFACE_MODE_1000BASEX: @@ -1123,20 +1150,92 @@ static unsigned int phylink_pcs_neg_mode(unsigned int mode, * as well, but drivers may not support this, so may * need to override this. */ - if (!phylink_autoneg_inband(mode)) - neg_mode = PHYLINK_PCS_NEG_OUTBAND; - else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - advertising)) - neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; - else - neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; + type = INBAND_8023Z; break; default: - neg_mode = PHYLINK_PCS_NEG_NONE; - break; + return PHYLINK_PCS_NEG_NONE; + } + + pcs_link_mode = phylink_pcs_query_inband(pcs, interface); + if (pl->phydev) + phy_link_mode = phy_query_inband(pl->phydev, interface); + + if (!phylink_autoneg_inband(mode)) { + /* If either the PCS or PHY requires inband to be enabled, + * this is an invalid configuration. Provide a diagnostic + * message for this case, but don't try to force the issue. + */ + if ((pcs_link_mode | phy_link_mode) & LINK_INBAND_REQUIRED) { + const char *s1, *s2, *s3, *empty = ""; + + s1 = s2 = s3 = empty; + if (pcs_link_mode & LINK_INBAND_REQUIRED) + s1 = "PCS"; + + if (phy_link_mode & LINK_INBAND_REQUIRED) + s3 = "PHY"; + + if (s1 != empty && s3 != empty) + s2 = " and "; + + phylink_warn(pl, + "firmware wants %s mode, but %s%s%s requires inband\n", + phylink_an_mode_str(mode), + s1, s2, s3); + } + return PHYLINK_PCS_NEG_OUTBAND; } + /* For SGMII modes, which are designed to be used with PHYs, we + * try to use inband mode where-ever possible. + */ + if (type == INBAND_CISCO_SGMII) { + /* If the PCS or PHY can not provide inband, then use + * out of band. + */ + if (pcs_link_mode == LINK_INBAND_VALID || + phy_link_mode == LINK_INBAND_VALID) { + /* If either require inband, then we have a conflict. */ + return PHYLINK_PCS_NEG_OUTBAND; + } + + /* Otherwise, use inband as this is what was requested. + * This covers the case where the supported inband modes + * have not been provided, or the PCS and PHY report that + * they support inband. + */ + return PHYLINK_PCS_NEG_INBAND_ENABLED; + } + + /* For 802.3z, handle the PHY present vs absent cases separately */ + if (!pl->phydev) { + /* PHY absent: always use inband but inband may be disabled */ + /* If the PCS doesn't support inband, then inband must be + * disabled. + */ + if (pcs_link_mode == LINK_INBAND_VALID) + return PHYLINK_PCS_NEG_INBAND_DISABLED; + + /* If the PCS requires inband, then inband must always be + * enabled. + */ + if (pcs_link_mode & LINK_INBAND_REQUIRED) + return PHYLINK_PCS_NEG_INBAND_ENABLED; + + /* For the possible case, fall through to the "legacy" code. */ + } else { + /* PHY present, inband mode depends on the capabilities + * of both. + */ + } + + /* Legacy, so determine inband depending on the advertising bit */ + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + else + neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; + return neg_mode; } @@ -1151,10 +1250,6 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); - pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, - state->interface, - state->advertising); - if (pl->using_mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) { @@ -1167,6 +1262,11 @@ static void phylink_major_config(struct phylink *pl, bool restart, pcs_changed = pcs && pl->pcs != pcs; } + pl->pcs_neg_mode = phylink_pcs_neg_mode(pl, pcs, + pl->cur_link_an_mode, + state->interface, + state->advertising); + phylink_pcs_poll_stop(pl); if (pl->mac_ops->mac_prepare) { @@ -1257,9 +1357,10 @@ static int phylink_change_inband_advert(struct phylink *pl) pl->link_config.pause); /* Recompute the PCS neg mode */ - pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, - pl->link_config.interface, - pl->link_config.advertising); + pl->pcs_neg_mode = phylink_pcs_neg_mode(pl, pl->pcs, + pl->cur_link_an_mode, + pl->link_config.interface, + pl->link_config.advertising); neg_mode = pl->cur_link_an_mode; if (pl->pcs->neg_mode) @@ -1365,6 +1466,75 @@ static const char *phylink_pause_to_str(int pause) } } +static void phylink_disable_tx_lpi(struct phylink *pl) +{ + phylink_dbg(pl, "disabling tx_lpi\n"); + + if (pl->mac_ops->mac_disable_tx_lpi) + pl->mac_ops->mac_disable_tx_lpi(pl->config); +} + +static void phylink_enable_tx_lpi(struct phylink *pl) +{ + phylink_dbg(pl, "enabling tx_lpi, timer %uus\n", + pl->eee_cfg.tx_lpi_timer); + + if (pl->mac_ops->mac_enable_tx_lpi) + pl->mac_ops->mac_enable_tx_lpi(pl->config, + pl->eee_cfg.tx_lpi_timer); +} + +static bool phylink_eee_is_active(struct phylink *pl) +{ + return phylink_init_eee(pl, pl->config->eee_clk_stop_enable) >= 0; +} + +static void phylink_deactivate_eee(struct phylink *pl) +{ + phylink_dbg(pl, "deactivating EEE, was %sactive\n", + pl->eee_active ? "" : "in"); + + if (pl->eee_active) { + pl->eee_active = false; + phylink_disable_tx_lpi(pl); + } +} + +static void phylink_activate_eee(struct phylink *pl) +{ + pl->eee_active = phylink_eee_is_active(pl); + + phylink_dbg(pl, "can LPI, EEE enabled, %sactive\n", + pl->eee_active ? "" : "in"); + + if (pl->eee_active) + phylink_enable_tx_lpi(pl); +} + +/* Determine whether the MAC has new EEE support. We detect this by checking + * for the two new methods being present, but for DSA it will populate these + * anyway, so also check that lpi_capabilities is non-zero. + */ +static bool phylink_mac_supports_eee(struct phylink *pl) +{ + return pl->mac_ops->mac_disable_tx_lpi && + pl->mac_ops->mac_enable_tx_lpi && + pl->config->lpi_capabilities; +} + +static void phylink_phy_restrict_eee(struct phylink *pl, struct phy_device *phy) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(eee_supported); + + /* Convert the MAC's LPI capabilities to linkmodes */ + linkmode_zero(eee_supported); + phylink_caps_to_linkmodes(eee_supported, pl->config->lpi_capabilities); + + /* Mask out EEE modes that are not supported */ + linkmode_and(phy->supported_eee, phy->supported_eee, eee_supported); + linkmode_and(phy->advertising_eee, phy->advertising_eee, eee_supported); +} + static void phylink_link_up(struct phylink *pl, struct phylink_link_state link_state) { @@ -1411,6 +1581,9 @@ static void phylink_link_up(struct phylink *pl, pl->cur_interface, speed, duplex, !!(link_state.pause & MLO_PAUSE_TX), rx_pause); + if (eeecfg_mac_can_tx_lpi(&pl->eee_cfg)) + phylink_activate_eee(pl); + if (ndev) netif_carrier_on(ndev); @@ -1427,25 +1600,29 @@ static void phylink_link_down(struct phylink *pl) if (ndev) netif_carrier_off(ndev); + + phylink_deactivate_eee(pl); + pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode, pl->cur_interface); phylink_info(pl, "Link is Down\n"); } +static bool phylink_link_is_up(struct phylink *pl) +{ + return pl->netdev ? netif_carrier_ok(pl->netdev) : pl->old_link_state; +} + static void phylink_resolve(struct work_struct *w) { struct phylink *pl = container_of(w, struct phylink, resolve); struct phylink_link_state link_state; - struct net_device *ndev = pl->netdev; bool mac_config = false; bool retrigger = false; bool cur_link_state; mutex_lock(&pl->state_mutex); - if (pl->netdev) - cur_link_state = netif_carrier_ok(ndev); - else - cur_link_state = pl->old_link_state; + cur_link_state = phylink_link_is_up(pl); if (pl->phylink_disable_state) { pl->mac_link_dropped = false; @@ -1681,7 +1858,10 @@ struct phylink *phylink_create(struct phylink_config *config, linkmode_fill(pl->supported); linkmode_copy(pl->link_config.advertising, pl->supported); - phylink_validate(pl, pl->supported, &pl->link_config); + phylink_validate(pl, MLO_AN_FIXED, pl->supported, &pl->link_config); + + /* Set the default EEE configuration */ + pl->eee_cfg = pl->config->eee; ret = phylink_parse_mode(pl, fwnode); if (ret < 0) { @@ -1689,7 +1869,7 @@ struct phylink *phylink_create(struct phylink_config *config, return ERR_PTR(ret); } - if (pl->cfg_link_an_mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(pl->cfg_link_an_mode)) { ret = phylink_parse_fixedlink(pl, fwnode); if (ret < 0) { kfree(pl); @@ -1783,6 +1963,9 @@ static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, struct phylink_link_state *state) { DECLARE_PHY_INTERFACE_MASK(interfaces); + unsigned int mode; + + mode = pl->cfg_link_an_mode; /* If the PHY provides a bitmap of the interfaces it will be using * depending on the negotiated media speeds, use this to validate @@ -1819,10 +2002,13 @@ static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, phy->possible_interfaces, (int)PHY_INTERFACE_MODE_MAX, interfaces); - return phylink_validate_mask(pl, phy, supported, state, + return phylink_validate_mask(pl, phy, mode, supported, state, interfaces); } + phylink_dbg(pl, "PHY %s doesn't supply possible interfaces\n", + phydev_name(phy)); + /* Check whether we would use rate matching for the proposed interface * mode. */ @@ -1845,7 +2031,7 @@ static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy, state->interface != PHY_INTERFACE_MODE_USXGMII) state->interface = PHY_INTERFACE_MODE_NA; - return phylink_validate(pl, supported, state); + return phylink_validate(pl, mode, supported, state); } static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, @@ -1902,6 +2088,13 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, /* Restrict the phy advertisement according to the MAC support. */ linkmode_copy(phy->advertising, config.advertising); + + /* If the MAC supports phylink managed EEE, restrict the EEE + * advertisement according to the MAC's LPI capabilities. + */ + if (phylink_mac_supports_eee(pl)) + phylink_phy_restrict_eee(pl, phy); + mutex_unlock(&pl->state_mutex); mutex_unlock(&phy->lock); @@ -1923,8 +2116,8 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, phy_interface_t interface) { - if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || - (pl->cfg_link_an_mode == MLO_AN_INBAND && + if (WARN_ON(phylink_mode_fixed(pl->cfg_link_an_mode) || + (phylink_mode_inband(pl->cfg_link_an_mode) && phy_interface_mode_is_8023z(interface) && !pl->sfp_bus))) return -EINVAL; @@ -2010,14 +2203,14 @@ int phylink_fwnode_phy_connect(struct phylink *pl, int ret; /* Fixed links and 802.3z are handled without needing a PHY */ - if (pl->cfg_link_an_mode == MLO_AN_FIXED || - (pl->cfg_link_an_mode == MLO_AN_INBAND && + if (phylink_mode_fixed(pl->cfg_link_an_mode) || + (phylink_mode_inband(pl->cfg_link_an_mode) && phy_interface_mode_is_8023z(pl->link_interface))) return 0; phy_fwnode = fwnode_get_phy_node(fwnode); if (IS_ERR(phy_fwnode)) { - if (pl->cfg_link_an_mode == MLO_AN_PHY) + if (phylink_mode_phy(pl->cfg_link_an_mode)) return -ENODEV; return 0; } @@ -2164,7 +2357,7 @@ void phylink_start(struct phylink *pl) phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_STOPPED); - if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) { + if (phylink_mode_fixed(pl->cfg_link_an_mode) && pl->link_gpio) { int irq = gpiod_to_irq(pl->link_gpio); if (irq > 0) { @@ -2431,6 +2624,39 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, } EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get); +static int phylink_query_inband(struct phylink *pl, phy_interface_t interface) +{ + struct phylink_pcs *pcs; + + if (!pl->using_mac_select_pcs) + return 0; + + pcs = pl->mac_ops->mac_select_pcs(pl->config, interface); + if (!pcs) + return 0; + + return phylink_pcs_query_inband(pcs, interface); +} + +static bool phylink_validate_pcs_an(struct phylink *pl, + phy_interface_t interface, bool an_state) +{ + int link_inband = phylink_query_inband(pl, interface); + + /* If the PCS doesn't implement inband support, be permissive. */ + if (!(link_inband & LINK_INBAND_VALID)) + return true; + + /* If the PCS can configure the use of inband, allow either state */ + if (link_inband & LINK_INBAND_POSSIBLE) + return true; + + /* Otherwise, require the AN state to be fixed according to the + * required flag. + */ + return an_state == !!(link_inband & LINK_INBAND_REQUIRED); +} + /** * phylink_ethtool_ksettings_set() - set the link settings * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -2492,7 +2718,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, /* If we have a fixed link, refuse to change link parameters. * If the link parameters match, accept them but do nothing. */ - if (pl->cur_link_an_mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(pl->cur_link_an_mode)) { if (s->speed != pl->link_config.speed || s->duplex != pl->link_config.duplex) return -EINVAL; @@ -2508,7 +2734,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, * is our default case) but do not allow the advertisement to * be changed. If the advertisement matches, simply return. */ - if (pl->cur_link_an_mode == MLO_AN_FIXED) { + if (phylink_mode_fixed(pl->cur_link_an_mode)) { if (!linkmode_equal(config.advertising, pl->link_config.advertising)) return -EINVAL; @@ -2546,7 +2772,8 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, /* Revalidate with the selected interface */ linkmode_copy(support, pl->supported); - if (phylink_validate(pl, support, &config)) { + if (phylink_validate(pl, pl->cur_link_an_mode, support, + &config)) { phylink_err(pl, "validation of %s/%s with support %*pb failed\n", phylink_an_mode_str(pl->cur_link_an_mode), phy_modes(config.interface), @@ -2556,7 +2783,8 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, } else { /* Validate without changing the current supported mask. */ linkmode_copy(support, pl->supported); - if (phylink_validate(pl, support, &config)) + if (phylink_validate(pl, pl->cur_link_an_mode, support, + &config)) return -EINVAL; } @@ -2566,6 +2794,14 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, phylink_is_empty_linkmode(config.advertising)) return -EINVAL; + /* Validate the autonegotiation state. We don't have a PHY in this + * situation, so the PCS is the media-facing entity. + */ + if (!phylink_validate_pcs_an(pl, config.interface, + linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + config.advertising))) + return -EINVAL; + mutex_lock(&pl->state_mutex); pl->link_config.speed = config.speed; pl->link_config.duplex = config.duplex; @@ -2648,7 +2884,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, ASSERT_RTNL(); - if (pl->cur_link_an_mode == MLO_AN_FIXED) + if (phylink_mode_fixed(pl->cur_link_an_mode)) return -EOPNOTSUPP; if (!phylink_test(pl->supported, Pause) && @@ -2756,6 +2992,8 @@ int phylink_init_eee(struct phylink *pl, bool clk_stop_enable) if (pl->phydev) ret = phy_init_eee(pl->phydev, clk_stop_enable); + else if (pl->sfp_bus && phylink_mac_supports_eee(pl)) + ret = 0; return ret; } @@ -2772,8 +3010,19 @@ int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee) ASSERT_RTNL(); - if (pl->phydev) + if (pl->phydev) { ret = phy_ethtool_get_eee(pl->phydev, eee); + } else if (pl->sfp_bus && phylink_mac_supports_eee(pl)) { + /* For optical SFPs, ensure that eee->supported is nonzero. */ + eee->supported = SUPPORTED_FIBRE; + ret = 0; + } + + if (!ret && phylink_mac_supports_eee(pl)) { + /* Overwrite phylib's interpretation of configuration */ + eeecfg_to_eee(&pl->eee_cfg, eee); + eee->eee_active = pl->eee_active; + } return ret; } @@ -2787,11 +3036,52 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee) { int ret = -EOPNOTSUPP; + bool mac_eee; ASSERT_RTNL(); + mac_eee = phylink_mac_supports_eee(pl); + + phylink_dbg(pl, "mac %s phylink EEE%s, adv 0x%08x, LPI%s timer %uus\n", + mac_eee ? "supports" : "does not support", + eee->eee_enabled ? ", enabled" : "", eee->advertised, + eee->tx_lpi_enabled ? " enabled" : "", eee->tx_lpi_timer); + + /* Clamp the LPI timer maximum value */ + if (mac_eee && eee->tx_lpi_timer > pl->config->lpi_timer_limit_us) { + eee->tx_lpi_timer = pl->config->lpi_timer_limit_us; + phylink_dbg(pl, "LPI timer limited to %uus\n", + eee->tx_lpi_timer); + } + if (pl->phydev) ret = phy_ethtool_set_eee(pl->phydev, eee); + else if (pl->sfp_bus && phylink_mac_supports_eee(pl)) + ret = 0; + + if (!ret && mac_eee) { + bool can_lpi, old_can_lpi; + + mutex_lock(&pl->state_mutex); + old_can_lpi = eeecfg_mac_can_tx_lpi(&pl->eee_cfg); + eee_to_eeecfg(eee, &pl->eee_cfg); + can_lpi = eeecfg_mac_can_tx_lpi(&pl->eee_cfg); + + phylink_dbg(pl, "can_lpi %u -> %u\n", old_can_lpi, can_lpi); + + /* If the link is up, and the configuration changes the + * LPI permissive state, deal with the change at the MAC. + */ + if (phylink_link_is_up(pl) && old_can_lpi != can_lpi) { + phylink_dbg(pl, "link is up, lpi changed\n"); + if (can_lpi) + phylink_activate_eee(pl); + else + phylink_deactivate_eee(pl); + } + + mutex_unlock(&pl->state_mutex); + } return ret; } @@ -3144,8 +3434,7 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, phylink_mac_initial_config(pl, false); } -static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, - struct phy_device *phy) +static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy) { __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); __ETHTOOL_DECLARE_LINK_MODE_MASK(support); @@ -3163,7 +3452,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, config.pause = MLO_PAUSE_AN; /* Ignore errors if we're expecting a PHY to attach later */ - ret = phylink_validate(pl, support, &config); + ret = phylink_validate(pl, pl->sfp_link_an_mode, support, &config); if (ret) { phylink_err(pl, "validation with support %*pb failed: %pe\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support, @@ -3181,11 +3470,11 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, config.interface = iface; linkmode_copy(support1, support); - ret = phylink_validate(pl, support1, &config); + ret = phylink_validate(pl, pl->sfp_link_an_mode, support1, &config); if (ret) { phylink_err(pl, "validation of %s/%s with support %*pb failed: %pe\n", - phylink_an_mode_str(mode), + phylink_an_mode_str(pl->sfp_link_an_mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support, ERR_PTR(ret)); @@ -3194,7 +3483,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, pl->link_port = pl->sfp_port; - phylink_sfp_set_config(pl, mode, support, &config); + phylink_sfp_set_config(pl, pl->sfp_link_an_mode, support, &config); return 0; } @@ -3233,8 +3522,8 @@ static int phylink_sfp_config_optical(struct phylink *pl) /* For all the interfaces that are supported, reduce the sfp_support * mask to only those link modes that can be supported. */ - ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config, - interfaces); + ret = phylink_validate_mask(pl, NULL, MLO_AN_INBAND, pl->sfp_support, + &config, interfaces); if (ret) { phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support); @@ -3250,10 +3539,17 @@ static int phylink_sfp_config_optical(struct phylink *pl) phylink_dbg(pl, "optical SFP: chosen %s interface\n", phy_modes(interface)); + if (!phylink_validate_pcs_an(pl, interface, + linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + config.advertising))) { + phylink_err(pl, "autoneg setting not compatible with PCS"); + return -EINVAL; + } + config.interface = interface; /* Ignore errors if we're expecting a PHY to attach later */ - ret = phylink_validate(pl, support, &config); + ret = phylink_validate(pl, MLO_AN_INBAND, support, &config); if (ret) { phylink_err(pl, "validation with support %*pb failed: %pe\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support, @@ -3279,6 +3575,7 @@ static int phylink_sfp_module_insert(void *upstream, phy_interface_zero(pl->sfp_interfaces); sfp_parse_support(pl->sfp_bus, id, pl->sfp_support, pl->sfp_interfaces); pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, pl->sfp_support); + pl->sfp_link_an_mode = MLO_AN_INBAND; /* If this module may have a PHY connecting later, defer until later */ pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); @@ -3334,21 +3631,12 @@ static void phylink_sfp_link_up(void *upstream) phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK); } -/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII - * or 802.3z control word, so inband will not work. - */ -static bool phylink_phy_no_inband(struct phy_device *phy) -{ - return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1], - 0xae025150, 0xfffffff0); -} - static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) { + DECLARE_PHY_INTERFACE_MASK(interfaces); struct phylink *pl = upstream; phy_interface_t interface; - u8 mode; - int ret; + int link_inband, ret; /* * This is the new way of dealing with flow control for PHYs, @@ -3359,21 +3647,63 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) */ phy_support_asym_pause(phy); - if (phylink_phy_no_inband(phy)) - mode = MLO_AN_PHY; - else - mode = MLO_AN_INBAND; - /* Set the PHY's host supported interfaces */ phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, pl->config->supported_interfaces); - /* Do the initial configuration */ - ret = phylink_sfp_config_phy(pl, mode, phy); - if (ret < 0) - return ret; + if (phy_interface_empty(phy->supported_interfaces)) { + phylink_dbg(pl, "copper SFP: PHY provides empty supported_interfaces\n"); + + /* Do the initial configuration */ + ret = phylink_sfp_config_phy(pl, phy); + if (ret < 0) + return ret; + } else { + phylink_dbg(pl, "copper SFP: interfaces=[mac=%*pbl, sfp=%*pbl]\n", + (int)PHY_INTERFACE_MODE_MAX, + pl->config->supported_interfaces, + (int)PHY_INTERFACE_MODE_MAX, + phy->supported_interfaces); + + phy_interface_and(interfaces, phy->supported_interfaces, + pl->config->supported_interfaces); + interface = phylink_choose_sfp_interface(pl, interfaces); + if (interface == PHY_INTERFACE_MODE_NA) { + phylink_err(pl, + "selection of interface for PHY failed\n"); + return -EINVAL; + } + + phylink_dbg(pl, "copper SFP: chosen %s interface\n", + phy_modes(interface)); + + link_inband = phy_query_inband(phy, interface); + phylink_dbg(pl, "copper SFP: PHY link in-band modes 0x%x\n", + link_inband); + + /* If the link inband is valid but the PHY doesn't support + * inband, then we have to use PHY mode. E.g. BCM84881. + */ + if (link_inband == LINK_INBAND_VALID) + pl->sfp_link_an_mode = MLO_AN_PHY; + + if (pl->cur_link_an_mode != pl->sfp_link_an_mode || + pl->link_config.interface != interface) { + pl->link_config.interface = interface; + pl->cur_link_an_mode = pl->sfp_link_an_mode; + + phylink_info(pl, "switched to %s/%s link mode\n", + phylink_an_mode_str(pl->sfp_link_an_mode), + phy_modes(interface)); + } + + if (!test_bit(PHYLINK_DISABLE_STOPPED, + &pl->phylink_disable_state)) + phylink_mac_initial_config(pl, false); + } interface = pl->link_config.interface; + ret = phylink_attach_phy(pl, phy, interface); if (ret < 0) return ret; @@ -3501,12 +3831,18 @@ static void phylink_decode_sgmii_word(struct phylink_link_state *state, * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word * * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation - * code word. Decode the USXGMII code word and populate the corresponding fields - * (speed, duplex) into the phylink_link_state structure. + * code word. Decode the USXGMII code word and populate the corresponding fields + * (speed, duplex) into the phylink_link_state structure. If the code word + * indicates link is down, or we are unable to decode it, set the link down. */ void phylink_decode_usxgmii_word(struct phylink_link_state *state, uint16_t lpa) { + if (!(lpa & MDIO_USXGMII_LINK)) { + state->link = false; + return; + } + switch (lpa & MDIO_USXGMII_SPD_MASK) { case MDIO_USXGMII_10: state->speed = SPEED_10; diff --git a/drivers/net/phy/sff.c b/drivers/net/phy/sff.c new file mode 100644 index 000000000000..a2eb56118dd4 --- /dev/null +++ b/drivers/net/phy/sff.c @@ -0,0 +1,114 @@ +#include +#include +#include "sff.h" + +const char *sff_link_len(char *buf, size_t size, unsigned int length, + unsigned int multiplier) +{ + if (length == 0) + return "unsupported/unspecified"; + + if (length == 255) { + *buf++ = '>'; + size -= 1; + length -= 1; + } + + length *= multiplier; + + if (length >= 1000) + snprintf(buf, size, "%u.%0*ukm", + length / 1000, + multiplier > 100 ? 1 : + multiplier > 10 ? 2 : 3, + length % 1000); + else + snprintf(buf, size, "%um", length); + + return buf; +} +EXPORT_SYMBOL_GPL(sff_link_len); + +const char *sff_bitfield(char *buf, size_t size, + const struct sff_bitfield *bits, unsigned int val) +{ + char *p = buf; + int n; + + *p = '\0'; + while (bits->mask) { + if ((val & bits->mask) == bits->val) { + n = snprintf(p, size, "%s%s", + buf != p ? ", " : "", + bits->str); + if (n == size) + break; + p += n; + size -= n; + } + bits++; + } + + return buf; +} +EXPORT_SYMBOL_GPL(sff_bitfield); + +const char *sff_connector(unsigned int connector) +{ + switch (connector) { + case SFF8024_CONNECTOR_UNSPEC: + return "unknown/unspecified"; + case SFF8024_CONNECTOR_SC: + return "SC"; + case SFF8024_CONNECTOR_FIBERJACK: + return "Fiberjack"; + case SFF8024_CONNECTOR_LC: + return "LC"; + case SFF8024_CONNECTOR_MT_RJ: + return "MT-RJ"; + case SFF8024_CONNECTOR_MU: + return "MU"; + case SFF8024_CONNECTOR_SG: + return "SG"; + case SFF8024_CONNECTOR_OPTICAL_PIGTAIL: + return "Optical pigtail"; + case SFF8024_CONNECTOR_MPO_1X12: + return "MPO 1X12"; + case SFF8024_CONNECTOR_MPO_2X16: + return "MPO 2X16"; + case SFF8024_CONNECTOR_HSSDC_II: + return "HSSDC II"; + case SFF8024_CONNECTOR_COPPER_PIGTAIL: + return "Copper pigtail"; + case SFF8024_CONNECTOR_RJ45: + return "RJ45"; + case SFF8024_CONNECTOR_MXC_2X16: + return "MXC 2X16"; + default: + return "unknown"; + } +} +EXPORT_SYMBOL_GPL(sff_connector); + +const char *sff_encoding(unsigned int encoding) +{ + switch (encoding) { + case SFF8024_ENCODING_UNSPEC: + return "unspecified"; + case SFF8024_ENCODING_8472_64B66B: + return "64b66b"; + case SFF8024_ENCODING_8B10B: + return "8b10b"; + case SFF8024_ENCODING_4B5B: + return "4b5b"; + case SFF8024_ENCODING_NRZ: + return "NRZ"; + case SFF8024_ENCODING_8472_MANCHESTER: + return "MANCHESTER"; + default: + return "unknown"; + } +} +EXPORT_SYMBOL_GPL(sff_encoding); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/sff.h b/drivers/net/phy/sff.h new file mode 100644 index 000000000000..cd7bb7c7ae4a --- /dev/null +++ b/drivers/net/phy/sff.h @@ -0,0 +1,16 @@ +#ifndef SFF_H +#define SFF_H + +struct sff_bitfield { + unsigned int mask; + unsigned int val; + const char *str; +}; + +const char *sff_link_len(char *buf, size_t size, unsigned int length, + unsigned int multiplier); +const char *sff_bitfield(char *buf, size_t size, + const struct sff_bitfield *bits, unsigned int val); +const char *sff_connector(unsigned int connector); +const char *sff_encoding(unsigned int encoding); +#endif diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index f75c9eb3958e..ddf671621796 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -16,6 +16,7 @@ #include #include +#include "sff.h" #include "sfp.h" #include "swphy.h" @@ -172,6 +173,7 @@ static const enum gpiod_flags gpio_flags[] = { #define T_WAIT msecs_to_jiffies(50) #define T_START_UP msecs_to_jiffies(300) #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) +#define T_START_UP_COOLED msecs_to_jiffies(90000) /* t_reset is the time required to assert the TX_DISABLE signal to reset * an indicated TX_FAULT. @@ -337,6 +339,7 @@ static const struct sff_data sfp_data = { static const struct of_device_id sfp_of_match[] = { { .compatible = "sff,sff", .data = &sff_data, }, { .compatible = "sff,sfp", .data = &sfp_data, }, + { .compatible = "sff,sfp+", .data = &sfp_data, }, { }, }; MODULE_DEVICE_TABLE(of, sfp_of_match); @@ -1663,6 +1666,114 @@ static void sfp_hwmon_exit(struct sfp *sfp) } #endif +static const struct sff_bitfield sfp_options[] = { + { + .mask = SFP_OPTIONS_HIGH_POWER_LEVEL, + .val = SFP_OPTIONS_HIGH_POWER_LEVEL, + .str = "hpl", + }, { + .mask = SFP_OPTIONS_PAGING_A2, + .val = SFP_OPTIONS_PAGING_A2, + .str = "paginga2", + }, { + .mask = SFP_OPTIONS_RETIMER, + .val = SFP_OPTIONS_RETIMER, + .str = "retimer", + }, { + .mask = SFP_OPTIONS_COOLED_XCVR, + .val = SFP_OPTIONS_COOLED_XCVR, + .str = "cooled", + }, { + .mask = SFP_OPTIONS_POWER_DECL, + .val = SFP_OPTIONS_POWER_DECL, + .str = "powerdecl", + }, { + .mask = SFP_OPTIONS_RX_LINEAR_OUT, + .val = SFP_OPTIONS_RX_LINEAR_OUT, + .str = "rxlinear", + }, { + .mask = SFP_OPTIONS_RX_DECISION_THRESH, + .val = SFP_OPTIONS_RX_DECISION_THRESH, + .str = "rxthresh", + }, { + .mask = SFP_OPTIONS_TUNABLE_TX, + .val = SFP_OPTIONS_TUNABLE_TX, + .str = "tunabletx", + }, { + .mask = SFP_OPTIONS_RATE_SELECT, + .val = SFP_OPTIONS_RATE_SELECT, + .str = "ratesel", + }, { + .mask = SFP_OPTIONS_TX_DISABLE, + .val = SFP_OPTIONS_TX_DISABLE, + .str = "txdisable", + }, { + .mask = SFP_OPTIONS_TX_FAULT, + .val = SFP_OPTIONS_TX_FAULT, + .str = "txfault", + }, { + .mask = SFP_OPTIONS_LOS_INVERTED, + .val = SFP_OPTIONS_LOS_INVERTED, + .str = "los-", + }, { + .mask = SFP_OPTIONS_LOS_NORMAL, + .val = SFP_OPTIONS_LOS_NORMAL, + .str = "los+", + }, { } +}; + +static const struct sff_bitfield diagmon[] = { + { + .mask = SFP_DIAGMON_DDM, + .val = SFP_DIAGMON_DDM, + .str = "ddm", + }, { + .mask = SFP_DIAGMON_INT_CAL, + .val = SFP_DIAGMON_INT_CAL, + .str = "intcal", + }, { + .mask = SFP_DIAGMON_EXT_CAL, + .val = SFP_DIAGMON_EXT_CAL, + .str = "extcal", + }, { + .mask = SFP_DIAGMON_RXPWR_AVG, + .val = SFP_DIAGMON_RXPWR_AVG, + .str = "rxpwravg", + }, { } +}; + +static const struct sff_bitfield sfp_enhopts[] = { + { + .mask = SFP_ENHOPTS_ALARMWARN, + .val = SFP_ENHOPTS_ALARMWARN, + .str = "alarmwarn", + }, { + .mask = SFP_ENHOPTS_SOFT_TX_DISABLE, + .val = SFP_ENHOPTS_SOFT_TX_DISABLE, + .str = "soft_tx_dis", + }, { + .mask = SFP_ENHOPTS_SOFT_TX_FAULT, + .val = SFP_ENHOPTS_SOFT_TX_FAULT, + .str = "soft_tx_fault", + }, { + .mask = SFP_ENHOPTS_SOFT_RX_LOS, + .val = SFP_ENHOPTS_SOFT_RX_LOS, + .str = "soft_rx_los", + }, { + .mask = SFP_ENHOPTS_SOFT_RATE_SELECT, + .val = SFP_ENHOPTS_SOFT_RATE_SELECT, + .str = "soft_rs", + }, { + .mask = SFP_ENHOPTS_APP_SELECT_SFF8079, + .val = SFP_ENHOPTS_APP_SELECT_SFF8079, + .str = "app_sel", + }, { + .mask = SFP_ENHOPTS_SOFT_RATE_SFF8431, + .val = SFP_ENHOPTS_SOFT_RATE_SFF8431, + .str = "soft_r8431", + }, { } +}; + /* Helpers */ static void sfp_module_tx_disable(struct sfp *sfp) { @@ -2164,6 +2275,111 @@ static int sfp_cotsworks_fixup_check(struct sfp *sfp, struct sfp_eeprom_id *id) return 0; } +static void sfp_print_module_info(struct sfp *sfp, + const struct sfp_eeprom_id *id, bool cotsworks) +{ + unsigned int br_nom, br_min, br_max; + char date[9]; + char options[80]; + + /* Cotsworks also gets the date code wrong. */ + date[0] = id->ext.datecode[4 - 2 * cotsworks]; + date[1] = id->ext.datecode[5 - 2 * cotsworks]; + date[2] = '-'; + date[3] = id->ext.datecode[2 + 2 * cotsworks]; + date[4] = id->ext.datecode[3 + 2 * cotsworks]; + date[5] = '-'; + date[6] = id->ext.datecode[0]; + date[7] = id->ext.datecode[1]; + date[8] = '\0'; + + if (id->base.br_nominal == 0) { + br_min = br_nom = br_max = 0; + } else if (id->base.br_nominal == 255) { + br_nom = 250 * id->ext.br_max; + br_max = br_nom + br_nom * id->ext.br_min / 100; + br_min = br_nom - br_nom * id->ext.br_min / 100; + } else { + br_nom = id->base.br_nominal * 100; + br_min = br_nom - id->base.br_nominal * id->ext.br_min; + br_max = br_nom + id->base.br_nominal * id->ext.br_max; + } + + dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %s\n", + (int)sizeof(id->base.vendor_name), id->base.vendor_name, + (int)sizeof(id->base.vendor_pn), id->base.vendor_pn, + (int)sizeof(id->base.vendor_rev), id->base.vendor_rev, + (int)sizeof(id->ext.vendor_sn), id->ext.vendor_sn, date); + dev_info(sfp->dev, " %s connector, encoding %s, bitrate %u.%03u (%u.%03u-%u.%03u) Gbps\n", + sff_connector(id->base.connector), + sff_encoding(id->base.encoding), + br_nom / 1000, br_nom % 1000, + br_min / 1000, br_min % 1000, br_max / 1000, br_max % 1000); + dev_info(sfp->dev, " 1000BaseSX%c 1000BaseLX%c 1000BaseCX%c 1000BaseT%c 100BaseLX%c 100BaseFX%c BaseBX10%c BasePX%c\n", + id->base.e1000_base_sx ? '+' : '-', + id->base.e1000_base_lx ? '+' : '-', + id->base.e1000_base_cx ? '+' : '-', + id->base.e1000_base_t ? '+' : '-', + id->base.e100_base_lx ? '+' : '-', + id->base.e100_base_fx ? '+' : '-', + id->base.e_base_bx10 ? '+' : '-', + id->base.e_base_px ? '+' : '-'); + dev_info(sfp->dev, " 10GBaseSR%c 10GBaseLR%c 10GBaseLRM%c 10GBaseER%c\n", + id->base.e10g_base_sr ? '+' : '-', + id->base.e10g_base_lr ? '+' : '-', + id->base.e10g_base_lrm ? '+' : '-', + id->base.e10g_base_er ? '+' : '-'); + + if (!id->base.sfp_ct_passive && !id->base.sfp_ct_active && + !id->base.e1000_base_t) { + char len_9um[16], len_om[16]; + + dev_info(sfp->dev, " Wavelength %unm, fiber lengths:\n", + be16_to_cpup(&id->base.optical_wavelength)); + + if (id->base.link_len[0] == 255) + strcpy(len_9um, ">254km"); + else if (id->base.link_len[1] && id->base.link_len[1] != 255) + sprintf(len_9um, "%um", + id->base.link_len[1] * 100); + else if (id->base.link_len[0]) + sprintf(len_9um, "%ukm", id->base.link_len[0]); + else if (id->base.link_len[1] == 255) + strcpy(len_9um, ">25.4km"); + else + strcpy(len_9um, "unsupported"); + + dev_info(sfp->dev, " 9µm SM : %s\n", len_9um); + dev_info(sfp->dev, " 62.5µm MM OM1: %s\n", + sff_link_len(len_om, sizeof(len_om), + id->base.link_len[3], 10)); + dev_info(sfp->dev, " 50µm MM OM2: %s\n", + sff_link_len(len_om, sizeof(len_om), + id->base.link_len[2], 10)); + dev_info(sfp->dev, " 50µm MM OM3: %s\n", + sff_link_len(len_om, sizeof(len_om), + id->base.link_len[5], 10)); + dev_info(sfp->dev, " 50µm MM OM4: %s\n", + sff_link_len(len_om, sizeof(len_om), + id->base.link_len[4], 10)); + } else { + char len[16]; + dev_info(sfp->dev, " Copper length: %s\n", + sff_link_len(len, sizeof(len), + id->base.link_len[4], 1)); + } + + dev_info(sfp->dev, " Options: %s\n", + sff_bitfield(options, sizeof(options), sfp_options, + be16_to_cpu(id->ext.options))); + dev_info(sfp->dev, " Diagnostics: %s\n", + sff_bitfield(options, sizeof(options), diagmon, + id->ext.diagmon)); + dev_info(sfp->dev, " EnhOpts: %s\n", + sff_bitfield(options, sizeof(options), sfp_enhopts, + id->ext.enhopts)); +} + static int sfp_module_parse_sff8472(struct sfp *sfp) { /* If the module requires address swap mode, warn about it */ @@ -2230,9 +2446,9 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) } } - /* Cotsworks do not seem to update the checksums when they - * do the final programming with the final module part number, - * serial number and date code. + /* Cotsworks do not seem to update the checksums when they update the + * module part number, serial number and date code. They also format + * the date code incorrectly. */ cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS ", 16); cotsworks_sfbg = !memcmp(id.base.vendor_pn, "SFBG", 4); @@ -2293,14 +2509,9 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) } } - sfp->id = id; + sfp_print_module_info(sfp, &id, cotsworks); - dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %.*s\n", - (int)sizeof(id.base.vendor_name), id.base.vendor_name, - (int)sizeof(id.base.vendor_pn), id.base.vendor_pn, - (int)sizeof(id.base.vendor_rev), id.base.vendor_rev, - (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn, - (int)sizeof(id.ext.datecode), id.ext.datecode); + sfp->id = id; /* Check whether we support this module */ if (!sfp->type->module_supported(&id)) { @@ -2334,8 +2545,11 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) mask |= SFP_F_RS0; if (sfp->gpio[GPIO_RS1]) mask |= SFP_F_RS1; + if (id.ext.options & cpu_to_be16(SFP_OPTIONS_COOLED_XCVR)) + sfp->module_t_start_up = T_START_UP_COOLED; + else + sfp->module_t_start_up = T_START_UP; - sfp->module_t_start_up = T_START_UP; sfp->module_t_wait = T_WAIT; sfp->phy_t_retry = T_PHY_RETRY; @@ -2585,10 +2799,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) break; if (sfp->state & SFP_F_TX_FAULT) { - /* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431) - * from the TX_DISABLE deassertion for the module to - * initialise, which is indicated by TX_FAULT - * deasserting. + /* Wait up to t_init (SFF-8472), t_start_up (SFF-8431), + * or t_start_up_cooled (SFF-8431) from the TX_DISABLE + * deassertion for the module to initialise, which is + * indicated by TX_FAULT deasserting. */ timeout = sfp->module_t_start_up; if (timeout > sfp->module_t_wait) @@ -2607,8 +2821,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) case SFP_S_INIT: if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { - /* TX_FAULT is still asserted after t_init - * or t_start_up, so assume there is a fault. + /* TX_FAULT is still asserted after t_init, t_start_up + * or t_start_up_cooled, so assume there is a fault. */ sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, sfp->sm_fault_retries == N_FAULT_INIT); diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c index 7fd9fe6a602b..7b1bc5fcef9b 100644 --- a/drivers/net/phy/xilinx_gmii2rgmii.c +++ b/drivers/net/phy/xilinx_gmii2rgmii.c @@ -22,7 +22,7 @@ struct gmii2rgmii { struct phy_device *phy_dev; - struct phy_driver *phy_drv; + const struct phy_driver *phy_drv; struct phy_driver conv_phy_drv; struct mdio_device *mdio; }; diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 79ceee3c8673..08d091913808 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -32,6 +32,8 @@ struct mdio_device { char modalias[MDIO_NAME_SIZE]; int (*bus_match)(struct device *dev, struct device_driver *drv); + int (*bus_uevent)(struct mdio_device *mdiodev, + struct kobj_uevent_env *env); void (*device_free)(struct mdio_device *mdiodev); void (*device_remove)(struct mdio_device *mdiodev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 684efaeca07c..ded6ce314710 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -638,7 +638,7 @@ struct phy_device { /* Information about the PHY type */ /* And management functions */ - struct phy_driver *drv; + const struct phy_driver *drv; struct device_link *devlink; @@ -691,6 +691,15 @@ struct phy_device { u8 master_slave_set; u8 master_slave_state; + /* + * private to phylib: the resolved pause state - only valid if + * resolved_pause_valid is true. only phy drivers and phylib + * should touch this. + */ + bool resolved_pause_valid; + bool resolved_tx_pause; + bool resolved_rx_pause; + /* Union of PHY and Attached devices' supported link modes */ /* See ethtool.h for more info */ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); @@ -706,6 +715,9 @@ struct phy_device { /* Host supported PHY interface types. Should be ignored if empty. */ DECLARE_PHY_INTERFACE_MASK(host_interfaces); + /* supported PHY interface types */ + DECLARE_PHY_INTERFACE_MASK(supported_interfaces); + /* Energy efficient ethernet modes which should be prohibited */ u32 eee_broken_modes; @@ -795,6 +807,24 @@ struct phy_tdr_config { }; #define PHY_PAIR_ALL -1 +/** + * enum link_inband_signalling - inband signalling modes that are supported + * + * @LINK_INBAND_VALID: inband signalling report is valid + * @LINK_INBAND_POSSIBLE: inband signalling can be used + * @LINK_INBAND_REQUIRED: inband signalling is required + * + * The possible and required bits can only be used if the valid bit is set. + * If possible is clear, that means inband signalling can not be used. + * Required is only valid when possible is set, and means that inband + * signalling must be used. + */ +enum link_inband_signalling { + LINK_INBAND_VALID = BIT(0), + LINK_INBAND_POSSIBLE = BIT(1), + LINK_INBAND_REQUIRED = BIT(2), +}; + /** * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision * Avoidance) Reconciliation Sublayer. @@ -924,6 +954,14 @@ struct phy_driver { */ int (*get_features)(struct phy_device *phydev); + /** + * @query_inband: query whether inband is supported for the given PHY + * interface mode. Returns a bitmask of bits defined by enum + * link_inband_signalling. + */ + unsigned int (*query_inband)(struct phy_device *phydev, + phy_interface_t interface); + /** * @get_rate_matching: Get the supported type of rate matching for a * particular phy interface. This is used by phy consumers to determine @@ -942,6 +980,9 @@ struct phy_driver { /** @resume: Resume the hardware, restoring state if needed */ int (*resume)(struct phy_device *phydev); + int (*start)(struct phy_device *phydev); + void (*stop)(struct phy_device *phydev); + /** * @config_aneg: Configures the advertisement and resets * autonegotiation if phydev->autoneg is on, @@ -1744,6 +1785,8 @@ int phy_config_aneg(struct phy_device *phydev); int _phy_start_aneg(struct phy_device *phydev); int phy_start_aneg(struct phy_device *phydev); int phy_aneg_done(struct phy_device *phydev); +unsigned int phy_query_inband(struct phy_device *phydev, + phy_interface_t interface); int phy_speed_down(struct phy_device *phydev, bool sync); int phy_speed_up(struct phy_device *phydev); bool phy_check_valid(int speed, int duplex, unsigned long *features); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index d589f89c612c..8664b3442a3a 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -5,6 +5,8 @@ #include #include +#include + struct device_node; struct ethtool_cmd; struct fwnode_handle; @@ -93,11 +95,26 @@ enum { MAC_400000FD = BIT(18), }; -static inline bool phylink_autoneg_inband(unsigned int mode) +static inline bool phylink_mode_inband(unsigned int mode) { return mode == MLO_AN_INBAND; } +static inline bool phylink_mode_fixed(unsigned int mode) +{ + return mode == MLO_AN_FIXED; +} + +static inline bool phylink_mode_phy(unsigned int mode) +{ + return mode == MLO_AN_PHY; +} + +static inline bool phylink_autoneg_inband(unsigned int mode) +{ + return phylink_mode_inband(mode); +} + /** * struct phylink_link_state - link state structure * @advertising: ethtool bitmask containing advertised link modes @@ -139,11 +156,15 @@ enum phylink_op_type { * if MAC link is at %MLO_AN_FIXED mode. * @mac_managed_pm: if true, indicate the MAC driver is responsible for PHY PM. * @ovr_an_inband: if true, override PCS to MLO_AN_INBAND + * @eee_clk_stop_enable: if true, PHY can stop the receive clock during LPI * @get_fixed_state: callback to execute to determine the fixed link state, * if MAC link is at %MLO_AN_FIXED mode. * @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx * are supported by the MAC/PCS. * @mac_capabilities: MAC pause/speed/duplex capabilities. + * @lpi_capabilities: MAC speeds which can support LPI signalling + * @eee: default EEE configuration. + * @lpi_timer_limit_us: Maximum (inclusive) value of the EEE LPI timer. */ struct phylink_config { struct device *dev; @@ -151,10 +172,14 @@ struct phylink_config { bool poll_fixed_state; bool mac_managed_pm; bool ovr_an_inband; + bool eee_clk_stop_enable; void (*get_fixed_state)(struct phylink_config *config, struct phylink_link_state *state); DECLARE_PHY_INTERFACE_MASK(supported_interfaces); unsigned long mac_capabilities; + unsigned long lpi_capabilities; + struct eee_config eee; + u32 lpi_timer_limit_us; }; void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed); @@ -168,6 +193,8 @@ void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed); * @mac_finish: finish a major reconfiguration of the interface. * @mac_link_down: take the link down. * @mac_link_up: allow the link to come up. + * @mac_disable_tx_lpi: disable LPI. + * @mac_enable_tx_lpi: enable and configure LPI. * * The individual methods are described more fully below. */ @@ -188,6 +215,8 @@ struct phylink_mac_ops { struct phy_device *phy, unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause); + void (*mac_disable_tx_lpi)(struct phylink_config *config); + void (*mac_enable_tx_lpi)(struct phylink_config *config, u32 timer); }; #if 0 /* For kernel-doc purposes only. */ @@ -382,6 +411,28 @@ void mac_link_down(struct phylink_config *config, unsigned int mode, void mac_link_up(struct phylink_config *config, struct phy_device *phy, unsigned int mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause); + +/** + * mac_disable_tx_lpi() - disable LPI generation at the MAC + * @config: a pointer to a &struct phylink_config. + * + * Disable generation of LPI at the MAC, effectively preventing the MAC + * from indicating that it is idle. + */ +void mac_disable_tx_lpi(struct phylink_config *config); + +/** + * mac_enable_tx_lpi() - configure and enable LPI generation at the MAC + * @config: a pointer to a &struct phylink_config. + * @timer: LPI timeout in microseconds. + * + * Configure the LPI timeout accordingly. This will only be called when + * the link is already up, to cater for situations where the hardware + * needs to be programmed according to the link speed. + * + * Enable LPI generation at the MAC. + */ +void mac_enable_tx_lpi(struct phylink_config *config, u32 timer); #endif struct phylink_pcs_ops; @@ -409,6 +460,7 @@ struct phylink_pcs { /** * struct phylink_pcs_ops - MAC PCS operations structure. * @pcs_validate: validate the link configuration. + * @pcs_query_inband: query inband support for interface mode. * @pcs_enable: enable the PCS. * @pcs_disable: disable the PCS. * @pcs_pre_config: pre-mac_config method (for errata) @@ -420,8 +472,11 @@ struct phylink_pcs { * (where necessary). */ struct phylink_pcs_ops { - int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, + int (*pcs_validate)(struct phylink_pcs *pcs, unsigned int mode, + unsigned long *supported, const struct phylink_link_state *state); + unsigned int (*pcs_query_inband)(struct phylink_pcs *pcs, + phy_interface_t interface); int (*pcs_enable)(struct phylink_pcs *pcs); void (*pcs_disable)(struct phylink_pcs *pcs); void (*pcs_pre_config)(struct phylink_pcs *pcs, @@ -443,6 +498,7 @@ struct phylink_pcs_ops { /** * pcs_validate() - validate the link configuration. * @pcs: a pointer to a &struct phylink_pcs. + * @mode: link autonegotiation mode * @supported: ethtool bitmask for supported link modes. * @state: a const pointer to a &struct phylink_link_state. * @@ -454,8 +510,22 @@ struct phylink_pcs_ops { * Returns -EINVAL if the interface mode/autoneg mode is not supported. * Returns non-zero positive if the link state can be supported. */ -int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported, - const struct phylink_link_state *state); +int pcs_validate(struct phylink_pcs *pcs, unsigned int mode, + unsigned long *supported, struct phylink_link_state *state); + +/** + * pcs_query_inband - query inband support for interface mode. + * @pcs: a pointer to a &struct phylink_pcs. + * @interface: interface mode to be queried + * + * Returns zero if it is unknown what in-band signalling is supported by the + * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, + * returns a bit mask of the LINK_INBAND_* values from + * &enum link_inband_signalling to describe which inband modes are supported + * for this interface mode. + */ +unsigned int pcs_query_inband(struct phylink_pcs *pcs, + phy_interface_t interface); /** * pcs_enable() - enable the PCS. diff --git a/include/net/dsa.h b/include/net/dsa.h index 82135fbdb1e6..340f04d21cd1 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -327,6 +327,12 @@ struct dsa_port { }; }; +static inline struct dsa_port * +dsa_phylink_to_port(struct phylink_config *config) +{ + return container_of(config, struct dsa_port, pl_config); +} + /* TODO: ideally DSA ports would have a single dp->link_dp member, * and no dst->rtable nor this struct dsa_link would be needed, * but this would require some more complex tree walking, @@ -451,6 +457,11 @@ struct dsa_switch { */ const struct dsa_switch_ops *ops; + /* + * Allow a DSA switch driver to override the phylink MAC ops + */ + const struct phylink_mac_ops *phylink_mac_ops; + /* * User mii_bus and devices for the individual ports. */ @@ -891,6 +902,9 @@ struct dsa_switch_ops { struct phy_device *phydev, int speed, int duplex, bool tx_pause, bool rx_pause); + void (*phylink_mac_disable_tx_lpi)(struct dsa_switch *ds, int port); + void (*phylink_mac_enable_tx_lpi)(struct dsa_switch *ds, int port, + u32 timer); void (*phylink_fixed_state)(struct dsa_switch *ds, int port, struct phylink_link_state *state); /* diff --git a/include/net/eee.h b/include/net/eee.h new file mode 100644 index 000000000000..d353b79ae79f --- /dev/null +++ b/include/net/eee.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _EEE_H +#define _EEE_H + +#include + +struct eee_config { + u32 tx_lpi_timer; + bool tx_lpi_enabled; + bool eee_enabled; +}; + +static inline bool eeecfg_mac_can_tx_lpi(const struct eee_config *eeecfg) +{ + /* eee_enabled is the master on/off */ + if (!eeecfg->eee_enabled || !eeecfg->tx_lpi_enabled) + return false; + + return true; +} + +static inline void eeecfg_to_eee(const struct eee_config *eeecfg, + struct ethtool_eee *eee) +{ + eee->tx_lpi_timer = eeecfg->tx_lpi_timer; + eee->tx_lpi_enabled = eeecfg->tx_lpi_enabled; + eee->eee_enabled = eeecfg->eee_enabled; +} + +static inline void eee_to_eeecfg(const struct ethtool_eee *eee, + struct eee_config *eeecfg) +{ + eeecfg->tx_lpi_timer = eee->tx_lpi_timer; + eeecfg->tx_lpi_enabled = eee->tx_lpi_enabled; + eeecfg->eee_enabled = eee->eee_enabled; +} + +#endif diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ac7be864e80d..a2479f133005 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -1510,6 +1510,17 @@ static int dsa_switch_probe(struct dsa_switch *ds) if (!ds->num_ports) return -EINVAL; + if (ds->phylink_mac_ops) { + if (ds->ops->phylink_mac_select_pcs || + ds->ops->phylink_mac_prepare || + ds->ops->phylink_mac_config || + ds->ops->phylink_mac_finish || + ds->ops->phylink_mac_link_down || + ds->ops->phylink_mac_link_up || + ds->ops->adjust_link) + return -EINVAL; + } + if (np) { err = dsa_switch_parse_of(ds, np); if (err) diff --git a/net/dsa/port.c b/net/dsa/port.c index c42dac87671b..f8499c50dd40 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -1558,7 +1558,7 @@ static struct phylink_pcs * dsa_port_phylink_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); struct dsa_switch *ds = dp->ds; @@ -1572,7 +1572,7 @@ static int dsa_port_phylink_mac_prepare(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct dsa_switch *ds = dp->ds; int err = 0; @@ -1587,7 +1587,7 @@ static void dsa_port_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct dsa_switch *ds = dp->ds; if (!ds->ops->phylink_mac_config) @@ -1600,7 +1600,7 @@ static int dsa_port_phylink_mac_finish(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct dsa_switch *ds = dp->ds; int err = 0; @@ -1615,7 +1615,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct phy_device *phydev = NULL; struct dsa_switch *ds = dp->ds; @@ -1638,7 +1638,7 @@ static void dsa_port_phylink_mac_link_up(struct phylink_config *config, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct dsa_switch *ds = dp->ds; if (!ds->ops->phylink_mac_link_up) { @@ -1651,6 +1651,26 @@ static void dsa_port_phylink_mac_link_up(struct phylink_config *config, speed, duplex, tx_pause, rx_pause); } +static void dsa_port_phylink_mac_disable_tx_lpi(struct phylink_config *config) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->phylink_mac_disable_tx_lpi) + ds->ops->phylink_mac_disable_tx_lpi(ds, dp->index); + +} + +static void dsa_port_phylink_mac_enable_tx_lpi(struct phylink_config *config, + u32 timer) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->phylink_mac_enable_tx_lpi) + ds->ops->phylink_mac_enable_tx_lpi(ds, dp->index, timer); +} + static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .mac_select_pcs = dsa_port_phylink_mac_select_pcs, .mac_prepare = dsa_port_phylink_mac_prepare, @@ -1658,10 +1678,13 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .mac_finish = dsa_port_phylink_mac_finish, .mac_link_down = dsa_port_phylink_mac_link_down, .mac_link_up = dsa_port_phylink_mac_link_up, + .mac_disable_tx_lpi = dsa_port_phylink_mac_disable_tx_lpi, + .mac_enable_tx_lpi = dsa_port_phylink_mac_enable_tx_lpi, }; int dsa_port_phylink_create(struct dsa_port *dp) { + const struct phylink_mac_ops *mac_ops; struct dsa_switch *ds = dp->ds; phy_interface_t mode; struct phylink *pl; @@ -1685,8 +1708,12 @@ int dsa_port_phylink_create(struct dsa_port *dp) } } - pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), - mode, &dsa_port_phylink_mac_ops); + mac_ops = &dsa_port_phylink_mac_ops; + if (ds->phylink_mac_ops) + mac_ops = ds->phylink_mac_ops; + + pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode, + mac_ops); if (IS_ERR(pl)) { pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl)); return PTR_ERR(pl); @@ -1952,12 +1979,23 @@ static void dsa_shared_port_validate_of(struct dsa_port *dp, dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); } +static void dsa_shared_port_link_down(struct dsa_port *dp) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down) + ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED, + PHY_INTERFACE_MODE_NA); + else if (ds->ops->phylink_mac_link_down) + ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED, + PHY_INTERFACE_MODE_NA); +} + int dsa_shared_port_link_register_of(struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; bool missing_link_description; bool missing_phy_mode; - int port = dp->index; dsa_shared_port_validate_of(dp, &missing_phy_mode, &missing_link_description); @@ -1973,9 +2011,7 @@ int dsa_shared_port_link_register_of(struct dsa_port *dp) "Skipping phylink registration for %s port %d\n", dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); } else { - if (ds->ops->phylink_mac_link_down) - ds->ops->phylink_mac_link_down(ds, port, - MLO_AN_FIXED, PHY_INTERFACE_MODE_NA); + dsa_shared_port_link_down(dp); return dsa_shared_port_phylink_register(dp); } diff --git a/net/dsa/user.c b/net/dsa/user.c index b15e71cc342c..a0ee4d338d1f 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -1228,16 +1228,21 @@ static int dsa_user_set_eee(struct net_device *dev, struct ethtool_eee *e) struct dsa_switch *ds = dp->ds; int ret; - /* Port's PHY and MAC both need to be EEE capable */ - if (!dev->phydev || !dp->pl) - return -ENODEV; + /* If the port is using phylink managed EEE, then get_mac_eee is + * unnecessary. + */ + if (!dp->pl_config.lpi_capabilities) { + /* Port's PHY and MAC both need to be EEE capable */ + if (!dev->phydev || !dp->pl) + return -ENODEV; - if (!ds->ops->set_mac_eee) - return -EOPNOTSUPP; + if (!ds->ops->set_mac_eee) + return -EOPNOTSUPP; - ret = ds->ops->set_mac_eee(ds, dp->index, e); - if (ret) - return ret; + ret = ds->ops->set_mac_eee(ds, dp->index, e); + if (ret) + return ret; + } return phylink_ethtool_set_eee(dp->pl, e); } @@ -1248,16 +1253,21 @@ static int dsa_user_get_eee(struct net_device *dev, struct ethtool_eee *e) struct dsa_switch *ds = dp->ds; int ret; - /* Port's PHY and MAC both need to be EEE capable */ - if (!dev->phydev || !dp->pl) - return -ENODEV; + /* If the port is using phylink managed EEE, then get_mac_eee is + * unnecessary. + */ + if (!dp->pl_config.lpi_capabilities) { + /* Port's PHY and MAC both need to be EEE capable */ + if (!dev->phydev || !dp->pl) + return -ENODEV; - if (!ds->ops->get_mac_eee) - return -EOPNOTSUPP; + if (!ds->ops->get_mac_eee) + return -EOPNOTSUPP; - ret = ds->ops->get_mac_eee(ds, dp->index, e); - if (ret) - return ret; + ret = ds->ops->get_mac_eee(ds, dp->index, e); + if (ret) + return ret; + } return phylink_ethtool_get_eee(dp->pl, e); } @@ -2445,7 +2455,7 @@ EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); static void dsa_user_phylink_fixed_state(struct phylink_config *config, struct phylink_link_state *state) { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_port *dp = dsa_phylink_to_port(config); struct dsa_switch *ds = dp->ds; /* No need to check that this operation is valid, the callback would