]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
leds: trigger: netdev: Add support for tx_err and rx_err notification with LEDs
authorLukasz Majewski <lukma@denx.de>
Wed, 10 Jul 2024 10:06:51 +0000 (12:06 +0200)
committerLee Jones <lee@kernel.org>
Thu, 1 Aug 2024 12:40:01 +0000 (13:40 +0100)
This patch provides support for enabling blinking of LEDs when RX or TX
errors are detected.

Approach taken in this patch is similar to one for TX or RX data
transmission indication (i.e. TRIGGER_NETDEV_TX/RX attribute).

One can inspect transmission errors with:
ip -s link show eth0

Example LED configuration:
cd /sys/devices/platform/amba_pl@0/a001a000.leds/leds/
echo netdev > mode:blue/trigger && \
echo eth0 > mode:blue/device_name && \
echo 1 > mode:blue/tx_err

Signed-off-by: Lukasz Majewski <lukma@denx.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20240710100651.4059887-1-lukma@denx.de
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/leds/trigger/ledtrig-netdev.c
include/linux/leds.h

index 22bba8e97642a49822e17b1b0ae6942aad3394e1..4b0863db901a9e3acf7a9a91f44597a05e36481e 100644 (file)
@@ -39,6 +39,8 @@
  *         (has carrier) or not
  * tx -  LED blinks on transmitted data
  * rx -  LED blinks on receive data
+ * tx_err -  LED blinks on transmit error
+ * rx_err -  LED blinks on receive error
  *
  * Note: If the user selects a mode that is not supported by hw, default
  * behavior is to fall back to software control of the LED. However not every
@@ -144,7 +146,9 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
                 * checking stats
                 */
                if (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ||
-                   test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
+                   test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ||
+                   test_bit(TRIGGER_NETDEV_TX_ERR, &trigger_data->mode) ||
+                   test_bit(TRIGGER_NETDEV_RX_ERR, &trigger_data->mode))
                        schedule_delayed_work(&trigger_data->work, 0);
        }
 }
@@ -337,6 +341,8 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
        case TRIGGER_NETDEV_FULL_DUPLEX:
        case TRIGGER_NETDEV_TX:
        case TRIGGER_NETDEV_RX:
+       case TRIGGER_NETDEV_TX_ERR:
+       case TRIGGER_NETDEV_RX_ERR:
                bit = attr;
                break;
        default:
@@ -371,6 +377,8 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
        case TRIGGER_NETDEV_FULL_DUPLEX:
        case TRIGGER_NETDEV_TX:
        case TRIGGER_NETDEV_RX:
+       case TRIGGER_NETDEV_TX_ERR:
+       case TRIGGER_NETDEV_RX_ERR:
                bit = attr;
                break;
        default:
@@ -429,6 +437,8 @@ DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
 DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
 DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
 DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
+DEFINE_NETDEV_TRIGGER(tx_err, TRIGGER_NETDEV_TX_ERR);
+DEFINE_NETDEV_TRIGGER(rx_err, TRIGGER_NETDEV_RX_ERR);
 
 static ssize_t interval_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
@@ -538,6 +548,8 @@ static struct attribute *netdev_trig_attrs[] = {
        &dev_attr_half_duplex.attr,
        &dev_attr_rx.attr,
        &dev_attr_tx.attr,
+       &dev_attr_rx_err.attr,
+       &dev_attr_tx_err.attr,
        &dev_attr_interval.attr,
        &dev_attr_offloaded.attr,
        NULL
@@ -628,7 +640,9 @@ static void netdev_trig_work(struct work_struct *work)
 
        /* If we are not looking for RX/TX then return  */
        if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) &&
-           !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
+           !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) &&
+           !test_bit(TRIGGER_NETDEV_TX_ERR, &trigger_data->mode) &&
+           !test_bit(TRIGGER_NETDEV_RX_ERR, &trigger_data->mode))
                return;
 
        dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
@@ -636,7 +650,11 @@ static void netdev_trig_work(struct work_struct *work)
            (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ?
                dev_stats->tx_packets : 0) +
            (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ?
-               dev_stats->rx_packets : 0);
+               dev_stats->rx_packets : 0) +
+           (test_bit(TRIGGER_NETDEV_TX_ERR, &trigger_data->mode) ?
+               dev_stats->tx_errors : 0) +
+           (test_bit(TRIGGER_NETDEV_RX_ERR, &trigger_data->mode) ?
+               dev_stats->rx_errors : 0);
 
        if (trigger_data->last_activity != new_activity) {
                led_stop_software_blink(trigger_data->led_cdev);
index 6885603f211bb58cc56106ff3f16bcec97db0ec1..e5968c3ed4ae085ab38ab66e922def275ae182eb 100644 (file)
@@ -611,6 +611,8 @@ enum led_trigger_netdev_modes {
        TRIGGER_NETDEV_FULL_DUPLEX,
        TRIGGER_NETDEV_TX,
        TRIGGER_NETDEV_RX,
+       TRIGGER_NETDEV_TX_ERR,
+       TRIGGER_NETDEV_RX_ERR,
 
        /* Keep last */
        __TRIGGER_NETDEV_MAX,