diff mbox series

[v2,16/17] leds: leds-nuc: add support for changing the ethernet type indicator

Message ID 792598f4a1a3219b6517057c92559b0f0a95b419.1621349814.git.mchehab+huawei@kernel.org
State New
Headers show
Series Adding support for controlling the leds found on Intel NUC | expand

Commit Message

Mauro Carvalho Chehab May 18, 2021, 3:09 p.m. UTC
The Ethernet type indicator can be configured to show the status
of LAN1, LAN1 or both. Add support for it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/leds/leds-nuc.c | 89 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

Comments

Marek Behún May 19, 2021, 8:02 a.m. UTC | #1
What possible configurations does this support?

Does this blink on rx/tx activity for a specific ethernet port?

There is a work in progress to add support for transparent offloading of
LED triggers, with the netdev trigger being the first target.

This means that after that is done, you could implement this driver so
that when netdev trigger is enabled on a supported interface, your
driver will offload the blinking to the HW.

This should probably also work for HDD activity, but this would need a
blockdev trigger first...

Marek
Mauro Carvalho Chehab May 19, 2021, 10:18 a.m. UTC | #2
Em Wed, 19 May 2021 10:02:53 +0200
Marek Behún <kabel@kernel.org> escreveu:

> What possible configurations does this support?

> 

> Does this blink on rx/tx activity for a specific ethernet port?

> 


When the indicator is set to monitor Ethernet, it can work on either
LAN1, LAN2 or both LAN interfaces.

> There is a work in progress to add support for transparent offloading of

> LED triggers, with the netdev trigger being the first target.

> 

> This means that after that is done, you could implement this driver so

> that when netdev trigger is enabled on a supported interface, your

> driver will offload the blinking to the HW.


On NUC leds, this is already offloaded to HW/firmware. 

All it takes is to tell the BIOS via ACPI/WMI what LED will be used
for monitoring the Ethernet activity, and on what port(s).
 
> This should probably also work for HDD activity, but this would need a

> blockdev trigger first...


HDD activity is also HW/firmware monitored. The only thing the Kernel
needs to to is to select what LED will be set as the HDD activity
indicator.

Thanks,
Mauro
Marek Behún May 19, 2021, 12:11 p.m. UTC | #3
On Wed, 19 May 2021 12:18:12 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> Em Wed, 19 May 2021 10:02:53 +0200

> Marek Behún <kabel@kernel.org> escreveu:

> 

> > What possible configurations does this support?

> > 

> > Does this blink on rx/tx activity for a specific ethernet port?

> >   

> 

> When the indicator is set to monitor Ethernet, it can work on either

> LAN1, LAN2 or both LAN interfaces.

> 

> > There is a work in progress to add support for transparent offloading of

> > LED triggers, with the netdev trigger being the first target.

> > 

> > This means that after that is done, you could implement this driver so

> > that when netdev trigger is enabled on a supported interface, your

> > driver will offload the blinking to the HW.  

> 

> On NUC leds, this is already offloaded to HW/firmware. 

> 

> All it takes is to tell the BIOS via ACPI/WMI what LED will be used

> for monitoring the Ethernet activity, and on what port(s).


Can the LED be put into software controlled mode and also into HW
controlled mode so that HW blinks the LED on ethernet activity?

If so, then this is what I am talking about: transparent HW offloading
of LED triggers:
- I have a LED in /sys/class/leds
- I set "netdev" trigger on this LED
- I set ethernet interface for which the LED should blink
- if the HW can blink the LED for that particular ethernet interface,
  the driver should use HW blinking...

> > This should probably also work for HDD activity, but this would need a

> > blockdev trigger first...  

> 

> HDD activity is also HW/firmware monitored. The only thing the Kernel

> needs to to is to select what LED will be set as the HDD activity

> indicator.


Ditto as above, if we had a "blockdev" LED trigger.

Marek
Mauro Carvalho Chehab May 19, 2021, 2:24 p.m. UTC | #4
Em Wed, 19 May 2021 14:11:02 +0200
Marek Behún <kabel@kernel.org> escreveu:

> On Wed, 19 May 2021 12:18:12 +0200

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> 

> > Em Wed, 19 May 2021 10:02:53 +0200

> > Marek Behún <kabel@kernel.org> escreveu:

> >   

> > > What possible configurations does this support?

> > > 

> > > Does this blink on rx/tx activity for a specific ethernet port?

> > >     

> > 

> > When the indicator is set to monitor Ethernet, it can work on either

> > LAN1, LAN2 or both LAN interfaces.

> >   

> > > There is a work in progress to add support for transparent offloading of

> > > LED triggers, with the netdev trigger being the first target.

> > > 

> > > This means that after that is done, you could implement this driver so

> > > that when netdev trigger is enabled on a supported interface, your

> > > driver will offload the blinking to the HW.    

> > 

> > On NUC leds, this is already offloaded to HW/firmware. 

> > 

> > All it takes is to tell the BIOS via ACPI/WMI what LED will be used

> > for monitoring the Ethernet activity, and on what port(s).  

> 

> Can the LED be put into software controlled mode and also into HW

> controlled mode so that HW blinks the LED on ethernet activity?


On a given time, a LED will either be in hardware-controlled mode or in
Software-controlled one. It should be noticed that software-controlled
mode should first be enabled by a BIOS option.

The default is to be hardware-controlled.

I don't intend to implement myself support for software-controlled
mode in Kernel, as this will probably be a lot worse than letting
the hardware control the led directly. 

See, changing the LED in software on NUC happens via ACPI calls, meaning
that the Kernel should be interrupted in order to run some code
inside the BIOS that will actually program the hardware. Switching to
BIOS produces context switching and may also interrupt the other
CPUs, as the BIOS may need to do CPU locking, in order to prevent 
L1/L2/L3 cache issues.

On other words, if no extra care is taken, it could have bad side 
effects at the machine's performance and affect system's latency,
eventually resulting on things like audio clicks and pops, if some
audio is playing while such calls keep happening.

So, IMO, there's very little sense on trying to re-implement the
already existing hardware-controlled events via software emulation.

> If so, then this is what I am talking about: transparent HW offloading

> of LED triggers:

> - I have a LED in /sys/class/leds

> - I set "netdev" trigger on this LED

> - I set ethernet interface for which the LED should blink

> - if the HW can blink the LED for that particular ethernet interface,

>   the driver should use HW blinking...


Sorry, but I guess I missed something here. Are you meaning to use
the code under "ledtrig-netdev.c" or something else? 

The code at ledtrig-netdev.c allocates a trigger data, initializes a
spin lock, initializes a delayed work, registers a notifier, sets a 
trigger interval, etc. It is perfectly fine for software-controlled
LEDs, but none of those will ever be used by the NUC driver, 
if it only implements HW blinking for the Ethernet interfaces
(and, as said before, there's little sense emulating it via software
on such devices).

Thanks,
Mauro
Marek Behún May 19, 2021, 3:55 p.m. UTC | #5
On Wed, 19 May 2021 16:24:13 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> On other words, if no extra care is taken, it could have bad side 

> effects at the machine's performance and affect system's latency,

> eventually resulting on things like audio clicks and pops, if some

> audio is playing while such calls keep happening.


In general we want for every LED that is registered into kernel as a LED
classdev to be possible to control the brightness by software. If the
hardware supports it, it should be available. There is a _blocking
.brightness_set_blocking callback for LEDs which may block when setting
brightness.
But even if we did not want to support software control, the transparent
trigger offloading is still relevant. See below.

> So, IMO, there's very little sense on trying to re-implement the

> already existing hardware-controlled events via software emulation.


We have a misunderstanding here, probably because of my bad
explanation, I will try to clarify.

> Sorry, but I guess I missed something here. Are you meaning to use

> the code under "ledtrig-netdev.c" or something else? 

> 

> The code at ledtrig-netdev.c allocates a trigger data, initializes a

> spin lock, initializes a delayed work, registers a notifier, sets a 

> trigger interval, etc. It is perfectly fine for software-controlled

> LEDs, but none of those will ever be used by the NUC driver, 

> if it only implements HW blinking for the Ethernet interfaces

> (and, as said before, there's little sense emulating it via software

> on such devices).


The idea of transparent offloading of LED triggers to HW (if HW
supports it) is to have a consistent and unified interface.

Currently we have a driver (leds-ns2 I think) which allows putting the
LED into HW controlled mode (to blink on SATA disk activity). This is
done by writing 1 into /sys/class/leds/<LED>/sata.

In your proposal you are creating several sysfs files:
  indicator
  hdd_default (notice difference from "sata" sysfs file in leds-ns2
               driver)
  ethernet_type

So the problem here is that this API is not unified. This is different
from how leds-ns2 driver does this, and both of these solutions are
wrong, because they are not extendable.

The correct way to do this is via LED triggers, i.e. if I want a LED to
blink on network activity, then I should use netdev trigger and nothing
else. The netdev trigger should determine whether the underlying LED
driver can set the LED to blink on network activity in HW. If HW
supports it, netdev trigger should use this, otherwise netdev trigger
should blink the LED in software.

Currently the netdev trigger does the blinking in software only
(code in "ledtrig-netdev.c" file). There is a WIP to add the necessary
support for the netdev trigger to have the ability to offload blinking
to HW. I will try to respin this WIP and send patches for review.

Once netdev trigger supports this feature, you can implement your
driver in this way. You can even make your driver depend on netdev
trigger and set the specific LED into netdev triggering by default, and
even forbidding anything else. But this is the corrent way to do this,
instead of creating new sysfs API that is non-extendable.

I am sorry that I did not explain this thoroughly in previous mails.
Hopefully this explanation is better.

Marek

PS: This is relevant for disk activity as well.
Mauro Carvalho Chehab May 19, 2021, 6:30 p.m. UTC | #6
Em Wed, 19 May 2021 17:55:03 +0200
Marek Behún <kabel@kernel.org> escreveu:

> On Wed, 19 May 2021 16:24:13 +0200

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> 

> > On other words, if no extra care is taken, it could have bad side 

> > effects at the machine's performance and affect system's latency,

> > eventually resulting on things like audio clicks and pops, if some

> > audio is playing while such calls keep happening.  

> 

> In general we want for every LED that is registered into kernel as a LED

> classdev to be possible to control the brightness by software. If the

> hardware supports it, it should be available. 


This is supported, but maybe not the same way as on other drivers.

There are two separate things: ON/OFF and LED brightness, when turned ON.

On other words, NUC leds allow to set the brightness ranging from 0 to 100,
but if the brightness is, let's say 50%, it means that, when the LED
is triggered by the hardware:

	- ON would mean 50%; and 
	- OFF would mean 0%.

On other words, it actually adjusts the maximum brightness level.

Btw, this also applies to software control, as the hardware can still
blink the LED, the available properties for software control indicator
are:
	- brightness.
	- blink behavior and frequency;
	- led color (available only if BIOS says that it is a 
	  multi-colored led);

> There is a _blocking

> .brightness_set_blocking callback for LEDs which may block when setting

> brightness.

> But even if we did not want to support software control, the transparent

> trigger offloading is still relevant. See below.

> 

> > So, IMO, there's very little sense on trying to re-implement the

> > already existing hardware-controlled events via software emulation.  

> 

> We have a misunderstanding here, probably because of my bad

> explanation, I will try to clarify.

> 

> > Sorry, but I guess I missed something here. Are you meaning to use

> > the code under "ledtrig-netdev.c" or something else? 

> > 

> > The code at ledtrig-netdev.c allocates a trigger data, initializes a

> > spin lock, initializes a delayed work, registers a notifier, sets a 

> > trigger interval, etc. It is perfectly fine for software-controlled

> > LEDs, but none of those will ever be used by the NUC driver, 

> > if it only implements HW blinking for the Ethernet interfaces

> > (and, as said before, there's little sense emulating it via software

> > on such devices).  

> 

> The idea of transparent offloading of LED triggers to HW (if HW

> supports it) is to have a consistent and unified interface.


Makes sense, but not sure if the current API will work.

> Currently we have a driver (leds-ns2 I think) which allows putting the

> LED into HW controlled mode (to blink on SATA disk activity). This is

> done by writing 1 into /sys/class/leds/<LED>/sata.

> 

> In your proposal you are creating several sysfs files:

>   indicator

>   hdd_default (notice difference from "sata" sysfs file in leds-ns2

>                driver)

>   ethernet_type

> 

> So the problem here is that this API is not unified. This is different

> from how leds-ns2 driver does this, and both of these solutions are

> wrong, because they are not extendable.


Partially agreed, but I'm not so sure if the reverse is not true ;-)

I mean, the current LED API was designed and tested on drivers that
allow direct control of the LED (and then extended to some cases
where the hardware allows offloading).

The NUC API is just the opposite: there, the BIOS has full control of
the hardware, but it provides an interface that allows changing
the LED behavior, up to some extend. It also allows controlling the
LED hardware and make it blink while it is suspended/hibernating, 
which is something that a direct LED control wouldn't allow.

So, for instance, if we stick with the current LED API, there's no
way to tell that the power LED should:

	- blink on every 5 seconds, using up to 20% of brightness
	  when the system is suspended;
	- strobe on every 10 seconds using up to 50% of brightness
	  when the system is hibernated;
	- use 100% of brigntness and don't blink when powered up.

> The correct way to do this is via LED triggers, i.e. if I want a LED to

> blink on network activity, then I should use netdev trigger and nothing

> else. The netdev trigger should determine whether the underlying LED

> driver can set the LED to blink on network activity in HW. If HW

> supports it, netdev trigger should use this, otherwise netdev trigger

> should blink the LED in software.


I understand the desire of exposing the same API, but the current
trigger code doesn't seem to be fit. I mean, the init sequence
done at netdev_trig_activate():

	trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
	if (!trigger_data)
		return -ENOMEM;

	spin_lock_init(&trigger_data->lock);

	trigger_data->notifier.notifier_call = netdev_trig_notify;
	trigger_data->notifier.priority = 10;

	INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);

	trigger_data->led_cdev = led_cdev;
	trigger_data->net_dev = NULL;
	trigger_data->device_name[0] = 0;

	trigger_data->mode = 0;
	atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
	trigger_data->last_activity = 0;

	led_set_trigger_data(led_cdev, trigger_data);

	rc = register_netdevice_notifier(&trigger_data->notifier);
	if (rc)
		kfree(trigger_data);

doesn't make sense when the LED will be trigged by the hardware,
and registering a notifier for netdevice is overkill.

The exported attributes:

	static struct attribute *netdev_trig_attrs[] = {
		&dev_attr_device_name.attr,
		&dev_attr_link.attr,
		&dev_attr_rx.attr,
		&dev_attr_tx.attr,
		&dev_attr_interval.attr,
		NULL
	};
	ATTRIBUTE_GROUPS(netdev_trig);

also won't apply, as the NUC API doesn't support setting device_name, 
RX, TX, link or interval.

Instead, it allows to set:
- the maximum brightness;
- the color (if the LED is multi-colored);
- the physical port(s) that will be monitored:
	- LAN1
	- LAN2
	- LAN1+LAN2

where LAN1 and LAN2 are two physical ports behind the NUC device.
The netdev layer knows those as "eno1" and "enp5s0" (not 
necessarily at the same order).

Also, while netdev trigger seems to use just one device name,
the NUC allows to monitor both interfaces at the same time.

See, unfortunately I can't see a common API that would fit
nicely on both cases.

> Currently the netdev trigger does the blinking in software only

> (code in "ledtrig-netdev.c" file). There is a WIP to add the necessary

> support for the netdev trigger to have the ability to offload blinking

> to HW. I will try to respin this WIP and send patches for review.

> 

> Once netdev trigger supports this feature, you can implement your

> driver in this way. You can even make your driver depend on netdev

> trigger 


> and set the specific LED into netdev triggering by default, and

> even forbidding anything else. 


This is also probably one of the differences from other hardware:
In principle, *any* led can monitor *any* hardware event[1].

[1] There are some bitmaps at the interface that would allow the
    BIOS to restrict it, but, at least on the device I have
    (Hades Canyon), there's no such restriction: the same bitmap
    masks are returned for all LEDs.

> But this is the corrent way to do this,

> instead of creating new sysfs API that is non-extendable.

> 

> I am sorry that I did not explain this thoroughly in previous mails.

> Hopefully this explanation is better.


Yes, it is a lot better. Thanks for the explanation!

Still, as I pointed above, I'm so far unable to see much in common 
with the way the existing LED drivers work and the way NUC LEDS are
controlled.

So, as much I would love to just reuse something that already exists,
perhaps it would make more sense to create a separate class for such
kind of usage.

> 

> Marek

> 

> PS: This is relevant for disk activity as well.




Thanks,
Mauro
Marek Behún May 20, 2021, 11 a.m. UTC | #7
On Wed, 19 May 2021 20:30:14 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> Em Wed, 19 May 2021 17:55:03 +0200

> Marek Behún <kabel@kernel.org> escreveu:

> 

> > On Wed, 19 May 2021 16:24:13 +0200

> > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> >   

> > > On other words, if no extra care is taken, it could have bad side 

> > > effects at the machine's performance and affect system's latency,

> > > eventually resulting on things like audio clicks and pops, if some

> > > audio is playing while such calls keep happening.    

> > 

> > In general we want for every LED that is registered into kernel as

> > a LED classdev to be possible to control the brightness by

> > software. If the hardware supports it, it should be available.   

> 

> This is supported, but maybe not the same way as on other drivers.

> 

> There are two separate things: ON/OFF and LED brightness, when turned

> ON.

> 

> On other words, NUC leds allow to set the brightness ranging from 0

> to 100, but if the brightness is, let's say 50%, it means that, when

> the LED is triggered by the hardware:

> 

> 	- ON would mean 50%; and 

> 	- OFF would mean 0%.


Not a problem, there are other controller which also work this way,
leds-turris-omnia for example. Also LED triggers are supposed to work
this way: if a LED supports non-binary brightness (for exmaple 0-100),
and the user sets brightness 50, and then a trigger, then the trigger
should blink the LED with brightness 50.

> On other words, it actually adjusts the maximum brightness level.

> 

> Btw, this also applies to software control, as the hardware can still

> blink the LED, the available properties for software control indicator

> are:

> 	- brightness.

> 	- blink behavior and frequency;

> 	- led color (available only if BIOS says that it is a 

> 	  multi-colored led);


- if the hw supports setting the LED to blink with a specific frequency
  (not depending on any other HW like disk or ethernet, just blinking),
  you should also implement the .blink_set method (look at
  Documentation/leds/leds-class.rst section Hardware accelerated blink
  of LEDs)
- if BIOS says the LED is multi-colored, you should register it as
  multi-colored LED via multicolor framework

> > There is a _blocking

> > .brightness_set_blocking callback for LEDs which may block when

> > setting brightness.

> > But even if we did not want to support software control, the

> > transparent trigger offloading is still relevant. See below.

> >   

> > > So, IMO, there's very little sense on trying to re-implement the

> > > already existing hardware-controlled events via software

> > > emulation.    

> > 

> > We have a misunderstanding here, probably because of my bad

> > explanation, I will try to clarify.

> >   

> > > Sorry, but I guess I missed something here. Are you meaning to use

> > > the code under "ledtrig-netdev.c" or something else? 

> > > 

> > > The code at ledtrig-netdev.c allocates a trigger data,

> > > initializes a spin lock, initializes a delayed work, registers a

> > > notifier, sets a trigger interval, etc. It is perfectly fine for

> > > software-controlled LEDs, but none of those will ever be used by

> > > the NUC driver, if it only implements HW blinking for the

> > > Ethernet interfaces (and, as said before, there's little sense

> > > emulating it via software on such devices).    

> > 

> > The idea of transparent offloading of LED triggers to HW (if HW

> > supports it) is to have a consistent and unified interface.  

> 

> Makes sense, but not sure if the current API will work.

> 

> > Currently we have a driver (leds-ns2 I think) which allows putting

> > the LED into HW controlled mode (to blink on SATA disk activity).

> > This is done by writing 1 into /sys/class/leds/<LED>/sata.

> > 

> > In your proposal you are creating several sysfs files:

> >   indicator

> >   hdd_default (notice difference from "sata" sysfs file in leds-ns2

> >                driver)

> >   ethernet_type

> > 

> > So the problem here is that this API is not unified. This is

> > different from how leds-ns2 driver does this, and both of these

> > solutions are wrong, because they are not extendable.  

> 

> Partially agreed, but I'm not so sure if the reverse is not true ;-)

> 

> I mean, the current LED API was designed and tested on drivers that

> allow direct control of the LED (and then extended to some cases

> where the hardware allows offloading).

> 

> The NUC API is just the opposite: there, the BIOS has full control of

> the hardware, but it provides an interface that allows changing

> the LED behavior, up to some extend. It also allows controlling the

> LED hardware and make it blink while it is suspended/hibernating, 

> which is something that a direct LED control wouldn't allow.


If the controller can make the LED to do a specific behaviour when the
system is suspended, please use the private LED trigger API and register
a LED private trigger (a trigger that is only available for that
specific LED) with a name like "suspend-indicator" or something.

> So, for instance, if we stick with the current LED API, there's no

> way to tell that the power LED should:

> 

> 	- blink on every 5 seconds, using up to 20% of brightness

> 	  when the system is suspended;


There is. Implement the .blink_set method.

> 	- strobe on every 10 seconds using up to 50% of brightness

> 	  when the system is hibernated;


Implement a LED private trigger.

> 	- use 100% of brigntness and don't blink when powered up.


Implement a LED private trigger.

> > The correct way to do this is via LED triggers, i.e. if I want a

> > LED to blink on network activity, then I should use netdev trigger

> > and nothing else. The netdev trigger should determine whether the

> > underlying LED driver can set the LED to blink on network activity

> > in HW. If HW supports it, netdev trigger should use this, otherwise

> > netdev trigger should blink the LED in software.  

> 

> I understand the desire of exposing the same API, but the current

> trigger code doesn't seem to be fit. I mean, the init sequence

> done at netdev_trig_activate():

> 

> 	trigger_data = kzalloc(sizeof(struct led_netdev_data),

> GFP_KERNEL); if (!trigger_data)

> 		return -ENOMEM;

> 

> 	spin_lock_init(&trigger_data->lock);

> 

> 	trigger_data->notifier.notifier_call = netdev_trig_notify;

> 	trigger_data->notifier.priority = 10;

> 

> 	INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);

> 

> 	trigger_data->led_cdev = led_cdev;

> 	trigger_data->net_dev = NULL;

> 	trigger_data->device_name[0] = 0;

> 

> 	trigger_data->mode = 0;

> 	atomic_set(&trigger_data->interval, msecs_to_jiffies(50));

> 	trigger_data->last_activity = 0;

> 

> 	led_set_trigger_data(led_cdev, trigger_data);

> 

> 	rc = register_netdevice_notifier(&trigger_data->notifier);

> 	if (rc)

> 		kfree(trigger_data);

> 

> doesn't make sense when the LED will be trigged by the hardware,

> and registering a notifier for netdevice is overkill.

> 

> The exported attributes:

> 

> 	static struct attribute *netdev_trig_attrs[] = {

> 		&dev_attr_device_name.attr,

> 		&dev_attr_link.attr,

> 		&dev_attr_rx.attr,

> 		&dev_attr_tx.attr,

> 		&dev_attr_interval.attr,

> 		NULL

> 	};

> 	ATTRIBUTE_GROUPS(netdev_trig);

> 

> also won't apply, as the NUC API doesn't support setting device_name, 

> RX, TX, link or interval.

> 

> Instead, it allows to set:

> - the maximum brightness;

> - the color (if the LED is multi-colored);

> - the physical port(s) that will be monitored:

> 	- LAN1

> 	- LAN2

> 	- LAN1+LAN2

> 

> where LAN1 and LAN2 are two physical ports behind the NUC device.

> The netdev layer knows those as "eno1" and "enp5s0" (not 

> necessarily at the same order).


The only problem I see with trigger_data in this case is that only one
netdevice can be set, while your LED can be configured to blink on
activity on two netdevices.

Otherwise all these settings are relevant.
What your driver offload callback should do (once HW offloading of LED
triggers is merged) is this:
  - the offload method is called by the netdev trigger
  - the offload method looks at the trigger_data structure. This
    contains settings rx, tx, link, interval, device_name/device. If the
    device_name is "eno1" or "end5s0" (or better, if the device points
    to one of the 2 netdevices that are supported by the HW), and if
    the rx, tx, link and interval parameters are configured to values
    that can be done by the LED controller, than put the LED into HW
    controlled state (to blink with these parameters on network
    activity on that netdevice) and return 0
  - otherwise the offload method should return -EOPNOTSUPP, and the
    netdev trigger will know that the requested settings are not
    supported by the HW, and the netdev trigger will blink the LED in
    SW


> Also, while netdev trigger seems to use just one device name,

> the NUC allows to monitor both interfaces at the same time.


Yes. This can be solved in the future by extending netdev trigger to
support blinking on activity on multiple netdevices. I also thought
about this for use with another HW (mv88e6xxx switch).

> See, unfortunately I can't see a common API that would fit

> nicely on both cases.


Well I can.

The only problem here is that it is not supported yet. I will try to
send patches ASAP and poke Pavel to review them.

> > Currently the netdev trigger does the blinking in software only

> > (code in "ledtrig-netdev.c" file). There is a WIP to add the

> > necessary support for the netdev trigger to have the ability to

> > offload blinking to HW. I will try to respin this WIP and send

> > patches for review.

> > 

> > Once netdev trigger supports this feature, you can implement your

> > driver in this way. You can even make your driver depend on netdev

> > trigger   

> 

> > and set the specific LED into netdev triggering by default, and

> > even forbidding anything else.   

> 

> This is also probably one of the differences from other hardware:

> In principle, *any* led can monitor *any* hardware event[1].

> 

> [1] There are some bitmaps at the interface that would allow the

>     BIOS to restrict it, but, at least on the device I have

>     (Hades Canyon), there's no such restriction: the same bitmap

>     masks are returned for all LEDs.

> 

> > But this is the corrent way to do this,

> > instead of creating new sysfs API that is non-extendable.

> > 

> > I am sorry that I did not explain this thoroughly in previous mails.

> > Hopefully this explanation is better.  

> 

> Yes, it is a lot better. Thanks for the explanation!

> 

> Still, as I pointed above, I'm so far unable to see much in common 

> with the way the existing LED drivers work and the way NUC LEDS are

> controlled.

> 

> So, as much I would love to just reuse something that already exists,

> perhaps it would make more sense to create a separate class for such

> kind of usage.


The problem is that this API is not yet available in upstream kernel. I
will try to push it and return to you.

In the meantime let's see what others think about your code.

Marek
Mauro Carvalho Chehab May 20, 2021, 4 p.m. UTC | #8
Em Thu, 20 May 2021 13:00:14 +0200
Marek Behún <marek.behun@nic.cz> escreveu:

> On Wed, 19 May 2021 20:30:14 +0200

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> 

> > Em Wed, 19 May 2021 17:55:03 +0200

> > Marek Behún <kabel@kernel.org> escreveu:

> >   

> > > On Wed, 19 May 2021 16:24:13 +0200

> > > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> > >     

> > > > On other words, if no extra care is taken, it could have bad side 

> > > > effects at the machine's performance and affect system's latency,

> > > > eventually resulting on things like audio clicks and pops, if some

> > > > audio is playing while such calls keep happening.      

> > > 

> > > In general we want for every LED that is registered into kernel as

> > > a LED classdev to be possible to control the brightness by

> > > software. If the hardware supports it, it should be available.     

> > 

> > This is supported, but maybe not the same way as on other drivers.

> > 

> > There are two separate things: ON/OFF and LED brightness, when turned

> > ON.

> > 

> > On other words, NUC leds allow to set the brightness ranging from 0

> > to 100, but if the brightness is, let's say 50%, it means that, when

> > the LED is triggered by the hardware:

> > 

> > 	- ON would mean 50%; and 

> > 	- OFF would mean 0%.  

> 

> Not a problem, there are other controller which also work this way,

> leds-turris-omnia for example. 


OK.

> Also LED triggers are supposed to work

> this way: if a LED supports non-binary brightness (for exmaple 0-100),

> and the user sets brightness 50, and then a trigger, then the trigger

> should blink the LED with brightness 50.

> 

> > On other words, it actually adjusts the maximum brightness level.

> > 

> > Btw, this also applies to software control, as the hardware can still

> > blink the LED, the available properties for software control indicator

> > are:

> > 	- brightness.

> > 	- blink behavior and frequency;

> > 	- led color (available only if BIOS says that it is a 

> > 	  multi-colored led);  

> 

> - if the hw supports setting the LED to blink with a specific frequency

>   (not depending on any other HW like disk or ethernet, just blinking),

>   you should also implement the .blink_set method (look at

>   Documentation/leds/leds-class.rst section Hardware accelerated blink

>   of LEDs)


Ok.

How the blink pattern is specified? NUC supports 3 different
patterns (breathing, pulsing, strobing).

> - if BIOS says the LED is multi-colored, you should register it as

>   multi-colored LED via multicolor framework


Ok. I'll check how much work this will lead after we finish the API
discussions, as all sysfs attributes that won't fit at the triggers
will need to be implemented twice - one for mono-colored and another one
for multicolored, as the priv pointer will use different structures.

> > The exported attributes:

> > 

> > 	static struct attribute *netdev_trig_attrs[] = {

> > 		&dev_attr_device_name.attr,

> > 		&dev_attr_link.attr,

> > 		&dev_attr_rx.attr,

> > 		&dev_attr_tx.attr,

> > 		&dev_attr_interval.attr,

> > 		NULL

> > 	};

> > 	ATTRIBUTE_GROUPS(netdev_trig);

> > 

> > also won't apply, as the NUC API doesn't support setting device_name, 

> > RX, TX, link or interval.

> > 

> > Instead, it allows to set:

> > - the maximum brightness;

> > - the color (if the LED is multi-colored);

> > - the physical port(s) that will be monitored:

> > 	- LAN1

> > 	- LAN2

> > 	- LAN1+LAN2

> > 

> > where LAN1 and LAN2 are two physical ports behind the NUC device.

> > The netdev layer knows those as "eno1" and "enp5s0" (not 

> > necessarily at the same order).  

> 

> The only problem I see with trigger_data in this case is that only one

> netdevice can be set, while your LED can be configured to blink on

> activity on two netdevices.

> 

> Otherwise all these settings are relevant.

> What your driver offload callback should do (once HW offloading of LED

> triggers is merged) is this:

>   - the offload method is called by the netdev trigger

>   - the offload method looks at the trigger_data structure. This

>     contains settings rx, tx, link, interval, device_name/device. If the

>     device_name is "eno1" or "end5s0" (or better, if the device points

>     to one of the 2 netdevices that are supported by the HW), and if

>     the rx, tx, link and interval parameters are configured to values

>     that can be done by the LED controller, than put the LED into HW

>     controlled state (to blink with these parameters on network

>     activity on that netdevice) and return 0

>   - otherwise the offload method should return -EOPNOTSUPP, and the

>     netdev trigger will know that the requested settings are not

>     supported by the HW, and the netdev trigger will blink the LED in

>     SW


See, there's nothing that the driver can possible do with
rx, tx, link, interval, device_name/device, as the the BIOS allows
to set to "LAN1", "LAN2" or "LAN1+LAN2". the WMI interface doesn't
provide *any* information about what LAN1 means.

In the case of my NUC, there are even two different drivers:

	00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (2) I219-LM (rev 31)
	Kernel modules: e1000e

	05:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)
	Kernel modules: igb

So, even the probing order can be different after a reboot.

So, there isn't a portable way to tell if LAN1 means to either
"eno1" or "end5s0"(*), as netdev and the associated net drivers
talk with the hardware directly, and not via BIOS. So, the BIOS
internal name is not known. Even the DMI tables don't tell it:

	Handle 0x000F, DMI type 8, 9 bytes
	Port Connector Information
	        Internal Reference Designator: CON4501
	        Internal Connector Type: None
	        External Reference Designator: LAN
	        External Connector Type: RJ-45
	        Port Type: Network Port
	
	Handle 0x0010, DMI type 8, 9 bytes
	Port Connector Information
	        Internal Reference Designator: CON4401
	        Internal Connector Type: None
	        External Reference Designator: LAN
	        External Connector Type: RJ-45
	        Port Type: Network Port

(*)  I'm using the interface names on this specific model, but
     I'm pretty sure other models will have different names
     and will even use different network drivers.

The point is, while the current netdev trigger API can be generic
enough when the LED is controlled by netdev, it is *not*
generic enough to cover the case where it is trigged by the
firmware, as the information exposed by the firmware can be
(and it is on this case) completely different than what netdev
exposes.


> > Also, while netdev trigger seems to use just one device name,

> > the NUC allows to monitor both interfaces at the same time.  

> 

> Yes. This can be solved in the future by extending netdev trigger to

> support blinking on activity on multiple netdevices. I also thought

> about this for use with another HW (mv88e6xxx switch).

> 

> > See, unfortunately I can't see a common API that would fit

> > nicely on both cases.  

> 

> Well I can.


Then the API needs to change, in order to allow to abstract from
netdev-centric view of Ethernet interfaces. Or, instead, some
other trigger is needed for firmware-controlled events.

-

One thing that it is not clear to me: let's say that the LED
called "front1" is currently handling Ethernet events, but
the user wants to use, instead, the "front2" LED, disabling
the "front1" one (or using for another event, like wifi, which
is not monitored on BIOS default).

How this can be done using the trigger's API?

> The only problem here is that it is not supported yet. I will try to

> send patches ASAP and poke Pavel to review them.


Ok. Please c/c on such patches.

> > > Currently the netdev trigger does the blinking in software only

> > > (code in "ledtrig-netdev.c" file). There is a WIP to add the

> > > necessary support for the netdev trigger to have the ability to

> > > offload blinking to HW. I will try to respin this WIP and send

> > > patches for review.

> > > 

> > > Once netdev trigger supports this feature, you can implement your

> > > driver in this way. You can even make your driver depend on netdev

> > > trigger     

> >   

> > > and set the specific LED into netdev triggering by default, and

> > > even forbidding anything else.     

> > 

> > This is also probably one of the differences from other hardware:

> > In principle, *any* led can monitor *any* hardware event[1].

> > 

> > [1] There are some bitmaps at the interface that would allow the

> >     BIOS to restrict it, but, at least on the device I have

> >     (Hades Canyon), there's no such restriction: the same bitmap

> >     masks are returned for all LEDs.

> >   

> > > But this is the corrent way to do this,

> > > instead of creating new sysfs API that is non-extendable.

> > > 

> > > I am sorry that I did not explain this thoroughly in previous mails.

> > > Hopefully this explanation is better.    

> > 

> > Yes, it is a lot better. Thanks for the explanation!

> > 

> > Still, as I pointed above, I'm so far unable to see much in common 

> > with the way the existing LED drivers work and the way NUC LEDS are

> > controlled.

> > 

> > So, as much I would love to just reuse something that already exists,

> > perhaps it would make more sense to create a separate class for such

> > kind of usage.  

> 

> The problem is that this API is not yet available in upstream kernel. I

> will try to push it and return to you.


Ok.

> 

> In the meantime let's see what others think about your code.


Ok, thank you!

Thanks,
Mauro
Marek Behún May 20, 2021, 4:36 p.m. UTC | #9
On Thu, 20 May 2021 18:00:28 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> Em Thu, 20 May 2021 13:00:14 +0200

> Marek Behún <marek.behun@nic.cz> escreveu:

> 

> > On Wed, 19 May 2021 20:30:14 +0200

> > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> >   

> > > Em Wed, 19 May 2021 17:55:03 +0200

> > > Marek Behún <kabel@kernel.org> escreveu:

> > >     

> > > > On Wed, 19 May 2021 16:24:13 +0200

> > > > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> > > >       

> > > > > On other words, if no extra care is taken, it could have bad side 

> > > > > effects at the machine's performance and affect system's latency,

> > > > > eventually resulting on things like audio clicks and pops, if some

> > > > > audio is playing while such calls keep happening.        

> > > > 

> > > > In general we want for every LED that is registered into kernel as

> > > > a LED classdev to be possible to control the brightness by

> > > > software. If the hardware supports it, it should be available.       

> > > 

> > > This is supported, but maybe not the same way as on other drivers.

> > > 

> > > There are two separate things: ON/OFF and LED brightness, when turned

> > > ON.

> > > 

> > > On other words, NUC leds allow to set the brightness ranging from 0

> > > to 100, but if the brightness is, let's say 50%, it means that, when

> > > the LED is triggered by the hardware:

> > > 

> > > 	- ON would mean 50%; and 

> > > 	- OFF would mean 0%.    

> > 

> > Not a problem, there are other controller which also work this way,

> > leds-turris-omnia for example.   

> 

> OK.

> 

> > Also LED triggers are supposed to work

> > this way: if a LED supports non-binary brightness (for exmaple 0-100),

> > and the user sets brightness 50, and then a trigger, then the trigger

> > should blink the LED with brightness 50.

> >   

> > > On other words, it actually adjusts the maximum brightness level.

> > > 

> > > Btw, this also applies to software control, as the hardware can still

> > > blink the LED, the available properties for software control indicator

> > > are:

> > > 	- brightness.

> > > 	- blink behavior and frequency;

> > > 	- led color (available only if BIOS says that it is a 

> > > 	  multi-colored led);    

> > 

> > - if the hw supports setting the LED to blink with a specific frequency

> >   (not depending on any other HW like disk or ethernet, just blinking),

> >   you should also implement the .blink_set method (look at

> >   Documentation/leds/leds-class.rst section Hardware accelerated blink

> >   of LEDs)  

> 

> Ok.

> 

> How the blink pattern is specified? NUC supports 3 different

> patterns (breathing, pulsing, strobing).

> 

> > - if BIOS says the LED is multi-colored, you should register it as

> >   multi-colored LED via multicolor framework  

> 

> Ok. I'll check how much work this will lead after we finish the API

> discussions, as all sysfs attributes that won't fit at the triggers

> will need to be implemented twice - one for mono-colored and another one

> for multicolored, as the priv pointer will use different structures.

> 

> > > The exported attributes:

> > > 

> > > 	static struct attribute *netdev_trig_attrs[] = {

> > > 		&dev_attr_device_name.attr,

> > > 		&dev_attr_link.attr,

> > > 		&dev_attr_rx.attr,

> > > 		&dev_attr_tx.attr,

> > > 		&dev_attr_interval.attr,

> > > 		NULL

> > > 	};

> > > 	ATTRIBUTE_GROUPS(netdev_trig);

> > > 

> > > also won't apply, as the NUC API doesn't support setting device_name, 

> > > RX, TX, link or interval.

> > > 

> > > Instead, it allows to set:

> > > - the maximum brightness;

> > > - the color (if the LED is multi-colored);

> > > - the physical port(s) that will be monitored:

> > > 	- LAN1

> > > 	- LAN2

> > > 	- LAN1+LAN2

> > > 

> > > where LAN1 and LAN2 are two physical ports behind the NUC device.

> > > The netdev layer knows those as "eno1" and "enp5s0" (not 

> > > necessarily at the same order).    

> > 

> > The only problem I see with trigger_data in this case is that only one

> > netdevice can be set, while your LED can be configured to blink on

> > activity on two netdevices.

> > 

> > Otherwise all these settings are relevant.

> > What your driver offload callback should do (once HW offloading of LED

> > triggers is merged) is this:

> >   - the offload method is called by the netdev trigger

> >   - the offload method looks at the trigger_data structure. This

> >     contains settings rx, tx, link, interval, device_name/device. If the

> >     device_name is "eno1" or "end5s0" (or better, if the device points

> >     to one of the 2 netdevices that are supported by the HW), and if

> >     the rx, tx, link and interval parameters are configured to values

> >     that can be done by the LED controller, than put the LED into HW

> >     controlled state (to blink with these parameters on network

> >     activity on that netdevice) and return 0

> >   - otherwise the offload method should return -EOPNOTSUPP, and the

> >     netdev trigger will know that the requested settings are not

> >     supported by the HW, and the netdev trigger will blink the LED in

> >     SW  

> 

> See, there's nothing that the driver can possible do with

> rx, tx, link, interval, device_name/device, as the the BIOS allows

> to set to "LAN1", "LAN2" or "LAN1+LAN2". the WMI interface doesn't

> provide *any* information about what LAN1 means.


On the contrary, there is something the driver can do with these
attributes. If the specific combination is not supported, the driver
should return -EOPNOTSUPP in the trigger_offload method and let the
netdev trigger do the work in software. What exactly do the LEDs do
when configured to blink on activity on a network device? Do they just
blink on RX/TX, and otherwise are off? Or are they on when a cable is
plugged, blink on rx/tx and otherwise off?

>

> In the case of my NUC, there are even two different drivers:

> 

> 	00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (2) I219-LM (rev 31)

> 	Kernel modules: e1000e

> 

> 	05:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)

> 	Kernel modules: igb

> 

> So, even the probing order can be different after a reboot.

>

> So, there isn't a portable way to tell if LAN1 means to either

> "eno1" or "end5s0"(*), as netdev and the associated net drivers

> talk with the hardware directly, and not via BIOS. So, the BIOS

> internal name is not known. Even the DMI tables don't tell it:

> 

> 	Handle 0x000F, DMI type 8, 9 bytes

> 	Port Connector Information

> 	        Internal Reference Designator: CON4501

> 	        Internal Connector Type: None

> 	        External Reference Designator: LAN

> 	        External Connector Type: RJ-45

> 	        Port Type: Network Port

> 	

> 	Handle 0x0010, DMI type 8, 9 bytes

> 	Port Connector Information

> 	        Internal Reference Designator: CON4401

> 	        Internal Connector Type: None

> 	        External Reference Designator: LAN

> 	        External Connector Type: RJ-45

> 	        Port Type: Network Port

> 

> (*)  I'm using the interface names on this specific model, but

>      I'm pretty sure other models will have different names

>      and will even use different network drivers.


Have you looked into DSDT and SSDT tables?

> The point is, while the current netdev trigger API can be generic

> enough when the LED is controlled by netdev, it is *not*

> generic enough to cover the case where it is trigged by the

> firmware, as the information exposed by the firmware can be

> (and it is on this case) completely different than what netdev

> exposes.


If even DSDT data is not enough to reliably find out which of the 2
network interfaces belongs to which LED setting, the worst case scenario
here is for your driver to need to have a list containing this
information for specific motherboards, and other people can then extend
the driver to support their motherboards as well.

> 

> > > Also, while netdev trigger seems to use just one device name,

> > > the NUC allows to monitor both interfaces at the same time.    

> > 

> > Yes. This can be solved in the future by extending netdev trigger to

> > support blinking on activity on multiple netdevices. I also thought

> > about this for use with another HW (mv88e6xxx switch).

> >   

> > > See, unfortunately I can't see a common API that would fit

> > > nicely on both cases.    

> > 

> > Well I can.  

> 

> Then the API needs to change, in order to allow to abstract from

> netdev-centric view of Ethernet interfaces. Or, instead, some

> other trigger is needed for firmware-controlled events.


No. If the necessary information for determining which network
interface pairs to LED1 and which to LED2 cannot be reliably determined
from ACPI tables, then IMO the driver should specify this information
for each motherboard that wants to use this feature.

> -

> 

> One thing that it is not clear to me: let's say that the LED

> called "front1" is currently handling Ethernet events, but

> the user wants to use, instead, the "front2" LED, disabling

> the "front1" one (or using for another event, like wifi, which

> is not monitored on BIOS default).

> 

> How this can be done using the trigger's API?


cd /sys/class/leds/front1
echo none >trigger
cd /sys/class/leds/front2
echo netdev >trigger
echo ifname >device_name
echo 1 >rx
echo 1 >tx
Mauro Carvalho Chehab May 20, 2021, 6:59 p.m. UTC | #10
Em Thu, 20 May 2021 18:36:33 +0200
Marek Behún <kabel@kernel.org> escreveu:

> On Thu, 20 May 2021 18:00:28 +0200

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> 

> > Em Thu, 20 May 2021 13:00:14 +0200

> > Marek Behún <marek.behun@nic.cz> escreveu:

> >   

> > > On Wed, 19 May 2021 20:30:14 +0200

> > > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> > >     

> > > > Em Wed, 19 May 2021 17:55:03 +0200

> > > > Marek Behún <kabel@kernel.org> escreveu:

> > > >       

> > > > > On Wed, 19 May 2021 16:24:13 +0200

> > > > > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> > > > >         

> > > > > > On other words, if no extra care is taken, it could have bad side 

> > > > > > effects at the machine's performance and affect system's latency,

> > > > > > eventually resulting on things like audio clicks and pops, if some

> > > > > > audio is playing while such calls keep happening.          

> > > > > 

> > > > > In general we want for every LED that is registered into kernel as

> > > > > a LED classdev to be possible to control the brightness by

> > > > > software. If the hardware supports it, it should be available.         

> > > > 

> > > > This is supported, but maybe not the same way as on other drivers.

> > > > 

> > > > There are two separate things: ON/OFF and LED brightness, when turned

> > > > ON.

> > > > 

> > > > On other words, NUC leds allow to set the brightness ranging from 0

> > > > to 100, but if the brightness is, let's say 50%, it means that, when

> > > > the LED is triggered by the hardware:

> > > > 

> > > > 	- ON would mean 50%; and 

> > > > 	- OFF would mean 0%.      

> > > 

> > > Not a problem, there are other controller which also work this way,

> > > leds-turris-omnia for example.     

> > 

> > OK.

> >   

> > > Also LED triggers are supposed to work

> > > this way: if a LED supports non-binary brightness (for exmaple 0-100),

> > > and the user sets brightness 50, and then a trigger, then the trigger

> > > should blink the LED with brightness 50.

> > >     

> > > > On other words, it actually adjusts the maximum brightness level.

> > > > 

> > > > Btw, this also applies to software control, as the hardware can still

> > > > blink the LED, the available properties for software control indicator

> > > > are:

> > > > 	- brightness.

> > > > 	- blink behavior and frequency;

> > > > 	- led color (available only if BIOS says that it is a 

> > > > 	  multi-colored led);      

> > > 

> > > - if the hw supports setting the LED to blink with a specific frequency

> > >   (not depending on any other HW like disk or ethernet, just blinking),

> > >   you should also implement the .blink_set method (look at

> > >   Documentation/leds/leds-class.rst section Hardware accelerated blink

> > >   of LEDs)    

> > 

> > Ok.

> > 

> > How the blink pattern is specified? NUC supports 3 different

> > patterns (breathing, pulsing, strobing).

> >   

> > > - if BIOS says the LED is multi-colored, you should register it as

> > >   multi-colored LED via multicolor framework    

> > 

> > Ok. I'll check how much work this will lead after we finish the API

> > discussions, as all sysfs attributes that won't fit at the triggers

> > will need to be implemented twice - one for mono-colored and another one

> > for multicolored, as the priv pointer will use different structures.

> >   

> > > > The exported attributes:

> > > > 

> > > > 	static struct attribute *netdev_trig_attrs[] = {

> > > > 		&dev_attr_device_name.attr,

> > > > 		&dev_attr_link.attr,

> > > > 		&dev_attr_rx.attr,

> > > > 		&dev_attr_tx.attr,

> > > > 		&dev_attr_interval.attr,

> > > > 		NULL

> > > > 	};

> > > > 	ATTRIBUTE_GROUPS(netdev_trig);

> > > > 

> > > > also won't apply, as the NUC API doesn't support setting device_name, 

> > > > RX, TX, link or interval.

> > > > 

> > > > Instead, it allows to set:

> > > > - the maximum brightness;

> > > > - the color (if the LED is multi-colored);

> > > > - the physical port(s) that will be monitored:

> > > > 	- LAN1

> > > > 	- LAN2

> > > > 	- LAN1+LAN2

> > > > 

> > > > where LAN1 and LAN2 are two physical ports behind the NUC device.

> > > > The netdev layer knows those as "eno1" and "enp5s0" (not 

> > > > necessarily at the same order).      

> > > 

> > > The only problem I see with trigger_data in this case is that only one

> > > netdevice can be set, while your LED can be configured to blink on

> > > activity on two netdevices.

> > > 

> > > Otherwise all these settings are relevant.

> > > What your driver offload callback should do (once HW offloading of LED

> > > triggers is merged) is this:

> > >   - the offload method is called by the netdev trigger

> > >   - the offload method looks at the trigger_data structure. This

> > >     contains settings rx, tx, link, interval, device_name/device. If the

> > >     device_name is "eno1" or "end5s0" (or better, if the device points

> > >     to one of the 2 netdevices that are supported by the HW), and if

> > >     the rx, tx, link and interval parameters are configured to values

> > >     that can be done by the LED controller, than put the LED into HW

> > >     controlled state (to blink with these parameters on network

> > >     activity on that netdevice) and return 0

> > >   - otherwise the offload method should return -EOPNOTSUPP, and the

> > >     netdev trigger will know that the requested settings are not

> > >     supported by the HW, and the netdev trigger will blink the LED in

> > >     SW    

> > 

> > See, there's nothing that the driver can possible do with

> > rx, tx, link, interval, device_name/device, as the the BIOS allows

> > to set to "LAN1", "LAN2" or "LAN1+LAN2". the WMI interface doesn't

> > provide *any* information about what LAN1 means.  

> 

> On the contrary, there is something the driver can do with these

> attributes. If the specific combination is not supported, the driver

> should return -EOPNOTSUPP in the trigger_offload method and let the

> netdev trigger do the work in software. 


Letting netdev to trigger is something we don't want to allow, as this
can cause side effects, making it doing slow the system due to BIOS calls
for no good reason.

> What exactly do the LEDs do

> when configured to blink on activity on a network device? Do they just

> blink on RX/TX, and otherwise are off?  Or are they on when a cable is

> plugged, blink on rx/tx and otherwise off?


They are on when a cable is plugged, blink on rx/tx and otherwise off.

Worth mentioning that, besides the LEDs controlled by this driver, each
RJ-45 port also a couple leds that behave just like normal RJ-45 ones: 
a yellow led for Ethernet PHY detection and a green one for traffic.

> 

> >

> > In the case of my NUC, there are even two different drivers:

> > 

> > 	00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (2) I219-LM (rev 31)

> > 	Kernel modules: e1000e

> > 

> > 	05:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)

> > 	Kernel modules: igb

> > 

> > So, even the probing order can be different after a reboot.

> >

> > So, there isn't a portable way to tell if LAN1 means to either

> > "eno1" or "end5s0"(*), as netdev and the associated net drivers

> > talk with the hardware directly, and not via BIOS. So, the BIOS

> > internal name is not known. Even the DMI tables don't tell it:

> > 

> > 	Handle 0x000F, DMI type 8, 9 bytes

> > 	Port Connector Information

> > 	        Internal Reference Designator: CON4501

> > 	        Internal Connector Type: None

> > 	        External Reference Designator: LAN

> > 	        External Connector Type: RJ-45

> > 	        Port Type: Network Port

> > 	

> > 	Handle 0x0010, DMI type 8, 9 bytes

> > 	Port Connector Information

> > 	        Internal Reference Designator: CON4401

> > 	        Internal Connector Type: None

> > 	        External Reference Designator: LAN

> > 	        External Connector Type: RJ-45

> > 	        Port Type: Network Port

> > 

> > (*)  I'm using the interface names on this specific model, but

> >      I'm pretty sure other models will have different names

> >      and will even use different network drivers.  

> 

> Have you looked into DSDT and SSDT tables?


It doesn't help.

	# ./generate/unix/bin/acpidump -b
	# for i in *.dat; do
	#	./generate/unix/bin/iasl -d $i
	# done

	$ grep -i lan *dsl
	dsdt.dsl:            \_SB.PCI0.GLAN.GPEH ()
	dsdt.dsl:        Device (GLAN)
	dsdt.dsl:                    Notify (GLAN, 0x02) // Device Wake
	dsdt.dsl:                    _HID = "ELAN2097"
	dsdt.dsl:            Name (_MLS, Package (0x01)  // _MLS: Multiple Language String

> > The point is, while the current netdev trigger API can be generic

> > enough when the LED is controlled by netdev, it is *not*

> > generic enough to cover the case where it is trigged by the

> > firmware, as the information exposed by the firmware can be

> > (and it is on this case) completely different than what netdev

> > exposes.  

> 

> If even DSDT data is not enough to reliably find out which of the 2

> network interfaces belongs to which LED setting, the worst case scenario

> here is for your driver to need to have a list containing this

> information for specific motherboards, and other people can then extend

> the driver to support their motherboards as well.


Needing something like that sucks and it is hard to maintain,
and depends on people reporting issues.

Ok, on some cases, there are no other options, but this is not
the case here, as the user of such API that wants to monitor
just a single interface (default is to monitor both) can easily 
ask the driver to monitor LAN1. If it doesn't work, switch to LAN2.

That's a way more elegant than adding some guessing code that
would be checking for the machine codes, eventually printing
a warning and disabling support for monitoring LAN when the
machine is not properly identified.

Also, implementing such table can be painful. I can't see an
easy way to implement it, specially without having any information
about how all other models that support the WMI API are shipped,
and how to map "LAN1", "LAN2" into something that matches netdev
detection. OK, if each one have a different BUS ID,
a mapping table could associate each one with a different BUS
ID, and then some logic at netdev would convert BUS ID into
the device name.

> > > > Also, while netdev trigger seems to use just one device name,

> > > > the NUC allows to monitor both interfaces at the same time.      

> > > 

> > > Yes. This can be solved in the future by extending netdev trigger to

> > > support blinking on activity on multiple netdevices. I also thought

> > > about this for use with another HW (mv88e6xxx switch).

> > >     

> > > > See, unfortunately I can't see a common API that would fit

> > > > nicely on both cases.      

> > > 

> > > Well I can.    

> > 

> > Then the API needs to change, in order to allow to abstract from

> > netdev-centric view of Ethernet interfaces. Or, instead, some

> > other trigger is needed for firmware-controlled events.  

> 

> No. If the necessary information for determining which network

> interface pairs to LED1 and which to LED2 cannot be reliably determined

> from ACPI tables, then IMO the driver should specify this information

> for each motherboard that wants to use this feature.


What's the gain of adding such extra complexity to the driver?

All the user wants is to blink a led only for one of the LAN ports.

Denying it and using a more complex API doesn't make much sense, IMO.

> > -

> > 

> > One thing that it is not clear to me: let's say that the LED

> > called "front1" is currently handling Ethernet events, but

> > the user wants to use, instead, the "front2" LED, disabling

> > the "front1" one (or using for another event, like wifi, which

> > is not monitored on BIOS default).

> > 

> > How this can be done using the trigger's API?  

> 

> cd /sys/class/leds/front1

> echo none >trigger

> cd /sys/class/leds/front2

> echo netdev >trigger


Clear enough to me.

> echo ifname >device_name

> echo 1 >rx

> echo 1 >tx


And that's the part that it makes no sense for this hardware ;-)

It can't identify RX/TX in separate. It can only monitor both RX and TX at
the same time.

So, for this specific device, neither "rx", "tx" or "interval"
attributes should be shown.

Provided that we could use the Ethernet label as "device_name", this
would work:

  echo "LAN1+LAN2" > device_name
  echo "LAN1" > device_name
  echo "LAN2" > device_name

or, in order to avoid confusion, we could use a different name on
this specific driver, like:

  echo "LAN1+LAN2" > port_name
  echo "LAN1" > port_name
  echo "LAN2" > port_name

FYI, the default (LAN1+LAN2) is usually good enough for most use
cases, for a couple of reasons:

	- I guess only high end models have more than one Eth port;
	- Most people use just one LAN cable;
	- the back panel leds at the RJ45 are enough to check if
	  ethernet signal was detected.

Yet, at least for me, having the NUC led monitoring eth is interesting,
as here I use the LAN ports to connect with some testing hardware.

So, when the LED is on, it means that my hardware is turned on and
the Ethernet connection should be working.


Thanks,
Mauro
Marek Behún May 20, 2021, 8:07 p.m. UTC | #11
On Thu, 20 May 2021 20:59:33 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> > On the contrary, there is something the driver can do with these

> > attributes. If the specific combination is not supported, the driver

> > should return -EOPNOTSUPP in the trigger_offload method and let the

> > netdev trigger do the work in software.   

> 

> Letting netdev to trigger is something we don't want to allow, as this

> can cause side effects, making it doing slow the system due to BIOS calls

> for no good reason.

>

> > What exactly do the LEDs do

> > when configured to blink on activity on a network device? Do they just

> > blink on RX/TX, and otherwise are off?  Or are they on when a cable is

> > plugged, blink on rx/tx and otherwise off?  

> 

> They are on when a cable is plugged, blink on rx/tx and otherwise off.

> 

> Worth mentioning that, besides the LEDs controlled by this driver, each

> RJ-45 port also a couple leds that behave just like normal RJ-45 ones: 

> a yellow led for Ethernet PHY detection and a green one for traffic.


So what the LED does when configured for ethernet is almost equivalent
to netdev setting [link=1, rx=1, activity=1]. Almost because we still have
the correct device setting and interval setting.

Theoretically what you can do is deny the netdev trigger for every
other netdev setting (since, according to you, it would use too much
CPU time in BIOS via software control). This could be done by the
offload method returning another error value, or maybe just returning 0
and printing info about this into kernel log. I wonder what others
think about this possible resolution.

> > Have you looked into DSDT and SSDT tables?  

> 

> It doesn't help.


Pity :(

> > If even DSDT data is not enough to reliably find out which of the 2

> > network interfaces belongs to which LED setting, the worst case scenario

> > here is for your driver to need to have a list containing this

> > information for specific motherboards, and other people can then extend

> > the driver to support their motherboards as well.  

> 

> Needing something like that sucks and it is hard to maintain,

> and depends on people reporting issues.


I don't see much difference between this and various drivers having
different OF compatible strings for different chips all supported by
one driver.

> Ok, on some cases, there are no other options, but this is not

> the case here, as the user of such API that wants to monitor

> just a single interface (default is to monitor both) can easily 

> ask the driver to monitor LAN1. If it doesn't work, switch to LAN2.

> 

> That's a way more elegant than adding some guessing code that

> would be checking for the machine codes, eventually printing

> a warning and disabling support for monitoring LAN when the

> machine is not properly identified.

> 

> Also, implementing such table can be painful. I can't see an

> easy way to implement it, specially without having any information

> about how all other models that support the WMI API are shipped,

> and how to map "LAN1", "LAN2" into something that matches netdev

> detection. OK, if each one have a different BUS ID,

> a mapping table could associate each one with a different BUS

> ID, and then some logic at netdev would convert BUS ID into

> the device name.

> 

> > > > > Also, while netdev trigger seems to use just one device name,

> > > > > the NUC allows to monitor both interfaces at the same time.        

> > > > 

> > > > Yes. This can be solved in the future by extending netdev trigger to

> > > > support blinking on activity on multiple netdevices. I also thought

> > > > about this for use with another HW (mv88e6xxx switch).

> > > >       

> > > > > See, unfortunately I can't see a common API that would fit

> > > > > nicely on both cases.        

> > > > 

> > > > Well I can.      

> > > 

> > > Then the API needs to change, in order to allow to abstract from

> > > netdev-centric view of Ethernet interfaces. Or, instead, some

> > > other trigger is needed for firmware-controlled events.    

> > 

> > No. If the necessary information for determining which network

> > interface pairs to LED1 and which to LED2 cannot be reliably determined

> > from ACPI tables, then IMO the driver should specify this information

> > for each motherboard that wants to use this feature.  

> 

> What's the gain of adding such extra complexity to the driver?


Having a consistent API on different devices is a benefit in itself, I
would think.

> All the user wants is to blink a led only for one of the LAN ports.

> 

> Denying it and using a more complex API doesn't make much sense, IMO.


As I see it you are the one wanting to introduce more complexity into
the sysfs ABI. There is already a solution together with documentation
and everything for when the user wants to "blink a led only for one of
the LAN ports". It is the netdev trigger. And you want to complicate
that ABI.

> > > -

> > > 

> > > One thing that it is not clear to me: let's say that the LED

> > > called "front1" is currently handling Ethernet events, but

> > > the user wants to use, instead, the "front2" LED, disabling

> > > the "front1" one (or using for another event, like wifi, which

> > > is not monitored on BIOS default).

> > > 

> > > How this can be done using the trigger's API?    

> > 

> > cd /sys/class/leds/front1

> > echo none >trigger

> > cd /sys/class/leds/front2

> > echo netdev >trigger  

> 

> Clear enough to me.

> 

> > echo ifname >device_name

> > echo 1 >rx

> > echo 1 >tx  

> 

> And that's the part that it makes no sense for this hardware ;-)

> 

> It can't identify RX/TX in separate. It can only monitor both RX and TX at

> the same time.

> 

> So, for this specific device, neither "rx", "tx" or "interval"

> attributes should be shown.


If a netdev setting is not supported by the HW, it should be done in SW.
You say that for this controller it would be bad to do in SW, because it
would take too much time in BIOS calls. (I wonder how much...) If this
is really the case then I still think it is more preferable to do this
via netdev trigger, and forbid settings not supported by HW. The result
could be:

     # I want the LED to blink on ethernet activity
   $ echo netdev >trigger
     # ok, but I only wan't it to blink on rx activity, not tx
   $ echo 0 >tx
   Operation not supported.

Pavel, what is your opinion here?

Marek
Mauro Carvalho Chehab May 21, 2021, 9:14 a.m. UTC | #12
Em Thu, 20 May 2021 22:07:03 +0200
Marek Behún <kabel@kernel.org> escreveu:

> On Thu, 20 May 2021 20:59:33 +0200

> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> 

> > > On the contrary, there is something the driver can do with these

> > > attributes. If the specific combination is not supported, the driver

> > > should return -EOPNOTSUPP in the trigger_offload method and let the

> > > netdev trigger do the work in software.     

> > 

> > Letting netdev to trigger is something we don't want to allow, as this

> > can cause side effects, making it doing slow the system due to BIOS calls

> > for no good reason.

> >  

> > > What exactly do the LEDs do

> > > when configured to blink on activity on a network device? Do they just

> > > blink on RX/TX, and otherwise are off?  Or are they on when a cable is

> > > plugged, blink on rx/tx and otherwise off?    

> > 

> > They are on when a cable is plugged, blink on rx/tx and otherwise off.

> > 

> > Worth mentioning that, besides the LEDs controlled by this driver, each

> > RJ-45 port also a couple leds that behave just like normal RJ-45 ones: 

> > a yellow led for Ethernet PHY detection and a green one for traffic.  

> 

> So what the LED does when configured for ethernet is almost equivalent

> to netdev setting [link=1, rx=1, activity=1]. Almost because we still have

> the correct device setting and interval setting.

> 

> Theoretically what you can do is deny the netdev trigger for every

> other netdev setting (since, according to you, it would use too much

> CPU time in BIOS via software control). This could be done by the

> offload method returning another error value, or maybe just returning 0

> and printing info about this into kernel log. I wonder what others

> think about this possible resolution.


IMO, it would be preferred to have a different trigger here, as this
is not a netdev-based trigger. So, its implementation should not call:

	register_netdevice_notifier()

nor set timers, etc.

See, the hardware won't use any information provided by the netdev,
trigger and the API is not the same, as the hardware trigger only
wants to know if just one interface will trigger the led or both.

> > > If even DSDT data is not enough to reliably find out which of the 2

> > > network interfaces belongs to which LED setting, the worst case scenario

> > > here is for your driver to need to have a list containing this

> > > information for specific motherboards, and other people can then extend

> > > the driver to support their motherboards as well.    

> > 

> > Needing something like that sucks and it is hard to maintain,

> > and depends on people reporting issues.  

> 

> I don't see much difference between this and various drivers having

> different OF compatible strings for different chips all supported by

> one driver.


It is somewhat similar: on my experiences, the upstream OF compatibles
are almost always outdated uptream: only OOT Kernels have the full
OF stuff :-p

The major difference is that hardware vendors usually develop and
provide OF.

In this case, you want users to fill bug reports that will ask a
Kernel developer to add new entries for their machines to work
properly. While we do this on other drivers, doing that is time
consuming and may lead into errors. Believe me: this is needed
on media drivers, as there are things like GPIOs that are
device-specific. It is a pain to maintain those things.

> > > > Then the API needs to change, in order to allow to abstract from

> > > > netdev-centric view of Ethernet interfaces. Or, instead, some

> > > > other trigger is needed for firmware-controlled events.      

> > > 

> > > No. If the necessary information for determining which network

> > > interface pairs to LED1 and which to LED2 cannot be reliably determined

> > > from ACPI tables, then IMO the driver should specify this information

> > > for each motherboard that wants to use this feature.    

> > 

> > What's the gain of adding such extra complexity to the driver?  

> 

> Having a consistent API on different devices is a benefit in itself, I

> would think.


It wouldn't be consistent. Hardware sees the events on different
ways than netdev, and associating netdev's view of the interface with
the hardware's view will always be an issue, on any driver that would
trigger such kind of events.

See, let's assume someone would implement a hardware trigger for
the LEDs on an 48-ports Ethernet switch, and different versions of
such hub would use different Ethernet drivers.

No matter how netdev sees the hardware, or if some of the ports
can be replaced (some devices allow port hot-plugging), from userspace
perspective, what it really matter is the port number as seen at
the switch panel, no matter how netdev sees it.

So, for hardware-triggered events, the hardware "label" is a lot
more relevant than any linux-internal representation.

> > All the user wants is to blink a led only for one of the LAN ports.

> > 

> > Denying it and using a more complex API doesn't make much sense, IMO.  

> 

> As I see it you are the one wanting to introduce more complexity into

> the sysfs ABI. There is already a solution together with documentation

> and everything for when the user wants to "blink a led only for one of

> the LAN ports". It is the netdev trigger. And you want to complicate

> that ABI.


No. The existing in-kernel API is to blink a led based on software
events originated from netdev from a single network port. 

It could monitor an interface that doesn't physically exist 
(a virtual network interface, like tun0). It could even monitor traffic
on a single VLAN, if the interface is specified like eth0.100[1].

[1] As we're discussing API here, I didn't test/check if the current
    implementation allows monitoring virtual and VLAN interfaces.
    From API's perspective, it makes perfect sense to be able to
    monitor any physical or logical interface supported by netdev.

The HW trigger is different: led blinks if the hardware detects Ethernet
activity on one or more physical interfaces.

See, the netdev trigger monitors a netdev event with may or may not
be due to an Ethernet port.

An Ethernet HW trigger monitors activity on a set of physical
Ethernet ports.

In essence, the only thing in common is that both triggers are related to
network, but they're actually monitoring two different types of events.

Merging them into a single one sounds a conceptual mistake on my eyes.

> You say that for this controller it would be bad to do in SW, because it

> would take too much time in BIOS calls. (I wonder how much...) 


Yeah, it would be interesting to know how much. However, measuring BIOS
latency and time spent on such calls can be tricky: one needs to use a
high-res clock that it is not used anywhere else, in order to measure
it. 

Thanks,
Mauro
Pavel Machek May 26, 2021, 2:47 p.m. UTC | #13
Hi!

> > > See, there's nothing that the driver can possible do with

> > > rx, tx, link, interval, device_name/device, as the the BIOS allows

> > > to set to "LAN1", "LAN2" or "LAN1+LAN2". the WMI interface doesn't

> > > provide *any* information about what LAN1 means.  

> > 

> > On the contrary, there is something the driver can do with these

> > attributes. If the specific combination is not supported, the driver

> > should return -EOPNOTSUPP in the trigger_offload method and let the

> > netdev trigger do the work in software. 

> 

> Letting netdev to trigger is something we don't want to allow, as this

> can cause side effects, making it doing slow the system due to BIOS calls

> for no good reason.


I'm with Marek here. Please listen to him.

Yes, operating LEDs can cost some CPU cycles. That's the case on most
hardware. Yet we want to support most triggers on most hardware.

Best regards,

								Pavel
-- 
http://www.livejournal.com/~pavelmachek
Pavel Machek May 26, 2021, 2:51 p.m. UTC | #14
Hi!

> > You say that for this controller it would be bad to do in SW, because it

> > would take too much time in BIOS calls. (I wonder how much...) 

> 

> Yeah, it would be interesting to know how much. However, measuring BIOS

> latency and time spent on such calls can be tricky: one needs to use a

> high-res clock that it is not used anywhere else, in order to measure

> it. 


I'm sure you can time kernel compilation while LEDs are using software
netdev trigger, for example.

								Pavel
-- 
http://www.livejournal.com/~pavelmachek
Mauro Carvalho Chehab May 28, 2021, 11:24 a.m. UTC | #15
Em Wed, 26 May 2021 16:47:51 +0200
Pavel Machek <pavel@ucw.cz> escreveu:

> Hi!

> 

> > > > See, there's nothing that the driver can possible do with

> > > > rx, tx, link, interval, device_name/device, as the the BIOS allows

> > > > to set to "LAN1", "LAN2" or "LAN1+LAN2". the WMI interface doesn't

> > > > provide *any* information about what LAN1 means.    

> > > 

> > > On the contrary, there is something the driver can do with these

> > > attributes. If the specific combination is not supported, the driver

> > > should return -EOPNOTSUPP in the trigger_offload method and let the

> > > netdev trigger do the work in software.   

> > 

> > Letting netdev to trigger is something we don't want to allow, as this

> > can cause side effects, making it doing slow the system due to BIOS calls

> > for no good reason.  

> 

> I'm with Marek here. Please listen to him.

> 

> Yes, operating LEDs can cost some CPU cycles. That's the case on most

> hardware. Yet we want to support most triggers on most hardware.


There are two separate things here:

1. a "normal" LED operation can indeed take some CPU cycles, specially
   if done via an I2C bus. Yet, the Kernel will still be kept running.
   A BIOS call means that the Kernel will remain interrupted until when
   the BIOS decide to return control back to it. This affects all CPUs,
   and not just the one that would be busy setting the LED.

   So, it is not a matter of just wasting some CPU cycles, but, instead,
   on potentially preventing all CPUs to run Kernel code, if the BIOS
   decides to lock until it finishes the LED setting and decides to
   return the control back to Linux.

   In practice, depending on what workload is used, their real time 
   requirements, and what the BIOS does (which may vary from device
   to device and on different BIOS versions) this could cause loses.
   This will mainly affect Real Time (e. g. audio and video apps).

   A realistic test would be to make the LED blink as fast as possible,
   while a pro-Audio device using JACK outputs something using the 
   smallest possible delay and see if blinking the leds would cause
   any audio issues.

   While I'm not against allowing using a software-triggered
   event, as this *can* cause userspace problems, IMO the user needs
   to explicitly allow the usage of it and be aware when a software
   trigger is used. Letting the LEDs core or driver to fallback
   to software and cause disturbance at userspace doesn't sound right.

2. a netdev trigger monitors a different event than the hardware
   event.

   See, if we have something like:

        LAN1  ----> eno1 ---> eno1.100     # VLAN 100 traffic at eno1
        port              |
                          +-> eno1.200     # VLAN 200 traffic at eno1

        LAN2  ---> enp5s0 ---> enp5s0.100  # VLAN 100 traffic at enp5s0
        port               |
                           +-> enp5s0.200  # VLAN 200 traffic at enp5s0


   The hardware triggered event monitors a group of physical interfaces,
   e. g.:
	- none
	- LAN1
	- LAN2
	- both LAN1 and LAN2 (default)

   The netdev trigger monitors software events at the network stack.
   So, it can be set to monitor a single software representation of an 
   interface, e. g. it can monitor either:

	- eno1
	- enp5so
	- eno1.100
	- eno1.200
	- enp5s0.100
	- enp5so.200

   It doesn't allow monitoring multiple interfaces at the same time.

   So, it is not possible to monitor both eno1 and enp5so.

   Also, even if it would be possible, what hardware detects could
   be different than what the network stack detects.

   On other words, even if we keep the BIOS default on front2 led
   and set front3 led to netdev trigger for eno1 they will blink
   differently, as one would be monitoring a single interface
   and another one will monitor both.

   It will even more different if netdev is set to monitor,
   let's say, VLAN 100 traffic at eno1.100, while hw trigger
   is set to LAN1+LAN2.

Thanks,
Mauro
Mauro Carvalho Chehab May 28, 2021, 11:33 a.m. UTC | #16
Em Wed, 26 May 2021 16:51:12 +0200
Pavel Machek <pavel@ucw.cz> escreveu:

> Hi!

> 

> > > You say that for this controller it would be bad to do in SW, because it

> > > would take too much time in BIOS calls. (I wonder how much...)   

> > 

> > Yeah, it would be interesting to know how much. However, measuring BIOS

> > latency and time spent on such calls can be tricky: one needs to use a

> > high-res clock that it is not used anywhere else, in order to measure

> > it.   

> 

> I'm sure you can time kernel compilation while LEDs are using software

> netdev trigger, for example.


I can't see how. I mean, the problem is to monitor the impact of the
BIOS call with may affect not only the application using the LED, but
all other applications running at the same time on different CPUs,
as the BIOS may want/need to lock other CPUs while its code is running, as
it can't see the Linux CPU locks.

Thanks,
Mauro
diff mbox series

Patch

diff --git a/drivers/leds/leds-nuc.c b/drivers/leds/leds-nuc.c
index 4d4ea6fbeff4..f84ec5662f5c 100644
--- a/drivers/leds/leds-nuc.c
+++ b/drivers/leds/leds-nuc.c
@@ -1698,12 +1698,100 @@  static ssize_t store_hdd_default(struct device *dev,
 	return len;
 }
 
+/* Ethernet type  */
+static const char * const ethernet_type[] = {
+	"LAN1",
+	"LAN2",
+	"LAN1+LAN2"
+};
+
+static ssize_t show_ethernet_type(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev);
+	u8 input[NUM_INPUT_ARGS] = { 0 };
+	u8 output[NUM_OUTPUT_ARGS];
+	int ctrl, ret, val, i, n;
+	int size = PAGE_SIZE;
+	char *p = buf;
+
+	if (led->indicator != LED_IND_ETHERNET)
+		return -EINVAL;
+
+	ctrl = led->reg_table[led->indicator][LED_FUNC_ETH_TYPE];
+
+	if (!nuc_wmi_test_control(dev, led, ctrl))
+		return -ENODEV;
+
+	input[0] = LED_NEW_GET_CONTROL_ITEM;
+	input[1] = led->id;
+	input[2] = led->indicator;
+	input[3] = ctrl;
+
+	ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output);
+	if (ret)
+		return ret;
+
+	val = output[0];
+
+	for (i = 0; i < ARRAY_SIZE(ethernet_type); i++) {
+		if (i == val)
+			n = scnprintf(p, size, "[%s]  ", ethernet_type[i]);
+		else
+			n = scnprintf(p, size, "%s  ", ethernet_type[i]);
+		p += n;
+		size -= n;
+	}
+	size -= scnprintf(p, size, "\n");
+
+	return PAGE_SIZE - size;
+}
+
+static ssize_t store_ethernet_type(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t len)
+{
+	struct led_classdev *cdev = dev_get_drvdata(dev);
+	struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev);
+	u8 input[NUM_INPUT_ARGS] = { 0 };
+	int ctrl, val, ret;
+	const char *tmp;
+
+	if (led->indicator != LED_IND_ETHERNET)
+		return -EINVAL;
+
+	ctrl = led->reg_table[led->indicator][LED_FUNC_ETH_TYPE];
+
+	if (!nuc_wmi_test_control(dev, led, ctrl))
+		return -ENODEV;
+
+	for (val = 0; val < ARRAY_SIZE(ethernet_type); val++)
+		if (!strcasecmp(tmp, ethernet_type[val]))
+			break;
+
+	if (val >= ARRAY_SIZE(ethernet_type))
+		return -EINVAL;
+
+	input[0] = led->id;
+	input[1] = led->indicator;
+	input[2] = ctrl;
+	input[3] = val;
+
+	ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL);
+	if (ret)
+		return ret;
+
+	return len;
+}
 
 static LED_ATTR_RW(indicator);
 static LED_ATTR_RW(color);
 static LED_ATTR_RW(blink_behavior);
 static LED_ATTR_RW(blink_frequency);
 static LED_ATTR_RW(hdd_default);
+static LED_ATTR_RW(ethernet_type);
 
 LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0);
 LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0);
@@ -1732,6 +1820,7 @@  LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blink_frequency, 2);
 static struct attribute *nuc_wmi_led_attr[] = {
 	&dev_attr_indicator.attr,
 	&dev_attr_hdd_default.attr,
+	&dev_attr_ethernet_type.attr,
 	NULL,
 };