mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	generic: 6.1: backport patch adding support for LED PHY
Backport patch adding support for LED PHY directly in PHY ops struct. Add new PHYLIB_LEDS config and refresh patches. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
		
							parent
							
								
									c46ac89ec6
								
							
						
					
					
						commit
						6b63fcf8df
					
				@ -0,0 +1,65 @@
 | 
			
		||||
From 4bb7aac70b5d8a4bddf4ee0791b834f9f56883d2 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Arnd Bergmann <arnd@arndb.de>
 | 
			
		||||
Date: Thu, 20 Apr 2023 10:45:51 +0200
 | 
			
		||||
Subject: [PATCH] net: phy: fix circular LEDS_CLASS dependencies
 | 
			
		||||
 | 
			
		||||
The CONFIG_PHYLIB symbol is selected by a number of device drivers that
 | 
			
		||||
need PHY support, but it now has a dependency on CONFIG_LEDS_CLASS,
 | 
			
		||||
which may not be enabled, causing build failures.
 | 
			
		||||
 | 
			
		||||
Avoid the risk of missing and circular dependencies by guarding the
 | 
			
		||||
phylib LED support itself in another Kconfig symbol that can only be
 | 
			
		||||
enabled if the dependency is met.
 | 
			
		||||
 | 
			
		||||
This could be made a hidden symbol and always enabled when both CONFIG_OF
 | 
			
		||||
and CONFIG_LEDS_CLASS are reachable from the phylib, but there may be an
 | 
			
		||||
advantage in having users see this option when they have a misconfigured
 | 
			
		||||
kernel without built-in LED support.
 | 
			
		||||
 | 
			
		||||
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
 | 
			
		||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
 | 
			
		||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230420084624.3005701-1-arnd@kernel.org
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/Kconfig      | 9 ++++++++-
 | 
			
		||||
 drivers/net/phy/phy_device.c | 3 ++-
 | 
			
		||||
 2 files changed, 10 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -18,7 +18,6 @@ menuconfig PHYLIB
 | 
			
		||||
 	depends on NETDEVICES
 | 
			
		||||
 	select MDIO_DEVICE
 | 
			
		||||
 	select MDIO_DEVRES
 | 
			
		||||
-	depends on LEDS_CLASS || LEDS_CLASS=n
 | 
			
		||||
 	help
 | 
			
		||||
 	  Ethernet controllers are usually attached to PHY
 | 
			
		||||
 	  devices.  This option provides infrastructure for
 | 
			
		||||
@@ -45,6 +44,14 @@ config LED_TRIGGER_PHY
 | 
			
		||||
 		<Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link
 | 
			
		||||
 		for any speed known to the PHY.
 | 
			
		||||
 
 | 
			
		||||
+config PHYLIB_LEDS
 | 
			
		||||
+	bool "Support probing LEDs from device tree"
 | 
			
		||||
+	depends on LEDS_CLASS=y || LEDS_CLASS=PHYLIB
 | 
			
		||||
+	depends on OF
 | 
			
		||||
+	default y
 | 
			
		||||
+	help
 | 
			
		||||
+	  When LED class support is enabled, phylib can automatically
 | 
			
		||||
+	  probe LED setting from device tree.
 | 
			
		||||
 
 | 
			
		||||
 config FIXED_PHY
 | 
			
		||||
 	tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -3208,7 +3208,8 @@ static int phy_probe(struct device *dev)
 | 
			
		||||
 	/* Get the LEDs from the device tree, and instantiate standard
 | 
			
		||||
 	 * LEDs for them.
 | 
			
		||||
 	 */
 | 
			
		||||
-	err = of_phy_leds(phydev);
 | 
			
		||||
+	if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
 | 
			
		||||
+		err = of_phy_leds(phydev);
 | 
			
		||||
 
 | 
			
		||||
 out:
 | 
			
		||||
 	/* Re-assert the reset signal on error */
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
From aed8fdad2152d946add50bec00a6b07c457bdcdf Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Alexander Stein <alexander.stein@ew.tq-group.com>
 | 
			
		||||
Date: Mon, 24 Apr 2023 16:16:48 +0200
 | 
			
		||||
Subject: [PATCH] net: phy: Fix reading LED reg property
 | 
			
		||||
 | 
			
		||||
'reg' is always encoded in 32 bits, thus it has to be read using the
 | 
			
		||||
function with the corresponding bit width.
 | 
			
		||||
 | 
			
		||||
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
 | 
			
		||||
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
 | 
			
		||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230424141648.317944-1-alexander.stein@ew.tq-group.com
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy_device.c | 6 +++++-
 | 
			
		||||
 1 file changed, 5 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -2971,6 +2971,7 @@ static int of_phy_led(struct phy_device
 | 
			
		||||
 	struct led_init_data init_data = {};
 | 
			
		||||
 	struct led_classdev *cdev;
 | 
			
		||||
 	struct phy_led *phyled;
 | 
			
		||||
+	u32 index;
 | 
			
		||||
 	int err;
 | 
			
		||||
 
 | 
			
		||||
 	phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
 | 
			
		||||
@@ -2980,10 +2981,13 @@ static int of_phy_led(struct phy_device
 | 
			
		||||
 	cdev = &phyled->led_cdev;
 | 
			
		||||
 	phyled->phydev = phydev;
 | 
			
		||||
 
 | 
			
		||||
-	err = of_property_read_u8(led, "reg", &phyled->index);
 | 
			
		||||
+	err = of_property_read_u32(led, "reg", &index);
 | 
			
		||||
 	if (err)
 | 
			
		||||
 		return err;
 | 
			
		||||
+	if (index > U8_MAX)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
 
 | 
			
		||||
+	phyled->index = index;
 | 
			
		||||
 	if (phydev->drv->led_brightness_set)
 | 
			
		||||
 		cdev->brightness_set_blocking = phy_led_set_brightness;
 | 
			
		||||
 	if (phydev->drv->led_blink_set)
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
From c938ab4da0eb1620ae3243b0b24c572ddfc318fc Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Date: Sat, 17 Jun 2023 17:55:00 +0200
 | 
			
		||||
Subject: [PATCH] net: phy: Manual remove LEDs to ensure correct ordering
 | 
			
		||||
 | 
			
		||||
If the core is left to remove the LEDs via devm_, it is performed too
 | 
			
		||||
late, after the PHY driver is removed from the PHY. This results in
 | 
			
		||||
dereferencing a NULL pointer when the LED core tries to turn the LED
 | 
			
		||||
off before destroying the LED.
 | 
			
		||||
 | 
			
		||||
Manually unregister the LEDs at a safe point in phy_remove.
 | 
			
		||||
 | 
			
		||||
Cc: stable@vger.kernel.org
 | 
			
		||||
Reported-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Suggested-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
			
		||||
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy_device.c | 15 ++++++++++++++-
 | 
			
		||||
 1 file changed, 14 insertions(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -2964,6 +2964,15 @@ static int phy_led_blink_set(struct led_
 | 
			
		||||
 	return err;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void phy_leds_unregister(struct phy_device *phydev)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phy_led *phyled;
 | 
			
		||||
+
 | 
			
		||||
+	list_for_each_entry(phyled, &phydev->leds, list) {
 | 
			
		||||
+		led_classdev_unregister(&phyled->led_cdev);
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int of_phy_led(struct phy_device *phydev,
 | 
			
		||||
 		      struct device_node *led)
 | 
			
		||||
 {
 | 
			
		||||
@@ -2997,7 +3006,7 @@ static int of_phy_led(struct phy_device
 | 
			
		||||
 	init_data.fwnode = of_fwnode_handle(led);
 | 
			
		||||
 	init_data.devname_mandatory = true;
 | 
			
		||||
 
 | 
			
		||||
-	err = devm_led_classdev_register_ext(dev, cdev, &init_data);
 | 
			
		||||
+	err = led_classdev_register_ext(dev, cdev, &init_data);
 | 
			
		||||
 	if (err)
 | 
			
		||||
 		return err;
 | 
			
		||||
 
 | 
			
		||||
@@ -3026,6 +3035,7 @@ static int of_phy_leds(struct phy_device
 | 
			
		||||
 		err = of_phy_led(phydev, led);
 | 
			
		||||
 		if (err) {
 | 
			
		||||
 			of_node_put(led);
 | 
			
		||||
+			phy_leds_unregister(phydev);
 | 
			
		||||
 			return err;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
@@ -3229,6 +3239,9 @@ static int phy_remove(struct device *dev
 | 
			
		||||
 
 | 
			
		||||
 	cancel_delayed_work_sync(&phydev->state_queue);
 | 
			
		||||
 
 | 
			
		||||
+	if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
 | 
			
		||||
+		phy_leds_unregister(phydev);
 | 
			
		||||
+
 | 
			
		||||
 	phydev->state = PHY_DOWN;
 | 
			
		||||
 
 | 
			
		||||
 	sfp_bus_del_upstream(phydev->sfp_bus);
 | 
			
		||||
@ -0,0 +1,44 @@
 | 
			
		||||
From af7320ecae0ce646fd2c4a88341a3fbc243553da Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Yang Li <yang.lee@linux.alibaba.com>
 | 
			
		||||
Date: Thu, 11 May 2023 15:08:20 +0800
 | 
			
		||||
Subject: [PATCH] leds: trigger: netdev: Remove NULL check before dev_{put,
 | 
			
		||||
 hold}
 | 
			
		||||
 | 
			
		||||
The call netdev_{put, hold} of dev_{put, hold} will check NULL,
 | 
			
		||||
so there is no need to check before using dev_{put, hold},
 | 
			
		||||
remove it to silence the warnings:
 | 
			
		||||
 | 
			
		||||
./drivers/leds/trigger/ledtrig-netdev.c:291:3-10: WARNING: NULL check before dev_{put, hold} functions is not needed.
 | 
			
		||||
./drivers/leds/trigger/ledtrig-netdev.c:401:2-9: WARNING: NULL check before dev_{put, hold} functions is not needed.
 | 
			
		||||
 | 
			
		||||
Reported-by: Abaci Robot <abaci@linux.alibaba.com>
 | 
			
		||||
Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=4929
 | 
			
		||||
Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230511070820.52731-1-yang.lee@linux.alibaba.com
 | 
			
		||||
Signed-off-by: Lee Jones <lee@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/leds/trigger/ledtrig-netdev.c | 6 ++----
 | 
			
		||||
 1 file changed, 2 insertions(+), 4 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
@@ -462,8 +462,7 @@ static int netdev_trig_notify(struct not
 | 
			
		||||
 		get_device_state(trigger_data);
 | 
			
		||||
 		fallthrough;
 | 
			
		||||
 	case NETDEV_REGISTER:
 | 
			
		||||
-		if (trigger_data->net_dev)
 | 
			
		||||
-			dev_put(trigger_data->net_dev);
 | 
			
		||||
+		dev_put(trigger_data->net_dev);
 | 
			
		||||
 		dev_hold(dev);
 | 
			
		||||
 		trigger_data->net_dev = dev;
 | 
			
		||||
 		break;
 | 
			
		||||
@@ -594,8 +593,7 @@ static void netdev_trig_deactivate(struc
 | 
			
		||||
 
 | 
			
		||||
 	cancel_delayed_work_sync(&trigger_data->work);
 | 
			
		||||
 
 | 
			
		||||
-	if (trigger_data->net_dev)
 | 
			
		||||
-		dev_put(trigger_data->net_dev);
 | 
			
		||||
+	dev_put(trigger_data->net_dev);
 | 
			
		||||
 
 | 
			
		||||
 	kfree(trigger_data);
 | 
			
		||||
 }
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
From 97c5209b3d374a25ebdb4c2ea9e9c1b121768da0 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Dan Carpenter <dan.carpenter@linaro.org>
 | 
			
		||||
Date: Wed, 14 Jun 2023 10:03:59 +0300
 | 
			
		||||
Subject: [PATCH] leds: trigger: netdev: uninitialized variable in
 | 
			
		||||
 netdev_trig_activate()
 | 
			
		||||
 | 
			
		||||
The qca8k_cled_hw_control_get() function which implements ->hw_control_get
 | 
			
		||||
sets the appropriate bits but does not clear them.  This leads to an
 | 
			
		||||
uninitialized variable bug.  Fix this by setting mode to zero at the
 | 
			
		||||
start.
 | 
			
		||||
 | 
			
		||||
Fixes: e0256648c831 ("net: dsa: qca8k: implement hw_control ops")
 | 
			
		||||
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
 | 
			
		||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Acked-by: Lee Jones <lee@kernel.org>
 | 
			
		||||
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
			
		||||
---
 | 
			
		||||
 drivers/leds/trigger/ledtrig-netdev.c | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
@@ -538,7 +538,7 @@ static void netdev_trig_work(struct work
 | 
			
		||||
 static int netdev_trig_activate(struct led_classdev *led_cdev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct led_netdev_data *trigger_data;
 | 
			
		||||
-	unsigned long mode;
 | 
			
		||||
+	unsigned long mode = 0;
 | 
			
		||||
 	struct device *dev;
 | 
			
		||||
 	int rc;
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,57 @@
 | 
			
		||||
From 7df1f14c04cbb1950e79c19793420f87227c3e80 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Date: Tue, 8 Aug 2023 23:04:33 +0200
 | 
			
		||||
Subject: [PATCH 1/4] led: trig: netdev: Fix requesting offload device
 | 
			
		||||
 | 
			
		||||
When the netdev trigger is activates, it tries to determine what
 | 
			
		||||
device the LED blinks for, and what the current blink mode is.
 | 
			
		||||
 | 
			
		||||
The documentation for hw_control_get() says:
 | 
			
		||||
 | 
			
		||||
	 * Return 0 on success, a negative error number on failing parsing the
 | 
			
		||||
	 * initial mode. Error from this function is NOT FATAL as the device
 | 
			
		||||
	 * may be in a not supported initial state by the attached LED trigger.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
For the Marvell PHY and the Armada 370-rd board, the initial LED blink
 | 
			
		||||
mode is not supported by the trigger, so it returns an error. This
 | 
			
		||||
resulted in not getting the device the LED is blinking for. As a
 | 
			
		||||
result, the device is unknown and offloaded is never performed.
 | 
			
		||||
 | 
			
		||||
Change to condition to always get the device if offloading is
 | 
			
		||||
supported, and reduce the scope of testing for an error from
 | 
			
		||||
hw_control_get() to skip setting trigger internal state if there is an
 | 
			
		||||
error.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Simon Horman <simon.horman@corigine.com>
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230808210436.838995-2-andrew@lunn.ch
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/leds/trigger/ledtrig-netdev.c | 8 +++++---
 | 
			
		||||
 1 file changed, 5 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
@@ -564,15 +564,17 @@ static int netdev_trig_activate(struct l
 | 
			
		||||
 	/* Check if hw control is active by default on the LED.
 | 
			
		||||
 	 * Init already enabled mode in hw control.
 | 
			
		||||
 	 */
 | 
			
		||||
-	if (supports_hw_control(led_cdev) &&
 | 
			
		||||
-	    !led_cdev->hw_control_get(led_cdev, &mode)) {
 | 
			
		||||
+	if (supports_hw_control(led_cdev)) {
 | 
			
		||||
 		dev = led_cdev->hw_control_get_device(led_cdev);
 | 
			
		||||
 		if (dev) {
 | 
			
		||||
 			const char *name = dev_name(dev);
 | 
			
		||||
 
 | 
			
		||||
 			set_device_name(trigger_data, name, strlen(name));
 | 
			
		||||
 			trigger_data->hw_control = true;
 | 
			
		||||
-			trigger_data->mode = mode;
 | 
			
		||||
+
 | 
			
		||||
+			rc = led_cdev->hw_control_get(led_cdev, &mode);
 | 
			
		||||
+			if (!rc)
 | 
			
		||||
+				trigger_data->mode = mode;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,149 @@
 | 
			
		||||
From 1dcc03c9a7a824a31eaaecdfaa03542fb25feb6c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Date: Tue, 8 Aug 2023 23:04:34 +0200
 | 
			
		||||
Subject: [PATCH 2/4] net: phy: phy_device: Call into the PHY driver to set LED
 | 
			
		||||
 offload
 | 
			
		||||
 | 
			
		||||
Linux LEDs can be requested to perform hardware accelerated blinking
 | 
			
		||||
to indicate link, RX, TX etc. Pass the rules for blinking to the PHY
 | 
			
		||||
driver, if it implements the ops needed to determine if a given
 | 
			
		||||
pattern can be offloaded, to offload it, and what the current offload
 | 
			
		||||
is. Additionally implement the op needed to get what device the LED is
 | 
			
		||||
for.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Simon Horman <simon.horman@corigine.com>
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/phy_device.c | 68 ++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 include/linux/phy.h          | 33 +++++++++++++++++
 | 
			
		||||
 2 files changed, 101 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -2964,6 +2964,61 @@ static int phy_led_blink_set(struct led_
 | 
			
		||||
 	return err;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static __maybe_unused struct device *
 | 
			
		||||
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phy_led *phyled = to_phy_led(led_cdev);
 | 
			
		||||
+	struct phy_device *phydev = phyled->phydev;
 | 
			
		||||
+
 | 
			
		||||
+	if (phydev->attached_dev)
 | 
			
		||||
+		return &phydev->attached_dev->dev;
 | 
			
		||||
+	return NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int __maybe_unused
 | 
			
		||||
+phy_led_hw_control_get(struct led_classdev *led_cdev,
 | 
			
		||||
+		       unsigned long *rules)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phy_led *phyled = to_phy_led(led_cdev);
 | 
			
		||||
+	struct phy_device *phydev = phyled->phydev;
 | 
			
		||||
+	int err;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&phydev->lock);
 | 
			
		||||
+	err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
 | 
			
		||||
+	mutex_unlock(&phydev->lock);
 | 
			
		||||
+
 | 
			
		||||
+	return err;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int __maybe_unused
 | 
			
		||||
+phy_led_hw_control_set(struct led_classdev *led_cdev,
 | 
			
		||||
+		       unsigned long rules)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phy_led *phyled = to_phy_led(led_cdev);
 | 
			
		||||
+	struct phy_device *phydev = phyled->phydev;
 | 
			
		||||
+	int err;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&phydev->lock);
 | 
			
		||||
+	err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
 | 
			
		||||
+	mutex_unlock(&phydev->lock);
 | 
			
		||||
+
 | 
			
		||||
+	return err;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
 | 
			
		||||
+						  unsigned long rules)
 | 
			
		||||
+{
 | 
			
		||||
+	struct phy_led *phyled = to_phy_led(led_cdev);
 | 
			
		||||
+	struct phy_device *phydev = phyled->phydev;
 | 
			
		||||
+	int err;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&phydev->lock);
 | 
			
		||||
+	err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
 | 
			
		||||
+	mutex_unlock(&phydev->lock);
 | 
			
		||||
+
 | 
			
		||||
+	return err;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void phy_leds_unregister(struct phy_device *phydev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct phy_led *phyled;
 | 
			
		||||
@@ -3001,6 +3056,19 @@ static int of_phy_led(struct phy_device
 | 
			
		||||
 		cdev->brightness_set_blocking = phy_led_set_brightness;
 | 
			
		||||
 	if (phydev->drv->led_blink_set)
 | 
			
		||||
 		cdev->blink_set = phy_led_blink_set;
 | 
			
		||||
+
 | 
			
		||||
+#ifdef CONFIG_LEDS_TRIGGERS
 | 
			
		||||
+	if (phydev->drv->led_hw_is_supported &&
 | 
			
		||||
+	    phydev->drv->led_hw_control_set &&
 | 
			
		||||
+	    phydev->drv->led_hw_control_get) {
 | 
			
		||||
+		cdev->hw_control_is_supported = phy_led_hw_is_supported;
 | 
			
		||||
+		cdev->hw_control_set = phy_led_hw_control_set;
 | 
			
		||||
+		cdev->hw_control_get = phy_led_hw_control_get;
 | 
			
		||||
+		cdev->hw_control_trigger = "netdev";
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	cdev->hw_control_get_device = phy_led_hw_control_get_device;
 | 
			
		||||
+#endif
 | 
			
		||||
 	cdev->max_brightness = 1;
 | 
			
		||||
 	init_data.devicename = dev_name(&phydev->mdio.dev);
 | 
			
		||||
 	init_data.fwnode = of_fwnode_handle(led);
 | 
			
		||||
--- a/include/linux/phy.h
 | 
			
		||||
+++ b/include/linux/phy.h
 | 
			
		||||
@@ -1013,6 +1013,39 @@ struct phy_driver {
 | 
			
		||||
 	int (*led_blink_set)(struct phy_device *dev, u8 index,
 | 
			
		||||
 			     unsigned long *delay_on,
 | 
			
		||||
 			     unsigned long *delay_off);
 | 
			
		||||
+	/**
 | 
			
		||||
+	 * @led_hw_is_supported: Can the HW support the given rules.
 | 
			
		||||
+	 * @dev: PHY device which has the LED
 | 
			
		||||
+	 * @index: Which LED of the PHY device
 | 
			
		||||
+	 * @rules The core is interested in these rules
 | 
			
		||||
+	 *
 | 
			
		||||
+	 * Return 0 if yes,  -EOPNOTSUPP if not, or an error code.
 | 
			
		||||
+	 */
 | 
			
		||||
+	int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
 | 
			
		||||
+				   unsigned long rules);
 | 
			
		||||
+	/**
 | 
			
		||||
+	 * @led_hw_control_set: Set the HW to control the LED
 | 
			
		||||
+	 * @dev: PHY device which has the LED
 | 
			
		||||
+	 * @index: Which LED of the PHY device
 | 
			
		||||
+	 * @rules The rules used to control the LED
 | 
			
		||||
+	 *
 | 
			
		||||
+	 * Returns 0, or a an error code.
 | 
			
		||||
+	 */
 | 
			
		||||
+	int (*led_hw_control_set)(struct phy_device *dev, u8 index,
 | 
			
		||||
+				  unsigned long rules);
 | 
			
		||||
+	/**
 | 
			
		||||
+	 * @led_hw_control_get: Get how the HW is controlling the LED
 | 
			
		||||
+	 * @dev: PHY device which has the LED
 | 
			
		||||
+	 * @index: Which LED of the PHY device
 | 
			
		||||
+	 * @rules Pointer to the rules used to control the LED
 | 
			
		||||
+	 *
 | 
			
		||||
+	 * Set *@rules to how the HW is currently blinking. Returns 0
 | 
			
		||||
+	 * on success, or a error code if the current blinking cannot
 | 
			
		||||
+	 * be represented in rules, or some other error happens.
 | 
			
		||||
+	 */
 | 
			
		||||
+	int (*led_hw_control_get)(struct phy_device *dev, u8 index,
 | 
			
		||||
+				  unsigned long *rules);
 | 
			
		||||
+
 | 
			
		||||
 };
 | 
			
		||||
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),		\
 | 
			
		||||
 				      struct phy_driver, mdiodrv)
 | 
			
		||||
@ -0,0 +1,344 @@
 | 
			
		||||
From 460b0b648fab24f576c481424e0de5479ffb9786 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Date: Tue, 8 Aug 2023 23:04:35 +0200
 | 
			
		||||
Subject: [PATCH 3/4] net: phy: marvell: Add support for offloading LED
 | 
			
		||||
 blinking
 | 
			
		||||
 | 
			
		||||
Add the code needed to indicate if a given blinking pattern can be
 | 
			
		||||
offloaded, to offload a pattern and to try to return the current
 | 
			
		||||
pattern.
 | 
			
		||||
 | 
			
		||||
Reviewed-by: Simon Horman <simon.horman@corigine.com>
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230808210436.838995-4-andrew@lunn.ch
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/net/phy/marvell.c | 281 ++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 1 file changed, 281 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/marvell.c
 | 
			
		||||
+++ b/drivers/net/phy/marvell.c
 | 
			
		||||
@@ -2893,6 +2893,272 @@ static int m88e1318_led_blink_set(struct
 | 
			
		||||
 			       MII_88E1318S_PHY_LED_FUNC, reg);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+struct marvell_led_rules {
 | 
			
		||||
+	int mode;
 | 
			
		||||
+	unsigned long rules;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct marvell_led_rules marvell_led0[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 0,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 1,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 3,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 4,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 5,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_TX),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 6,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 7,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK_1000),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 8,
 | 
			
		||||
+		.rules = 0,
 | 
			
		||||
+	},
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct marvell_led_rules marvell_led1[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 1,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 2,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_RX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 3,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 4,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 6,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK_100) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_LINK_1000)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 7,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK_100),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 8,
 | 
			
		||||
+		.rules = 0,
 | 
			
		||||
+	},
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct marvell_led_rules marvell_led2[] = {
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 0,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 1,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 3,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 4,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_RX) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_TX)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 5,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_TX),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 6,
 | 
			
		||||
+		.rules = (BIT(TRIGGER_NETDEV_LINK_10) |
 | 
			
		||||
+			  BIT(TRIGGER_NETDEV_LINK_1000)),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 7,
 | 
			
		||||
+		.rules = BIT(TRIGGER_NETDEV_LINK_10),
 | 
			
		||||
+	},
 | 
			
		||||
+	{
 | 
			
		||||
+		.mode = 8,
 | 
			
		||||
+		.rules = 0,
 | 
			
		||||
+	},
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static int marvell_find_led_mode(unsigned long rules,
 | 
			
		||||
+				 const struct marvell_led_rules *marvell_rules,
 | 
			
		||||
+				 int count,
 | 
			
		||||
+				 int *mode)
 | 
			
		||||
+{
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 0; i < count; i++) {
 | 
			
		||||
+		if (marvell_rules[i].rules == rules) {
 | 
			
		||||
+			*mode = marvell_rules[i].mode;
 | 
			
		||||
+			return 0;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+	return -EOPNOTSUPP;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int marvell_get_led_mode(u8 index, unsigned long rules, int *mode)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	switch (index) {
 | 
			
		||||
+	case 0:
 | 
			
		||||
+		ret = marvell_find_led_mode(rules, marvell_led0,
 | 
			
		||||
+					    ARRAY_SIZE(marvell_led0), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	case 1:
 | 
			
		||||
+		ret = marvell_find_led_mode(rules, marvell_led1,
 | 
			
		||||
+					    ARRAY_SIZE(marvell_led1), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	case 2:
 | 
			
		||||
+		ret = marvell_find_led_mode(rules, marvell_led2,
 | 
			
		||||
+					    ARRAY_SIZE(marvell_led2), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		ret = -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int marvell_find_led_rules(unsigned long *rules,
 | 
			
		||||
+				  const struct marvell_led_rules *marvell_rules,
 | 
			
		||||
+				  int count,
 | 
			
		||||
+				  int mode)
 | 
			
		||||
+{
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 0; i < count; i++) {
 | 
			
		||||
+		if (marvell_rules[i].mode == mode) {
 | 
			
		||||
+			*rules = marvell_rules[i].rules;
 | 
			
		||||
+			return 0;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+	return -EOPNOTSUPP;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int marvell_get_led_rules(u8 index, unsigned long *rules, int mode)
 | 
			
		||||
+{
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	switch (index) {
 | 
			
		||||
+	case 0:
 | 
			
		||||
+		ret = marvell_find_led_rules(rules, marvell_led0,
 | 
			
		||||
+					     ARRAY_SIZE(marvell_led0), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	case 1:
 | 
			
		||||
+		ret = marvell_find_led_rules(rules, marvell_led1,
 | 
			
		||||
+					     ARRAY_SIZE(marvell_led1), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	case 2:
 | 
			
		||||
+		ret = marvell_find_led_rules(rules, marvell_led2,
 | 
			
		||||
+					     ARRAY_SIZE(marvell_led2), mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		ret = -EOPNOTSUPP;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index,
 | 
			
		||||
+					unsigned long rules)
 | 
			
		||||
+{
 | 
			
		||||
+	int mode, ret;
 | 
			
		||||
+
 | 
			
		||||
+	switch (index) {
 | 
			
		||||
+	case 0:
 | 
			
		||||
+	case 1:
 | 
			
		||||
+	case 2:
 | 
			
		||||
+		ret = marvell_get_led_mode(index, rules, &mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		ret = -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index,
 | 
			
		||||
+				       unsigned long rules)
 | 
			
		||||
+{
 | 
			
		||||
+	int mode, ret, reg;
 | 
			
		||||
+
 | 
			
		||||
+	switch (index) {
 | 
			
		||||
+	case 0:
 | 
			
		||||
+	case 1:
 | 
			
		||||
+	case 2:
 | 
			
		||||
+		ret = marvell_get_led_mode(index, rules, &mode);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		ret = -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	if (ret < 0)
 | 
			
		||||
+		return ret;
 | 
			
		||||
+
 | 
			
		||||
+	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
 | 
			
		||||
+			     MII_88E1318S_PHY_LED_FUNC);
 | 
			
		||||
+	if (reg < 0)
 | 
			
		||||
+		return reg;
 | 
			
		||||
+
 | 
			
		||||
+	reg &= ~(0xf << (4 * index));
 | 
			
		||||
+	reg |= mode << (4 * index);
 | 
			
		||||
+	return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
 | 
			
		||||
+			       MII_88E1318S_PHY_LED_FUNC, reg);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index,
 | 
			
		||||
+				       unsigned long *rules)
 | 
			
		||||
+{
 | 
			
		||||
+	int mode, reg;
 | 
			
		||||
+
 | 
			
		||||
+	if (index > 2)
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
 | 
			
		||||
+			     MII_88E1318S_PHY_LED_FUNC);
 | 
			
		||||
+	if (reg < 0)
 | 
			
		||||
+		return reg;
 | 
			
		||||
+
 | 
			
		||||
+	mode = (reg >> (4 * index)) & 0xf;
 | 
			
		||||
+
 | 
			
		||||
+	return marvell_get_led_rules(index, rules, mode);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int marvell_probe(struct phy_device *phydev)
 | 
			
		||||
 {
 | 
			
		||||
 	struct marvell_priv *priv;
 | 
			
		||||
@@ -3144,6 +3410,9 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.get_stats = marvell_get_stats,
 | 
			
		||||
 		.led_brightness_set = m88e1318_led_brightness_set,
 | 
			
		||||
 		.led_blink_set = m88e1318_led_blink_set,
 | 
			
		||||
+		.led_hw_is_supported = m88e1318_led_hw_is_supported,
 | 
			
		||||
+		.led_hw_control_set = m88e1318_led_hw_control_set,
 | 
			
		||||
+		.led_hw_control_get = m88e1318_led_hw_control_get,
 | 
			
		||||
 	},
 | 
			
		||||
 	{
 | 
			
		||||
 		.phy_id = MARVELL_PHY_ID_88E1145,
 | 
			
		||||
@@ -3252,6 +3521,9 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.cable_test_get_status = marvell_vct7_cable_test_get_status,
 | 
			
		||||
 		.led_brightness_set = m88e1318_led_brightness_set,
 | 
			
		||||
 		.led_blink_set = m88e1318_led_blink_set,
 | 
			
		||||
+		.led_hw_is_supported = m88e1318_led_hw_is_supported,
 | 
			
		||||
+		.led_hw_control_set = m88e1318_led_hw_control_set,
 | 
			
		||||
+		.led_hw_control_get = m88e1318_led_hw_control_get,
 | 
			
		||||
 	},
 | 
			
		||||
 	{
 | 
			
		||||
 		.phy_id = MARVELL_PHY_ID_88E1540,
 | 
			
		||||
@@ -3280,6 +3552,9 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.cable_test_get_status = marvell_vct7_cable_test_get_status,
 | 
			
		||||
 		.led_brightness_set = m88e1318_led_brightness_set,
 | 
			
		||||
 		.led_blink_set = m88e1318_led_blink_set,
 | 
			
		||||
+		.led_hw_is_supported = m88e1318_led_hw_is_supported,
 | 
			
		||||
+		.led_hw_control_set = m88e1318_led_hw_control_set,
 | 
			
		||||
+		.led_hw_control_get = m88e1318_led_hw_control_get,
 | 
			
		||||
 	},
 | 
			
		||||
 	{
 | 
			
		||||
 		.phy_id = MARVELL_PHY_ID_88E1545,
 | 
			
		||||
@@ -3308,6 +3583,9 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.cable_test_get_status = marvell_vct7_cable_test_get_status,
 | 
			
		||||
 		.led_brightness_set = m88e1318_led_brightness_set,
 | 
			
		||||
 		.led_blink_set = m88e1318_led_blink_set,
 | 
			
		||||
+		.led_hw_is_supported = m88e1318_led_hw_is_supported,
 | 
			
		||||
+		.led_hw_control_set = m88e1318_led_hw_control_set,
 | 
			
		||||
+		.led_hw_control_get = m88e1318_led_hw_control_get,
 | 
			
		||||
 	},
 | 
			
		||||
 	{
 | 
			
		||||
 		.phy_id = MARVELL_PHY_ID_88E3016,
 | 
			
		||||
@@ -3451,6 +3729,9 @@ static struct phy_driver marvell_drivers
 | 
			
		||||
 		.set_tunable = m88e1540_set_tunable,
 | 
			
		||||
 		.led_brightness_set = m88e1318_led_brightness_set,
 | 
			
		||||
 		.led_blink_set = m88e1318_led_blink_set,
 | 
			
		||||
+		.led_hw_is_supported = m88e1318_led_hw_is_supported,
 | 
			
		||||
+		.led_hw_control_set = m88e1318_led_hw_control_set,
 | 
			
		||||
+		.led_hw_control_get = m88e1318_led_hw_control_get,
 | 
			
		||||
 	},
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
From e8fbcc47a8e935f36f044d85f21a99acecbd7bfb Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Date: Tue, 8 Aug 2023 23:04:36 +0200
 | 
			
		||||
Subject: [PATCH 4/4] leds: trig-netdev: Disable offload on deactivation of
 | 
			
		||||
 trigger
 | 
			
		||||
 | 
			
		||||
Ensure that the offloading of blinking is stopped when the trigger is
 | 
			
		||||
deactivated. Calling led_set_brightness() is documented as stopping
 | 
			
		||||
offload and setting the LED to a constant brightness.
 | 
			
		||||
 | 
			
		||||
Suggested-by: Daniel Golle <daniel@makrotopia.org>
 | 
			
		||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
 | 
			
		||||
Reviewed-by: Simon Horman <simon.horman@corigine.com>
 | 
			
		||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/20230808210436.838995-5-andrew@lunn.ch
 | 
			
		||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 | 
			
		||||
---
 | 
			
		||||
 drivers/leds/trigger/ledtrig-netdev.c | 2 ++
 | 
			
		||||
 1 file changed, 2 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
 | 
			
		||||
@@ -595,6 +595,8 @@ static void netdev_trig_deactivate(struc
 | 
			
		||||
 
 | 
			
		||||
 	cancel_delayed_work_sync(&trigger_data->work);
 | 
			
		||||
 
 | 
			
		||||
+	led_set_brightness(led_cdev, LED_OFF);
 | 
			
		||||
+
 | 
			
		||||
 	dev_put(trigger_data->net_dev);
 | 
			
		||||
 
 | 
			
		||||
 	kfree(trigger_data);
 | 
			
		||||
@ -4831,6 +4831,7 @@ CONFIG_PCI_SYSCALL=y
 | 
			
		||||
# CONFIG_PHANTOM is not set
 | 
			
		||||
# CONFIG_PHONET is not set
 | 
			
		||||
# CONFIG_PHYLIB is not set
 | 
			
		||||
# CONFIG_PHYLIB_LEDS is not set
 | 
			
		||||
# CONFIG_PHYS_ADDR_T_64BIT is not set
 | 
			
		||||
# CONFIG_PHY_CADENCE_DP is not set
 | 
			
		||||
# CONFIG_PHY_CADENCE_DPHY is not set
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -62,6 +62,80 @@ config SFP
 | 
			
		||||
@@ -69,6 +69,80 @@ config SFP
 | 
			
		||||
 	depends on HWMON || HWMON=n
 | 
			
		||||
 	select MDIO_I2C
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user