On Tue, 9 Nov 2021 03:26:06 +0100 Ansuel Smith <ansuelsmth@xxxxxxxxx> wrote: > Add Hardware Only Trigger for PHY Activity. This special trigger is used to > configure and expose the different HW trigger that are provided by the > PHY. Each blink mode can be configured by sysfs and on trigger > activation the hardware mode is enabled. > > This currently implement these hw triggers: > - blink_tx: Blink LED on tx packet receive > - blink_rx: Blink LED on rx packet receive > - keep_link_10m: Keep LED on with 10m link speed > - keep_link_100m: Keep LED on with 100m link speed > - kepp_link_1000m: Keep LED on with 1000m link speed > - keep_half_duplex: Keep LED on with half duplex link > - keep_full_duplex: Keep LED on with full duplex link > - option_linkup_over: Ignore blink tx/rx with link keep not active > - option_power_on_reset: Keep LED on with switch reset > - option_blink_2hz: Set blink speed at 2hz for every blink event > - option_blink_4hz: Set blink speed at 4hz for every blink event > - option_blink_8hz: Set blink speed at 8hz for every blink event > - option_blink_auto: Set blink speed at 2hz for 10m link speed, > 4hz for 100m and 8hz for 1000m > > The trigger will check if the LED driver support the various blink modes > and will expose the blink modes in sysfs. > It will finally enable hw mode for the LED without configuring any rule. > This mean that the LED will blink/follow whatever offload trigger is > active by default and the user needs to manually configure the desired > offload triggers using sysfs. > A flag is passed to configure_offload with the related rule from this > trigger to active or disable. > It's in the led driver interest the detection and knowing how to > elaborate the passed flags and should report -EOPNOTSUPP otherwise. > > The different hw triggers are exposed in the led sysfs dir under the > offload-phy-activity subdir. > > Signed-off-by: Ansuel Smith <ansuelsmth@xxxxxxxxx> > --- > drivers/leds/trigger/Kconfig | 28 +++ > drivers/leds/trigger/Makefile | 1 + > .../trigger/ledtrig-hardware-phy-activity.c | 171 ++++++++++++++++++ > include/linux/leds.h | 22 +++ > 4 files changed, 222 insertions(+) > create mode 100644 drivers/leds/trigger/ledtrig-hardware-phy-activity.c > > diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig > index dc6816d36d06..b947b238be3f 100644 > --- a/drivers/leds/trigger/Kconfig > +++ b/drivers/leds/trigger/Kconfig > @@ -154,4 +154,32 @@ config LEDS_TRIGGER_TTY > > When build as a module this driver will be called ledtrig-tty. > > +config LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY > + tristate "LED Trigger for PHY Activity for Hardware Controlled LED" > + depends on LEDS_HARDWARE_CONTROL > + help > + This allows LEDs to be configured to run by hardware and offloaded > + based on some rules. The LED will blink or be on based on the PHY > + Activity for example on packet receive or based on the link speed. > + > + The current supported offload triggers are: > + - blink_tx: Blink LED on tx packet receive > + - blink_rx: Blink LED on rx packet receive > + - keep_link_10m: Keep LED on with 10m link speed > + - keep_link_100m: Keep LED on with 100m link speed > + - keep_link_1000m: Keep LED on with 1000m link speed > + - keep_half_duplex: Keep LED on with half duplex link > + - keep_full_duplex: Keep LED on with full duplex link > + - option_linkup_over: Blink rules are ignored with absent link > + - option_power_on_reset: Power ON Led on Switch/PHY reset > + - option_blink_2hz: Set blink speed at 2hz for every blink event > + - option_blink_4hz: Set blink speed at 4hz for every blink event > + - option_blink_8hz: Set blink speed at 8hz for every blink event > + > + These blink modes are present in the LED sysfs dir under > + hardware-phy-activity if supported by the LED driver. > + > + This trigger can be used only by LEDs that supports Hardware mode > + > + > endif # LEDS_TRIGGERS > diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile > index 25c4db97cdd4..f5d0d0057d2b 100644 > --- a/drivers/leds/trigger/Makefile > +++ b/drivers/leds/trigger/Makefile > @@ -16,3 +16,4 @@ obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o > obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o > obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o > obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o > +obj-$(CONFIG_LEDS_TRIGGER_HARDWARE_PHY_ACTIVITY) += ledtrig-hardware-phy-activity.o > diff --git a/drivers/leds/trigger/ledtrig-hardware-phy-activity.c b/drivers/leds/trigger/ledtrig-hardware-phy-activity.c > new file mode 100644 > index 000000000000..7fd0557fe878 > --- /dev/null > +++ b/drivers/leds/trigger/ledtrig-hardware-phy-activity.c > @@ -0,0 +1,171 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/leds.h> > +#include <linux/slab.h> > + > +#define PHY_ACTIVITY_MAX_TRIGGERS 12 > + > +#define DEFINE_OFFLOAD_TRIGGER(trigger_name, trigger) \ > + static ssize_t trigger_name##_show(struct device *dev, \ > + struct device_attribute *attr, char *buf) \ > + { \ > + struct led_classdev *led_cdev = led_trigger_get_led(dev); \ > + int val; \ > + val = led_cdev->hw_control_configure(led_cdev, trigger, BLINK_MODE_READ); \ > + return sprintf(buf, "%d\n", val ? 1 : 0); \ > + } \ > + static ssize_t trigger_name##_store(struct device *dev, \ > + struct device_attribute *attr, \ > + const char *buf, size_t size) \ > + { \ > + struct led_classdev *led_cdev = led_trigger_get_led(dev); \ > + unsigned long state; \ > + int cmd, ret; \ > + ret = kstrtoul(buf, 0, &state); \ > + if (ret) \ > + return ret; \ > + cmd = !!state ? BLINK_MODE_ENABLE : BLINK_MODE_DISABLE; \ > + /* Update the configuration with every change */ \ > + led_cdev->hw_control_configure(led_cdev, trigger, cmd); \ > + return size; \ > + } \ > + DEVICE_ATTR_RW(trigger_name) > + > +/* Expose sysfs for every blink to be configurable from userspace */ > +DEFINE_OFFLOAD_TRIGGER(blink_tx, BLINK_TX); > +DEFINE_OFFLOAD_TRIGGER(blink_rx, BLINK_RX); > +DEFINE_OFFLOAD_TRIGGER(keep_link_10m, KEEP_LINK_10M); > +DEFINE_OFFLOAD_TRIGGER(keep_link_100m, KEEP_LINK_100M); > +DEFINE_OFFLOAD_TRIGGER(keep_link_1000m, KEEP_LINK_1000M); > +DEFINE_OFFLOAD_TRIGGER(keep_half_duplex, KEEP_HALF_DUPLEX); > +DEFINE_OFFLOAD_TRIGGER(keep_full_duplex, KEEP_FULL_DUPLEX); > +DEFINE_OFFLOAD_TRIGGER(option_linkup_over, OPTION_LINKUP_OVER); > +DEFINE_OFFLOAD_TRIGGER(option_power_on_reset, OPTION_POWER_ON_RESET); > +DEFINE_OFFLOAD_TRIGGER(option_blink_2hz, OPTION_BLINK_2HZ); > +DEFINE_OFFLOAD_TRIGGER(option_blink_4hz, OPTION_BLINK_4HZ); > +DEFINE_OFFLOAD_TRIGGER(option_blink_8hz, OPTION_BLINK_8HZ); This is very strange. Is option_blink_2hz a trigger on itself? Or just an option for another trigger? It seems that it is an option, so that I can set something like blink_tx,option_blink_2hz and the LED will blink on tx activity with frequency 2 Hz... If that is so, I think you are misnaming your macros or something, since you are defining option_blink_2hz as a trigger with DEFINE_OFFLOAD_TRIGGER Marek