2 * arch/ubicom32/mach-common/switch-core.c
3 * Ubicom32 architecture switch and /proc/switch/... implementation.
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright (C) 2005 Felix Fietkau <openwrt@nbd.name>
8 * This file is part of the Ubicom32 Linux Kernel Port.
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.
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.
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/>.
24 * Ubicom32 implementation derived from (with many thanks):
29 * Basic doc of driver's /proc interface:
30 * /proc/switch/<interface>/
31 * registers: read-only
33 * reset: write causes hardware reset
35 * enable_vlan: "0", "1"
38 * link state: read-only
39 * media: "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD"
41 * ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*")
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>
53 #include "switch-core.h"
56 * Pointer to the root of our filesystem
58 static struct proc_dir_entry *switch_root;
61 * Lock used to manage access to the switch list
63 DECLARE_RWSEM(switch_list_lock);
64 EXPORT_SYMBOL_GPL(switch_list_lock);
67 * List of switches we are managing
69 LIST_HEAD(switch_list);
70 EXPORT_SYMBOL_GPL(switch_list);
73 * List of handlers we have
75 LIST_HEAD(switch_handler_list);
76 EXPORT_SYMBOL_GPL(switch_handler_list);
79 * Keep track of all the handlers we added
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;
90 * Keep track of all VLAN dirs we created
92 struct switch_vlan_entry {
93 struct list_head node;
94 struct proc_dir_entry *pde;
96 const struct switch_handler *handlers;
100 * switch_parse_vlan_ports
101 * Parse the vlan properties written to <driver>/vlan/<vlan_id>/ports
103 void switch_parse_vlan_ports(struct switch_device *switch_dev,
104 char *buf, u32_t *untag,
105 u32_t *ports, u32_t *def)
114 * Skip any leading spaces
116 while (isspace(*buf)) {
121 * Parse out the string
124 u32_t port = simple_strtoul(buf, &buf, 10);
125 u32_t mask = (1 << port);
128 * Parse out any flags
130 while (*buf && !isspace(*buf)) {
145 while (isspace(*buf)) {
150 *untag = ~tag & *ports;
155 * Handle reads from the procfs, dispatches the driver specific handler
157 static ssize_t switch_proc_read(struct file *file, char *buf, size_t count,
160 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
164 page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL);
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,
180 len = min_t(int, len - *ppos, count);
181 if (copy_to_user(buf, (page + *ppos), len)) {
197 * Handle writes from the procfs, dispatches the driver specific handler
199 static ssize_t switch_proc_write(struct file *file, const char *buf,
200 size_t count, loff_t *data)
202 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
206 page = kmalloc(count + 1, GFP_KERNEL);
210 if (copy_from_user(page, buf, count)) {
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);
232 * File operations for the proc_fs, we must cast here since proc_fs' definitions
233 * differ from file_operations definitions.
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,
245 static int switch_add_handler(struct switch_device *switch_dev,
246 struct proc_dir_entry *parent,
247 const struct switch_handler *handler,
250 struct switch_handler_entry *she;
251 struct proc_dir_entry *pde;
254 she = (struct switch_handler_entry *)
255 kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL);
260 INIT_LIST_HEAD(&she->node);
261 she->parent = parent;
262 she->dev = switch_dev;
264 she->handler = handler;
265 list_add(&she->node, &switch_dev->handlers);
268 if (handler->read != NULL) {
271 if (handler->write != NULL) {
275 pde = create_proc_entry(handler->name, mode, parent);
278 printk("Failed to create node '%s' in parent %p\n",
279 handler->name, parent);
282 pde->data = (void *)she;
283 pde->proc_fops = &switch_proc_fops;
289 * switch_add_handlers
291 static int switch_add_handlers(struct switch_device *switch_dev,
292 struct proc_dir_entry *parent,
293 const struct switch_handler *handlers,
296 while (handlers->name) {
297 int ret = switch_add_handler(switch_dev,
298 parent, handlers, inst);
309 * switch_remove_vlan_dirs
310 * Removes all vlan directories
312 * Assumes all vlan directories are empty, should be called after
313 * switch_remove_handlers
315 static void switch_remove_vlan_dirs(struct switch_device *switch_dev)
317 struct list_head *pos;
318 struct list_head *tmp;
319 struct switch_vlan_entry *sve;
321 list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) {
322 sve = list_entry(pos, struct switch_vlan_entry, node);
324 remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
330 * switch_remove_handlers
331 * Removes all handlers registered to the given switch_device
333 static void switch_remove_handlers(struct switch_device *switch_dev)
335 struct list_head *pos;
336 struct list_head *tmp;
337 struct switch_handler_entry *she;
339 list_for_each_safe(pos, tmp, &switch_dev->handlers) {
340 she = list_entry(pos, struct switch_handler_entry, node);
342 remove_proc_entry(she->handler->name, she->parent);
348 * switch_unregister_proc_nodes
349 * Unregisters all proc nodes related to switch_dev
351 void switch_unregister_proc_nodes(struct switch_device *switch_dev)
353 switch_remove_handlers(switch_dev);
355 if (switch_dev->port_dirs) {
358 for (i = 0; i < switch_dev->ports; i++) {
359 if (switch_dev->port_dirs[i]) {
361 switch_dev->port_dirs[i]->name,
362 switch_dev->port_dir);
367 if (switch_dev->port_dir) {
368 remove_proc_entry("port", switch_dev->driver_dir);
369 switch_dev->port_dir = NULL;
372 if (switch_dev->reg_dir) {
373 remove_proc_entry("reg", switch_dev->reg_dir);
374 switch_dev->reg_dir = NULL;
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;
383 if (switch_dev->driver_dir) {
384 remove_proc_entry(switch_dev->name, switch_root);
385 switch_dev->driver_dir = NULL;
390 * switch_remove_vlan_dir
391 * Removes vlan dir in switch/<switch_driver>/vlan/<vlan_id>
393 int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id)
395 struct list_head *pos;
396 struct switch_vlan_entry *sve = NULL;
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) {
412 * Remove it from the list
417 * Remove the handlers
419 while (sve->handlers->name) {
420 remove_proc_entry(sve->handlers->name, sve->pde);
425 * Remove the proc entry for the <vlan_id> dir
427 remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
435 * switch_create_vlan_dir
436 * Creates vlan dir in switch/<switch_driver>/vlan/<vlan_id>
438 int switch_create_vlan_dir(struct switch_device *switch_dev,
439 int vlan_id, const struct switch_handler *handlers)
442 struct proc_dir_entry *pde = NULL;
443 struct switch_vlan_entry *sve = NULL;
445 struct list_head *pos;
448 * Check to see if it exists already
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) {
459 * Create the vlan directory if we didn't have it before
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) {
467 if (switch_dev->vlan_handlers) {
468 ret = switch_add_handlers(switch_dev,
469 switch_dev->vlan_dir,
470 switch_dev->vlan_handlers, 0);
478 * Create the vlan_id directory
480 snprintf(s, 14, "%d", vlan_id);
481 pde = proc_mkdir(s, switch_dev->vlan_dir);
487 * Create the handlers for this vlan
490 ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id);
497 * Keep track of all the switch vlan entries created
499 sve = (struct switch_vlan_entry *)
500 kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL);
504 INIT_LIST_HEAD(&sve->node);
505 sve->handlers = handlers;
506 sve->vlan_id = vlan_id;
508 list_add(&sve->node, &switch_dev->vlan_dirs);
519 * Remove any proc entries we might have created
521 while (handlers->name) {
522 remove_proc_entry(handlers->name, pde);
526 remove_proc_entry(s, switch_dev->driver_dir);
533 * switch_register_proc_nodes
535 int switch_register_proc_nodes(struct switch_device *switch_dev)
540 switch_dev->port_dirs = kzalloc(switch_dev->ports *
541 sizeof(struct proc_dir_entry *),
543 if (!switch_dev->port_dirs) {
548 * Create a new proc entry for this switch
550 switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root);
551 if (!switch_dev->driver_dir) {
554 if (switch_dev->driver_handlers) {
555 switch_add_handlers(switch_dev,
556 switch_dev->driver_dir,
557 switch_dev->driver_handlers,
564 switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir);
565 if (!switch_dev->port_dir) {
568 for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
569 if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
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]) {
578 if (switch_dev->port_handlers) {
579 switch_add_handlers(switch_dev,
580 switch_dev->port_dirs[n],
581 switch_dev->port_handlers,
589 * Create the register directory for switch register access.
591 if (switch_dev->reg_handlers) {
592 switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir);
593 if (!switch_dev->reg_dir) {
597 switch_add_handlers(switch_dev,
599 switch_dev->reg_handlers,
604 * Create the vlan directory
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) {
612 if (switch_dev->vlan_handlers) {
613 switch_add_handlers(switch_dev,
614 switch_dev->vlan_dir,
615 switch_dev->vlan_handlers,
623 switch_unregister_proc_nodes(switch_dev);
630 void switch_release(struct switch_device *switch_dev)
638 struct switch_device *switch_alloc(void)
640 struct switch_device *switch_dev =
641 kzalloc(sizeof(struct switch_device),
643 INIT_LIST_HEAD(&switch_dev->node);
644 INIT_LIST_HEAD(&switch_dev->vlan_dirs);
645 INIT_LIST_HEAD(&switch_dev->handlers);
652 int switch_register(struct switch_device *switch_dev)
658 * Make sure that the number of ports and the port mask make sense
660 for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
661 if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
665 if (ret > switch_dev->ports) {
670 * Create the /proc entries
672 ret = switch_register_proc_nodes(switch_dev);
678 * Add it to the list of switches
680 down_write(&switch_list_lock);
681 list_add_tail(&switch_dev->node, &switch_list);
682 up_write(&switch_list_lock);
684 printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name);
688 EXPORT_SYMBOL_GPL(switch_register);
692 * Unregisters a previously registered switch_device object
694 void switch_unregister(struct switch_device *switch_dev)
697 * remove the proc entries
699 switch_unregister_proc_nodes(switch_dev);
702 * Remove it from the list of switches
704 down_write(&switch_list_lock);
705 list_del(&switch_dev->node);
706 up_write(&switch_list_lock);
708 printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name);
710 EXPORT_SYMBOL_GPL(switch_unregister);
715 static int __init switch_init(void)
717 switch_root = proc_mkdir("switch", NULL);
719 printk(KERN_WARNING "Failed to make root switch node\n");
724 module_init(switch_init);
729 static void __exit switch_exit(void)
731 remove_proc_entry("switch", NULL);
733 module_exit(switch_exit);
735 MODULE_AUTHOR("Patrick Tjin");
736 MODULE_LICENSE("GPL");
737 MODULE_DESCRIPTION("Ethernet Switch Class Interface");