linux/net/dsa/dsa.c
<<
>>
Prefs
   1/*
   2 * net/dsa/dsa.c - Hardware switch handling
   3 * Copyright (c) 2008-2009 Marvell Semiconductor
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10
  11#include <linux/list.h>
  12#include <linux/netdevice.h>
  13#include <linux/platform_device.h>
  14#include <net/dsa.h>
  15#include "dsa_priv.h"
  16
  17char dsa_driver_version[] = "0.1";
  18
  19
  20/* switch driver registration ***********************************************/
  21static DEFINE_MUTEX(dsa_switch_drivers_mutex);
  22static LIST_HEAD(dsa_switch_drivers);
  23
  24void register_switch_driver(struct dsa_switch_driver *drv)
  25{
  26        mutex_lock(&dsa_switch_drivers_mutex);
  27        list_add_tail(&drv->list, &dsa_switch_drivers);
  28        mutex_unlock(&dsa_switch_drivers_mutex);
  29}
  30
  31void unregister_switch_driver(struct dsa_switch_driver *drv)
  32{
  33        mutex_lock(&dsa_switch_drivers_mutex);
  34        list_del_init(&drv->list);
  35        mutex_unlock(&dsa_switch_drivers_mutex);
  36}
  37
  38static struct dsa_switch_driver *
  39dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
  40{
  41        struct dsa_switch_driver *ret;
  42        struct list_head *list;
  43        char *name;
  44
  45        ret = NULL;
  46        name = NULL;
  47
  48        mutex_lock(&dsa_switch_drivers_mutex);
  49        list_for_each(list, &dsa_switch_drivers) {
  50                struct dsa_switch_driver *drv;
  51
  52                drv = list_entry(list, struct dsa_switch_driver, list);
  53
  54                name = drv->probe(bus, sw_addr);
  55                if (name != NULL) {
  56                        ret = drv;
  57                        break;
  58                }
  59        }
  60        mutex_unlock(&dsa_switch_drivers_mutex);
  61
  62        *_name = name;
  63
  64        return ret;
  65}
  66
  67
  68/* basic switch operations **************************************************/
  69static struct dsa_switch *
  70dsa_switch_setup(struct dsa_switch_tree *dst, int index,
  71                 struct device *parent, struct mii_bus *bus)
  72{
  73        struct dsa_chip_data *pd = dst->pd->chip + index;
  74        struct dsa_switch_driver *drv;
  75        struct dsa_switch *ds;
  76        int ret;
  77        char *name;
  78        int i;
  79
  80        /*
  81         * Probe for switch model.
  82         */
  83        drv = dsa_switch_probe(bus, pd->sw_addr, &name);
  84        if (drv == NULL) {
  85                printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
  86                       dst->master_netdev->name, index);
  87                return ERR_PTR(-EINVAL);
  88        }
  89        printk(KERN_INFO "%s[%d]: detected a %s switch\n",
  90                dst->master_netdev->name, index, name);
  91
  92
  93        /*
  94         * Allocate and initialise switch state.
  95         */
  96        ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
  97        if (ds == NULL)
  98                return ERR_PTR(-ENOMEM);
  99
 100        ds->dst = dst;
 101        ds->index = index;
 102        ds->pd = dst->pd->chip + index;
 103        ds->drv = drv;
 104        ds->master_mii_bus = bus;
 105
 106
 107        /*
 108         * Validate supplied switch configuration.
 109         */
 110        for (i = 0; i < DSA_MAX_PORTS; i++) {
 111                char *name;
 112
 113                name = pd->port_names[i];
 114                if (name == NULL)
 115                        continue;
 116
 117                if (!strcmp(name, "cpu")) {
 118                        if (dst->cpu_switch != -1) {
 119                                printk(KERN_ERR "multiple cpu ports?!\n");
 120                                ret = -EINVAL;
 121                                goto out;
 122                        }
 123                        dst->cpu_switch = index;
 124                        dst->cpu_port = i;
 125                } else if (!strcmp(name, "dsa")) {
 126                        ds->dsa_port_mask |= 1 << i;
 127                } else {
 128                        ds->phys_port_mask |= 1 << i;
 129                }
 130        }
 131
 132
 133        /*
 134         * If the CPU connects to this switch, set the switch tree
 135         * tagging protocol to the preferred tagging format of this
 136         * switch.
 137         */
 138        if (ds->dst->cpu_switch == index)
 139                ds->dst->tag_protocol = drv->tag_protocol;
 140
 141
 142        /*
 143         * Do basic register setup.
 144         */
 145        ret = drv->setup(ds);
 146        if (ret < 0)
 147                goto out;
 148
 149        ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
 150        if (ret < 0)
 151                goto out;
 152
 153        ds->slave_mii_bus = mdiobus_alloc();
 154        if (ds->slave_mii_bus == NULL) {
 155                ret = -ENOMEM;
 156                goto out;
 157        }
 158        dsa_slave_mii_bus_init(ds);
 159
 160        ret = mdiobus_register(ds->slave_mii_bus);
 161        if (ret < 0)
 162                goto out_free;
 163
 164
 165        /*
 166         * Create network devices for physical switch ports.
 167         */
 168        for (i = 0; i < DSA_MAX_PORTS; i++) {
 169                struct net_device *slave_dev;
 170
 171                if (!(ds->phys_port_mask & (1 << i)))
 172                        continue;
 173
 174                slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
 175                if (slave_dev == NULL) {
 176                        printk(KERN_ERR "%s[%d]: can't create dsa "
 177                               "slave device for port %d(%s)\n",
 178                               dst->master_netdev->name,
 179                               index, i, pd->port_names[i]);
 180                        continue;
 181                }
 182
 183                ds->ports[i] = slave_dev;
 184        }
 185
 186        return ds;
 187
 188out_free:
 189        mdiobus_free(ds->slave_mii_bus);
 190out:
 191        kfree(ds);
 192        return ERR_PTR(ret);
 193}
 194
 195static void dsa_switch_destroy(struct dsa_switch *ds)
 196{
 197}
 198
 199
 200/* hooks for ethertype-less tagging formats *********************************/
 201/*
 202 * The original DSA tag format and some other tag formats have no
 203 * ethertype, which means that we need to add a little hack to the
 204 * networking receive path to make sure that received frames get
 205 * the right ->protocol assigned to them when one of those tag
 206 * formats is in use.
 207 */
 208bool dsa_uses_dsa_tags(void *dsa_ptr)
 209{
 210        struct dsa_switch_tree *dst = dsa_ptr;
 211
 212        return !!(dst->tag_protocol == htons(ETH_P_DSA));
 213}
 214
 215bool dsa_uses_trailer_tags(void *dsa_ptr)
 216{
 217        struct dsa_switch_tree *dst = dsa_ptr;
 218
 219        return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
 220}
 221
 222
 223/* link polling *************************************************************/
 224static void dsa_link_poll_work(struct work_struct *ugly)
 225{
 226        struct dsa_switch_tree *dst;
 227        int i;
 228
 229        dst = container_of(ugly, struct dsa_switch_tree, link_poll_work);
 230
 231        for (i = 0; i < dst->pd->nr_chips; i++) {
 232                struct dsa_switch *ds = dst->ds[i];
 233
 234                if (ds != NULL && ds->drv->poll_link != NULL)
 235                        ds->drv->poll_link(ds);
 236        }
 237
 238        mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));
 239}
 240
 241static void dsa_link_poll_timer(unsigned long _dst)
 242{
 243        struct dsa_switch_tree *dst = (void *)_dst;
 244
 245        schedule_work(&dst->link_poll_work);
 246}
 247
 248
 249/* platform driver init and cleanup *****************************************/
 250static int dev_is_class(struct device *dev, void *class)
 251{
 252        if (dev->class != NULL && !strcmp(dev->class->name, class))
 253                return 1;
 254
 255        return 0;
 256}
 257
 258static struct device *dev_find_class(struct device *parent, char *class)
 259{
 260        if (dev_is_class(parent, class)) {
 261                get_device(parent);
 262                return parent;
 263        }
 264
 265        return device_find_child(parent, class, dev_is_class);
 266}
 267
 268static struct mii_bus *dev_to_mii_bus(struct device *dev)
 269{
 270        struct device *d;
 271
 272        d = dev_find_class(dev, "mdio_bus");
 273        if (d != NULL) {
 274                struct mii_bus *bus;
 275
 276                bus = to_mii_bus(d);
 277                put_device(d);
 278
 279                return bus;
 280        }
 281
 282        return NULL;
 283}
 284
 285static struct net_device *dev_to_net_device(struct device *dev)
 286{
 287        struct device *d;
 288
 289        d = dev_find_class(dev, "net");
 290        if (d != NULL) {
 291                struct net_device *nd;
 292
 293                nd = to_net_dev(d);
 294                dev_hold(nd);
 295                put_device(d);
 296
 297                return nd;
 298        }
 299
 300        return NULL;
 301}
 302
 303static int dsa_probe(struct platform_device *pdev)
 304{
 305        static int dsa_version_printed;
 306        struct dsa_platform_data *pd = pdev->dev.platform_data;
 307        struct net_device *dev;
 308        struct dsa_switch_tree *dst;
 309        int i;
 310
 311        if (!dsa_version_printed++)
 312                printk(KERN_NOTICE "Distributed Switch Architecture "
 313                        "driver version %s\n", dsa_driver_version);
 314
 315        if (pd == NULL || pd->netdev == NULL)
 316                return -EINVAL;
 317
 318        dev = dev_to_net_device(pd->netdev);
 319        if (dev == NULL)
 320                return -EINVAL;
 321
 322        if (dev->dsa_ptr != NULL) {
 323                dev_put(dev);
 324                return -EEXIST;
 325        }
 326
 327        dst = kzalloc(sizeof(*dst), GFP_KERNEL);
 328        if (dst == NULL) {
 329                dev_put(dev);
 330                return -ENOMEM;
 331        }
 332
 333        platform_set_drvdata(pdev, dst);
 334
 335        dst->pd = pd;
 336        dst->master_netdev = dev;
 337        dst->cpu_switch = -1;
 338        dst->cpu_port = -1;
 339
 340        for (i = 0; i < pd->nr_chips; i++) {
 341                struct mii_bus *bus;
 342                struct dsa_switch *ds;
 343
 344                bus = dev_to_mii_bus(pd->chip[i].mii_bus);
 345                if (bus == NULL) {
 346                        printk(KERN_ERR "%s[%d]: no mii bus found for "
 347                                "dsa switch\n", dev->name, i);
 348                        continue;
 349                }
 350
 351                ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
 352                if (IS_ERR(ds)) {
 353                        printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
 354                                "instance (error %ld)\n", dev->name, i,
 355                                PTR_ERR(ds));
 356                        continue;
 357                }
 358
 359                dst->ds[i] = ds;
 360                if (ds->drv->poll_link != NULL)
 361                        dst->link_poll_needed = 1;
 362        }
 363
 364        /*
 365         * If we use a tagging format that doesn't have an ethertype
 366         * field, make sure that all packets from this point on get
 367         * sent to the tag format's receive function.
 368         */
 369        wmb();
 370        dev->dsa_ptr = (void *)dst;
 371
 372        if (dst->link_poll_needed) {
 373                INIT_WORK(&dst->link_poll_work, dsa_link_poll_work);
 374                init_timer(&dst->link_poll_timer);
 375                dst->link_poll_timer.data = (unsigned long)dst;
 376                dst->link_poll_timer.function = dsa_link_poll_timer;
 377                dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
 378                add_timer(&dst->link_poll_timer);
 379        }
 380
 381        return 0;
 382}
 383
 384static int dsa_remove(struct platform_device *pdev)
 385{
 386        struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
 387        int i;
 388
 389        if (dst->link_poll_needed)
 390                del_timer_sync(&dst->link_poll_timer);
 391
 392        flush_scheduled_work();
 393
 394        for (i = 0; i < dst->pd->nr_chips; i++) {
 395                struct dsa_switch *ds = dst->ds[i];
 396
 397                if (ds != NULL)
 398                        dsa_switch_destroy(ds);
 399        }
 400
 401        return 0;
 402}
 403
 404static void dsa_shutdown(struct platform_device *pdev)
 405{
 406}
 407
 408static struct platform_driver dsa_driver = {
 409        .probe          = dsa_probe,
 410        .remove         = dsa_remove,
 411        .shutdown       = dsa_shutdown,
 412        .driver = {
 413                .name   = "dsa",
 414                .owner  = THIS_MODULE,
 415        },
 416};
 417
 418static int __init dsa_init_module(void)
 419{
 420        return platform_driver_register(&dsa_driver);
 421}
 422module_init(dsa_init_module);
 423
 424static void __exit dsa_cleanup_module(void)
 425{
 426        platform_driver_unregister(&dsa_driver);
 427}
 428module_exit(dsa_cleanup_module);
 429
 430MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>")
 431MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
 432MODULE_LICENSE("GPL");
 433MODULE_ALIAS("platform:dsa");
 434
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.