disable sstrip when using musl
[lede.git] / target / linux / ubicom32 / files / arch / ubicom32 / mach-common / switch-core.c
1 /*
2  * arch/ubicom32/mach-common/switch-core.c
3  *   Ubicom32 architecture switch and /proc/switch/... implementation.
4  *
5  * (C) Copyright 2009, Ubicom, Inc.
6  * Copyright (C) 2005 Felix Fietkau <openwrt@nbd.name>
7  *
8  * This file is part of the Ubicom32 Linux Kernel Port.
9  *
10  * The Ubicom32 Linux Kernel Port is free software: you can redistribute
11  * it and/or modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation, either version 2 of the
13  * License, or (at your option) any later version.
14  *
15  * The Ubicom32 Linux Kernel Port is distributed in the hope that it
16  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
17  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
18  * the GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with the Ubicom32 Linux Kernel Port.  If not,
22  * see <http://www.gnu.org/licenses/>.
23  *
24  * Ubicom32 implementation derived from (with many thanks):
25  *   arch/m68knommu
26  *   arch/blackfin
27  *   arch/parisc
28  *
29  * Basic doc of driver's /proc interface:
30  * /proc/switch/<interface>/
31  *   registers:              read-only
32  *   counters:               read-only
33  *   reset:                  write causes hardware reset
34  *   enable:                 "0", "1"
35  *   enable_vlan:            "0", "1"
36  *   port/<port-number>/
37  *     enabled:              "0", "1"
38  *     link state:           read-only
39  *     media:                "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD"
40  *   vlan/<port-number>/
41  *     ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*")
42  */
43
44 #include <linux/module.h>
45 #include <linux/init.h>
46 #include <linux/uaccess.h>
47 #include <linux/ctype.h>
48 #include <linux/proc_fs.h>
49 #include <linux/list.h>
50 #include <linux/rwsem.h>
51 #include <linux/device.h>
52
53 #include "switch-core.h"
54
55 /*
56  * Pointer to the root of our filesystem
57  */
58 static struct proc_dir_entry *switch_root;
59
60 /*
61  * Lock used to manage access to the switch list
62  */
63 DECLARE_RWSEM(switch_list_lock);
64 EXPORT_SYMBOL_GPL(switch_list_lock);
65
66 /*
67  * List of switches we are managing
68  */
69 LIST_HEAD(switch_list);
70 EXPORT_SYMBOL_GPL(switch_list);
71
72 /*
73  * List of handlers we have
74  */
75 LIST_HEAD(switch_handler_list);
76 EXPORT_SYMBOL_GPL(switch_handler_list);
77
78 /*
79  * Keep track of all the handlers we added
80  */
81 struct switch_handler_entry {
82         struct list_head                node;
83         struct proc_dir_entry           *parent;
84         struct switch_device            *dev;
85         const struct switch_handler     *handler;
86         int                             inst;
87 };
88
89 /*
90  * Keep track of all VLAN dirs we created
91  */
92 struct switch_vlan_entry {
93         struct list_head                node;
94         struct proc_dir_entry           *pde;
95         int                             vlan_id;
96         const struct switch_handler     *handlers;
97 };
98
99 /*
100  * switch_parse_vlan_ports
101  *      Parse the vlan properties written to <driver>/vlan/<vlan_id>/ports
102  */
103 void switch_parse_vlan_ports(struct switch_device *switch_dev,
104                              char *buf, u32_t *untag,
105                              u32_t *ports, u32_t *def)
106 {
107         u32_t tag = 0;
108         *untag = 0;
109         *ports = 0;
110         *def = 0;
111
112
113         /*
114          * Skip any leading spaces
115          */
116         while (isspace(*buf)) {
117                 buf++;
118         }
119
120         /*
121          * Parse out the string
122          */
123         while (*buf) {
124                 u32_t port = simple_strtoul(buf, &buf, 10);
125                 u32_t mask = (1 << port);
126
127                 /*
128                  * Parse out any flags
129                  */
130                 while (*buf && !isspace(*buf)) {
131                         switch (*buf++) {
132                         case 't':
133                                 tag |= mask;
134                                 break;
135                         case '*':
136                                 *def |= mask;
137                                 break;
138                         }
139                 }
140                 *ports |= mask;
141
142                 /*
143                  * Skip any spaces
144                  */
145                 while (isspace(*buf)) {
146                         buf++;
147                 }
148         }
149
150         *untag = ~tag & *ports;
151 }
152
153 /*
154  * switch_proc_read
155  *      Handle reads from the procfs, dispatches the driver specific handler
156  */
157 static ssize_t switch_proc_read(struct file *file, char *buf, size_t count,
158                                 loff_t *ppos)
159 {
160         struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
161         char *page;
162         int len = 0;
163
164         page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL);
165         if (!page) {
166                 return -ENOBUFS;
167         }
168
169         if (pde->data != NULL) {
170                 struct switch_handler_entry *she =
171                         (struct switch_handler_entry *)pde->data;
172                 if (she->handler->read) {
173                         len += she->handler->read(she->dev, page + len,
174                                                   she->inst);
175                 }
176         }
177         len += 1;
178
179         if (*ppos < len) {
180                 len = min_t(int, len - *ppos, count);
181                 if (copy_to_user(buf, (page + *ppos), len)) {
182                         kfree(page);
183                         return -EFAULT;
184                 }
185                 *ppos += len;
186         } else {
187                 len = 0;
188         }
189
190         kfree(page);
191
192         return len;
193 }
194
195 /*
196  * switch_proc_write
197  *      Handle writes from the procfs, dispatches the driver specific handler
198  */
199 static ssize_t switch_proc_write(struct file *file, const char *buf,
200                                  size_t count, loff_t *data)
201 {
202         struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
203         char *page;
204         int ret = -EINVAL;
205
206         page = kmalloc(count + 1, GFP_KERNEL);
207         if (page == NULL)
208                 return -ENOBUFS;
209
210         if (copy_from_user(page, buf, count)) {
211                 kfree(page);
212                 return -EINVAL;
213         }
214         page[count] = 0;
215
216         if (pde->data != NULL) {
217                 struct switch_handler_entry *she =
218                         (struct switch_handler_entry *)pde->data;
219                 if (she->handler->write) {
220                         ret = she->handler->write(she->dev, page, she->inst);
221                         if (ret >= 0) {
222                                 ret = count;
223                         }
224                 }
225         }
226
227         kfree(page);
228         return ret;
229 }
230
231 /*
232  * File operations for the proc_fs, we must cast here since proc_fs' definitions
233  * differ from file_operations definitions.
234  */
235 static struct file_operations switch_proc_fops = {
236         .read = (ssize_t (*) (struct file *, char __user *,
237                               size_t, loff_t *))switch_proc_read,
238         .write = (ssize_t (*) (struct file *, const char __user *,
239                                size_t, loff_t *))switch_proc_write,
240 };
241
242 /*
243  * switch_add_handler
244  */
245 static int switch_add_handler(struct switch_device *switch_dev,
246                               struct proc_dir_entry *parent,
247                               const struct switch_handler *handler,
248                               int inst)
249 {
250         struct switch_handler_entry *she;
251         struct proc_dir_entry *pde;
252         int mode;
253
254         she = (struct switch_handler_entry *)
255                 kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL);
256         if (!she) {
257                 return -ENOMEM;
258         }
259
260         INIT_LIST_HEAD(&she->node);
261         she->parent = parent;
262         she->dev = switch_dev;
263         she->inst = inst;
264         she->handler = handler;
265         list_add(&she->node, &switch_dev->handlers);
266
267         mode = 0;
268         if (handler->read != NULL) {
269                 mode |= S_IRUSR;
270         }
271         if (handler->write != NULL) {
272                 mode |= S_IWUSR;
273         }
274
275         pde = create_proc_entry(handler->name, mode, parent);
276         if (!pde) {
277                 kfree(she);
278                 printk("Failed to create node '%s' in parent %p\n",
279                        handler->name, parent);
280                 return -ENOMEM;
281         }
282         pde->data = (void *)she;
283         pde->proc_fops = &switch_proc_fops;
284
285         return 0;
286 }
287
288 /*
289  * switch_add_handlers
290  */
291 static int switch_add_handlers(struct switch_device *switch_dev,
292                                struct proc_dir_entry *parent,
293                                const struct switch_handler *handlers,
294                                int inst)
295 {
296         while (handlers->name) {
297                 int ret = switch_add_handler(switch_dev,
298                                              parent, handlers, inst);
299                 if (ret) {
300                         return ret;
301                 }
302                 handlers++;
303         }
304
305         return 0;
306 }
307
308 /*
309  * switch_remove_vlan_dirs
310  *      Removes all vlan directories
311  *
312  * Assumes all vlan directories are empty, should be called after
313  * switch_remove_handlers
314  */
315 static void switch_remove_vlan_dirs(struct switch_device *switch_dev)
316 {
317         struct list_head *pos;
318         struct list_head *tmp;
319         struct switch_vlan_entry *sve;
320
321         list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) {
322                 sve = list_entry(pos, struct switch_vlan_entry, node);
323                 list_del(pos);
324                 remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
325                 kfree(sve);
326         }
327 }
328
329 /*
330  * switch_remove_handlers
331  *      Removes all handlers registered to the given switch_device
332  */
333 static void switch_remove_handlers(struct switch_device *switch_dev)
334 {
335         struct list_head *pos;
336         struct list_head *tmp;
337         struct switch_handler_entry *she;
338
339         list_for_each_safe(pos, tmp, &switch_dev->handlers) {
340                 she = list_entry(pos, struct switch_handler_entry, node);
341                 list_del(pos);
342                 remove_proc_entry(she->handler->name, she->parent);
343                 kfree(she);
344         }
345 }
346
347 /*
348  * switch_unregister_proc_nodes
349  *      Unregisters all proc nodes related to switch_dev
350  */
351 void switch_unregister_proc_nodes(struct switch_device *switch_dev)
352 {
353         switch_remove_handlers(switch_dev);
354
355         if (switch_dev->port_dirs) {
356                 int i;
357
358                 for (i = 0; i < switch_dev->ports; i++) {
359                         if (switch_dev->port_dirs[i]) {
360                                 remove_proc_entry(
361                                         switch_dev->port_dirs[i]->name,
362                                         switch_dev->port_dir);
363                         }
364                 }
365         }
366
367         if (switch_dev->port_dir) {
368                 remove_proc_entry("port", switch_dev->driver_dir);
369                 switch_dev->port_dir = NULL;
370         }
371
372         if (switch_dev->reg_dir) {
373                 remove_proc_entry("reg", switch_dev->reg_dir);
374                 switch_dev->reg_dir = NULL;
375         }
376
377         if (switch_dev->vlan_dir) {
378                 switch_remove_vlan_dirs(switch_dev);
379                 remove_proc_entry("vlan", switch_dev->driver_dir);
380                 switch_dev->vlan_dir = NULL;
381         }
382
383         if (switch_dev->driver_dir) {
384                 remove_proc_entry(switch_dev->name, switch_root);
385                 switch_dev->driver_dir = NULL;
386         }
387 }
388
389 /*
390  * switch_remove_vlan_dir
391  *      Removes vlan dir in switch/<switch_driver>/vlan/<vlan_id>
392  */
393 int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id)
394 {
395         struct list_head *pos;
396         struct switch_vlan_entry *sve = NULL;
397
398         list_for_each(pos, &switch_dev->vlan_dirs) {
399                 struct switch_vlan_entry *tmp =
400                         list_entry(pos, struct switch_vlan_entry, node);
401                 if (tmp->vlan_id == vlan_id) {
402                         sve = tmp;
403                         break;
404                 }
405         }
406
407         if (!sve) {
408                 return -ENOENT;
409         }
410
411         /*
412          * Remove it from the list
413          */
414         list_del(pos);
415
416         /*
417          * Remove the handlers
418          */
419         while (sve->handlers->name) {
420                 remove_proc_entry(sve->handlers->name, sve->pde);
421                 sve->handlers++;
422         }
423
424         /*
425          * Remove the proc entry for the <vlan_id> dir
426          */
427         remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
428
429         kfree(sve);
430
431         return 0;
432 }
433
434 /*
435  * switch_create_vlan_dir
436  *      Creates vlan dir in switch/<switch_driver>/vlan/<vlan_id>
437  */
438 int switch_create_vlan_dir(struct switch_device *switch_dev,
439                            int vlan_id, const struct switch_handler *handlers)
440 {
441         char s[14];
442         struct proc_dir_entry *pde = NULL;
443         struct switch_vlan_entry *sve = NULL;
444         int ret;
445         struct list_head *pos;
446
447         /*
448          * Check to see if it exists already
449          */
450         list_for_each(pos, &switch_dev->vlan_dirs) {
451                 sve = list_entry(pos, struct switch_vlan_entry, node);
452                 if (sve->vlan_id == vlan_id) {
453                         return -EEXIST;
454                 }
455         }
456         sve = NULL;
457
458         /*
459          * Create the vlan directory if we didn't have it before
460          */
461         if (!switch_dev->vlan_dir) {
462                 switch_dev->vlan_dir = proc_mkdir("vlan",
463                                                   switch_dev->driver_dir);
464                 if (!switch_dev->vlan_dir) {
465                         goto fail;
466                 }
467                 if (switch_dev->vlan_handlers) {
468                         ret = switch_add_handlers(switch_dev,
469                                                   switch_dev->vlan_dir,
470                                                   switch_dev->vlan_handlers, 0);
471                         if (ret) {
472                                 goto fail;
473                         }
474                 }
475         }
476
477         /*
478          * Create the vlan_id directory
479          */
480         snprintf(s, 14, "%d", vlan_id);
481         pde = proc_mkdir(s, switch_dev->vlan_dir);
482         if (!pde) {
483                 goto fail;
484         }
485
486         /*
487          * Create the handlers for this vlan
488          */
489         if (handlers) {
490                 ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id);
491                 if (ret) {
492                         goto fail;
493                 }
494         }
495
496         /*
497          * Keep track of all the switch vlan entries created
498          */
499         sve = (struct switch_vlan_entry *)
500                 kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL);
501         if (!sve) {
502                 goto fail;
503         }
504         INIT_LIST_HEAD(&sve->node);
505         sve->handlers = handlers;
506         sve->vlan_id = vlan_id;
507         sve->pde = pde;
508         list_add(&sve->node, &switch_dev->vlan_dirs);
509
510         return 0;
511
512 fail:
513         if (sve) {
514                 kfree(sve);
515         }
516
517         if (pde) {
518                 /*
519                  * Remove any proc entries we might have created
520                  */
521                 while (handlers->name) {
522                         remove_proc_entry(handlers->name, pde);
523                         handlers++;
524                 }
525
526                 remove_proc_entry(s, switch_dev->driver_dir);
527         }
528
529         return -ENOMEM;
530 }
531
532 /*
533  * switch_register_proc_nodes
534  */
535 int switch_register_proc_nodes(struct switch_device *switch_dev)
536 {
537         int i;
538         int n;
539
540         switch_dev->port_dirs = kzalloc(switch_dev->ports *
541                                         sizeof(struct proc_dir_entry *),
542                                         GFP_KERNEL);
543         if (!switch_dev->port_dirs) {
544                 return -ENOMEM;
545         }
546
547         /*
548          * Create a new proc entry for this switch
549          */
550         switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root);
551         if (!switch_dev->driver_dir) {
552                 goto fail;
553         }
554         if (switch_dev->driver_handlers) {
555                 switch_add_handlers(switch_dev,
556                                     switch_dev->driver_dir,
557                                     switch_dev->driver_handlers,
558                                     0);
559         }
560
561         /*
562          * Create the ports
563          */
564         switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir);
565         if (!switch_dev->port_dir) {
566                 goto fail;
567         }
568         for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
569                 if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
570                         char s[14];
571
572                         snprintf(s, 14, "%d", i);
573                         switch_dev->port_dirs[n] =
574                                 proc_mkdir(s, switch_dev->port_dir);
575                         if (!switch_dev->port_dirs[n]) {
576                                 goto fail;
577                         }
578                         if (switch_dev->port_handlers) {
579                                 switch_add_handlers(switch_dev,
580                                                     switch_dev->port_dirs[n],
581                                                     switch_dev->port_handlers,
582                                                     i);
583                         }
584                         n++;
585                 }
586         }
587
588         /*
589          * Create the register directory for switch register access.
590          */
591         if (switch_dev->reg_handlers) {
592                 switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir);
593                 if (!switch_dev->reg_dir) {
594                         goto fail;
595                 }
596
597                 switch_add_handlers(switch_dev,
598                                     switch_dev->reg_dir,
599                                     switch_dev->reg_handlers,
600                                     0);
601         }
602
603         /*
604          * Create the vlan directory
605          */
606         if (switch_dev->vlan_handlers) {
607                 switch_dev->vlan_dir = proc_mkdir("vlan",
608                                                   switch_dev->driver_dir);
609                 if (!switch_dev->vlan_dir) {
610                         goto fail;
611                 }
612                 if (switch_dev->vlan_handlers) {
613                         switch_add_handlers(switch_dev,
614                                             switch_dev->vlan_dir,
615                                             switch_dev->vlan_handlers,
616                                             0);
617                 }
618         }
619
620         return 0;
621
622 fail:
623         switch_unregister_proc_nodes(switch_dev);
624         return -ENOMEM;
625 }
626
627 /*
628  * switch_release
629  */
630 void switch_release(struct switch_device *switch_dev)
631 {
632         kfree(switch_dev);
633 }
634
635 /*
636  * switch_alloc
637  */
638 struct switch_device *switch_alloc(void)
639 {
640         struct switch_device *switch_dev =
641                 kzalloc(sizeof(struct switch_device),
642                                                 GFP_KERNEL);
643         INIT_LIST_HEAD(&switch_dev->node);
644         INIT_LIST_HEAD(&switch_dev->vlan_dirs);
645         INIT_LIST_HEAD(&switch_dev->handlers);
646         return switch_dev;
647 }
648
649 /*
650  * switch_register
651  */
652 int switch_register(struct switch_device *switch_dev)
653 {
654         int ret;
655         int i;
656
657         /*
658          * Make sure that the number of ports and the port mask make sense
659          */
660         for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
661                 if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
662                         ret++;
663                 }
664         }
665         if (ret > switch_dev->ports) {
666                 return -EINVAL;
667         }
668
669         /*
670          * Create the /proc entries
671          */
672         ret = switch_register_proc_nodes(switch_dev);
673         if (ret) {
674                 return ret;
675         }
676
677         /*
678          * Add it to the list of switches
679          */
680         down_write(&switch_list_lock);
681         list_add_tail(&switch_dev->node, &switch_list);
682         up_write(&switch_list_lock);
683
684         printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name);
685
686         return 0;
687 }
688 EXPORT_SYMBOL_GPL(switch_register);
689
690 /*
691  * switch_unregister
692  *      Unregisters a previously registered switch_device object
693  */
694 void switch_unregister(struct switch_device *switch_dev)
695 {
696         /*
697          * remove the proc entries
698          */
699         switch_unregister_proc_nodes(switch_dev);
700
701         /*
702          * Remove it from the list of switches
703          */
704         down_write(&switch_list_lock);
705         list_del(&switch_dev->node);
706         up_write(&switch_list_lock);
707
708         printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name);
709 }
710 EXPORT_SYMBOL_GPL(switch_unregister);
711
712 /*
713  * switch_init
714  */
715 static int __init switch_init(void)
716 {
717         switch_root = proc_mkdir("switch", NULL);
718         if (!switch_root) {
719                 printk(KERN_WARNING "Failed to make root switch node\n");
720                 return -ENODEV;
721         }
722         return 0;
723 }
724 module_init(switch_init);
725
726 /*
727  * switch_exit
728  */
729 static void __exit switch_exit(void)
730 {
731         remove_proc_entry("switch", NULL);
732 }
733 module_exit(switch_exit);
734
735 MODULE_AUTHOR("Patrick Tjin");
736 MODULE_LICENSE("GPL");
737 MODULE_DESCRIPTION("Ethernet Switch Class Interface");