mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-19 03:06:35 +00:00
generic: 6.1: backport LEDs patch adding additional modes
Backport LEDs patch adding additional modes for split link speed and half/full duplex state. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
984786a2f7
commit
adc3ee1cc8
@ -0,0 +1,242 @@
|
||||
From d5e01266e7f5fa12400d4c8aa4e86fe89dcc61e9 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 19 Jun 2023 22:46:58 +0200
|
||||
Subject: [PATCH 1/3] leds: trigger: netdev: add additional specific link speed
|
||||
mode
|
||||
|
||||
Add additional modes for specific link speed. Use ethtool APIs to get the
|
||||
current link speed and enable the LED accordingly. Under netdev event
|
||||
handler the rtnl lock is already held and is not needed to be set to
|
||||
access ethtool APIs.
|
||||
|
||||
This is especially useful for PHY and Switch that supports LEDs hw
|
||||
control for specific link speed. (example scenario a PHY that have 2 LED
|
||||
connected one green and one orange where the green is turned on with
|
||||
1000mbps speed and orange is turned on with 10mpbs speed)
|
||||
|
||||
On mode set from sysfs we check if we have enabled split link speed mode
|
||||
and reject enabling generic link mode to prevent wrong and redundant
|
||||
configuration.
|
||||
|
||||
Rework logic on the set baseline state to support these new modes to
|
||||
select if we need to turn on or off the LED.
|
||||
|
||||
Add additional modes:
|
||||
- link_10: Turn on LED when link speed is 10mbps
|
||||
- link_100: Turn on LED when link speed is 100mbps
|
||||
- link_1000: Turn on LED when link speed is 1000mbps
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Acked-by: Lee Jones <lee@kernel.org>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 80 +++++++++++++++++++++++----
|
||||
include/linux/leds.h | 3 +
|
||||
2 files changed, 73 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/device.h>
|
||||
+#include <linux/ethtool.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/rtnetlink.h>
|
||||
#include <linux/timer.h>
|
||||
#include "../leds.h"
|
||||
|
||||
@@ -52,6 +54,8 @@ struct led_netdev_data {
|
||||
unsigned int last_activity;
|
||||
|
||||
unsigned long mode;
|
||||
+ int link_speed;
|
||||
+
|
||||
bool carrier_link_up;
|
||||
bool hw_control;
|
||||
};
|
||||
@@ -77,7 +81,24 @@ static void set_baseline_state(struct le
|
||||
if (!trigger_data->carrier_link_up) {
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
} else {
|
||||
+ bool blink_on = false;
|
||||
+
|
||||
if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode))
|
||||
+ blink_on = true;
|
||||
+
|
||||
+ if (test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) &&
|
||||
+ trigger_data->link_speed == SPEED_10)
|
||||
+ blink_on = true;
|
||||
+
|
||||
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) &&
|
||||
+ trigger_data->link_speed == SPEED_100)
|
||||
+ blink_on = true;
|
||||
+
|
||||
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) &&
|
||||
+ trigger_data->link_speed == SPEED_1000)
|
||||
+ blink_on = true;
|
||||
+
|
||||
+ if (blink_on)
|
||||
led_set_brightness(led_cdev,
|
||||
led_cdev->blink_brightness);
|
||||
else
|
||||
@@ -161,6 +182,18 @@ static bool can_hw_control(struct led_ne
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void get_device_state(struct led_netdev_data *trigger_data)
|
||||
+{
|
||||
+ struct ethtool_link_ksettings cmd;
|
||||
+
|
||||
+ trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
|
||||
+ if (!trigger_data->carrier_link_up)
|
||||
+ return;
|
||||
+
|
||||
+ if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd))
|
||||
+ trigger_data->link_speed = cmd.base.speed;
|
||||
+}
|
||||
+
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -196,8 +229,12 @@ static int set_device_name(struct led_ne
|
||||
dev_get_by_name(&init_net, trigger_data->device_name);
|
||||
|
||||
trigger_data->carrier_link_up = false;
|
||||
- if (trigger_data->net_dev != NULL)
|
||||
- trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
|
||||
+ trigger_data->link_speed = SPEED_UNKNOWN;
|
||||
+ if (trigger_data->net_dev != NULL) {
|
||||
+ rtnl_lock();
|
||||
+ get_device_state(trigger_data);
|
||||
+ rtnl_unlock();
|
||||
+ }
|
||||
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
@@ -234,6 +271,9 @@ static ssize_t netdev_led_attr_show(stru
|
||||
|
||||
switch (attr) {
|
||||
case TRIGGER_NETDEV_LINK:
|
||||
+ case TRIGGER_NETDEV_LINK_10:
|
||||
+ case TRIGGER_NETDEV_LINK_100:
|
||||
+ case TRIGGER_NETDEV_LINK_1000:
|
||||
case TRIGGER_NETDEV_TX:
|
||||
case TRIGGER_NETDEV_RX:
|
||||
bit = attr;
|
||||
@@ -249,7 +289,7 @@ static ssize_t netdev_led_attr_store(str
|
||||
size_t size, enum led_trigger_netdev_modes attr)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
- unsigned long state;
|
||||
+ unsigned long state, mode = trigger_data->mode;
|
||||
int ret;
|
||||
int bit;
|
||||
|
||||
@@ -259,6 +299,9 @@ static ssize_t netdev_led_attr_store(str
|
||||
|
||||
switch (attr) {
|
||||
case TRIGGER_NETDEV_LINK:
|
||||
+ case TRIGGER_NETDEV_LINK_10:
|
||||
+ case TRIGGER_NETDEV_LINK_100:
|
||||
+ case TRIGGER_NETDEV_LINK_1000:
|
||||
case TRIGGER_NETDEV_TX:
|
||||
case TRIGGER_NETDEV_RX:
|
||||
bit = attr;
|
||||
@@ -267,13 +310,20 @@ static ssize_t netdev_led_attr_store(str
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- cancel_delayed_work_sync(&trigger_data->work);
|
||||
-
|
||||
if (state)
|
||||
- set_bit(bit, &trigger_data->mode);
|
||||
+ set_bit(bit, &mode);
|
||||
else
|
||||
- clear_bit(bit, &trigger_data->mode);
|
||||
+ clear_bit(bit, &mode);
|
||||
+
|
||||
+ if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
|
||||
+ (test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &mode)))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
+ trigger_data->mode = mode;
|
||||
trigger_data->hw_control = can_hw_control(trigger_data);
|
||||
|
||||
set_baseline_state(trigger_data);
|
||||
@@ -295,6 +345,9 @@ static ssize_t netdev_led_attr_store(str
|
||||
static DEVICE_ATTR_RW(trigger_name)
|
||||
|
||||
DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
|
||||
+DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
|
||||
+DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
|
||||
+DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
|
||||
DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
|
||||
DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
|
||||
|
||||
@@ -338,6 +391,9 @@ static DEVICE_ATTR_RW(interval);
|
||||
static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_link.attr,
|
||||
+ &dev_attr_link_10.attr,
|
||||
+ &dev_attr_link_100.attr,
|
||||
+ &dev_attr_link_1000.attr,
|
||||
&dev_attr_rx.attr,
|
||||
&dev_attr_tx.attr,
|
||||
&dev_attr_interval.attr,
|
||||
@@ -368,9 +424,10 @@ static int netdev_trig_notify(struct not
|
||||
mutex_lock(&trigger_data->lock);
|
||||
|
||||
trigger_data->carrier_link_up = false;
|
||||
+ trigger_data->link_speed = SPEED_UNKNOWN;
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGENAME:
|
||||
- trigger_data->carrier_link_up = netif_carrier_ok(dev);
|
||||
+ get_device_state(trigger_data);
|
||||
fallthrough;
|
||||
case NETDEV_REGISTER:
|
||||
if (trigger_data->net_dev)
|
||||
@@ -384,7 +441,7 @@ static int netdev_trig_notify(struct not
|
||||
break;
|
||||
case NETDEV_UP:
|
||||
case NETDEV_CHANGE:
|
||||
- trigger_data->carrier_link_up = netif_carrier_ok(dev);
|
||||
+ get_device_state(trigger_data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -427,7 +484,10 @@ static void netdev_trig_work(struct work
|
||||
if (trigger_data->last_activity != new_activity) {
|
||||
led_stop_software_blink(trigger_data->led_cdev);
|
||||
|
||||
- invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode);
|
||||
+ invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode);
|
||||
interval = jiffies_to_msecs(
|
||||
atomic_read(&trigger_data->interval));
|
||||
/* base state is ON (link present) */
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -530,6 +530,9 @@ static inline void *led_get_trigger_data
|
||||
/* Trigger specific enum */
|
||||
enum led_trigger_netdev_modes {
|
||||
TRIGGER_NETDEV_LINK = 0,
|
||||
+ TRIGGER_NETDEV_LINK_10,
|
||||
+ TRIGGER_NETDEV_LINK_100,
|
||||
+ TRIGGER_NETDEV_LINK_1000,
|
||||
TRIGGER_NETDEV_TX,
|
||||
TRIGGER_NETDEV_RX,
|
||||
|
@ -0,0 +1,138 @@
|
||||
From f22f95b9ff1551c9bab13104131929f33d51f23f Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 19 Jun 2023 22:46:59 +0200
|
||||
Subject: [PATCH 2/3] leds: trigger: netdev: add additional specific link
|
||||
duplex mode
|
||||
|
||||
Add additional modes for specific link duplex. Use ethtool APIs to get the
|
||||
current link duplex and enable the LED accordingly. Under netdev event
|
||||
handler the rtnl lock is already held and is not needed to be set to
|
||||
access ethtool APIs.
|
||||
|
||||
This is especially useful for PHY and Switch that supports LEDs hw
|
||||
control for specific link duplex.
|
||||
|
||||
Add additional modes:
|
||||
- half_duplex: Turn on LED when link is half duplex
|
||||
- full_duplex: Turn on LED when link is full duplex
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Acked-by: Lee Jones <lee@kernel.org>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 27 +++++++++++++++++++++++++--
|
||||
include/linux/leds.h | 2 ++
|
||||
2 files changed, 27 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -55,6 +55,7 @@ struct led_netdev_data {
|
||||
|
||||
unsigned long mode;
|
||||
int link_speed;
|
||||
+ u8 duplex;
|
||||
|
||||
bool carrier_link_up;
|
||||
bool hw_control;
|
||||
@@ -98,6 +99,14 @@ static void set_baseline_state(struct le
|
||||
trigger_data->link_speed == SPEED_1000)
|
||||
blink_on = true;
|
||||
|
||||
+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) &&
|
||||
+ trigger_data->duplex == DUPLEX_HALF)
|
||||
+ blink_on = true;
|
||||
+
|
||||
+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode) &&
|
||||
+ trigger_data->duplex == DUPLEX_FULL)
|
||||
+ blink_on = true;
|
||||
+
|
||||
if (blink_on)
|
||||
led_set_brightness(led_cdev,
|
||||
led_cdev->blink_brightness);
|
||||
@@ -190,8 +199,10 @@ static void get_device_state(struct led_
|
||||
if (!trigger_data->carrier_link_up)
|
||||
return;
|
||||
|
||||
- if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd))
|
||||
+ if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) {
|
||||
trigger_data->link_speed = cmd.base.speed;
|
||||
+ trigger_data->duplex = cmd.base.duplex;
|
||||
+ }
|
||||
}
|
||||
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
@@ -230,6 +241,7 @@ static int set_device_name(struct led_ne
|
||||
|
||||
trigger_data->carrier_link_up = false;
|
||||
trigger_data->link_speed = SPEED_UNKNOWN;
|
||||
+ trigger_data->duplex = DUPLEX_UNKNOWN;
|
||||
if (trigger_data->net_dev != NULL) {
|
||||
rtnl_lock();
|
||||
get_device_state(trigger_data);
|
||||
@@ -274,6 +286,8 @@ static ssize_t netdev_led_attr_show(stru
|
||||
case TRIGGER_NETDEV_LINK_10:
|
||||
case TRIGGER_NETDEV_LINK_100:
|
||||
case TRIGGER_NETDEV_LINK_1000:
|
||||
+ case TRIGGER_NETDEV_HALF_DUPLEX:
|
||||
+ case TRIGGER_NETDEV_FULL_DUPLEX:
|
||||
case TRIGGER_NETDEV_TX:
|
||||
case TRIGGER_NETDEV_RX:
|
||||
bit = attr;
|
||||
@@ -302,6 +316,8 @@ static ssize_t netdev_led_attr_store(str
|
||||
case TRIGGER_NETDEV_LINK_10:
|
||||
case TRIGGER_NETDEV_LINK_100:
|
||||
case TRIGGER_NETDEV_LINK_1000:
|
||||
+ case TRIGGER_NETDEV_HALF_DUPLEX:
|
||||
+ case TRIGGER_NETDEV_FULL_DUPLEX:
|
||||
case TRIGGER_NETDEV_TX:
|
||||
case TRIGGER_NETDEV_RX:
|
||||
bit = attr;
|
||||
@@ -348,6 +364,8 @@ DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETD
|
||||
DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
|
||||
DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
|
||||
DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
|
||||
+DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
|
||||
+DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
|
||||
DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
|
||||
DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
|
||||
|
||||
@@ -394,6 +412,8 @@ static struct attribute *netdev_trig_att
|
||||
&dev_attr_link_10.attr,
|
||||
&dev_attr_link_100.attr,
|
||||
&dev_attr_link_1000.attr,
|
||||
+ &dev_attr_full_duplex.attr,
|
||||
+ &dev_attr_half_duplex.attr,
|
||||
&dev_attr_rx.attr,
|
||||
&dev_attr_tx.attr,
|
||||
&dev_attr_interval.attr,
|
||||
@@ -425,6 +445,7 @@ static int netdev_trig_notify(struct not
|
||||
|
||||
trigger_data->carrier_link_up = false;
|
||||
trigger_data->link_speed = SPEED_UNKNOWN;
|
||||
+ trigger_data->duplex = DUPLEX_UNKNOWN;
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGENAME:
|
||||
get_device_state(trigger_data);
|
||||
@@ -487,7 +508,9 @@ static void netdev_trig_work(struct work
|
||||
invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) ||
|
||||
test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
|
||||
test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
|
||||
- test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode);
|
||||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) ||
|
||||
+ test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode);
|
||||
interval = jiffies_to_msecs(
|
||||
atomic_read(&trigger_data->interval));
|
||||
/* base state is ON (link present) */
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -533,6 +533,8 @@ enum led_trigger_netdev_modes {
|
||||
TRIGGER_NETDEV_LINK_10,
|
||||
TRIGGER_NETDEV_LINK_100,
|
||||
TRIGGER_NETDEV_LINK_1000,
|
||||
+ TRIGGER_NETDEV_HALF_DUPLEX,
|
||||
+ TRIGGER_NETDEV_FULL_DUPLEX,
|
||||
TRIGGER_NETDEV_TX,
|
||||
TRIGGER_NETDEV_RX,
|
||||
|
@ -0,0 +1,45 @@
|
||||
From b655892ffd6d89b0c7407e099c40dbde82ee3f03 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 19 Jun 2023 22:47:00 +0200
|
||||
Subject: [PATCH 3/3] leds: trigger: netdev: expose hw_control status via sysfs
|
||||
|
||||
Expose hw_control status via sysfs for the netdev trigger to give
|
||||
userspace better understanding of the current state of the trigger and
|
||||
the LED.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
|
||||
Acked-by: Lee Jones <lee@kernel.org>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/drivers/leds/trigger/ledtrig-netdev.c
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -406,6 +406,16 @@ static ssize_t interval_store(struct dev
|
||||
|
||||
static DEVICE_ATTR_RW(interval);
|
||||
|
||||
+static ssize_t hw_control_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", trigger_data->hw_control);
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RO(hw_control);
|
||||
+
|
||||
static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_link.attr,
|
||||
@@ -417,6 +427,7 @@ static struct attribute *netdev_trig_att
|
||||
&dev_attr_rx.attr,
|
||||
&dev_attr_tx.attr,
|
||||
&dev_attr_interval.attr,
|
||||
+ &dev_attr_hw_control.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(netdev_trig);
|
Loading…
Reference in New Issue
Block a user