1 From d5e01266e7f5fa12400d4c8aa4e86fe89dcc61e9 Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Mon, 19 Jun 2023 22:46:58 +0200
4 Subject: [PATCH 1/3] leds: trigger: netdev: add additional specific link speed
7 Add additional modes for specific link speed. Use ethtool APIs to get the
8 current link speed and enable the LED accordingly. Under netdev event
9 handler the rtnl lock is already held and is not needed to be set to
12 This is especially useful for PHY and Switch that supports LEDs hw
13 control for specific link speed. (example scenario a PHY that have 2 LED
14 connected one green and one orange where the green is turned on with
15 1000mbps speed and orange is turned on with 10mpbs speed)
17 On mode set from sysfs we check if we have enabled split link speed mode
18 and reject enabling generic link mode to prevent wrong and redundant
21 Rework logic on the set baseline state to support these new modes to
22 select if we need to turn on or off the LED.
25 - link_10: Turn on LED when link speed is 10mbps
26 - link_100: Turn on LED when link speed is 100mbps
27 - link_1000: Turn on LED when link speed is 1000mbps
29 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
30 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
31 Acked-by: Lee Jones <lee@kernel.org>
32 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
34 drivers/leds/trigger/ledtrig-netdev.c | 80 +++++++++++++++++++++++----
35 include/linux/leds.h | 3 +
36 2 files changed, 73 insertions(+), 10 deletions(-)
38 --- a/drivers/leds/trigger/ledtrig-netdev.c
39 +++ b/drivers/leds/trigger/ledtrig-netdev.c
41 #include <linux/atomic.h>
42 #include <linux/ctype.h>
43 #include <linux/device.h>
44 +#include <linux/ethtool.h>
45 #include <linux/init.h>
46 #include <linux/jiffies.h>
47 #include <linux/kernel.h>
49 #include <linux/module.h>
50 #include <linux/netdevice.h>
51 #include <linux/mutex.h>
52 +#include <linux/rtnetlink.h>
53 #include <linux/timer.h>
56 @@ -52,6 +54,8 @@ struct led_netdev_data {
57 unsigned int last_activity;
65 @@ -77,7 +81,24 @@ static void set_baseline_state(struct le
66 if (!trigger_data->carrier_link_up) {
67 led_set_brightness(led_cdev, LED_OFF);
69 + bool blink_on = false;
71 if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode))
74 + if (test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) &&
75 + trigger_data->link_speed == SPEED_10)
78 + if (test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) &&
79 + trigger_data->link_speed == SPEED_100)
82 + if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) &&
83 + trigger_data->link_speed == SPEED_1000)
87 led_set_brightness(led_cdev,
88 led_cdev->blink_brightness);
90 @@ -161,6 +182,18 @@ static bool can_hw_control(struct led_ne
94 +static void get_device_state(struct led_netdev_data *trigger_data)
96 + struct ethtool_link_ksettings cmd;
98 + trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
99 + if (!trigger_data->carrier_link_up)
102 + if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd))
103 + trigger_data->link_speed = cmd.base.speed;
106 static ssize_t device_name_show(struct device *dev,
107 struct device_attribute *attr, char *buf)
109 @@ -196,8 +229,12 @@ static int set_device_name(struct led_ne
110 dev_get_by_name(&init_net, trigger_data->device_name);
112 trigger_data->carrier_link_up = false;
113 - if (trigger_data->net_dev != NULL)
114 - trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
115 + trigger_data->link_speed = SPEED_UNKNOWN;
116 + if (trigger_data->net_dev != NULL) {
118 + get_device_state(trigger_data);
122 trigger_data->last_activity = 0;
124 @@ -234,6 +271,9 @@ static ssize_t netdev_led_attr_show(stru
127 case TRIGGER_NETDEV_LINK:
128 + case TRIGGER_NETDEV_LINK_10:
129 + case TRIGGER_NETDEV_LINK_100:
130 + case TRIGGER_NETDEV_LINK_1000:
131 case TRIGGER_NETDEV_TX:
132 case TRIGGER_NETDEV_RX:
134 @@ -249,7 +289,7 @@ static ssize_t netdev_led_attr_store(str
135 size_t size, enum led_trigger_netdev_modes attr)
137 struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
138 - unsigned long state;
139 + unsigned long state, mode = trigger_data->mode;
143 @@ -259,6 +299,9 @@ static ssize_t netdev_led_attr_store(str
146 case TRIGGER_NETDEV_LINK:
147 + case TRIGGER_NETDEV_LINK_10:
148 + case TRIGGER_NETDEV_LINK_100:
149 + case TRIGGER_NETDEV_LINK_1000:
150 case TRIGGER_NETDEV_TX:
151 case TRIGGER_NETDEV_RX:
153 @@ -267,13 +310,20 @@ static ssize_t netdev_led_attr_store(str
157 - cancel_delayed_work_sync(&trigger_data->work);
160 - set_bit(bit, &trigger_data->mode);
161 + set_bit(bit, &mode);
163 - clear_bit(bit, &trigger_data->mode);
164 + clear_bit(bit, &mode);
166 + if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
167 + (test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
168 + test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
169 + test_bit(TRIGGER_NETDEV_LINK_1000, &mode)))
172 + cancel_delayed_work_sync(&trigger_data->work);
174 + trigger_data->mode = mode;
175 trigger_data->hw_control = can_hw_control(trigger_data);
177 set_baseline_state(trigger_data);
178 @@ -295,6 +345,9 @@ static ssize_t netdev_led_attr_store(str
179 static DEVICE_ATTR_RW(trigger_name)
181 DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
182 +DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
183 +DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
184 +DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
185 DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
186 DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
188 @@ -338,6 +391,9 @@ static DEVICE_ATTR_RW(interval);
189 static struct attribute *netdev_trig_attrs[] = {
190 &dev_attr_device_name.attr,
192 + &dev_attr_link_10.attr,
193 + &dev_attr_link_100.attr,
194 + &dev_attr_link_1000.attr,
197 &dev_attr_interval.attr,
198 @@ -368,9 +424,10 @@ static int netdev_trig_notify(struct not
199 mutex_lock(&trigger_data->lock);
201 trigger_data->carrier_link_up = false;
202 + trigger_data->link_speed = SPEED_UNKNOWN;
204 case NETDEV_CHANGENAME:
205 - trigger_data->carrier_link_up = netif_carrier_ok(dev);
206 + get_device_state(trigger_data);
208 case NETDEV_REGISTER:
209 if (trigger_data->net_dev)
210 @@ -384,7 +441,7 @@ static int netdev_trig_notify(struct not
214 - trigger_data->carrier_link_up = netif_carrier_ok(dev);
215 + get_device_state(trigger_data);
219 @@ -427,7 +484,10 @@ static void netdev_trig_work(struct work
220 if (trigger_data->last_activity != new_activity) {
221 led_stop_software_blink(trigger_data->led_cdev);
223 - invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode);
224 + invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) ||
225 + test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
226 + test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
227 + test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode);
228 interval = jiffies_to_msecs(
229 atomic_read(&trigger_data->interval));
230 /* base state is ON (link present) */
231 --- a/include/linux/leds.h
232 +++ b/include/linux/leds.h
233 @@ -530,6 +530,9 @@ static inline void *led_get_trigger_data
234 /* Trigger specific enum */
235 enum led_trigger_netdev_modes {
236 TRIGGER_NETDEV_LINK = 0,
237 + TRIGGER_NETDEV_LINK_10,
238 + TRIGGER_NETDEV_LINK_100,
239 + TRIGGER_NETDEV_LINK_1000,