* [PATCH leds + devicetree v1 1/2] leds: trigger: add DT `trigger-sources` validating method
2020-09-14 23:41 [PATCH leds + devicetree v1 0/2] Parse DT property `trigger-sources` for netdev LED trigger Marek Behún
@ 2020-09-14 23:41 ` Marek Behún
2020-09-14 23:41 ` [PATCH leds + devicetree v1 2/2] leds: trigger: netdev: allow parsing `trigger-sources` from device tree Marek Behún
1 sibling, 0 replies; 4+ messages in thread
From: Marek Behún @ 2020-09-14 23:41 UTC (permalink / raw)
To: linux-leds
Cc: Pavel Machek, Dan Murphy, Ondřej Jirman, Russell King,
Andrew Lunn, linux-kernel, Matthias Schiffer, Marek Behún,
Rob Herring, devicetree
Currently we use the `linux,default-trigger` device tree property of a
LED to define the default trigger which should be activated for a LED.
But the LED device tree binding also documents the `trigger-sources`
property, which specifies the source device which should be triggering
the LED.
The `trigger-sources` property is currently implemented only in
drivers/usb/core/ledtrig-usbport.c.
Lets add a method to struct led_trigger which, if implemented, can check
whether this trigger should be enabled as default. This check shall be
done by checking whether the specified `trigger-sources` refers to a
device compatible with the trigger.
Signed-off-by: Marek Behún <marek.behun@nic.cz>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
---
drivers/leds/led-triggers.c | 26 ++++++++++++++++++--------
include/linux/leds.h | 6 ++++++
2 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 91da90cfb11d9..c96577f0bfe97 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -243,18 +243,30 @@ void led_trigger_remove(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_trigger_remove);
+static bool trigger_is_default(struct led_classdev *led_cdev,
+ struct led_trigger *trig)
+{
+ if (!trigger_relevant(led_cdev, trig))
+ return false;
+
+ if (led_cdev->default_trigger &&
+ !strcmp(led_cdev->default_trigger, trig->name))
+ return true;
+
+ if (trig->has_valid_source && trig->has_valid_source(led_cdev))
+ return true;
+
+ return false;
+}
+
void led_trigger_set_default(struct led_classdev *led_cdev)
{
struct led_trigger *trig;
- if (!led_cdev->default_trigger)
- return;
-
down_read(&triggers_list_lock);
down_write(&led_cdev->trigger_lock);
list_for_each_entry(trig, &trigger_list, next_trig) {
- if (!strcmp(led_cdev->default_trigger, trig->name) &&
- trigger_relevant(led_cdev, trig)) {
+ if (trigger_is_default(led_cdev, trig)) {
led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
led_trigger_set(led_cdev, trig);
break;
@@ -306,9 +318,7 @@ int led_trigger_register(struct led_trigger *trig)
down_read(&leds_list_lock);
list_for_each_entry(led_cdev, &leds_list, node) {
down_write(&led_cdev->trigger_lock);
- if (!led_cdev->trigger && led_cdev->default_trigger &&
- !strcmp(led_cdev->default_trigger, trig->name) &&
- trigger_relevant(led_cdev, trig)) {
+ if (!led_cdev->trigger && trigger_is_default(led_cdev, trig)) {
led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
led_trigger_set(led_cdev, trig);
}
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 6a8d6409c993e..4cbb826e4bec4 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -352,6 +352,12 @@ struct led_trigger {
int (*activate)(struct led_classdev *led_cdev);
void (*deactivate)(struct led_classdev *led_cdev);
+ /*
+ * Check whether LED has defined valid source for this trigger.
+ * If yes, this trigger should be set as default trigger for LED.
+ */
+ bool (*has_valid_source)(struct led_classdev *led_cdev);
+
/* LED-private triggers have this set */
struct led_hw_trigger_type *trigger_type;
--
2.26.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH leds + devicetree v1 2/2] leds: trigger: netdev: allow parsing `trigger-sources` from device tree
2020-09-14 23:41 [PATCH leds + devicetree v1 0/2] Parse DT property `trigger-sources` for netdev LED trigger Marek Behún
2020-09-14 23:41 ` [PATCH leds + devicetree v1 1/2] leds: trigger: add DT `trigger-sources` validating method Marek Behún
@ 2020-09-14 23:41 ` Marek Behún
2020-09-15 11:04 ` kernel test robot
1 sibling, 1 reply; 4+ messages in thread
From: Marek Behún @ 2020-09-14 23:41 UTC (permalink / raw)
To: linux-leds
Cc: Pavel Machek, Dan Murphy, Ondřej Jirman, Russell King,
Andrew Lunn, linux-kernel, Matthias Schiffer, Marek Behún,
Rob Herring, devicetree
Allow setting netdev LED trigger as default when given LED DT node has
the `trigger-sources` property pointing to a node corresponding to a
network device.
The specific netdev trigger mode is determined from the `function` LED
property.
Example:
eth0: ethernet@30000 {
compatible = "xyz";
#trigger-source-cells = <0>;
};
led {
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LINK;
trigger-sources = <ð0>;
};
Signed-off-by: Marek Behún <marek.behun@nic.cz>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree@vger.kernel.org
---
drivers/leds/trigger/ledtrig-netdev.c | 91 ++++++++++++++++++++++++++-
include/dt-bindings/leds/common.h | 1 +
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index d5e774d830215..c6dce28dc52ed 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -20,6 +20,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of_net.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include "../leds.h"
@@ -389,6 +390,81 @@ static void netdev_trig_work(struct work_struct *work)
(atomic_read(&trigger_data->interval)*2));
}
+static bool netdev_trig_of_parse(struct led_classdev *led_cdev,
+ struct led_netdev_data *trigger_data)
+{
+ struct of_phandle_args args;
+ struct net_device *netdev;
+ struct device_node *np;
+ const char *function;
+ unsigned long mode;
+ int count, err;
+
+ np = dev_of_node(led_cdev->dev);
+ if (!np)
+ return -EOPNOTSUPP;
+
+ count = of_count_phandle_with_args(np, "trigger-sources",
+ "#trigger-source-cells");
+ if (count == -ENOENT) {
+ return false;
+ } else if (count < 0) {
+ dev_warn(led_cdev->dev,
+ "Failed parsing trigger sources for %pOF!\n", np);
+ return false;
+ }
+
+ /* netdev trigger can have only one source */
+ if (count != 1)
+ return false;
+
+ err = of_parse_phandle_with_args(np, "trigger-sources",
+ "#trigger-source-cells", 0, &args);
+ if (err)
+ return false;
+
+ netdev = of_find_net_device_by_node(args.np);
+ if (!netdev)
+ return false;
+
+ err = of_property_read_string(np, "function", &function);
+ if (err && err != -ENOENT) {
+ dev_warn(led_cdev->dev, "Failed parsing function for %pOF!\n",
+ np);
+ return false;
+ } else if (err == -ENOENT) {
+ /* default function is link */
+ function = LED_FUNCTION_LINK;
+ }
+
+ mode = 0;
+ if (!strcmp(function, LED_FUNCTION_LINK)) {
+ set_bit(NETDEV_LED_LINK, &mode);
+ } else if (!strcmp(function, LED_FUNCTION_ACTIVITY)) {
+ set_bit(NETDEV_LED_TX, &mode);
+ set_bit(NETDEV_LED_RX, &mode);
+ } else if (!strcmp(function, LED_FUNCTION_RX)) {
+ set_bit(NETDEV_LED_RX, &mode);
+ } else if (!strcmp(function, LED_FUNCTION_TX)) {
+ set_bit(NETDEV_LED_TX, &mode);
+ } else {
+ dev_dbg(led_cdev->dev,
+ "Unsupported netdev trigger function for %pOF!\n", np);
+ return false;
+ }
+
+ if (trigger_data) {
+ dev_hold(netdev);
+ trigger_data->net_dev = netdev;
+ memcpy(trigger_data->device_name, netdev->name, IFNAMSIZ);
+ trigger_data->mode = mode;
+ if (netif_carrier_ok(netdev))
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
+ }
+
+ return true;
+}
+
static int netdev_trig_activate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data;
@@ -414,10 +490,17 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
trigger_data->last_activity = 0;
led_set_trigger_data(led_cdev, trigger_data);
+ netdev_trig_of_parse(led_cdev, trigger_data);
rc = register_netdevice_notifier(&trigger_data->notifier);
- if (rc)
+ if (rc) {
+ if (trigger_data->net_dev)
+ dev_put(trigger_data->net_dev);
kfree(trigger_data);
+ } else {
+ if (trigger_data->net_dev)
+ set_baseline_state(trigger_data);
+ }
return rc;
}
@@ -436,10 +519,16 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev)
kfree(trigger_data);
}
+static bool netdev_trig_has_valid_source(struct led_classdev *led_cdev)
+{
+ return netdev_trig_of_parse(led_cdev, NULL);
+}
+
static struct led_trigger netdev_led_trigger = {
.name = "netdev",
.activate = netdev_trig_activate,
.deactivate = netdev_trig_deactivate,
+ .has_valid_source = netdev_trig_has_valid_source,
.groups = netdev_trig_groups,
};
diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h
index 52b619d44ba25..c7f9d34d60206 100644
--- a/include/dt-bindings/leds/common.h
+++ b/include/dt-bindings/leds/common.h
@@ -77,6 +77,7 @@
#define LED_FUNCTION_HEARTBEAT "heartbeat"
#define LED_FUNCTION_INDICATOR "indicator"
#define LED_FUNCTION_LAN "lan"
+#define LED_FUNCTION_LINK "link"
#define LED_FUNCTION_MAIL "mail"
#define LED_FUNCTION_MTD "mtd"
#define LED_FUNCTION_PANIC "panic"
--
2.26.2
^ permalink raw reply related [flat|nested] 4+ messages in thread