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@xxxxxx> Cc: Rob Herring <robh+dt@xxxxxxxxxx> Cc: devicetree@xxxxxxxxxxxxxxx --- 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