818-v6.5-08-leds-trigger-netdev-add-support-for-LED-hw-control.patch 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. From 7c145a34ba6e380616af93262fcab9fc7261d851 Mon Sep 17 00:00:00 2001
  2. From: Christian Marangi <[email protected]>
  3. Date: Mon, 29 May 2023 18:32:38 +0200
  4. Subject: [PATCH 08/13] leds: trigger: netdev: add support for LED hw control
  5. Add support for LED hw control for the netdev trigger.
  6. The trigger on calling set_baseline_state to configure a new mode, will
  7. do various check to verify if hw control can be used for the requested
  8. mode in can_hw_control() function.
  9. It will first check if the LED driver supports hw control for the netdev
  10. trigger, then will use hw_control_is_supported() and finally will call
  11. hw_control_set() to apply the requested mode.
  12. To use such mode, interval MUST be set to the default value and net_dev
  13. MUST be set. If one of these 2 value are not valid, hw control will
  14. never be used and normal software fallback is used.
  15. The default interval value is moved to a define to make sure they are
  16. always synced.
  17. Signed-off-by: Christian Marangi <[email protected]>
  18. Reviewed-by: Andrew Lunn <[email protected]>
  19. Signed-off-by: David S. Miller <[email protected]>
  20. ---
  21. drivers/leds/trigger/ledtrig-netdev.c | 43 +++++++++++++++++++++++++--
  22. 1 file changed, 41 insertions(+), 2 deletions(-)
  23. --- a/drivers/leds/trigger/ledtrig-netdev.c
  24. +++ b/drivers/leds/trigger/ledtrig-netdev.c
  25. @@ -24,6 +24,8 @@
  26. #include <linux/timer.h>
  27. #include "../leds.h"
  28. +#define NETDEV_LED_DEFAULT_INTERVAL 50
  29. +
  30. /*
  31. * Configurable sysfs attributes:
  32. *
  33. @@ -68,6 +70,13 @@ static void set_baseline_state(struct le
  34. int current_brightness;
  35. struct led_classdev *led_cdev = trigger_data->led_cdev;
  36. + /* Already validated, hw control is possible with the requested mode */
  37. + if (trigger_data->hw_control) {
  38. + led_cdev->hw_control_set(led_cdev, trigger_data->mode);
  39. +
  40. + return;
  41. + }
  42. +
  43. current_brightness = led_cdev->brightness;
  44. if (current_brightness)
  45. led_cdev->blink_brightness = current_brightness;
  46. @@ -103,12 +112,42 @@ static bool supports_hw_control(struct l
  47. static bool can_hw_control(struct led_netdev_data *trigger_data)
  48. {
  49. + unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL);
  50. + unsigned int interval = atomic_read(&trigger_data->interval);
  51. struct led_classdev *led_cdev = trigger_data->led_cdev;
  52. + int ret;
  53. if (!supports_hw_control(led_cdev))
  54. return false;
  55. - return false;
  56. + /*
  57. + * Interval must be set to the default
  58. + * value. Any different value is rejected if in hw
  59. + * control.
  60. + */
  61. + if (interval != default_interval)
  62. + return false;
  63. +
  64. + /*
  65. + * net_dev must be set with hw control, otherwise no
  66. + * blinking can be happening and there is nothing to
  67. + * offloaded.
  68. + */
  69. + if (!trigger_data->net_dev)
  70. + return false;
  71. +
  72. + /* Check if the requested mode is supported */
  73. + ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode);
  74. + /* Fall back to software blinking if not supported */
  75. + if (ret == -EOPNOTSUPP)
  76. + return false;
  77. + if (ret) {
  78. + dev_warn(led_cdev->dev,
  79. + "Current mode check failed with error %d\n", ret);
  80. + return false;
  81. + }
  82. +
  83. + return true;
  84. }
  85. static ssize_t device_name_show(struct device *dev,
  86. @@ -413,7 +452,7 @@ static int netdev_trig_activate(struct l
  87. trigger_data->device_name[0] = 0;
  88. trigger_data->mode = 0;
  89. - atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
  90. + atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
  91. trigger_data->last_activity = 0;
  92. led_set_trigger_data(led_cdev, trigger_data);