From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:01
Hello,
this is v2 of series adding support for offloading LED triggers to HW.
The netdev trigger is the first user and leds-turris-omnia is the first
example implementation.
A video comparing SW (left LED) vs HW (right LED) netdev trigger on
Omnia
https://secure.nic.cz/files/mbehun/omnia-wan-netdev-trig-offload.mp4
Changes since v1:
- changed typo in doc
- the netdev trigger data structure now lives in
include/linux/ledtrig-netdev.h instead of ledtrig.h, as suggested by
Andrew. Also the structure is always defined, no guard against
CONFIG_LEDS_TRIGGER_NETDEV
- we do not export netdev_led_trigger variable. The trigger_offload()
method can look at led_cdev->trigger->name to see which trigger it
should try to offload, i.e. compare the string to "netdev"
- netdev trigger is being offloaded only if link is up, and at least one
of the rx, tx parameters are set. No need to offload otherwise
- a patch is added that moves setting flag LED_UNREGISTERING in
led_classdev_unregister() before unsetting trigger. This makes it
possible for the trigger_offload() method to determine whether the
offloading is being disabled because the LED is being unregistered.
The driver may put the LED into HW triggering mode in this case, to
achieve behaviour as was before the driver was loaded
- an example implementation for offloading the netdev trigger for the
WAN LED on Turris Omnia is added. LAN LEDs are not yet supported
Changes since RFC:
- split the patch adding HW offloading support to netdev trigger into
several separate patches (suggested by Pavel):
1. move trigger data structure to include/linux/ledtrig.h
2. support HW offloading
3. change spinlock to mutex
- fixed bug where the .offloaded variable was not set to false when
offloading was disabled (suggested by Pavel)
- removed the code saving one call to set_baseline_state() on the
NETDEV_CHANGE event. It is not needed, the trigger_offload() method
can handle this situation on its own (suggested by Pavel)
- documentation now explicitly says that when offloading is being
disabled, the function must return 0 (no error) (suggested by Pavel)
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
Documentation/leds/leds-class.rst | 22 ++
drivers/leds/Kconfig | 3 +
drivers/leds/led-class.c | 4 +-
drivers/leds/led-triggers.c | 1 +
drivers/leds/leds-turris-omnia.c | 284 ++++++++++++++++++++++++--
drivers/leds/trigger/ledtrig-netdev.c | 56 ++---
include/linux/leds.h | 29 +++
include/linux/ledtrig-netdev.h | 34 +++
8 files changed, 377 insertions(+), 56 deletions(-)
create mode 100644 include/linux/ledtrig-netdev.h
--
2.26.3
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:03
The trigger_data struct is allocated with kzalloc, so we do not need to
explicitly set members to zero.
Signed-off-by: Marek Behún <kabel@kernel.org>
Acked-by: Pavel Machek <redacted>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/leds/trigger/ledtrig-netdev.c | 4 ----
1 file changed, 4 deletions(-)
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:08
Add method trigger_offload() and member variable `offloaded` to struct
led_classdev. Add helper functions led_trigger_offload() and
led_trigger_offload_stop().
The trigger_offload() method, when implemented by the LED driver, should
be called (via led_trigger_offload() function) from trigger code wanting
to be offloaded at the moment when configuration of the trigger changes.
If the trigger is successfully offloaded, this method returns 0 and the
trigger does not have to blink the LED in software.
If the trigger with given configuration cannot be offloaded, the method
should return -EOPNOTSUPP, in which case the trigger must blink the LED
in SW.
The second argument to trigger_offload() being false means that the
offloading is being disabled. In this case the function must return 0,
errors are not permitted.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
Documentation/leds/leds-class.rst | 22 ++++++++++++++++++++++
drivers/leds/led-triggers.c | 1 +
include/linux/leds.h | 29 +++++++++++++++++++++++++++++
3 files changed, 52 insertions(+)
@@ -169,6 +169,28 @@ Setting the brightness to zero with brightness_set() callback function should completely turn off the LED and cancel the previously programmed hardware blinking function, if any.+Hardware offloading of LED triggers+===================================++Some LEDs can offload SW triggers to hardware (for example a LED connected to+an ethernet PHY or an ethernet switch can be configured to blink on activity on+the network, which in software is done by the netdev trigger).++To do such offloading, both the trigger code and LED driver must support this.+The LED must implement the trigger_offload() method and the trigger code must+try to call this method (via led_trigger_offload() function) when configuration+of the trigger (trigger_data) changes.++The implementation of the trigger_offload() method by the LED driver must return+0 if the offload is successful and -EOPNOTSUPP if the requested trigger+configuration is not supported and the trigger should be executed in software.+If trigger_offload() returns negative value, the triggering will be done in+software, so any active offloading must also be disabled.++If the second argument (enable) to the trigger_offload() method is false, any+active HW offloading must be deactivated. In this case errors are not permitted+in the trigger_offload() method.+ Known Issues ============
@@ -148,6 +148,11 @@ struct led_classdev {/* LEDs that have private triggers have this set */structled_hw_trigger_type*trigger_type;++/* some LEDs may be able to offload some SW triggers to HW */+int(*trigger_offload)(structled_classdev*led_cdev,+boolenable);+booloffloaded;#endif#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:11
In preparation for HW offloading of netdev trigger, move struct
led_netdev_data into global include directory, into file
linux/ledtrig-netdev.h, so that drivers wanting to offload the trigger
can see the requested settings.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 23 +-----------------
include/linux/ledtrig-netdev.h | 34 +++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 22 deletions(-)
create mode 100644 include/linux/ledtrig-netdev.h
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:16
Add support for HW offloading of the netdev trigger.
We are only offloading if the link is up and rx/tx blinking is
requested.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
@@ -52,9 +52,17 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)if(!led_cdev->blink_brightness)led_cdev->blink_brightness=led_cdev->max_brightness;-if(!test_bit(NETDEV_LED_MODE_LINKUP,&trigger_data->mode))+if(!test_bit(NETDEV_LED_MODE_LINKUP,&trigger_data->mode)){+led_trigger_offload_stop(led_cdev);led_set_brightness(led_cdev,LED_OFF);-else{+}else{+boolblink=test_bit(NETDEV_LED_TX,&trigger_data->mode)||+test_bit(NETDEV_LED_RX,&trigger_data->mode);+/* Try offload to HW only if RX/TX blinking is requested */+if(blink)+if(!led_trigger_offload(led_cdev))+return;+if(test_bit(NETDEV_LED_LINK,&trigger_data->mode))led_set_brightness(led_cdev,led_cdev->blink_brightness);
@@ -64,8 +72,7 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)/* If we are looking for RX/TX start periodically*checkingstats*/-if(test_bit(NETDEV_LED_TX,&trigger_data->mode)||-test_bit(NETDEV_LED_RX,&trigger_data->mode))+if(blink)schedule_delayed_work(&trigger_data->work,0);}}
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:17
Using spinlocks requires that the trigger_offload() method cannot sleep.
This can be problematic for some hardware, since access to registers may
sleep.
We can change the spinlock to mutex because, according to Jacek:
register_netdevice_notifier() registers raw notifier chain,
whose callbacks are not called from atomic context and there are
no restrictions on callbacks. See include/linux/notifier.h.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 14 +++++++-------
include/linux/ledtrig-netdev.h | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:17
Move setting of the LED_UNREGISTERING before deactivating the trigger in
led_classdev_unregister().
It can be useful for a LED trigger to know whether it is being
deactivated due to the LED being unregistered. This makes it possible
for LED drivers which implement trigger offloading to leave the LED in
HW triggering mode when the LED is unregistered, instead of disabling
it.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/led-class.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:18
In order to make trigger offloading code more readable, put the code
that sets/unsets software mode into a separate function.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/leds-turris-omnia.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
@@ -73,6 +73,13 @@ static int omnia_led_brightness_set_blocking(struct led_classdev *cdev,returnret;}+staticintomnia_led_set_sw_mode(structi2c_client*client,intled,boolsw)+{+returni2c_smbus_write_byte_data(client,CMD_LED_MODE,+CMD_LED_MODE_LED(led)|+(sw?CMD_LED_MODE_USER:0));+}+staticintomnia_led_register(structi2c_client*client,structomnia_led*led,structdevice_node*np){
@@ -114,9 +121,7 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,cdev->brightness_set_blocking=omnia_led_brightness_set_blocking;/* put the LED into software mode */-ret=i2c_smbus_write_byte_data(client,CMD_LED_MODE,-CMD_LED_MODE_LED(led->reg)|-CMD_LED_MODE_USER);+ret=omnia_led_set_sw_mode(client,led->reg,true);if(ret<0){dev_err(dev,"Cannot set LED %pOF to software mode: %i\n",np,ret);
@@ -250,8 +255,7 @@ static int omnia_leds_remove(struct i2c_client *client)u8buf[5];/* put all LEDs into default (HW triggered) mode */-i2c_smbus_write_byte_data(client,CMD_LED_MODE,-CMD_LED_MODE_LED(OMNIA_BOARD_LEDS));+omnia_led_set_sw_mode(client,OMNIA_BOARD_LEDS,false);/* set all LEDs color to [255, 255, 255] */buf[0]=CMD_LED_COLOR;
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:20
Move the code of brightness setting function guarded by mutex into
separate function. This will be useful when used from trigger offload
method.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/leds-turris-omnia.c | 35 +++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 12 deletions(-)
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:24
Initialize the intensity of each multi-color LED to white color (255,
255, 255).
This is what the hardware does by default when the driver is not
present.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/leds-turris-omnia.c | 3 +++
1 file changed, 3 insertions(+)
From: Marek Behún <kabel@kernel.org> Date: 2021-06-01 00:52:28
Add support for offloading netdev trigger for WAN LED.
Support for LAN LEDs will be added later, because it needs changes in
the mv88e6xxx driver.
Here is a simplified schema of how the corresponding chips are connected
on Turris Omnia:
[eth2] +-----+ [eth0 & eth1]
/-----------< SOC >-----------------\
| +--v--+ |
| | [i2c] |
| \-------------\ |
[MOD_DEF0] +------v--------+ | |
/---------> SerDes switch | [LED0_pin] +--v--+ | +----------+
| +--v-------v----+ /-------------> MCU >---|--> RGB LEDs |
| [srds0] | | | +--^--+ | +----------+
| /-------/ | | | |
| | [srds1]| | [LED_pins]| |
+-^----v---+ +---v-------^---+ +-------^------v-+
| SFP cage | | 88E1512 PHY | | 88E6176 Swtich |
+----------+ | with WAN port | | with LAN ports |
+---------------+ +----------------+
The RGB LEDs are controlled by the MCU and can be configured into the
following modes:
- SW mode - both color and whether the LED is on/off is controlled via
I2C
- HW mode - color is controlled via I2C, on/off state is controlled by
HW depending on LED:
- WAN LED on/off state reflects LED0_pin from the 88E1512 PHY
- LAN LED on/off states reflect corresponding LED_pins from 88E6176
switch [1]
- PCIe on/off states reflect the corresponding WWAN/WLAN/MSATA LED
pins from the MiniPCIe ports [1]
- Power LED is always on in HW mode
- User LEDs are always off in HW mode
Adding netdev trigger offload support for the WAN LED therefore
requires:
- checking whether the netdevice for which the netdev trigger should
trigger is indeed the WAN device
- checking whether SFP cage is empty. If there is a SFP module in the
cage, the 88E1512 PHY is not used and we have to trigger in SW.
Currently this is done by simply checking if sfp_bus is NULL, because
phylink does not yet have support for how the SFP cage is wired on
Omnia (via SerDes switch)
- configuring the behaviour of LED0_pin of the Marvell 88E1512 PHY
according to requested netdev trigger settings
- putting the WAN LED into HW mode
[1] For more info look at
https://wiki.turris.cz/doc/_media/rtrom01-schema.pdf
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/leds/Kconfig | 3 +
drivers/leds/leds-turris-omnia.c | 232 +++++++++++++++++++++++++++++++
2 files changed, 235 insertions(+)
@@ -91,6 +104,208 @@ static int omnia_led_set_sw_mode(struct i2c_client *client, int led, bool sw)(sw?CMD_LED_MODE_USER:0));}+staticintwan_led_round_blink_rate(unsignedlong*period)+{+/* Each interval is (0.7 * p, 1.3 * p), where p is the period supported+*bythechip.Shouldwechangethissothattherearenoholesbetween+*theseintervals?+*/+switch(*period){+case29...55:+*period=42;+return0;+case58...108:+*period=84;+return1;+case119...221:+*period=170;+return2;+case238...442:+*period=340;+return3;+case469...871:+*period=670;+return4;+default:+return-EOPNOTSUPP;+}+}++staticintomnia_led_trig_offload_wan(structomnia_leds*leds,+structomnia_led*led,+structled_netdev_data*trig)+{+unsignedlongperiod;+intret,blink_rate;+boollink,rx,tx;+u8fun;++/* HW offload on WAN port is supported only via internal PHY */+if(trig->net_dev->sfp_bus||!trig->net_dev->phydev)+return-EOPNOTSUPP;++link=test_bit(NETDEV_LED_LINK,&trig->mode);+rx=test_bit(NETDEV_LED_RX,&trig->mode);+tx=test_bit(NETDEV_LED_TX,&trig->mode);++if(link&&rx&&tx)+fun=0x1;+elseif(!link&&rx&&tx)+fun=0x4;+else+return-EOPNOTSUPP;++period=jiffies_to_msecs(atomic_read(&trig->interval))*2;+blink_rate=wan_led_round_blink_rate(&period);+if(blink_rate<0)+returnblink_rate;++mutex_lock(&leds->lock);++if(!led->phydev){+led->phydev=trig->net_dev->phydev;+get_device(&led->phydev->mdio.dev);+}++/* set PHY's LED[0] pin to blink according to trigger setting */+ret=phy_modify_paged(led->phydev,MII_MARVELL_LED_PAGE,+MII_PHY_LED_TCR,+MII_PHY_LED_TCR_PULSESTR_MASK|+MII_PHY_LED_TCR_BLINKRATE_MASK,+(0<<MII_PHY_LED_TCR_PULSESTR_SHIFT)|+(blink_rate<<MII_PHY_LED_TCR_BLINKRATE_SHIFT));+if(ret)+gotounlock;++ret=phy_modify_paged(led->phydev,MII_MARVELL_LED_PAGE,+MII_PHY_LED_CTRL,0xf,fun);+if(ret)+gotounlock;++/* put the LED into HW mode */+ret=omnia_led_set_sw_mode(leds->client,led->reg,false);+if(ret)+gotounlock;++/* set blinking brightness according to led_cdev->blink_brighness */+ret=omnia_led_brightness_set(leds->client,led,+led->mc_cdev.led_cdev.blink_brightness);+if(ret)+gotounlock;++atomic_set(&trig->interval,msecs_to_jiffies(period/2));++unlock:+mutex_unlock(&leds->lock);++if(ret)+dev_err(led->mc_cdev.led_cdev.dev,+"Error offloading trigger: %d\n",ret);++returnret;+}++staticintomnia_led_trig_offload_off(structomnia_leds*leds,+structomnia_led*led)+{+intret;++if(!led->phydev)+return0;++mutex_lock(&leds->lock);++/* set PHY's LED[0] pin to default values */+ret=phy_modify_paged(led->phydev,MII_MARVELL_LED_PAGE,+MII_PHY_LED_TCR,+MII_PHY_LED_TCR_PULSESTR_MASK|+MII_PHY_LED_TCR_BLINKRATE_MASK,+(4<<MII_PHY_LED_TCR_PULSESTR_SHIFT)|+(1<<MII_PHY_LED_TCR_BLINKRATE_SHIFT));++ret=phy_modify_paged(led->phydev,MII_MARVELL_LED_PAGE,+MII_PHY_LED_CTRL,0xf,0xe);++/*+*Returntosoftwarecontrolledmode,butonlyifwearen'tbeing+*calledfromled_classdev_unregister.+*/+if(!(led->mc_cdev.led_cdev.flags&LED_UNREGISTERING))+ret=omnia_led_set_sw_mode(leds->client,led->reg,true);++put_device(&led->phydev->mdio.dev);+led->phydev=NULL;++mutex_unlock(&leds->lock);++return0;+}++staticintomnia_led_trig_offload(structled_classdev*cdev,boolenable)+{+structomnia_leds*leds=dev_get_drvdata(cdev->dev->parent);+structled_classdev_mc*mc_cdev=lcdev_to_mccdev(cdev);+structomnia_led*led=to_omnia_led(mc_cdev);+structled_netdev_data*trig;+intret=-EOPNOTSUPP;++if(!enable)+returnomnia_led_trig_offload_off(leds,led);++if(!led->trig_src_np)+gotoend;++/* only netdev trigger offloading is supported currently */+if(strcmp(cdev->trigger->name,"netdev"))+gotoend;++trig=led_get_trigger_data(cdev);++if(!trig->net_dev)+gotoend;++if(dev_of_node(trig->net_dev->dev.parent)!=led->trig_src_np)+gotoend;++ret=omnia_led_trig_offload_wan(leds,led,trig);++end:+/*+*ifoffloadingfailed(parametersnotsupportedbyHW),ensureany+*previousoffloadingisdisabled+*/+if(ret)+omnia_led_trig_offload_off(leds,led);++returnret;+}++staticintread_trigger_sources(structomnia_led*led,structdevice_node*np)+{+structof_phandle_argsargs;+intret;++ret=of_count_phandle_with_args(np,"trigger-sources",+"#trigger-source-cells");+if(ret<0)+returnret==-ENOENT?0:ret;++if(!ret)+return0;++ret=of_parse_phandle_with_args(np,"trigger-sources",+"#trigger-source-cells",0,&args);+if(ret)+returnret;++if(of_device_is_compatible(args.np,"marvell,armada-370-neta"))+led->trig_src_np=args.np;+else+of_node_put(args.np);++return0;+}+staticintomnia_led_register(structi2c_client*client,structomnia_led*led,structdevice_node*np){
@@ -133,6 +355,8 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led,cdev=&led->mc_cdev.led_cdev;cdev->max_brightness=255;cdev->brightness_set_blocking=omnia_led_brightness_set_blocking;+if(led->trig_src_np)+cdev->trigger_offload=omnia_led_trig_offload;/* put the LED into software mode */ret=omnia_led_set_sw_mode(client,led->reg,true);
@@ -256,6 +480,7 @@ static int omnia_leds_probe(struct i2c_client *client,}led+=ret;+++leds->count;}if(devm_device_add_groups(dev,omnia_led_controller_groups))
@@ -266,8 +491,15 @@ static int omnia_leds_probe(struct i2c_client *client,staticintomnia_leds_remove(structi2c_client*client){+structomnia_leds*leds=i2c_get_clientdata(client);+structomnia_led*led;u8buf[5];+/* put away trigger source OF nodes */+for(led=&leds->leds[0];led<&leds->leds[leds->count];++led)+if(led->trig_src_np)+of_node_put(led->trig_src_np);+/* put all LEDs into default (HW triggered) mode */omnia_led_set_sw_mode(client,OMNIA_BOARD_LEDS,false);
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-06-01 21:13:00
On Tue, Jun 01, 2021 at 02:51:51AM +0200, Marek Behún wrote:
Move setting of the LED_UNREGISTERING before deactivating the trigger in
led_classdev_unregister().
It can be useful for a LED trigger to know whether it is being
deactivated due to the LED being unregistered. This makes it possible
for LED drivers which implement trigger offloading to leave the LED in
HW triggering mode when the LED is unregistered, instead of disabling
it.
Humm, i'm not sure that is a good idea. I don't expect my Ethernet
switch to keep forwarding frames when i unload the driver.
Andrew
From: Marek Behún <kabel@kernel.org> Date: 2021-06-02 12:44:50
On Tue, 1 Jun 2021 23:12:57 +0200
Andrew Lunn [off-list ref] wrote:
On Tue, Jun 01, 2021 at 02:51:51AM +0200, Marek Behún wrote:
quoted
Move setting of the LED_UNREGISTERING before deactivating the
trigger in led_classdev_unregister().
It can be useful for a LED trigger to know whether it is being
deactivated due to the LED being unregistered. This makes it
possible for LED drivers which implement trigger offloading to
leave the LED in HW triggering mode when the LED is unregistered,
instead of disabling it.
Humm, i'm not sure that is a good idea. I don't expect my Ethernet
switch to keep forwarding frames when i unload the driver.
We want to make it so that when leds-turris-omnia driver is unloaded,
the LEDs will start blinking in HW mode as they did before the driver
was loaded. This is needed for that.
Marek
Hi Marek,
On Tue, Jun 1, 2021 at 1:53 AM Marek Behún [off-list ref] wrote:
Hello,
this is v2 of series adding support for offloading LED triggers to HW.
The netdev trigger is the first user and leds-turris-omnia is the first
example implementation.
A video comparing SW (left LED) vs HW (right LED) netdev trigger on
Omnia
https://secure.nic.cz/files/mbehun/omnia-wan-netdev-trig-offload.mp4
Changes since v1:
- changed typo in doc
- the netdev trigger data structure now lives in
include/linux/ledtrig-netdev.h instead of ledtrig.h, as suggested by
Andrew. Also the structure is always defined, no guard against
CONFIG_LEDS_TRIGGER_NETDEV
- we do not export netdev_led_trigger variable. The trigger_offload()
method can look at led_cdev->trigger->name to see which trigger it
should try to offload, i.e. compare the string to "netdev"
- netdev trigger is being offloaded only if link is up, and at least one
of the rx, tx parameters are set. No need to offload otherwise
- a patch is added that moves setting flag LED_UNREGISTERING in
led_classdev_unregister() before unsetting trigger. This makes it
possible for the trigger_offload() method to determine whether the
offloading is being disabled because the LED is being unregistered.
The driver may put the LED into HW triggering mode in this case, to
achieve behaviour as was before the driver was loaded
- an example implementation for offloading the netdev trigger for the
WAN LED on Turris Omnia is added. LAN LEDs are not yet supported
Changes since RFC:
- split the patch adding HW offloading support to netdev trigger into
several separate patches (suggested by Pavel):
1. move trigger data structure to include/linux/ledtrig.h
2. support HW offloading
3. change spinlock to mutex
- fixed bug where the .offloaded variable was not set to false when
offloading was disabled (suggested by Pavel)
- removed the code saving one call to set_baseline_state() on the
NETDEV_CHANGE event. It is not needed, the trigger_offload() method
can handle this situation on its own (suggested by Pavel)
- documentation now explicitly says that when offloading is being
disabled, the function must return 0 (no error) (suggested by Pavel)
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
From: Andrew Lunn <andrew@lunn.ch> Date: 2025-10-16 13:14:37
quoted
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
Do you plan to progress with the above series anytime soon? If not I
want to give this patch [0] again a respin.
What features are you missing from the current kernel code, which this
series adds?
Andrew
Hi Andrew,
On Thu, Oct 16, 2025 at 2:14 PM Andrew Lunn [off-list ref] wrote:
quoted
quoted
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
Do you plan to progress with the above series anytime soon? If not I
want to give this patch [0] again a respin.
What features are you missing from the current kernel code, which this
series adds?
I’m working on a platform that uses the VSC8541 PHY. On this platform,
LED0 and LED1 are connected to the external connector, and LED1 is
also connected to the Ethernet switch to indicate the PHY link status.
As a result, whenever there is link activity, the PHY link status
signal to the switch toggles, causing the switch to incorrectly detect
the link as going up and down.
Cheers,
Prabhakar
From: Andrew Lunn <andrew@lunn.ch> Date: 2025-10-16 19:11:20
On Thu, Oct 16, 2025 at 07:53:17PM +0100, Lad, Prabhakar wrote:
Hi Andrew,
On Thu, Oct 16, 2025 at 2:14 PM Andrew Lunn [off-list ref] wrote:
quoted
quoted
quoted
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
Do you plan to progress with the above series anytime soon? If not I
want to give this patch [0] again a respin.
What features are you missing from the current kernel code, which this
series adds?
I’m working on a platform that uses the VSC8541 PHY. On this platform,
LED0 and LED1 are connected to the external connector, and LED1 is
also connected to the Ethernet switch to indicate the PHY link status.
As a result, whenever there is link activity, the PHY link status
signal to the switch toggles, causing the switch to incorrectly detect
the link as going up and down.
So you think the current /sys/class/leds code is not sufficient. You
can use it from udev etc, to make the LED indicate link, but then
userspace could change it to something else. I _think_ only root can
use /sys/class/leds to change the function of the LED, so it is not
too bad as is? Or do you really want to make the configuration read
only?
Andrew
Hi Andrew,
On Thu, Oct 16, 2025 at 8:11 PM Andrew Lunn [off-list ref] wrote:
On Thu, Oct 16, 2025 at 07:53:17PM +0100, Lad, Prabhakar wrote:
quoted
Hi Andrew,
On Thu, Oct 16, 2025 at 2:14 PM Andrew Lunn [off-list ref] wrote:
quoted
quoted
quoted
Marek Behún (10):
leds: trigger: netdev: don't explicitly zero kzalloced data
leds: trigger: add API for HW offloading of triggers
leds: trigger: netdev: move trigger data structure to global include
dir
leds: trigger: netdev: support HW offloading
leds: trigger: netdev: change spinlock to mutex
leds: core: inform trigger that it's deactivation is due to LED
removal
leds: turris-omnia: refactor sw mode setting code into separate
function
leds: turris-omnia: refactor brightness setting function
leds: turris-omnia: initialize each multicolor LED to white color
leds: turris-omnia: support offloading netdev trigger for WAN LED
Do you plan to progress with the above series anytime soon? If not I
want to give this patch [0] again a respin.
What features are you missing from the current kernel code, which this
series adds?
I’m working on a platform that uses the VSC8541 PHY. On this platform,
LED0 and LED1 are connected to the external connector, and LED1 is
also connected to the Ethernet switch to indicate the PHY link status.
As a result, whenever there is link activity, the PHY link status
signal to the switch toggles, causing the switch to incorrectly detect
the link as going up and down.
So you think the current /sys/class/leds code is not sufficient. You
can use it from udev etc, to make the LED indicate link, but then
userspace could change it to something else. I _think_ only root can
use /sys/class/leds to change the function of the LED, so it is not
too bad as is? Or do you really want to make the configuration read
only?
I haven't explored the current leds code tbh. Can you please point me
to any PHY which uses leds if any.
Cheers,
Prabhakar
From: Andrew Lunn <andrew@lunn.ch> Date: 2025-11-05 16:11:59
Sorry for the delayed response.
I started investigating adding PHY leds. In page 53 section "4.2.27
LED Behavior" [0] we have an option for LED0/1 combine feature
disable. For this is it OK to add a new DT property?
Why do you need a new property?
You just need to set this bit depending on what has been selected via
/sys/class/led.
And if the user asks for a mode which the hardware does not supported,
the core will fall back to use on/off and blink the LED itself.
PHY LEDs are the wild west. Every vendor has its own idea what is
important, and adds features which other vendors don't have. But that
does not mean we need to support all the features in Linux. So the
core has a reasonable set of features which we expect most PHYs can
support. I don't want to add more features unless you have a big
business case it is needed, and other PHY also have the same feature.
Andrew
Hi Andrew,
On Wed, Nov 5, 2025 at 3:49 PM Andrew Lunn [off-list ref] wrote:
quoted
Sorry for the delayed response.
I started investigating adding PHY leds. In page 53 section "4.2.27
LED Behavior" [0] we have an option for LED0/1 combine feature
disable. For this is it OK to add a new DT property?
Why do you need a new property?
You just need to set this bit depending on what has been selected via
/sys/class/led.
Ahh I get you now. When I trigger the sysfs file I get the below files:
# ls
brightness device device_name full_duplex half_duplex interval
link link_10 link_100 max_brightness offloaded power rx rx_err
subsystem trigger tx tx_err uevent
As per HW manual [0] we have,
0: Combine enabled (link/activity, duplex/collision).
1: Disable combination (link only, duplex only).
# Combine DISABLED (link + duplex only)
echo netdev > trigger
echo 1 > link
echo 1 > full_duplex # or half_duplex
echo 0 > rx
echo 0 > tx
# Combine ENABLED (link + activity + duplex + collision)
echo netdev > trigger
echo 1 > link
echo 1 > rx
echo 1 > tx
So to Enable/Disable LEDx combine feature we just need to write as
above. Is my understanding correct?
[0] https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/DataSheets/VMDS-10513_VSC8541-02_VSC8541-05_Datasheet.pdf
And if the user asks for a mode which the hardware does not supported,
the core will fall back to use on/off and blink the LED itself.
Ok.
PHY LEDs are the wild west. Every vendor has its own idea what is
important, and adds features which other vendors don't have. But that
does not mean we need to support all the features in Linux. So the
core has a reasonable set of features which we expect most PHYs can
support. I don't want to add more features unless you have a big
business case it is needed, and other PHY also have the same feature.
From: Andrew Lunn <andrew@lunn.ch> Date: 2025-11-05 18:35:33
# ls
brightness device device_name full_duplex half_duplex interval
link link_10 link_100 max_brightness offloaded power rx rx_err
subsystem trigger tx tx_err uevent
As per HW manual [0] we have,
0: Combine enabled (link/activity, duplex/collision).
1: Disable combination (link only, duplex only).
# Combine DISABLED (link + duplex only)
echo netdev > trigger
echo 1 > link
echo 1 > full_duplex # or half_duplex
echo 0 > rx
echo 0 > tx
# Combine ENABLED (link + activity + duplex + collision)
echo netdev > trigger
echo 1 > link
echo 1 > rx
echo 1 > tx
So to Enable/Disable LEDx combine feature we just need to write as
above. Is my understanding correct?
Yes. The PHY driver gets passed a bitmap of each features to
enable. Looking that those bits you need to decide on the 4 bit LED
mode value, and the combine bit. Or return -EOPNOTSUPP.
Andrew