diff mbox series

[2/2] leds: trigger: netdev: Introduce OF mode configuration using netdev-trigger-mode property

Message ID 20250113002346.297481-2-marex@denx.de
State New
Headers show
Series [1/2] dt-bindings: leds: Document netdev trigger netdev-trigger-mode property | expand

Commit Message

Marek Vasut Jan. 13, 2025, 12:23 a.m. UTC
Introduce netdev trigger specific netdev-trigger-mode property which
is used to configure the netdev trigger mode flags. Those mode flags
define events on which the LED acts upon when the hardware offload is
enabled. This is traditionally configured via sysfs, but that depends
on userspace, which is available too late and makes ethernet PHY LEDs
not work e.g. when NFS root is being mounted.

For each LED with linux,default-trigger = "netdev" described in DT, the
optional netdev-trigger-mode property supplies the default configuration
of the PHY LED mode via DT. This property should be set to a subset of
TRIGGER_NETDEV_* flags.

For each LED with linux,default-trigger = "netdev" described in DT, the
netdev trigger is activated during kernel boot. The trigger is extended
the parse the netdev-trigger-mode property and set it as a default value
of trigger_data->mode.

It is not possible to immediately configure the LED mode, because the
interface to which the PHY and the LED is connected to might not be
attached to the PHY yet. The netdev_trig_notify() is called when the
PHY got attached to interface, extend netdev_trig_notify() to detect
the condition where the LED does have netdev trigger configured in DT
but the mode was not yet configured and configure the baseline mode
from the notifier. This can reuse most of set_device_name() except for
the rtnl_lock() which cannot be claimed in the notifier, so split the
relevant core code into set_device_name_locked() and call only the core
code.

Signed-off-by: Marek Vasut <marex@denx.de>
---
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Christian Marangi <ansuelsmth@gmail.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Lee Jones <lee@kernel.org>
Cc: Lukasz Majewski <lukma@denx.de>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-leds@vger.kernel.org
---
 drivers/leds/trigger/ledtrig-netdev.c | 51 ++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index c15efe3e50780..20dfc9506c0a6 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -23,6 +23,7 @@ 
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/phy.h>
 #include <linux/rtnetlink.h>
 #include <linux/timer.h>
@@ -256,19 +257,9 @@  static ssize_t device_name_show(struct device *dev,
 	return len;
 }
 
-static int set_device_name(struct led_netdev_data *trigger_data,
-			   const char *name, size_t size)
+static void set_device_name_locked(struct led_netdev_data *trigger_data,
+				  const char *name, size_t size)
 {
-	if (size >= IFNAMSIZ)
-		return -EINVAL;
-
-	cancel_delayed_work_sync(&trigger_data->work);
-
-	/*
-	 * Take RTNL lock before trigger_data lock to prevent potential
-	 * deadlock with netdev notifier registration.
-	 */
-	rtnl_lock();
 	mutex_lock(&trigger_data->lock);
 
 	if (trigger_data->net_dev) {
@@ -298,6 +289,24 @@  static int set_device_name(struct led_netdev_data *trigger_data,
 		set_baseline_state(trigger_data);
 
 	mutex_unlock(&trigger_data->lock);
+}
+
+static int set_device_name(struct led_netdev_data *trigger_data,
+			   const char *name, size_t size)
+{
+	if (size >= IFNAMSIZ)
+		return -EINVAL;
+
+	cancel_delayed_work_sync(&trigger_data->work);
+
+	/*
+	 * Take RTNL lock before trigger_data lock to prevent potential
+	 * deadlock with netdev notifier registration.
+	 */
+	rtnl_lock();
+
+	set_device_name_locked(trigger_data, name, size);
+
 	rtnl_unlock();
 
 	return 0;
@@ -579,6 +588,20 @@  static int netdev_trig_notify(struct notifier_block *nb,
 	    && evt != NETDEV_CHANGENAME)
 		return NOTIFY_DONE;
 
+	if (evt == NETDEV_REGISTER && !trigger_data->device_name[0] &&
+	    led_cdev->hw_control_get && led_cdev->hw_control_set &&
+	    led_cdev->hw_control_is_supported) {
+		struct device *ndev = led_cdev->hw_control_get_device(led_cdev);
+		if (ndev) {
+			const char *name = dev_name(ndev);
+
+			trigger_data->hw_control = true;
+
+			cancel_delayed_work_sync(&trigger_data->work);
+			set_device_name_locked(trigger_data, name, strlen(name));
+		}
+	}
+
 	if (!(dev == trigger_data->net_dev ||
 	      (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
 	      (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
@@ -689,6 +712,7 @@  static int netdev_trig_activate(struct led_classdev *led_cdev)
 	struct led_netdev_data *trigger_data;
 	unsigned long mode = 0;
 	struct device *dev;
+	u32 val;
 	int rc;
 
 	trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
@@ -706,7 +730,8 @@  static int netdev_trig_activate(struct led_classdev *led_cdev)
 	trigger_data->net_dev = NULL;
 	trigger_data->device_name[0] = 0;
 
-	trigger_data->mode = 0;
+	rc = of_property_read_u32(led_cdev->dev->of_node, "netdev-trigger-mode", &val);
+	trigger_data->mode = rc ? 0 : val;
 	atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
 	trigger_data->last_activity = 0;