OSDN Git Service

leds: leds-mt6323: Adjust return/parameter types in wled get/set callbacks
[tomoyo/tomoyo-test1.git] / drivers / leds / trigger / ledtrig-netdev.c
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/mutex.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         struct mutex 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         bool carrier_link_up;
54 };
55
56 enum led_trigger_netdev_modes {
57         TRIGGER_NETDEV_LINK = 0,
58         TRIGGER_NETDEV_TX,
59         TRIGGER_NETDEV_RX,
60
61         /* Keep last */
62         __TRIGGER_NETDEV_MAX,
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 (!trigger_data->carrier_link_up) {
77                 led_set_brightness(led_cdev, LED_OFF);
78         } else {
79                 if (test_bit(TRIGGER_NETDEV_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(TRIGGER_NETDEV_TX, &trigger_data->mode) ||
89                     test_bit(TRIGGER_NETDEV_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         mutex_lock(&trigger_data->lock);
101         len = sprintf(buf, "%s\n", trigger_data->device_name);
102         mutex_unlock(&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         mutex_lock(&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         trigger_data->carrier_link_up = false;
135         if (trigger_data->net_dev != NULL)
136                 trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
137
138         trigger_data->last_activity = 0;
139
140         set_baseline_state(trigger_data);
141         mutex_unlock(&trigger_data->lock);
142
143         return size;
144 }
145
146 static DEVICE_ATTR_RW(device_name);
147
148 static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
149                                     enum led_trigger_netdev_modes attr)
150 {
151         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
152         int bit;
153
154         switch (attr) {
155         case TRIGGER_NETDEV_LINK:
156         case TRIGGER_NETDEV_TX:
157         case TRIGGER_NETDEV_RX:
158                 bit = attr;
159                 break;
160         default:
161                 return -EINVAL;
162         }
163
164         return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
165 }
166
167 static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
168                                      size_t size, enum led_trigger_netdev_modes attr)
169 {
170         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
171         unsigned long state;
172         int ret;
173         int bit;
174
175         ret = kstrtoul(buf, 0, &state);
176         if (ret)
177                 return ret;
178
179         switch (attr) {
180         case TRIGGER_NETDEV_LINK:
181         case TRIGGER_NETDEV_TX:
182         case TRIGGER_NETDEV_RX:
183                 bit = attr;
184                 break;
185         default:
186                 return -EINVAL;
187         }
188
189         cancel_delayed_work_sync(&trigger_data->work);
190
191         if (state)
192                 set_bit(bit, &trigger_data->mode);
193         else
194                 clear_bit(bit, &trigger_data->mode);
195
196         set_baseline_state(trigger_data);
197
198         return size;
199 }
200
201 #define DEFINE_NETDEV_TRIGGER(trigger_name, trigger) \
202         static ssize_t trigger_name##_show(struct device *dev, \
203                 struct device_attribute *attr, char *buf) \
204         { \
205                 return netdev_led_attr_show(dev, buf, trigger); \
206         } \
207         static ssize_t trigger_name##_store(struct device *dev, \
208                 struct device_attribute *attr, const char *buf, size_t size) \
209         { \
210                 return netdev_led_attr_store(dev, buf, size, trigger); \
211         } \
212         static DEVICE_ATTR_RW(trigger_name)
213
214 DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
215 DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
216 DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
217
218 static ssize_t interval_show(struct device *dev,
219                              struct device_attribute *attr, char *buf)
220 {
221         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
222
223         return sprintf(buf, "%u\n",
224                        jiffies_to_msecs(atomic_read(&trigger_data->interval)));
225 }
226
227 static ssize_t interval_store(struct device *dev,
228                               struct device_attribute *attr, const char *buf,
229                               size_t size)
230 {
231         struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
232         unsigned long value;
233         int ret;
234
235         ret = kstrtoul(buf, 0, &value);
236         if (ret)
237                 return ret;
238
239         /* impose some basic bounds on the timer interval */
240         if (value >= 5 && value <= 10000) {
241                 cancel_delayed_work_sync(&trigger_data->work);
242
243                 atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
244                 set_baseline_state(trigger_data);       /* resets timer */
245         }
246
247         return size;
248 }
249
250 static DEVICE_ATTR_RW(interval);
251
252 static struct attribute *netdev_trig_attrs[] = {
253         &dev_attr_device_name.attr,
254         &dev_attr_link.attr,
255         &dev_attr_rx.attr,
256         &dev_attr_tx.attr,
257         &dev_attr_interval.attr,
258         NULL
259 };
260 ATTRIBUTE_GROUPS(netdev_trig);
261
262 static int netdev_trig_notify(struct notifier_block *nb,
263                               unsigned long evt, void *dv)
264 {
265         struct net_device *dev =
266                 netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
267         struct led_netdev_data *trigger_data =
268                 container_of(nb, struct led_netdev_data, notifier);
269
270         if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
271             && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
272             && evt != NETDEV_CHANGENAME)
273                 return NOTIFY_DONE;
274
275         if (!(dev == trigger_data->net_dev ||
276               (evt == NETDEV_CHANGENAME && !strcmp(dev->name, trigger_data->device_name)) ||
277               (evt == NETDEV_REGISTER && !strcmp(dev->name, trigger_data->device_name))))
278                 return NOTIFY_DONE;
279
280         cancel_delayed_work_sync(&trigger_data->work);
281
282         mutex_lock(&trigger_data->lock);
283
284         trigger_data->carrier_link_up = false;
285         switch (evt) {
286         case NETDEV_CHANGENAME:
287                 trigger_data->carrier_link_up = netif_carrier_ok(dev);
288                 fallthrough;
289         case NETDEV_REGISTER:
290                 dev_put(trigger_data->net_dev);
291                 dev_hold(dev);
292                 trigger_data->net_dev = dev;
293                 break;
294         case NETDEV_UNREGISTER:
295                 dev_put(trigger_data->net_dev);
296                 trigger_data->net_dev = NULL;
297                 break;
298         case NETDEV_UP:
299         case NETDEV_CHANGE:
300                 trigger_data->carrier_link_up = netif_carrier_ok(dev);
301                 break;
302         }
303
304         set_baseline_state(trigger_data);
305
306         mutex_unlock(&trigger_data->lock);
307
308         return NOTIFY_DONE;
309 }
310
311 /* here's the real work! */
312 static void netdev_trig_work(struct work_struct *work)
313 {
314         struct led_netdev_data *trigger_data =
315                 container_of(work, struct led_netdev_data, work.work);
316         struct rtnl_link_stats64 *dev_stats;
317         unsigned int new_activity;
318         struct rtnl_link_stats64 temp;
319         unsigned long interval;
320         int invert;
321
322         /* If we dont have a device, insure we are off */
323         if (!trigger_data->net_dev) {
324                 led_set_brightness(trigger_data->led_cdev, LED_OFF);
325                 return;
326         }
327
328         /* If we are not looking for RX/TX then return  */
329         if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) &&
330             !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
331                 return;
332
333         dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
334         new_activity =
335             (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ?
336                 dev_stats->tx_packets : 0) +
337             (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ?
338                 dev_stats->rx_packets : 0);
339
340         if (trigger_data->last_activity != new_activity) {
341                 led_stop_software_blink(trigger_data->led_cdev);
342
343                 invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode);
344                 interval = jiffies_to_msecs(
345                                 atomic_read(&trigger_data->interval));
346                 /* base state is ON (link present) */
347                 led_blink_set_oneshot(trigger_data->led_cdev,
348                                       &interval,
349                                       &interval,
350                                       invert);
351                 trigger_data->last_activity = new_activity;
352         }
353
354         schedule_delayed_work(&trigger_data->work,
355                         (atomic_read(&trigger_data->interval)*2));
356 }
357
358 static int netdev_trig_activate(struct led_classdev *led_cdev)
359 {
360         struct led_netdev_data *trigger_data;
361         int rc;
362
363         trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
364         if (!trigger_data)
365                 return -ENOMEM;
366
367         mutex_init(&trigger_data->lock);
368
369         trigger_data->notifier.notifier_call = netdev_trig_notify;
370         trigger_data->notifier.priority = 10;
371
372         INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
373
374         trigger_data->led_cdev = led_cdev;
375         trigger_data->net_dev = NULL;
376         trigger_data->device_name[0] = 0;
377
378         trigger_data->mode = 0;
379         atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
380         trigger_data->last_activity = 0;
381
382         led_set_trigger_data(led_cdev, trigger_data);
383
384         rc = register_netdevice_notifier(&trigger_data->notifier);
385         if (rc)
386                 kfree(trigger_data);
387
388         return rc;
389 }
390
391 static void netdev_trig_deactivate(struct led_classdev *led_cdev)
392 {
393         struct led_netdev_data *trigger_data = led_get_trigger_data(led_cdev);
394
395         unregister_netdevice_notifier(&trigger_data->notifier);
396
397         cancel_delayed_work_sync(&trigger_data->work);
398
399         dev_put(trigger_data->net_dev);
400
401         kfree(trigger_data);
402 }
403
404 static struct led_trigger netdev_led_trigger = {
405         .name = "netdev",
406         .activate = netdev_trig_activate,
407         .deactivate = netdev_trig_deactivate,
408         .groups = netdev_trig_groups,
409 };
410
411 static int __init netdev_trig_init(void)
412 {
413         return led_trigger_register(&netdev_led_trigger);
414 }
415
416 static void __exit netdev_trig_exit(void)
417 {
418         led_trigger_unregister(&netdev_led_trigger);
419 }
420
421 module_init(netdev_trig_init);
422 module_exit(netdev_trig_exit);
423
424 MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
425 MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
426 MODULE_DESCRIPTION("Netdev LED trigger");
427 MODULE_LICENSE("GPL v2");