Skip to content

Commit d5e0126

Browse files
Ansuelkuba-moo
authored andcommitted
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 <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Acked-by: Lee Jones <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 7ad7b70 commit d5e0126

File tree

2 files changed

+73
-10
lines changed

2 files changed

+73
-10
lines changed

drivers/leds/trigger/ledtrig-netdev.c

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/atomic.h>
1414
#include <linux/ctype.h>
1515
#include <linux/device.h>
16+
#include <linux/ethtool.h>
1617
#include <linux/init.h>
1718
#include <linux/jiffies.h>
1819
#include <linux/kernel.h>
@@ -21,6 +22,7 @@
2122
#include <linux/module.h>
2223
#include <linux/netdevice.h>
2324
#include <linux/mutex.h>
25+
#include <linux/rtnetlink.h>
2426
#include <linux/timer.h>
2527
#include "../leds.h"
2628

@@ -52,6 +54,8 @@ struct led_netdev_data {
5254
unsigned int last_activity;
5355

5456
unsigned long mode;
57+
int link_speed;
58+
5559
bool carrier_link_up;
5660
bool hw_control;
5761
};
@@ -77,7 +81,24 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
7781
if (!trigger_data->carrier_link_up) {
7882
led_set_brightness(led_cdev, LED_OFF);
7983
} else {
84+
bool blink_on = false;
85+
8086
if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode))
87+
blink_on = true;
88+
89+
if (test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) &&
90+
trigger_data->link_speed == SPEED_10)
91+
blink_on = true;
92+
93+
if (test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) &&
94+
trigger_data->link_speed == SPEED_100)
95+
blink_on = true;
96+
97+
if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) &&
98+
trigger_data->link_speed == SPEED_1000)
99+
blink_on = true;
100+
101+
if (blink_on)
81102
led_set_brightness(led_cdev,
82103
led_cdev->blink_brightness);
83104
else
@@ -161,6 +182,18 @@ static bool can_hw_control(struct led_netdev_data *trigger_data)
161182
return true;
162183
}
163184

185+
static void get_device_state(struct led_netdev_data *trigger_data)
186+
{
187+
struct ethtool_link_ksettings cmd;
188+
189+
trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
190+
if (!trigger_data->carrier_link_up)
191+
return;
192+
193+
if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd))
194+
trigger_data->link_speed = cmd.base.speed;
195+
}
196+
164197
static ssize_t device_name_show(struct device *dev,
165198
struct device_attribute *attr, char *buf)
166199
{
@@ -196,8 +229,12 @@ static int set_device_name(struct led_netdev_data *trigger_data,
196229
dev_get_by_name(&init_net, trigger_data->device_name);
197230

198231
trigger_data->carrier_link_up = false;
199-
if (trigger_data->net_dev != NULL)
200-
trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
232+
trigger_data->link_speed = SPEED_UNKNOWN;
233+
if (trigger_data->net_dev != NULL) {
234+
rtnl_lock();
235+
get_device_state(trigger_data);
236+
rtnl_unlock();
237+
}
201238

202239
trigger_data->last_activity = 0;
203240

@@ -234,6 +271,9 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
234271

235272
switch (attr) {
236273
case TRIGGER_NETDEV_LINK:
274+
case TRIGGER_NETDEV_LINK_10:
275+
case TRIGGER_NETDEV_LINK_100:
276+
case TRIGGER_NETDEV_LINK_1000:
237277
case TRIGGER_NETDEV_TX:
238278
case TRIGGER_NETDEV_RX:
239279
bit = attr;
@@ -249,7 +289,7 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
249289
size_t size, enum led_trigger_netdev_modes attr)
250290
{
251291
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
252-
unsigned long state;
292+
unsigned long state, mode = trigger_data->mode;
253293
int ret;
254294
int bit;
255295

@@ -259,6 +299,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
259299

260300
switch (attr) {
261301
case TRIGGER_NETDEV_LINK:
302+
case TRIGGER_NETDEV_LINK_10:
303+
case TRIGGER_NETDEV_LINK_100:
304+
case TRIGGER_NETDEV_LINK_1000:
262305
case TRIGGER_NETDEV_TX:
263306
case TRIGGER_NETDEV_RX:
264307
bit = attr;
@@ -267,13 +310,20 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
267310
return -EINVAL;
268311
}
269312

270-
cancel_delayed_work_sync(&trigger_data->work);
271-
272313
if (state)
273-
set_bit(bit, &trigger_data->mode);
314+
set_bit(bit, &mode);
274315
else
275-
clear_bit(bit, &trigger_data->mode);
316+
clear_bit(bit, &mode);
317+
318+
if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
319+
(test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
320+
test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
321+
test_bit(TRIGGER_NETDEV_LINK_1000, &mode)))
322+
return -EINVAL;
323+
324+
cancel_delayed_work_sync(&trigger_data->work);
276325

326+
trigger_data->mode = mode;
277327
trigger_data->hw_control = can_hw_control(trigger_data);
278328

279329
set_baseline_state(trigger_data);
@@ -295,6 +345,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
295345
static DEVICE_ATTR_RW(trigger_name)
296346

297347
DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
348+
DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
349+
DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
350+
DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
298351
DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
299352
DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
300353

@@ -338,6 +391,9 @@ static DEVICE_ATTR_RW(interval);
338391
static struct attribute *netdev_trig_attrs[] = {
339392
&dev_attr_device_name.attr,
340393
&dev_attr_link.attr,
394+
&dev_attr_link_10.attr,
395+
&dev_attr_link_100.attr,
396+
&dev_attr_link_1000.attr,
341397
&dev_attr_rx.attr,
342398
&dev_attr_tx.attr,
343399
&dev_attr_interval.attr,
@@ -368,9 +424,10 @@ static int netdev_trig_notify(struct notifier_block *nb,
368424
mutex_lock(&trigger_data->lock);
369425

370426
trigger_data->carrier_link_up = false;
427+
trigger_data->link_speed = SPEED_UNKNOWN;
371428
switch (evt) {
372429
case NETDEV_CHANGENAME:
373-
trigger_data->carrier_link_up = netif_carrier_ok(dev);
430+
get_device_state(trigger_data);
374431
fallthrough;
375432
case NETDEV_REGISTER:
376433
if (trigger_data->net_dev)
@@ -384,7 +441,7 @@ static int netdev_trig_notify(struct notifier_block *nb,
384441
break;
385442
case NETDEV_UP:
386443
case NETDEV_CHANGE:
387-
trigger_data->carrier_link_up = netif_carrier_ok(dev);
444+
get_device_state(trigger_data);
388445
break;
389446
}
390447

@@ -427,7 +484,10 @@ static void netdev_trig_work(struct work_struct *work)
427484
if (trigger_data->last_activity != new_activity) {
428485
led_stop_software_blink(trigger_data->led_cdev);
429486

430-
invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode);
487+
invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) ||
488+
test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
489+
test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
490+
test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode);
431491
interval = jiffies_to_msecs(
432492
atomic_read(&trigger_data->interval));
433493
/* base state is ON (link present) */

include/linux/leds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
555555
/* Trigger specific enum */
556556
enum led_trigger_netdev_modes {
557557
TRIGGER_NETDEV_LINK = 0,
558+
TRIGGER_NETDEV_LINK_10,
559+
TRIGGER_NETDEV_LINK_100,
560+
TRIGGER_NETDEV_LINK_1000,
558561
TRIGGER_NETDEV_TX,
559562
TRIGGER_NETDEV_RX,
560563

0 commit comments

Comments
 (0)