linux/arch/xtensa/platforms/iss/network.c
<<
>>
Prefs
   1/*
   2 *
   3 * arch/xtensa/platforms/iss/network.c
   4 *
   5 * Platform specific initialization.
   6 *
   7 * Authors: Chris Zankel <chris@zankel.net>
   8 * Based on work form the UML team.
   9 *
  10 * Copyright 2005 Tensilica Inc.
  11 *
  12 * This program is free software; you can redistribute  it and/or modify it
  13 * under  the terms of  the GNU General  Public License as published by the
  14 * Free Software Foundation;  either version 2 of the  License, or (at your
  15 * option) any later version.
  16 *
  17 */
  18
  19#include <linux/list.h>
  20#include <linux/irq.h>
  21#include <linux/spinlock.h>
  22#include <linux/slab.h>
  23#include <linux/timer.h>
  24#include <linux/if_ether.h>
  25#include <linux/inetdevice.h>
  26#include <linux/init.h>
  27#include <linux/if_tun.h>
  28#include <linux/etherdevice.h>
  29#include <linux/interrupt.h>
  30#include <linux/ioctl.h>
  31#include <linux/bootmem.h>
  32#include <linux/ethtool.h>
  33#include <linux/rtnetlink.h>
  34#include <linux/platform_device.h>
  35
  36#include <platform/simcall.h>
  37
  38#define DRIVER_NAME "iss-netdev"
  39#define ETH_MAX_PACKET 1500
  40#define ETH_HEADER_OTHER 14
  41#define ISS_NET_TIMER_VALUE (HZ / 10)
  42
  43
  44static DEFINE_SPINLOCK(opened_lock);
  45static LIST_HEAD(opened);
  46
  47static DEFINE_SPINLOCK(devices_lock);
  48static LIST_HEAD(devices);
  49
  50/* ------------------------------------------------------------------------- */
  51
  52/* We currently only support the TUNTAP transport protocol. */
  53
  54#define TRANSPORT_TUNTAP_NAME "tuntap"
  55#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
  56
  57struct tuntap_info {
  58        char dev_name[IFNAMSIZ];
  59        int fd;
  60};
  61
  62/* ------------------------------------------------------------------------- */
  63
  64
  65/* This structure contains out private information for the driver. */
  66
  67struct iss_net_private {
  68        struct list_head device_list;
  69        struct list_head opened_list;
  70
  71        spinlock_t lock;
  72        struct net_device *dev;
  73        struct platform_device pdev;
  74        struct timer_list tl;
  75        struct net_device_stats stats;
  76
  77        struct timer_list timer;
  78        unsigned int timer_val;
  79
  80        int index;
  81        int mtu;
  82
  83        struct {
  84                union {
  85                        struct tuntap_info tuntap;
  86                } info;
  87
  88                int (*open)(struct iss_net_private *lp);
  89                void (*close)(struct iss_net_private *lp);
  90                int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
  91                int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
  92                unsigned short (*protocol)(struct sk_buff *skb);
  93                int (*poll)(struct iss_net_private *lp);
  94        } tp;
  95
  96};
  97
  98/* ================================ HELPERS ================================ */
  99
 100
 101static char *split_if_spec(char *str, ...)
 102{
 103        char **arg, *end;
 104        va_list ap;
 105
 106        va_start(ap, str);
 107        while ((arg = va_arg(ap, char**)) != NULL) {
 108                if (*str == '\0') {
 109                        va_end(ap);
 110                        return NULL;
 111                }
 112                end = strchr(str, ',');
 113                if (end != str)
 114                        *arg = str;
 115                if (end == NULL) {
 116                        va_end(ap);
 117                        return NULL;
 118                }
 119                *end++ = '\0';
 120                str = end;
 121        }
 122        va_end(ap);
 123        return str;
 124}
 125
 126/* Set Ethernet address of the specified device. */
 127
 128static void setup_etheraddr(struct net_device *dev, char *str)
 129{
 130        unsigned char *addr = dev->dev_addr;
 131
 132        if (str == NULL)
 133                goto random;
 134
 135        if (!mac_pton(str, addr)) {
 136                pr_err("%s: failed to parse '%s' as an ethernet address\n",
 137                       dev->name, str);
 138                goto random;
 139        }
 140        if (is_multicast_ether_addr(addr)) {
 141                pr_err("%s: attempt to assign a multicast ethernet address\n",
 142                       dev->name);
 143                goto random;
 144        }
 145        if (!is_valid_ether_addr(addr)) {
 146                pr_err("%s: attempt to assign an invalid ethernet address\n",
 147                       dev->name);
 148                goto random;
 149        }
 150        if (!is_local_ether_addr(addr))
 151                pr_warn("%s: assigning a globally valid ethernet address\n",
 152                        dev->name);
 153        return;
 154
 155random:
 156        pr_info("%s: choosing a random ethernet address\n",
 157                dev->name);
 158        eth_hw_addr_random(dev);
 159}
 160
 161/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
 162
 163static int tuntap_open(struct iss_net_private *lp)
 164{
 165        struct ifreq ifr;
 166        char *dev_name = lp->tp.info.tuntap.dev_name;
 167        int err = -EINVAL;
 168        int fd;
 169
 170        fd = simc_open("/dev/net/tun", 02, 0); /* O_RDWR */
 171        if (fd < 0) {
 172                pr_err("%s: failed to open /dev/net/tun, returned %d (errno = %d)\n",
 173                       lp->dev->name, fd, errno);
 174                return fd;
 175        }
 176
 177        memset(&ifr, 0, sizeof(ifr));
 178        ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
 179        strlcpy(ifr.ifr_name, dev_name, sizeof(ifr.ifr_name));
 180
 181        err = simc_ioctl(fd, TUNSETIFF, &ifr);
 182        if (err < 0) {
 183                pr_err("%s: failed to set interface %s, returned %d (errno = %d)\n",
 184                       lp->dev->name, dev_name, err, errno);
 185                simc_close(fd);
 186                return err;
 187        }
 188
 189        lp->tp.info.tuntap.fd = fd;
 190        return err;
 191}
 192
 193static void tuntap_close(struct iss_net_private *lp)
 194{
 195        simc_close(lp->tp.info.tuntap.fd);
 196        lp->tp.info.tuntap.fd = -1;
 197}
 198
 199static int tuntap_read(struct iss_net_private *lp, struct sk_buff **skb)
 200{
 201        return simc_read(lp->tp.info.tuntap.fd,
 202                        (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
 203}
 204
 205static int tuntap_write(struct iss_net_private *lp, struct sk_buff **skb)
 206{
 207        return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
 208}
 209
 210unsigned short tuntap_protocol(struct sk_buff *skb)
 211{
 212        return eth_type_trans(skb, skb->dev);
 213}
 214
 215static int tuntap_poll(struct iss_net_private *lp)
 216{
 217        return simc_poll(lp->tp.info.tuntap.fd);
 218}
 219
 220/*
 221 * ethX=tuntap,[mac address],device name
 222 */
 223
 224static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
 225{
 226        struct net_device *dev = lp->dev;
 227        char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
 228
 229        /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
 230
 231        if (strncmp(init, TRANSPORT_TUNTAP_NAME,
 232                    sizeof(TRANSPORT_TUNTAP_NAME) - 1))
 233                return 0;
 234
 235        init += sizeof(TRANSPORT_TUNTAP_NAME) - 1;
 236        if (*init == ',') {
 237                rem = split_if_spec(init + 1, &mac_str, &dev_name);
 238                if (rem != NULL) {
 239                        pr_err("%s: extra garbage on specification : '%s'\n",
 240                               dev->name, rem);
 241                        return 0;
 242                }
 243        } else if (*init != '\0') {
 244                pr_err("%s: invalid argument: %s. Skipping device!\n",
 245                       dev->name, init);
 246                return 0;
 247        }
 248
 249        if (!dev_name) {
 250                pr_err("%s: missing tuntap device name\n", dev->name);
 251                return 0;
 252        }
 253
 254        strlcpy(lp->tp.info.tuntap.dev_name, dev_name,
 255                sizeof(lp->tp.info.tuntap.dev_name));
 256
 257        setup_etheraddr(dev, mac_str);
 258
 259        lp->mtu = TRANSPORT_TUNTAP_MTU;
 260
 261        lp->tp.info.tuntap.fd = -1;
 262
 263        lp->tp.open = tuntap_open;
 264        lp->tp.close = tuntap_close;
 265        lp->tp.read = tuntap_read;
 266        lp->tp.write = tuntap_write;
 267        lp->tp.protocol = tuntap_protocol;
 268        lp->tp.poll = tuntap_poll;
 269
 270        return 1;
 271}
 272
 273/* ================================ ISS NET ================================ */
 274
 275static int iss_net_rx(struct net_device *dev)
 276{
 277        struct iss_net_private *lp = netdev_priv(dev);
 278        int pkt_len;
 279        struct sk_buff *skb;
 280
 281        /* Check if there is any new data. */
 282
 283        if (lp->tp.poll(lp) == 0)
 284                return 0;
 285
 286        /* Try to allocate memory, if it fails, try again next round. */
 287
 288        skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER);
 289        if (skb == NULL) {
 290                lp->stats.rx_dropped++;
 291                return 0;
 292        }
 293
 294        skb_reserve(skb, 2);
 295
 296        /* Setup skb */
 297
 298        skb->dev = dev;
 299        skb_reset_mac_header(skb);
 300        pkt_len = lp->tp.read(lp, &skb);
 301        skb_put(skb, pkt_len);
 302
 303        if (pkt_len > 0) {
 304                skb_trim(skb, pkt_len);
 305                skb->protocol = lp->tp.protocol(skb);
 306
 307                lp->stats.rx_bytes += skb->len;
 308                lp->stats.rx_packets++;
 309                netif_rx_ni(skb);
 310                return pkt_len;
 311        }
 312        kfree_skb(skb);
 313        return pkt_len;
 314}
 315
 316static int iss_net_poll(void)
 317{
 318        struct list_head *ele;
 319        int err, ret = 0;
 320
 321        spin_lock(&opened_lock);
 322
 323        list_for_each(ele, &opened) {
 324                struct iss_net_private *lp;
 325
 326                lp = list_entry(ele, struct iss_net_private, opened_list);
 327
 328                if (!netif_running(lp->dev))
 329                        break;
 330
 331                spin_lock(&lp->lock);
 332
 333                while ((err = iss_net_rx(lp->dev)) > 0)
 334                        ret++;
 335
 336                spin_unlock(&lp->lock);
 337
 338                if (err < 0) {
 339                        pr_err("Device '%s' read returned %d, shutting it down\n",
 340                               lp->dev->name, err);
 341                        dev_close(lp->dev);
 342                } else {
 343                        /* FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); */
 344                }
 345        }
 346
 347        spin_unlock(&opened_lock);
 348        return ret;
 349}
 350
 351
 352static void iss_net_timer(unsigned long priv)
 353{
 354        struct iss_net_private *lp = (struct iss_net_private *)priv;
 355
 356        iss_net_poll();
 357        spin_lock(&lp->lock);
 358        mod_timer(&lp->timer, jiffies + lp->timer_val);
 359        spin_unlock(&lp->lock);
 360}
 361
 362
 363static int iss_net_open(struct net_device *dev)
 364{
 365        struct iss_net_private *lp = netdev_priv(dev);
 366        int err;
 367
 368        spin_lock_bh(&lp->lock);
 369
 370        err = lp->tp.open(lp);
 371        if (err < 0)
 372                goto out;
 373
 374        netif_start_queue(dev);
 375
 376        /* clear buffer - it can happen that the host side of the interface
 377         * is full when we get here. In this case, new data is never queued,
 378         * SIGIOs never arrive, and the net never works.
 379         */
 380        while ((err = iss_net_rx(dev)) > 0)
 381                ;
 382
 383        spin_unlock_bh(&lp->lock);
 384        spin_lock_bh(&opened_lock);
 385        list_add(&lp->opened_list, &opened);
 386        spin_unlock_bh(&opened_lock);
 387        spin_lock_bh(&lp->lock);
 388
 389        init_timer(&lp->timer);
 390        lp->timer_val = ISS_NET_TIMER_VALUE;
 391        lp->timer.data = (unsigned long) lp;
 392        lp->timer.function = iss_net_timer;
 393        mod_timer(&lp->timer, jiffies + lp->timer_val);
 394
 395out:
 396        spin_unlock_bh(&lp->lock);
 397        return err;
 398}
 399
 400static int iss_net_close(struct net_device *dev)
 401{
 402        struct iss_net_private *lp = netdev_priv(dev);
 403        netif_stop_queue(dev);
 404        spin_lock_bh(&lp->lock);
 405
 406        spin_lock(&opened_lock);
 407        list_del(&opened);
 408        spin_unlock(&opened_lock);
 409
 410        del_timer_sync(&lp->timer);
 411
 412        lp->tp.close(lp);
 413
 414        spin_unlock_bh(&lp->lock);
 415        return 0;
 416}
 417
 418static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 419{
 420        struct iss_net_private *lp = netdev_priv(dev);
 421        int len;
 422
 423        netif_stop_queue(dev);
 424        spin_lock_bh(&lp->lock);
 425
 426        len = lp->tp.write(lp, &skb);
 427
 428        if (len == skb->len) {
 429                lp->stats.tx_packets++;
 430                lp->stats.tx_bytes += skb->len;
 431                dev->trans_start = jiffies;
 432                netif_start_queue(dev);
 433
 434                /* this is normally done in the interrupt when tx finishes */
 435                netif_wake_queue(dev);
 436
 437        } else if (len == 0) {
 438                netif_start_queue(dev);
 439                lp->stats.tx_dropped++;
 440
 441        } else {
 442                netif_start_queue(dev);
 443                pr_err("%s: %s failed(%d)\n", dev->name, __func__, len);
 444        }
 445
 446        spin_unlock_bh(&lp->lock);
 447
 448        dev_kfree_skb(skb);
 449        return NETDEV_TX_OK;
 450}
 451
 452
 453static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
 454{
 455        struct iss_net_private *lp = netdev_priv(dev);
 456        return &lp->stats;
 457}
 458
 459static void iss_net_set_multicast_list(struct net_device *dev)
 460{
 461}
 462
 463static void iss_net_tx_timeout(struct net_device *dev)
 464{
 465}
 466
 467static int iss_net_set_mac(struct net_device *dev, void *addr)
 468{
 469        struct iss_net_private *lp = netdev_priv(dev);
 470        struct sockaddr *hwaddr = addr;
 471
 472        if (!is_valid_ether_addr(hwaddr->sa_data))
 473                return -EADDRNOTAVAIL;
 474        spin_lock_bh(&lp->lock);
 475        memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
 476        spin_unlock_bh(&lp->lock);
 477        return 0;
 478}
 479
 480static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
 481{
 482        return -EINVAL;
 483}
 484
 485void iss_net_user_timer_expire(unsigned long _conn)
 486{
 487}
 488
 489
 490static struct platform_driver iss_net_driver = {
 491        .driver = {
 492                .name  = DRIVER_NAME,
 493        },
 494};
 495
 496static int driver_registered;
 497
 498static const struct net_device_ops iss_netdev_ops = {
 499        .ndo_open               = iss_net_open,
 500        .ndo_stop               = iss_net_close,
 501        .ndo_get_stats          = iss_net_get_stats,
 502        .ndo_start_xmit         = iss_net_start_xmit,
 503        .ndo_validate_addr      = eth_validate_addr,
 504        .ndo_change_mtu         = iss_net_change_mtu,
 505        .ndo_set_mac_address    = iss_net_set_mac,
 506        .ndo_tx_timeout         = iss_net_tx_timeout,
 507        .ndo_set_rx_mode        = iss_net_set_multicast_list,
 508};
 509
 510static int iss_net_configure(int index, char *init)
 511{
 512        struct net_device *dev;
 513        struct iss_net_private *lp;
 514        int err;
 515
 516        dev = alloc_etherdev(sizeof(*lp));
 517        if (dev == NULL) {
 518                pr_err("eth_configure: failed to allocate device\n");
 519                return 1;
 520        }
 521
 522        /* Initialize private element. */
 523
 524        lp = netdev_priv(dev);
 525        *lp = (struct iss_net_private) {
 526                .device_list            = LIST_HEAD_INIT(lp->device_list),
 527                .opened_list            = LIST_HEAD_INIT(lp->opened_list),
 528                .dev                    = dev,
 529                .index                  = index,
 530        };
 531
 532        spin_lock_init(&lp->lock);
 533        /*
 534         * If this name ends up conflicting with an existing registered
 535         * netdevice, that is OK, register_netdev{,ice}() will notice this
 536         * and fail.
 537         */
 538        snprintf(dev->name, sizeof(dev->name), "eth%d", index);
 539
 540        /*
 541         * Try all transport protocols.
 542         * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
 543         */
 544
 545        if (!tuntap_probe(lp, index, init)) {
 546                pr_err("%s: invalid arguments. Skipping device!\n",
 547                       dev->name);
 548                goto errout;
 549        }
 550
 551        pr_info("Netdevice %d (%pM)\n", index, dev->dev_addr);
 552
 553        /* sysfs register */
 554
 555        if (!driver_registered) {
 556                platform_driver_register(&iss_net_driver);
 557                driver_registered = 1;
 558        }
 559
 560        spin_lock(&devices_lock);
 561        list_add(&lp->device_list, &devices);
 562        spin_unlock(&devices_lock);
 563
 564        lp->pdev.id = index;
 565        lp->pdev.name = DRIVER_NAME;
 566        platform_device_register(&lp->pdev);
 567        SET_NETDEV_DEV(dev, &lp->pdev.dev);
 568
 569        dev->netdev_ops = &iss_netdev_ops;
 570        dev->mtu = lp->mtu;
 571        dev->watchdog_timeo = (HZ >> 1);
 572        dev->irq = -1;
 573
 574        rtnl_lock();
 575        err = register_netdevice(dev);
 576        rtnl_unlock();
 577
 578        if (err) {
 579                pr_err("%s: error registering net device!\n", dev->name);
 580                /* XXX: should we call ->remove() here? */
 581                free_netdev(dev);
 582                return 1;
 583        }
 584
 585        init_timer(&lp->tl);
 586        lp->tl.function = iss_net_user_timer_expire;
 587
 588        return 0;
 589
 590errout:
 591        /* FIXME: unregister; free, etc.. */
 592        return -EIO;
 593}
 594
 595/* ------------------------------------------------------------------------- */
 596
 597/* Filled in during early boot */
 598
 599struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
 600
 601struct iss_net_init {
 602        struct list_head list;
 603        char *init;             /* init string */
 604        int index;
 605};
 606
 607/*
 608 * Parse the command line and look for 'ethX=...' fields, and register all
 609 * those fields. They will be later initialized in iss_net_init.
 610 */
 611
 612#define ERR KERN_ERR "iss_net_setup: "
 613
 614static int __init iss_net_setup(char *str)
 615{
 616        struct iss_net_private *device = NULL;
 617        struct iss_net_init *new;
 618        struct list_head *ele;
 619        char *end;
 620        int rc;
 621        unsigned n;
 622
 623        end = strchr(str, '=');
 624        if (!end) {
 625                printk(ERR "Expected '=' after device number\n");
 626                return 1;
 627        }
 628        *end = 0;
 629        rc = kstrtouint(str, 0, &n);
 630        *end = '=';
 631        if (rc < 0) {
 632                printk(ERR "Failed to parse '%s'\n", str);
 633                return 1;
 634        }
 635        str = end;
 636
 637        spin_lock(&devices_lock);
 638
 639        list_for_each(ele, &devices) {
 640                device = list_entry(ele, struct iss_net_private, device_list);
 641                if (device->index == n)
 642                        break;
 643        }
 644
 645        spin_unlock(&devices_lock);
 646
 647        if (device && device->index == n) {
 648                printk(ERR "Device %u already configured\n", n);
 649                return 1;
 650        }
 651
 652        new = alloc_bootmem(sizeof(*new));
 653        if (new == NULL) {
 654                printk(ERR "Alloc_bootmem failed\n");
 655                return 1;
 656        }
 657
 658        INIT_LIST_HEAD(&new->list);
 659        new->index = n;
 660        new->init = str + 1;
 661
 662        list_add_tail(&new->list, &eth_cmd_line);
 663        return 1;
 664}
 665
 666#undef ERR
 667
 668__setup("eth", iss_net_setup);
 669
 670/*
 671 * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
 672 */
 673
 674static int iss_net_init(void)
 675{
 676        struct list_head *ele, *next;
 677
 678        /* Walk through all Ethernet devices specified in the command line. */
 679
 680        list_for_each_safe(ele, next, &eth_cmd_line) {
 681                struct iss_net_init *eth;
 682                eth = list_entry(ele, struct iss_net_init, list);
 683                iss_net_configure(eth->index, eth->init);
 684        }
 685
 686        return 1;
 687}
 688device_initcall(iss_net_init);
 689