linux-leds.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs
@ 2023-05-25 14:53 Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 01/13] leds: add APIs for LEDs hw control Christian Marangi
                   ` (13 more replies)
  0 siblings, 14 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Since this series is cross subsystem between LED and netdev,
a stable branch was created to facilitate merging process.

This is based on top of branch ib-leds-netdev-v6.5 present here [1].

This is a continue of [2]. It was decided to take a more gradual
approach to implement LEDs support for switch and phy starting with
basic support and then implementing the hw control part when we have all
the prereq done.

This is the main part of the series, the one that actually implement the
hw control API.

Some history about this feature and why
=======================================

This proposal is highly requested by the entire net community but the API
is not strictly designed for net usage but for a more generic usage.

Initial version were very flexible and designed to try to support every
aspect of the LED driver with many complex function that served multiple
purpose. There was an idea to have sw only and hw only LEDs and sw only
and hw only LEDs.

With some heads up from Andrew from the net mailing list, it was suggested
to implement a more basic yet easy to implement system.

These API strictly work with a designated trigger to offload their
function.
This may be confused with hw blink offload but LED may have an even more
advanced configuration where the entire aspect of the trigger is
offloaded and completely handled by the hardware.

An example of this usage are PHY or switch port LEDs. Almost every of
these kind of device have multiple LED attached and provide info of the
current port state.

Currently we lack any support of them but these device always provide a
way to configure them, from basic feature like turning the LED off or no
(implemented in previous series related to this feature) or even entirely
driven by the hw and power on/off/blink based on some events, like tx/rx
traffic, ethernet cable attached, link speed of 10mbps, 100mbps, 1000mbps
or more. They can also support multiple logic like blink with traffic only
if a particular link speed is attached. (an example of this is when a LED
is designated to be turned on only with 100mbps link speed and configured
to blink on traffic and a secondary LED of a different color is present to
serve the same function but only when the link speed is 1000mbps)

These case are very common for a PHY or a switch but they were never
standardized so OEM support all kind of variant and configuration.

Again with Andrew we compared some feature and we reached a common set
of modes that are for sure present in every kind of devices.

And this concludes history and why.

What is present in this series
==============================

This patch contain the required API to support this feature, I decided on
the name of hw control to quickly describe this feature.

I documented each require API in the related Documentation for leds-class
so I think it might me redundant to expose them here. Feel free to tell me
how to improve it if anything is not clear.

On an abstract idea, this feature require this:

    - The trigger needs to make use of it, this is currently implemented
      for the netdev trigger but other trigger can be expanded if the
      device expose these function. An idea might be a anything that
      handle a storage disk and have the LED configurable to blink when
      there is any activity to the disk.

    - The LED driver needs to expose and implement these new API.

Currently a LED driver supports only a trigger. The trigger should use
the related helper to check if the LED can be driven hy hardware.

The different modes a trigger support are exposed in the kernel include
leds.h header and are used by the LED driver to understand what to do.

From a user standpoint, he should enable modes as usual from sysfs and if
anything is not supported warned.

Final words and missing piece from this series
==============================================

I honestly hope this feature can finally be implemented.

This series originally had also additional modes and logic to add to the
netdev trigger, but I decided to strip them and implement only the API
and support basic tx and rx. After this is merged, I will quickly propose
these additional modes.

Currently this is limited to tx and rx and this is what the current user
qca8k use. Marvell PHY support link and a generic blink with any kind of
traffic (both rx and tx). qca8k switch supports keeping the LED on based on
link speed.

The next series will add the concept of hw control only modes to the netdev
trigger and support for these additional modes:
- link_10
- link_100
- link_1000
- activity

The current implementation is voluntary basic and limited to put the ground
work and have something easy to implement and usable. 99% part of the logic
is done on the trigger side, leaving to the LED driver only the validating
and the apply part.

As shown for the PHY led binding, people are really intrested in this
feature as quickly after they were merged, people were already working on
adding support for it.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git/?h=ib-leds-netdev-6.5
[2] https://lore.kernel.org/lkml/20230216013230.22978-1-ansuelsmth@gmail.com/

Changes in v2:
- Drop helper as currently used only by one trigger
- Improve Documentation and document return error of some functions
- Squash some patch to reduce series size
- Drop trigger mode mask as currently not used
- Rework hw control validating function to a simple implementation

Changes from previous v8 series:
- Rewrite Documentation from scratch and move to separate commit
- Strip additional trigger modes (to propose in a different series)
- Strip from qca8k driver additional modes (to implement in the different
  series)
- Split the netdev chages to smaller piece to permit easier review

Changelog in the previous v8 series: (stripped of unrelated changes)
v8:
- Improve the documentation of the new feature
- Rename to a more symbolic name
- Fix some bug in netdev trigger (not using BIT())
- Add more define for qca8k-leds driver
- Drop interval support
- Fix many bugs in the validate option in the netdev trigger
v7:
- Fix qca8k leds documentation warning
- Remove RFC tag
v6:
- Back to RFC.
- Drop additional trigger
- Rework netdev trigger to support common modes used by switch and
  hardware only triggers
- Refresh qca8k leds logic and driver
v5:
- Move out of RFC. (no comments from Andrew this is the right path?)
- Fix more spelling mistake (thx Randy)
- Fix error reported by kernel test bot
- Drop the additional HW_CONTROL flag. It does simplify CONFIG
  handling and hw control should be available anyway to support
  triggers as module.
v4:
- Rework implementation and drop hw_configure logic.
  We now expand blink_set.
- Address even more spelling mistake. (thx a lot Randy)
- Drop blink option and use blink_set delay.
v3:
- Rework start/stop as Andrew asked.
- Use test_bit API to check flag passed to hw_control_configure.
- Added a new cmd to hw_control_configure to reset any active blink_mode.
- Refactor all the patches to follow this new implementation.
v2:
- Fix spelling mistake (sorry)
- Drop patch 02 "permit to declare supported offload triggers".
  Change the logic, now the LED driver declare support for them
  using the configure_offload with the cmd TRIGGER_SUPPORTED.
- Rework code to follow this new implementation.
- Update Documentation to better describe how this offload
  implementation work.

Andrew Lunn (4):
  leds: add API to get attached device for LED hw control
  leds: trigger: netdev: refactor code setting device name
  leds: trigger: netdev: validate configured netdev
  net: dsa: qca8k: add op to get ports netdev

Christian Marangi (9):
  leds: add APIs for LEDs hw control
  Documentation: leds: leds-class: Document new Hardware driven LEDs
    APIs
  leds: trigger: netdev: introduce check for possible hw control
  leds: trigger: netdev: add basic check for hw control support
  leds: trigger: netdev: reject interval store for hw_control
  leds: trigger: netdev: add support for LED hw control
  leds: trigger: netdev: init mode if hw control already active
  leds: trigger: netdev: expose netdev trigger modes in linux include
  net: dsa: qca8k: implement hw_control ops

 Documentation/leds/leds-class.rst     |  80 ++++++++++++
 drivers/leds/trigger/ledtrig-netdev.c | 137 ++++++++++++++++---
 drivers/net/dsa/qca/qca8k-leds.c      | 181 ++++++++++++++++++++++++++
 include/linux/leds.h                  |  53 ++++++++
 4 files changed, 433 insertions(+), 18 deletions(-)

-- 
2.39.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 01/13] leds: add APIs for LEDs hw control
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 02/13] leds: add API to get attached device for LED " Christian Marangi
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Add an option to permit LED driver to declare support for a specific
trigger to use hw control and setup the LED to blink based on specific
provided modes.

Add APIs for LEDs hw control. These functions will be used to activate
hardware control where a LED will use the provided flags, from an
unique defined supported trigger, to setup the LED to be driven by
hardware.

Add hw_control_is_supported() to ask the LED driver if the requested
mode by the trigger are supported and the LED can be setup to follow
the requested modes.

Deactivate hardware blink control by setting brightness to LED_OFF via
the brightness_set() callback.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 include/linux/leds.h | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/include/linux/leds.h b/include/linux/leds.h
index c39bbf17a25b..4caf559b1922 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -183,6 +183,43 @@ struct led_classdev {
 
 	/* LEDs that have private triggers have this set */
 	struct led_hw_trigger_type	*trigger_type;
+
+	/* Unique trigger name supported by LED set in hw control mode */
+	const char		*hw_control_trigger;
+	/*
+	 * Check if the LED driver supports the requested mode provided by the
+	 * defined supported trigger to setup the LED to hw control mode.
+	 *
+	 * Return 0 on success. Return -EOPNOTSUPP when the passed flags are not
+	 * supported and software fallback needs to be used.
+	 * Return a negative error number on any other case  for check fail due
+	 * to various reason like device not ready or timeouts.
+	 */
+	int			(*hw_control_is_supported)(struct led_classdev *led_cdev,
+							   unsigned long flags);
+	/*
+	 * Activate hardware control, LED driver will use the provided flags
+	 * from the supported trigger and setup the LED to be driven by hardware
+	 * following the requested mode from the trigger flags.
+	 * Deactivate hardware blink control by setting brightness to LED_OFF via
+	 * the brightness_set() callback.
+	 *
+	 * Return 0 on success, a negative error number on flags apply fail.
+	 */
+	int			(*hw_control_set)(struct led_classdev *led_cdev,
+						  unsigned long flags);
+	/*
+	 * Get from the LED driver the current mode that the LED is set in hw
+	 * control mode and put them in flags.
+	 * Trigger can use this to get the initial state of a LED already set in
+	 * hardware blink control.
+	 *
+	 * Return 0 on success, a negative error number on failing parsing the
+	 * initial mode. Error from this function is NOT FATAL as the device
+	 * may be in a not supported initial state by the attached LED trigger.
+	 */
+	int			(*hw_control_get)(struct led_classdev *led_cdev,
+						  unsigned long *flags);
 #endif
 
 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 02/13] leds: add API to get attached device for LED hw control
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 01/13] leds: add APIs for LEDs hw control Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 03/13] Documentation: leds: leds-class: Document new Hardware driven LEDs APIs Christian Marangi
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

From: Andrew Lunn <andrew@lunn.ch>

Some specific LED triggers blink the LED based on events from a device
or subsystem.
For example, an LED could be blinked to indicate a network device is
receiving packets, or a disk is reading blocks. To correctly enable and
request the hw control of the LED, the trigger has to check if the
network interface or block device configured via a /sys/class/led file
match the one the LED driver provide for hw control for.

Provide an API call to get the device which the LED blinks for.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 include/linux/leds.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/leds.h b/include/linux/leds.h
index 4caf559b1922..3268b4e789d6 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -220,6 +220,12 @@ struct led_classdev {
 	 */
 	int			(*hw_control_get)(struct led_classdev *led_cdev,
 						  unsigned long *flags);
+	/*
+	 * Get the device this LED blinks in response to.
+	 * e.g. for a PHY LED, it is the network device. If the LED is
+	 * not yet associated to a device, return NULL.
+	 */
+	struct device		*(*hw_control_get_device)(struct led_classdev *led_cdev);
 #endif
 
 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 03/13] Documentation: leds: leds-class: Document new Hardware driven LEDs APIs
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 01/13] leds: add APIs for LEDs hw control Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 02/13] leds: add API to get attached device for LED " Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 04/13] leds: trigger: netdev: refactor code setting device name Christian Marangi
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Document new Hardware driven LEDs APIs.

Some LEDs can be programmed to be driven by hardware. This is not
limited to blink but also to turn off or on autonomously.
To support this feature, a LED needs to implement various additional
ops and needs to declare specific support for the supported triggers.

Add documentation for each required value and API to make hw control
possible and implementable by both LEDs and triggers.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 Documentation/leds/leds-class.rst | 80 +++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst
index cd155ead8703..3d7874c18982 100644
--- a/Documentation/leds/leds-class.rst
+++ b/Documentation/leds/leds-class.rst
@@ -169,6 +169,86 @@ 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 driven LEDs
+====================
+
+Some LEDs can be programmed to be driven by hardware. This is not
+limited to blink but also to turn off or on autonomously.
+To support this feature, a LED needs to implement various additional
+ops and needs to declare specific support for the supported triggers.
+
+With hw control we refer to the LED driven by hardware.
+
+LED driver must define the following value to support hw control:
+
+    - hw_control_trigger:
+               unique trigger name supported by the LED in hw control
+               mode.
+
+LED driver must implement the following API to support hw control:
+    - hw_control_is_supported:
+                check if the flags passed by the supported trigger can
+                be parsed and activate hw control on the LED.
+
+                Return 0 if the passed flags mask is supported and
+                can be set with hw_control_set().
+
+                If the passed flags mask is not supported -EOPNOTSUPP
+                must be returned, the LED trigger will use software
+                fallback in this case.
+
+                Return a negative error in case of any other error like
+                device not ready or timeouts.
+
+     - hw_control_set:
+                activate hw control. LED driver will use the provided
+                flags passed from the supported trigger, parse them to
+                a set of mode and setup the LED to be driven by hardware
+                following the requested modes.
+
+                Set LED_OFF via the brightness_set to deactivate hw control.
+
+                Return 0 on success, a negative error number on flags apply
+                fail.
+
+    - hw_control_get:
+                get active modes from a LED already in hw control, parse
+                them and set in flags the current active flags for the
+                supported trigger.
+
+                Return 0 on success, a negative error number on failing
+                parsing the initial mode.
+                Error from this function is NOT FATAL as the device may
+                be in a not supported initial state by the attached LED
+                trigger.
+
+    - hw_control_get_device:
+                return the device associated with the LED driver in
+                hw control. A trigger might use this to match the
+                returned device from this function with a configured
+                device for the trigger as the source for blinking
+                events and correctly enable hw control.
+                (example a netdev trigger configured to blink for a
+                particular dev match the returned dev from get_device
+                to set hw control)
+
+                Return a device or NULL if nothing is currently attached.
+
+LED driver can activate additional modes by default to workaround the
+impossibility of supporting each different mode on the supported trigger.
+Example are hardcoding the blink speed to a set interval, enable special
+feature like bypassing blink if some requirements are not met.
+
+A trigger should first check if the hw control API are supported by the LED
+driver and check if the trigger is supported to verify if hw control is possible,
+use hw_control_is_supported to check if the flags are supported and only at
+the end use hw_control_set to activate hw control.
+
+A trigger can use hw_control_get to check if a LED is already in hw control
+and init their flags.
+
+When the LED is in hw control, no software blink is possible and doing so
+will effectively disable hw control.
 
 Known Issues
 ============
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 04/13] leds: trigger: netdev: refactor code setting device name
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (2 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 03/13] Documentation: leds: leds-class: Document new Hardware driven LEDs APIs Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 05/13] leds: trigger: netdev: introduce check for possible hw control Christian Marangi
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

From: Andrew Lunn <andrew@lunn.ch>

Move the code into a helper, ready for it to be called at
other times. No intended behaviour change.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 29 ++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 305eb543ba84..c93ac3bc85a6 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -104,15 +104,9 @@ static ssize_t device_name_show(struct device *dev,
 	return len;
 }
 
-static ssize_t device_name_store(struct device *dev,
-				 struct device_attribute *attr, const char *buf,
-				 size_t size)
+static int set_device_name(struct led_netdev_data *trigger_data,
+			   const char *name, size_t size)
 {
-	struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
-
-	if (size >= IFNAMSIZ)
-		return -EINVAL;
-
 	cancel_delayed_work_sync(&trigger_data->work);
 
 	mutex_lock(&trigger_data->lock);
@@ -122,7 +116,7 @@ static ssize_t device_name_store(struct device *dev,
 		trigger_data->net_dev = NULL;
 	}
 
-	memcpy(trigger_data->device_name, buf, size);
+	memcpy(trigger_data->device_name, name, size);
 	trigger_data->device_name[size] = 0;
 	if (size > 0 && trigger_data->device_name[size - 1] == '\n')
 		trigger_data->device_name[size - 1] = 0;
@@ -140,6 +134,23 @@ static ssize_t device_name_store(struct device *dev,
 	set_baseline_state(trigger_data);
 	mutex_unlock(&trigger_data->lock);
 
+	return 0;
+}
+
+static ssize_t device_name_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t size)
+{
+	struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
+	int ret;
+
+	if (size >= IFNAMSIZ)
+		return -EINVAL;
+
+	ret = set_device_name(trigger_data, buf, size);
+
+	if (ret < 0)
+		return ret;
 	return size;
 }
 
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 05/13] leds: trigger: netdev: introduce check for possible hw control
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (3 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 04/13] leds: trigger: netdev: refactor code setting device name Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 06/13] leds: trigger: netdev: add basic check for hw control support Christian Marangi
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Introduce function to check if the requested mode can use hw control in
preparation for hw control support. Currently everything is handled in
software so can_hw_control will always return false.

Add knob with the new value hw_control in trigger_data struct to
set hw control possible. Useful for future implementation to implement
in set_baseline_state() the required function to set the requested mode
using LEDs hw control ops and in other function to reject set if hw
control is currently active.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index c93ac3bc85a6..e1f3cedd5d57 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -51,6 +51,7 @@ struct led_netdev_data {
 
 	unsigned long mode;
 	bool carrier_link_up;
+	bool hw_control;
 };
 
 enum led_trigger_netdev_modes {
@@ -91,6 +92,11 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
 	}
 }
 
+static bool can_hw_control(struct led_netdev_data *trigger_data)
+{
+	return false;
+}
+
 static ssize_t device_name_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -204,6 +210,8 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 	else
 		clear_bit(bit, &trigger_data->mode);
 
+	trigger_data->hw_control = can_hw_control(trigger_data);
+
 	set_baseline_state(trigger_data);
 
 	return size;
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 06/13] leds: trigger: netdev: add basic check for hw control support
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (4 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 05/13] leds: trigger: netdev: introduce check for possible hw control Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 07/13] leds: trigger: netdev: reject interval store for hw_control Christian Marangi
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Add basic check for hw control support. Check if the required API are
defined and check if the defined trigger supported in hw control for the
LED driver match netdev.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index e1f3cedd5d57..2101cbbda707 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -92,8 +92,22 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
 	}
 }
 
+static bool supports_hw_control(struct led_classdev *led_cdev)
+{
+	if (!led_cdev->hw_control_get || !led_cdev->hw_control_set ||
+	    !led_cdev->hw_control_is_supported)
+		return false;
+
+	return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name);
+}
+
 static bool can_hw_control(struct led_netdev_data *trigger_data)
 {
+	struct led_classdev *led_cdev = trigger_data->led_cdev;
+
+	if (!supports_hw_control(led_cdev))
+		return false;
+
 	return false;
 }
 
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 07/13] leds: trigger: netdev: reject interval store for hw_control
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (5 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 06/13] leds: trigger: netdev: add basic check for hw control support Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 08/13] leds: trigger: netdev: add support for LED hw control Christian Marangi
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Reject interval store with hw_control enabled. It's are currently not
supported and MUST be set to the default value with hw control enabled.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 2101cbbda707..cb2ec33abc4e 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -265,6 +265,9 @@ static ssize_t interval_store(struct device *dev,
 	unsigned long value;
 	int ret;
 
+	if (trigger_data->hw_control)
+		return -EINVAL;
+
 	ret = kstrtoul(buf, 0, &value);
 	if (ret)
 		return ret;
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 08/13] leds: trigger: netdev: add support for LED hw control
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (6 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 07/13] leds: trigger: netdev: reject interval store for hw_control Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 09/13] leds: trigger: netdev: validate configured netdev Christian Marangi
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Add support for LED hw control for the netdev trigger.

The trigger on calling set_baseline_state to configure a new mode, will
do various check to verify if hw control can be used for the requested
mode in can_hw_control() function.

It will first check if the LED driver supports hw control for the netdev
trigger, then will use hw_control_is_supported() and finally will call
hw_control_set() to apply the requested mode.

To use such mode, interval MUST be set to the default value and net_dev
MUST be set. If one of these 2 value are not valid, hw control will
never be used and normal software fallback is used.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 39 ++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index cb2ec33abc4e..8d6381415208 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -68,6 +68,13 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
 	int current_brightness;
 	struct led_classdev *led_cdev = trigger_data->led_cdev;
 
+	/* Already validated, hw control is possible with the requested mode */
+	if (trigger_data->hw_control) {
+		led_cdev->hw_control_set(led_cdev, trigger_data->mode);
+
+		return;
+	}
+
 	current_brightness = led_cdev->brightness;
 	if (current_brightness)
 		led_cdev->blink_brightness = current_brightness;
@@ -103,12 +110,42 @@ static bool supports_hw_control(struct led_classdev *led_cdev)
 
 static bool can_hw_control(struct led_netdev_data *trigger_data)
 {
+	unsigned int interval = atomic_read(&trigger_data->interval);
 	struct led_classdev *led_cdev = trigger_data->led_cdev;
+	unsigned long default_interval = msecs_to_jiffies(50);
+	int ret;
 
 	if (!supports_hw_control(led_cdev))
 		return false;
 
-	return false;
+	/*
+	 * Interval must be set to the default
+	 * value. Any different value is rejected if in hw
+	 * control.
+	 */
+	if (interval != default_interval)
+		return false;
+
+	/*
+	 * net_dev must be set with hw control, otherwise no
+	 * blinking can be happening and there is nothing to
+	 * offloaded.
+	 */
+	if (!trigger_data->net_dev)
+		return false;
+
+	/* Check if the requested mode is supported */
+	ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode);
+	/* Fall back to software blinking if not supported */
+	if (ret == -EOPNOTSUPP)
+		return false;
+	if (ret) {
+		dev_warn(led_cdev->dev,
+			 "Current mode check failed with error %d\n", ret);
+		return false;
+	}
+
+	return true;
 }
 
 static ssize_t device_name_show(struct device *dev,
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 09/13] leds: trigger: netdev: validate configured netdev
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (7 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 08/13] leds: trigger: netdev: add support for LED hw control Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 10/13] leds: trigger: netdev: init mode if hw control already active Christian Marangi
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

From: Andrew Lunn <andrew@lunn.ch>

The netdev which the LED should blink for is configurable in
/sys/class/led/foo/device_name. Ensure when offloading that the
configured netdev is the same as the netdev the LED is associated
with. If it is not, only perform software blinking.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 8d6381415208..5b59441fc415 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -108,6 +108,24 @@ static bool supports_hw_control(struct led_classdev *led_cdev)
 	return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name);
 }
 
+/*
+ * Validate the configured netdev is the same as the one associated with
+ * the LED driver in hw control.
+ */
+static bool validate_net_dev(struct led_classdev *led_cdev,
+			     struct net_device *net_dev)
+{
+	struct device *dev = led_cdev->hw_control_get_device(led_cdev);
+	struct net_device *ndev;
+
+	if (!dev)
+		return false;
+
+	ndev = to_net_dev(dev);
+
+	return ndev == net_dev;
+}
+
 static bool can_hw_control(struct led_netdev_data *trigger_data)
 {
 	unsigned int interval = atomic_read(&trigger_data->interval);
@@ -129,9 +147,11 @@ static bool can_hw_control(struct led_netdev_data *trigger_data)
 	/*
 	 * net_dev must be set with hw control, otherwise no
 	 * blinking can be happening and there is nothing to
-	 * offloaded.
+	 * offloaded. Additionally, for hw control to be
+	 * valid, the configured netdev must be the same as
+	 * netdev associated to the LED.
 	 */
-	if (!trigger_data->net_dev)
+	if (!validate_net_dev(led_cdev, trigger_data->net_dev))
 		return false;
 
 	/* Check if the requested mode is supported */
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 10/13] leds: trigger: netdev: init mode if hw control already active
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (8 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 09/13] leds: trigger: netdev: validate configured netdev Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:53 ` [net-next PATCH v2 11/13] leds: trigger: netdev: expose netdev trigger modes in linux include Christian Marangi
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

On netdev trigger activation, hw control may be already active by
default. If this is the case and a device is actually provided by
hw_control_get_device(), init the already active mode and set the
bool to hw_control bool to true to reflect the already set mode in the
trigger_data.

Co-developed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index 5b59441fc415..b0cab2b84ce2 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -452,6 +452,8 @@ static void netdev_trig_work(struct work_struct *work)
 static int netdev_trig_activate(struct led_classdev *led_cdev)
 {
 	struct led_netdev_data *trigger_data;
+	unsigned long mode;
+	struct device *dev;
 	int rc;
 
 	trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
@@ -473,6 +475,21 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
 	atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
 	trigger_data->last_activity = 0;
 
+	/* Check if hw control is active by default on the LED.
+	 * Init already enabled mode in hw control.
+	 */
+	if (supports_hw_control(led_cdev) &&
+	    !led_cdev->hw_control_get(led_cdev, &mode)) {
+		dev = led_cdev->hw_control_get_device(led_cdev);
+		if (dev) {
+			const char *name = dev_name(dev);
+
+			set_device_name(trigger_data, name, strlen(name));
+			trigger_data->hw_control = true;
+			trigger_data->mode = mode;
+		}
+	}
+
 	led_set_trigger_data(led_cdev, trigger_data);
 
 	rc = register_netdevice_notifier(&trigger_data->notifier);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 11/13] leds: trigger: netdev: expose netdev trigger modes in linux include
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (9 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 10/13] leds: trigger: netdev: init mode if hw control already active Christian Marangi
@ 2023-05-25 14:53 ` Christian Marangi
  2023-05-25 14:54 ` [net-next PATCH v2 12/13] net: dsa: qca8k: implement hw_control ops Christian Marangi
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:53 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Expose netdev trigger modes to make them accessible by LED driver that
will support netdev trigger for hw control.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/leds/trigger/ledtrig-netdev.c |  9 ---------
 include/linux/leds.h                  | 10 ++++++++++
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index b0cab2b84ce2..8fbca94edfce 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -54,15 +54,6 @@ struct led_netdev_data {
 	bool hw_control;
 };
 
-enum led_trigger_netdev_modes {
-	TRIGGER_NETDEV_LINK = 0,
-	TRIGGER_NETDEV_TX,
-	TRIGGER_NETDEV_RX,
-
-	/* Keep last */
-	__TRIGGER_NETDEV_MAX,
-};
-
 static void set_baseline_state(struct led_netdev_data *trigger_data)
 {
 	int current_brightness;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 3268b4e789d6..8af62ff431f0 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -552,6 +552,16 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
 
 #endif /* CONFIG_LEDS_TRIGGERS */
 
+/* Trigger specific enum */
+enum led_trigger_netdev_modes {
+	TRIGGER_NETDEV_LINK = 0,
+	TRIGGER_NETDEV_TX,
+	TRIGGER_NETDEV_RX,
+
+	/* Keep last */
+	__TRIGGER_NETDEV_MAX,
+};
+
 /* Trigger specific functions */
 #ifdef CONFIG_LEDS_TRIGGER_DISK
 void ledtrig_disk_activity(bool write);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 12/13] net: dsa: qca8k: implement hw_control ops
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (10 preceding siblings ...)
  2023-05-25 14:53 ` [net-next PATCH v2 11/13] leds: trigger: netdev: expose netdev trigger modes in linux include Christian Marangi
@ 2023-05-25 14:54 ` Christian Marangi
  2023-05-25 14:54 ` [net-next PATCH v2 13/13] net: dsa: qca8k: add op to get ports netdev Christian Marangi
  2023-05-26  3:43 ` [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Jakub Kicinski
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:54 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

Implement hw_control ops to drive Switch LEDs based on hardware events.

Netdev trigger is the declared supported trigger for hw control
operation and supports the following mode:
- tx
- rx

When hw_control_set is called, LEDs are set to follow the requested
mode.
Each LEDs will blink at 4Hz by default.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca/qca8k-leds.c | 154 +++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c
index b883692b7d86..1e0c61726487 100644
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -31,6 +31,43 @@ qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en
 	return 0;
 }
 
+static int
+qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
+{
+	reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
+
+	/* 6 total control rule:
+	 * 3 control rules for phy0-3 that applies to all their leds
+	 * 3 control rules for phy4
+	 */
+	if (port_num == 4)
+		reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
+	else
+		reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
+
+	return 0;
+}
+
+static int
+qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger)
+{
+	/* Parsing specific to netdev trigger */
+	if (test_bit(TRIGGER_NETDEV_TX, &rules))
+		*offload_trigger |= QCA8K_LED_TX_BLINK_MASK;
+	if (test_bit(TRIGGER_NETDEV_RX, &rules))
+		*offload_trigger |= QCA8K_LED_RX_BLINK_MASK;
+
+	if (rules && !*offload_trigger)
+		return -EOPNOTSUPP;
+
+	/* Enable some default rule by default to the requested mode:
+	 * - Blink at 4Hz by default
+	 */
+	*offload_trigger |= QCA8K_LED_BLINK_4HZ;
+
+	return 0;
+}
+
 static int
 qca8k_led_brightness_set(struct qca8k_led *led,
 			 enum led_brightness brightness)
@@ -164,6 +201,119 @@ qca8k_cled_blink_set(struct led_classdev *ldev,
 	return 0;
 }
 
+static int
+qca8k_cled_trigger_offload(struct led_classdev *ldev, bool enable)
+{
+	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+
+	struct qca8k_led_pattern_en reg_info;
+	struct qca8k_priv *priv = led->priv;
+	u32 mask, val = QCA8K_LED_ALWAYS_OFF;
+
+	qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
+
+	if (enable)
+		val = QCA8K_LED_RULE_CONTROLLED;
+
+	if (led->port_num == 0 || led->port_num == 4) {
+		mask = QCA8K_LED_PATTERN_EN_MASK;
+		val <<= QCA8K_LED_PATTERN_EN_SHIFT;
+	} else {
+		mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
+	}
+
+	return regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
+				  val << reg_info.shift);
+}
+
+static bool
+qca8k_cled_hw_control_status(struct led_classdev *ldev)
+{
+	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+
+	struct qca8k_led_pattern_en reg_info;
+	struct qca8k_priv *priv = led->priv;
+	u32 val;
+
+	qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
+
+	regmap_read(priv->regmap, reg_info.reg, &val);
+
+	val >>= reg_info.shift;
+
+	if (led->port_num == 0 || led->port_num == 4) {
+		val &= QCA8K_LED_PATTERN_EN_MASK;
+		val >>= QCA8K_LED_PATTERN_EN_SHIFT;
+	} else {
+		val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
+	}
+
+	return val == QCA8K_LED_RULE_CONTROLLED;
+}
+
+static int
+qca8k_cled_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
+{
+	u32 offload_trigger = 0;
+
+	return qca8k_parse_netdev(rules, &offload_trigger);
+}
+
+static int
+qca8k_cled_hw_control_set(struct led_classdev *ldev, unsigned long rules)
+{
+	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+	struct qca8k_led_pattern_en reg_info;
+	struct qca8k_priv *priv = led->priv;
+	u32 offload_trigger = 0;
+	int ret;
+
+	ret = qca8k_parse_netdev(rules, &offload_trigger);
+	if (ret)
+		return ret;
+
+	ret = qca8k_cled_trigger_offload(ldev, true);
+	if (ret)
+		return ret;
+
+	qca8k_get_control_led_reg(led->port_num, led->led_num, &reg_info);
+
+	return regmap_update_bits(priv->regmap, reg_info.reg,
+				  QCA8K_LED_RULE_MASK << reg_info.shift,
+				  offload_trigger << reg_info.shift);
+}
+
+static int
+qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
+{
+	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+	struct qca8k_led_pattern_en reg_info;
+	struct qca8k_priv *priv = led->priv;
+	u32 val;
+	int ret;
+
+	/* With hw control not active return err */
+	if (!qca8k_cled_hw_control_status(ldev))
+		return -EINVAL;
+
+	qca8k_get_control_led_reg(led->port_num, led->led_num, &reg_info);
+
+	ret = regmap_read(priv->regmap, reg_info.reg, &val);
+	if (ret)
+		return ret;
+
+	val >>= reg_info.shift;
+	val &= QCA8K_LED_RULE_MASK;
+
+	/* Parsing specific to netdev trigger */
+	if (val & QCA8K_LED_TX_BLINK_MASK)
+		set_bit(TRIGGER_NETDEV_TX, rules);
+	if (val & QCA8K_LED_RX_BLINK_MASK)
+		set_bit(TRIGGER_NETDEV_RX, rules);
+
+	return 0;
+}
+
 static int
 qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
 {
@@ -224,6 +374,10 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
 		port_led->cdev.max_brightness = 1;
 		port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
 		port_led->cdev.blink_set = qca8k_cled_blink_set;
+		port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
+		port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
+		port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
+		port_led->cdev.hw_control_trigger = "netdev";
 		init_data.default_label = ":port";
 		init_data.fwnode = led;
 		init_data.devname_mandatory = true;
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [net-next PATCH v2 13/13] net: dsa: qca8k: add op to get ports netdev
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (11 preceding siblings ...)
  2023-05-25 14:54 ` [net-next PATCH v2 12/13] net: dsa: qca8k: implement hw_control ops Christian Marangi
@ 2023-05-25 14:54 ` Christian Marangi
  2023-05-26  3:43 ` [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Jakub Kicinski
  13 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-25 14:54 UTC (permalink / raw)
  To: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Christian Marangi, linux-leds,
	linux-doc, linux-kernel, netdev

From: Andrew Lunn <andrew@lunn.ch>

In order that the LED trigger can blink the switch MAC ports LED, it
needs to know the netdev associated to the port. Add the callback to
return the struct device of the netdev.

Add an helper function qca8k_phy_to_port() to convert the phy back to
dsa_port index, as we reference LED port based on the internal PHY
index and needs to be converted back.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca/qca8k-leds.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c
index 1e0c61726487..6f02029b454b 100644
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -5,6 +5,18 @@
 #include "qca8k.h"
 #include "qca8k_leds.h"
 
+static u32 qca8k_phy_to_port(int phy)
+{
+	/* Internal PHY 0 has port at index 1.
+	 * Internal PHY 1 has port at index 2.
+	 * Internal PHY 2 has port at index 3.
+	 * Internal PHY 3 has port at index 4.
+	 * Internal PHY 4 has port at index 5.
+	 */
+
+	return phy + 1;
+}
+
 static int
 qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
 {
@@ -314,6 +326,20 @@ qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
 	return 0;
 }
 
+static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev)
+{
+	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
+	struct qca8k_priv *priv = led->priv;
+	struct dsa_port *dp;
+
+	dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num));
+	if (!dp)
+		return NULL;
+	if (dp->slave)
+		return &dp->slave->dev;
+	return NULL;
+}
+
 static int
 qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
 {
@@ -377,6 +403,7 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
 		port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
 		port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
 		port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
+		port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;
 		port_led->cdev.hw_control_trigger = "netdev";
 		init_data.default_label = ":port";
 		init_data.fwnode = led;
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs
  2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
                   ` (12 preceding siblings ...)
  2023-05-25 14:54 ` [net-next PATCH v2 13/13] net: dsa: qca8k: add op to get ports netdev Christian Marangi
@ 2023-05-26  3:43 ` Jakub Kicinski
  2023-05-27 11:31   ` Christian Marangi
  13 siblings, 1 reply; 16+ messages in thread
From: Jakub Kicinski @ 2023-05-26  3:43 UTC (permalink / raw)
  To: Christian Marangi
  Cc: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Paolo Abeni, linux-leds, linux-doc, linux-kernel, netdev

On Thu, 25 May 2023 16:53:48 +0200 Christian Marangi wrote:
> This is based on top of branch ib-leds-netdev-v6.5 present here [1].

I merged that PR now, but you'll need to repost.
Build bots don't read English (yet?) so posting patches which can't 
be immediately applied is basically an RFC (and should be marked as
such).

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs
  2023-05-26  3:43 ` [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Jakub Kicinski
@ 2023-05-27 11:31   ` Christian Marangi
  0 siblings, 0 replies; 16+ messages in thread
From: Christian Marangi @ 2023-05-27 11:31 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Pavel Machek, Lee Jones, Jonathan Corbet, Andrew Lunn,
	Florian Fainelli, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Paolo Abeni, linux-leds, linux-doc, linux-kernel, netdev

On Thu, May 25, 2023 at 08:43:38PM -0700, Jakub Kicinski wrote:
> On Thu, 25 May 2023 16:53:48 +0200 Christian Marangi wrote:
> > This is based on top of branch ib-leds-netdev-v6.5 present here [1].
> 
> I merged that PR now, but you'll need to repost.
> Build bots don't read English (yet?) so posting patches which can't 
> be immediately applied is basically an RFC (and should be marked as
> such).

Hi, thanks for helping in this! The series already applied directly on
net-next but I sent v3 anyway rebased on latest commit from net-next
just to be sure.

-- 
	Ansuel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-05-27 11:32 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-25 14:53 [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 01/13] leds: add APIs for LEDs hw control Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 02/13] leds: add API to get attached device for LED " Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 03/13] Documentation: leds: leds-class: Document new Hardware driven LEDs APIs Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 04/13] leds: trigger: netdev: refactor code setting device name Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 05/13] leds: trigger: netdev: introduce check for possible hw control Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 06/13] leds: trigger: netdev: add basic check for hw control support Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 07/13] leds: trigger: netdev: reject interval store for hw_control Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 08/13] leds: trigger: netdev: add support for LED hw control Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 09/13] leds: trigger: netdev: validate configured netdev Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 10/13] leds: trigger: netdev: init mode if hw control already active Christian Marangi
2023-05-25 14:53 ` [net-next PATCH v2 11/13] leds: trigger: netdev: expose netdev trigger modes in linux include Christian Marangi
2023-05-25 14:54 ` [net-next PATCH v2 12/13] net: dsa: qca8k: implement hw_control ops Christian Marangi
2023-05-25 14:54 ` [net-next PATCH v2 13/13] net: dsa: qca8k: add op to get ports netdev Christian Marangi
2023-05-26  3:43 ` [net-next PATCH v2 00/13] leds: introduce new LED hw control APIs Jakub Kicinski
2023-05-27 11:31   ` Christian Marangi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).