root/drivers/leds/trigger/ledtrig-netdev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_baseline_state
  2. device_name_show
  3. device_name_store
  4. netdev_led_attr_show
  5. netdev_led_attr_store
  6. link_show
  7. link_store
  8. tx_show
  9. tx_store
  10. rx_show
  11. rx_store
  12. interval_show
  13. interval_store
  14. netdev_trig_notify
  15. netdev_trig_work
  16. netdev_trig_activate
  17. netdev_trig_deactivate
  18. netdev_trig_init
  19. netdev_trig_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright 2017 Ben Whitten <ben.whitten@gmail.com>
   3 // Copyright 2007 Oliver Jowett <oliver@opencloud.com>
   4 //
   5 // LED Kernel Netdev Trigger
   6 //
   7 // Toggles the LED to reflect the link and traffic state of a named net device
   8 //
   9 // Derived from ledtrig-timer.c which is:
  10 //  Copyright 2005-2006 Openedhand Ltd.
  11 //  Author: Richard Purdie <rpurdie@openedhand.com>
  12 
  13 #include <linux/atomic.h>
  14 #include <linux/ctype.h>
  15 #include <linux/device.h>
  16 #include <linux/init.h>
  17 #include <linux/jiffies.h>
  18 #include <linux/kernel.h>
  19 #include <linux/leds.h>
  20 #include <linux/list.h>
  21 #include <linux/module.h>
  22 #include <linux/netdevice.h>
  23 #include <linux/spinlock.h>
  24 #include <linux/timer.h>
  25 #include "../leds.h"
  26 
  27 /*
  28  * Configurable sysfs attributes:
  29  *
  30  * device_name - network device name to monitor
  31  * interval - duration of LED blink, in milliseconds
  32  * link -  LED's normal state reflects whether the link is up
  33  *         (has carrier) or not
  34  * tx -  LED blinks on transmitted data
  35  * rx -  LED blinks on receive data
  36  *
  37  */
  38 
  39 struct led_netdev_data {
  40         spinlock_t lock;
  41 
  42         struct delayed_work work;
  43         struct notifier_block notifier;
  44 
  45         struct led_classdev *led_cdev;
  46         struct net_device *net_dev;
  47 
  48         char device_name[IFNAMSIZ];
  49         atomic_t interval;
  50         unsigned int last_activity;
  51 
  52         unsigned long mode;
  53 #define NETDEV_LED_LINK 0
  54 #define NETDEV_LED_TX   1
  55 #define NETDEV_LED_RX   2
  56 #define NETDEV_LED_MODE_LINKUP  3
  57 };
  58 
  59 enum netdev_led_attr {
  60         NETDEV_ATTR_LINK,
  61         NETDEV_ATTR_TX,
  62         NETDEV_ATTR_RX
  63 };
  64 
  65 static void set_baseline_state(struct led_netdev_data *trigger_data)
  66 {
  67         int current_brightness;
  68         struct led_classdev *led_cdev = trigger_data->led_cdev;
  69 
  70         current_brightness = led_cdev->brightness;
  71         if (current_brightness)
  72                 led_cdev->blink_brightness = current_brightness;
  73         if (!led_cdev->blink_brightness)
  74                 led_cdev->blink_brightness = led_cdev->max_brightness;
  75 
  76         if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
  77                 led_set_brightness(led_cdev, LED_OFF);
  78         else {
  79                 if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
  80                         led_set_brightness(led_cdev,
  81                                            led_cdev->blink_brightness);
  82                 else
  83                         led_set_brightness(led_cdev, LED_OFF);
  84 
  85                 /* If we are looking for RX/TX start periodically
  86                  * checking stats
  87                  */
  88                 if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
  89                     test_bit(NETDEV_LED_RX, &trigger_data->mode))
  90                         schedule_delayed_work(&trigger_data->work, 0);
  91         }
  92 }
  93 
  94 static ssize_t device_name_show(struct device *dev,
  95                                 struct device_attribute *attr, char *buf)
  96 {
  97         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
  98         ssize_t len;
  99 
 100         spin_lock_bh(&trigger_data->lock);
 101         len = sprintf(buf, "%s\n", trigger_data->device_name);
 102         spin_unlock_bh(&trigger_data->lock);
 103 
 104         return len;
 105 }
 106 
 107 static ssize_t device_name_store(struct device *dev,
 108                                  struct device_attribute *attr, const char *buf,
 109                                  size_t size)
 110 {
 111         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 112 
 113         if (size >= IFNAMSIZ)
 114                 return -EINVAL;
 115 
 116         cancel_delayed_work_sync(&trigger_data->work);
 117 
 118         spin_lock_bh(&trigger_data->lock);
 119 
 120         if (trigger_data->net_dev) {
 121                 dev_put(trigger_data->net_dev);
 122                 trigger_data->net_dev = NULL;
 123         }
 124 
 125         memcpy(trigger_data->device_name, buf, size);
 126         trigger_data->device_name[size] = 0;
 127         if (size > 0 && trigger_data->device_name[size - 1] == '\n')
 128                 trigger_data->device_name[size - 1] = 0;
 129 
 130         if (trigger_data->device_name[0] != 0)
 131                 trigger_data->net_dev =
 132                     dev_get_by_name(&init_net, trigger_data->device_name);
 133 
 134         clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
 135         if (trigger_data->net_dev != NULL)
 136                 if (netif_carrier_ok(trigger_data->net_dev))
 137                         set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
 138 
 139         trigger_data->last_activity = 0;
 140 
 141         set_baseline_state(trigger_data);
 142         spin_unlock_bh(&trigger_data->lock);
 143 
 144         return size;
 145 }
 146 
 147 static DEVICE_ATTR_RW(device_name);
 148 
 149 static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
 150         enum netdev_led_attr attr)
 151 {
 152         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 153         int bit;
 154 
 155         switch (attr) {
 156         case NETDEV_ATTR_LINK:
 157                 bit = NETDEV_LED_LINK;
 158                 break;
 159         case NETDEV_ATTR_TX:
 160                 bit = NETDEV_LED_TX;
 161                 break;
 162         case NETDEV_ATTR_RX:
 163                 bit = NETDEV_LED_RX;
 164                 break;
 165         default:
 166                 return -EINVAL;
 167         }
 168 
 169         return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
 170 }
 171 
 172 static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
 173         size_t size, enum netdev_led_attr attr)
 174 {
 175         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 176         unsigned long state;
 177         int ret;
 178         int bit;
 179 
 180         ret = kstrtoul(buf, 0, &state);
 181         if (ret)
 182                 return ret;
 183 
 184         switch (attr) {
 185         case NETDEV_ATTR_LINK:
 186                 bit = NETDEV_LED_LINK;
 187                 break;
 188         case NETDEV_ATTR_TX:
 189                 bit = NETDEV_LED_TX;
 190                 break;
 191         case NETDEV_ATTR_RX:
 192                 bit = NETDEV_LED_RX;
 193                 break;
 194         default:
 195                 return -EINVAL;
 196         }
 197 
 198         cancel_delayed_work_sync(&trigger_data->work);
 199 
 200         if (state)
 201                 set_bit(bit, &trigger_data->mode);
 202         else
 203                 clear_bit(bit, &trigger_data->mode);
 204 
 205         set_baseline_state(trigger_data);
 206 
 207         return size;
 208 }
 209 
 210 static ssize_t link_show(struct device *dev,
 211         struct device_attribute *attr, char *buf)
 212 {
 213         return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
 214 }
 215 
 216 static ssize_t link_store(struct device *dev,
 217         struct device_attribute *attr, const char *buf, size_t size)
 218 {
 219         return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
 220 }
 221 
 222 static DEVICE_ATTR_RW(link);
 223 
 224 static ssize_t tx_show(struct device *dev,
 225         struct device_attribute *attr, char *buf)
 226 {
 227         return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
 228 }
 229 
 230 static ssize_t tx_store(struct device *dev,
 231         struct device_attribute *attr, const char *buf, size_t size)
 232 {
 233         return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
 234 }
 235 
 236 static DEVICE_ATTR_RW(tx);
 237 
 238 static ssize_t rx_show(struct device *dev,
 239         struct device_attribute *attr, char *buf)
 240 {
 241         return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
 242 }
 243 
 244 static ssize_t rx_store(struct device *dev,
 245         struct device_attribute *attr, const char *buf, size_t size)
 246 {
 247         return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
 248 }
 249 
 250 static DEVICE_ATTR_RW(rx);
 251 
 252 static ssize_t interval_show(struct device *dev,
 253                              struct device_attribute *attr, char *buf)
 254 {
 255         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 256 
 257         return sprintf(buf, "%u\n",
 258                        jiffies_to_msecs(atomic_read(&trigger_data->interval)));
 259 }
 260 
 261 static ssize_t interval_store(struct device *dev,
 262                               struct device_attribute *attr, const char *buf,
 263                               size_t size)
 264 {
 265         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
 266         unsigned long value;
 267         int ret;
 268 
 269         ret = kstrtoul(buf, 0, &value);
 270         if (ret)
 271                 return ret;
 272 
 273         /* impose some basic bounds on the timer interval */
 274         if (value >= 5 && value <= 10000) {
 275                 cancel_delayed_work_sync(&trigger_data->work);
 276 
 277                 atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
 278                 set_baseline_state(trigger_data);       /* resets timer */
 279         }
 280 
 281         return size;
 282 }
 283 
 284 static DEVICE_ATTR_RW(interval);
 285 
 286 static struct attribute *netdev_trig_attrs[] = {
 287         &dev_attr_device_name.attr,
 288         &dev_attr_link.attr,
 289         &dev_attr_rx.attr,
 290         &dev_attr_tx.attr,
 291         &dev_attr_interval.attr,
 292         NULL
 293 };
 294 ATTRIBUTE_GROUPS(netdev_trig);
 295 
 296 static int netdev_trig_notify(struct notifier_block *nb,
 297                               unsigned long evt, void *dv)
 298 {
 299         struct net_device *dev =
 300                 netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
 301         struct led_netdev_data *trigger_data =
 302                 container_of(nb, struct led_netdev_data, notifier);
 303 
 304         if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
 305             && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
 306             && evt != NETDEV_CHANGENAME)
 307                 return NOTIFY_DONE;
 308 
 309         if (!(dev == trigger_data->net_dev ||
 310               (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
 311               (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
 312                 return NOTIFY_DONE;
 313 
 314         cancel_delayed_work_sync(&trigger_data->work);
 315 
 316         spin_lock_bh(&trigger_data->lock);
 317 
 318         clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
 319         switch (evt) {
 320         case NETDEV_CHANGENAME:
 321         case NETDEV_REGISTER:
 322                 if (trigger_data->net_dev)
 323                         dev_put(trigger_data->net_dev);
 324                 dev_hold(dev);
 325                 trigger_data->net_dev = dev;
 326                 break;
 327         case NETDEV_UNREGISTER:
 328                 dev_put(trigger_data->net_dev);
 329                 trigger_data->net_dev = NULL;
 330                 break;
 331         case NETDEV_UP:
 332         case NETDEV_CHANGE:
 333                 if (netif_carrier_ok(dev))
 334                         set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
 335                 break;
 336         }
 337 
 338         set_baseline_state(trigger_data);
 339 
 340         spin_unlock_bh(&trigger_data->lock);
 341 
 342         return NOTIFY_DONE;
 343 }
 344 
 345 /* here's the real work! */
 346 static void netdev_trig_work(struct work_struct *work)
 347 {
 348         struct led_netdev_data *trigger_data =
 349                 container_of(work, struct led_netdev_data, work.work);
 350         struct rtnl_link_stats64 *dev_stats;
 351         unsigned int new_activity;
 352         struct rtnl_link_stats64 temp;
 353         unsigned long interval;
 354         int invert;
 355 
 356         /* If we dont have a device, insure we are off */
 357         if (!trigger_data->net_dev) {
 358                 led_set_brightness(trigger_data->led_cdev, LED_OFF);
 359                 return;
 360         }
 361 
 362         /* If we are not looking for RX/TX then return  */
 363         if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
 364             !test_bit(NETDEV_LED_RX, &trigger_data->mode))
 365                 return;
 366 
 367         dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
 368         new_activity =
 369             (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
 370                 dev_stats->tx_packets : 0) +
 371             (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
 372                 dev_stats->rx_packets : 0);
 373 
 374         if (trigger_data->last_activity != new_activity) {
 375                 led_stop_software_blink(trigger_data->led_cdev);
 376 
 377                 invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
 378                 interval = jiffies_to_msecs(
 379                                 atomic_read(&trigger_data->interval));
 380                 /* base state is ON (link present) */
 381                 led_blink_set_oneshot(trigger_data->led_cdev,
 382                                       &interval,
 383                                       &interval,
 384                                       invert);
 385                 trigger_data->last_activity = new_activity;
 386         }
 387 
 388         schedule_delayed_work(&trigger_data->work,
 389                         (atomic_read(&trigger_data->interval)*2));
 390 }
 391 
 392 static int netdev_trig_activate(struct led_classdev *led_cdev)
 393 {
 394         struct led_netdev_data *trigger_data;
 395         int rc;
 396 
 397         trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
 398         if (!trigger_data)
 399                 return -ENOMEM;
 400 
 401         spin_lock_init(&trigger_data->lock);
 402 
 403         trigger_data->notifier.notifier_call = netdev_trig_notify;
 404         trigger_data->notifier.priority = 10;
 405 
 406         INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
 407 
 408         trigger_data->led_cdev = led_cdev;
 409         trigger_data->net_dev = NULL;
 410         trigger_data->device_name[0] = 0;
 411 
 412         trigger_data->mode = 0;
 413         atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
 414         trigger_data->last_activity = 0;
 415 
 416         led_set_trigger_data(led_cdev, trigger_data);
 417 
 418         rc = register_netdevice_notifier(&trigger_data->notifier);
 419         if (rc)
 420                 kfree(trigger_data);
 421 
 422         return rc;
 423 }
 424 
 425 static void netdev_trig_deactivate(struct led_classdev *led_cdev)
 426 {
 427         struct led_netdev_data *trigger_data = led_get_trigger_data(led_cdev);
 428 
 429         unregister_netdevice_notifier(&trigger_data->notifier);
 430 
 431         cancel_delayed_work_sync(&trigger_data->work);
 432 
 433         if (trigger_data->net_dev)
 434                 dev_put(trigger_data->net_dev);
 435 
 436         kfree(trigger_data);
 437 }
 438 
 439 static struct led_trigger netdev_led_trigger = {
 440         .name = "netdev",
 441         .activate = netdev_trig_activate,
 442         .deactivate = netdev_trig_deactivate,
 443         .groups = netdev_trig_groups,
 444 };
 445 
 446 static int __init netdev_trig_init(void)
 447 {
 448         return led_trigger_register(&netdev_led_trigger);
 449 }
 450 
 451 static void __exit netdev_trig_exit(void)
 452 {
 453         led_trigger_unregister(&netdev_led_trigger);
 454 }
 455 
 456 module_init(netdev_trig_init);
 457 module_exit(netdev_trig_exit);
 458 
 459 MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
 460 MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
 461 MODULE_DESCRIPTION("Netdev LED trigger");
 462 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */