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#define pr_fmt(fmt) "%s: " fmt, __func__
  20
  21#include <linux/list.h>
  22#include <linux/irq.h>
  23#include <linux/spinlock.h>
  24#include <linux/slab.h>
  25#include <linux/timer.h>
  26#include <linux/if_ether.h>
  27#include <linux/inetdevice.h>
  28#include <linux/init.h>
  29#include <linux/if_tun.h>
  30#include <linux/etherdevice.h>
  31#include <linux/interrupt.h>
  32#include <linux/ioctl.h>
  33#include <linux/memblock.h>
  34#include <linux/ethtool.h>
  35#include <linux/rtnetlink.h>
  36#include <linux/platform_device.h>
  37
  38#include <platform/simcall.h>
  39
  40#define DRIVER_NAME "iss-netdev"
  41#define ETH_MAX_PACKET 1500
  42#define ETH_HEADER_OTHER 14
  43#define ISS_NET_TIMER_VALUE (HZ / 10)
  44
  45
  46static DEFINE_SPINLOCK(opened_lock);
  47static LIST_HEAD(opened);
  48
  49static DEFINE_SPINLOCK(devices_lock);
  50static LIST_HEAD(devices);
  51
  52/* ------------------------------------------------------------------------- */
  53
  54/* We currently only support the TUNTAP transport protocol. */
  55
  56#define TRANSPORT_TUNTAP_NAME "tuntap"
  57#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
  58
  59struct tuntap_info {
  60        char dev_name[IFNAMSIZ];
  61        int fd;
  62};
  63
  64/* ------------------------------------------------------------------------- */
  65
  66
  67/* This structure contains out private information for the driver. */
  68
  69struct iss_net_private {
  70        struct list_head device_list;
  71        struct list_head opened_list;
  72
  73        spinlock_t lock;
  74        struct net_device *dev;
  75        struct platform_device pdev;
  76        struct timer_list tl;
  77        struct net_device_stats stats;
  78
  79        struct timer_list timer;
  80        unsigned int timer_val;
  81
  82        int index;
  83        int mtu;
  84
  85        struct {
  86                union {
  87                        struct tuntap_info tuntap;
  88                } info;
  89
  90                int (*open)(struct iss_net_private *lp);
  91                void (*close)(struct iss_net_private *lp);
  92                int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
  93                int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
  94                unsigned short (*protocol)(struct sk_buff *skb);
  95                int (*poll)(struct iss_net_private *lp);
  96        } tp;
  97
  98};
  99
 100/* ================================ HELPERS ================================ */
 101
 102
 103static char *split_if_spec(char *str, ...)
 104{
 105        char **arg, *end;
 106        va_list ap;
 107
 108        va_start(ap, str);
 109        while ((arg = va_arg(ap, char**)) != NULL) {
 110                if (*str == '\0') {
 111                        va_end(ap);
 112                        return NULL;
 113                }
 114                end = strchr(str, ',');
 115                if (end != str)
 116                        *arg = str;
 117                if (end == NULL) {
 118                        va_end(ap);
 119                        return NULL;
 120                }
 121                *end++ = '\0';
 122                str = end;
 123        }
 124        va_end(ap);
 125        return str;
 126}
 127
 128/* Set Ethernet address of the specified device. */
 129
 130static void setup_etheraddr(struct net_device *dev, char *str)
 131{
 132        unsigned char *addr = dev->dev_addr;
 133
 134        if (str == NULL)
 135                goto random;
 136
 137        if (!mac_pton(str, addr)) {
 138                pr_err("%s: failed to parse '%s' as an ethernet address\n",
 139                       dev->name, str);
 140                goto random;
 141        }
 142        if (is_multicast_ether_addr(addr)) {
 143                pr_err("%s: attempt to assign a multicast ethernet address\n",
 144                       dev->name);
 145                goto random;
 146        }
 147        if (!is_valid_ether_addr(addr)) {
 148                pr_err("%s: attempt to assign an invalid ethernet address\n",
 149                       dev->name);
 150                goto random;
 151        }
 152        if (!is_local_ether_addr(addr))
 153                pr_warn("%s: assigning a globally valid ethernet address\n",
 154                        dev->name);
 155        return;
 156
 157random:
 158        pr_info("%s: choosing a random ethernet address\n",
 159                dev->name);
 160        eth_hw_addr_random(dev);
 161}
 162
 163/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
 164
 165static int tuntap_open(struct iss_net_private *lp)
 166{
 167        struct ifreq ifr;
 168        char *dev_name = lp->tp.info.tuntap.dev_name;
 169        int err = -EINVAL;
 170        int fd;
 171
 172        fd = simc_open("/dev/net/tun", 02, 0); /* O_RDWR */
 173        if (fd < 0) {
 174                pr_err("%s: failed to open /dev/net/tun, returned %d (errno = %d)\n",
 175                       lp->dev->name, fd, errno);
 176                return fd;
 177        }
 178
 179        memset(&ifr, 0, sizeof(ifr));
 180        ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
 181        strlcpy(ifr.ifr_name, dev_name, sizeof(ifr.ifr_name));
 182
 183        err = simc_ioctl(fd, TUNSETIFF, &ifr);
 184        if (err < 0) {
 185                pr_err("%s: failed to set interface %s, returned %d (errno = %d)\n",
 186                       lp->dev->name, dev_name, err, errno);
 187                simc_close(fd);
 188                return err;
 189        }
 190
 191        lp->tp.info.tuntap.fd = fd;
 192        return err;
 193}
 194
 195static void tuntap_close(struct iss_net_private *lp)
 196{
 197        simc_close(lp->tp.info.tuntap.fd);
 198        lp->tp.info.tuntap.fd = -1;
 199}
 200
 201static int tuntap_read(struct iss_net_private *lp, struct sk_buff **skb)
 202{
 203        return simc_read(lp->tp.info.tuntap.fd,
 204                        (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
 205}
 206
 207static int tuntap_write(struct iss_net_private *lp, struct sk_buff **skb)
 208{
 209        return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
 210}
 211
 212unsigned short tuntap_protocol(struct sk_buff *skb)
 213{
 214        return eth_type_trans(skb, skb->dev);
 215}
 216
 217static int tuntap_poll(struct iss_net_private *lp)
 218{
 219        return simc_poll(lp->tp.info.tuntap.fd);
 220}
 221
 222/*
 223 * ethX=tuntap,[mac address],device name
 224 */
 225
 226static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
 227{
 228        struct net_device *dev = lp->dev;
 229        char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
 230
 231        /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
 232
 233        if (strncmp(init, TRANSPORT_TUNTAP_NAME,
 234                    sizeof(TRANSPORT_TUNTAP_NAME) - 1))
 235                return 0;
 236
 237        init += sizeof(TRANSPORT_TUNTAP_NAME) - 1;
 238        if (*init == ',') {
 239                rem = split_if_spec(init + 1, &mac_str, &dev_name);
 240                if (rem != NULL) {
 241                        pr_err("%s: extra garbage on specification : '%s'\n",
 242                               dev->name, rem);
 243                        return 0;
 244                }
 245        } else if (*init != '\0') {
 246                pr_err("%s: invalid argument: %s. Skipping device!\n",
 247                       dev->name, init);
 248                return 0;
 249        }
 250
 251        if (!dev_name) {
 252                pr_err("%s: missing tuntap device name\n", dev->name);
 253                return 0;
 254        }
 255
 256        strlcpy(lp->tp.info.tuntap.dev_name, dev_name,
 257                sizeof(lp->tp.info.tuntap.dev_name));
 258
 259        setup_etheraddr(dev, mac_str);
 260
 261        lp->mtu = TRANSPORT_TUNTAP_MTU;
 262
 263        lp->tp.info.tuntap.fd = -1;
 264
 265        lp->tp.open = tuntap_open;
 266        lp->tp.close = tuntap_close;
 267        lp->tp.read = tuntap_read;
 268        lp->tp.write = tuntap_write;
 269        lp->tp.protocol = tuntap_protocol;
 270        lp->tp.poll = tuntap_poll;
 271
 272        return 1;
 273}
 274
 275/* ================================ ISS NET ================================ */
 276
 277static int iss_net_rx(struct net_device *dev)
 278{
 279        struct iss_net_private *lp = netdev_priv(dev);
 280        int pkt_len;
 281        struct sk_buff *skb;
 282
 283        /* Check if there is any new data. */
 284
 285        if (lp->tp.poll(lp) == 0)
 286                return 0;
 287
 288        /* Try to allocate memory, if it fails, try again next round. */
 289
 290        skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER);
 291        if (skb == NULL) {
 292                lp->stats.rx_dropped++;
 293                return 0;
 294        }
 295
 296        skb_reserve(skb, 2);
 297
 298        /* Setup skb */
 299
 300        skb->dev = dev;
 301        skb_reset_mac_header(skb);
 302        pkt_len = lp->tp.read(lp, &skb);
 303        skb_put(skb, pkt_len);
 304
 305        if (pkt_len > 0) {
 306                skb_trim(skb, pkt_len);
 307                skb->protocol = lp->tp.protocol(skb);
 308
 309                lp->stats.rx_bytes += skb->len;
 310                lp->stats.rx_packets++;
 311                netif_rx_ni(skb);
 312                return pkt_len;
 313        }
 314        kfree_skb(skb);
 315        return pkt_len;
 316}
 317
 318static int iss_net_poll(void)
 319{
 320        struct list_head *ele;
 321        int err, ret = 0;
 322
 323        spin_lock(&opened_lock);
 324
 325        list_for_each(ele, &opened) {
 326                struct iss_net_private *lp;
 327
 328                lp = list_entry(ele, struct iss_net_private, opened_list);
 329
 330                if (!netif_running(lp->dev))
 331                        break;
 332
 333                spin_lock(&lp->lock);
 334
 335                while ((err = iss_net_rx(lp->dev)) > 0)
 336                        ret++;
 337
 338                spin_unlock(&lp->lock);
 339
 340                if (err < 0) {
 341                        pr_err("Device '%s' read returned %d, shutting it down\n",
 342                               lp->dev->name, err);
 343                        dev_close(lp->dev);
 344                } else {
 345                        /* FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); */
 346                }
 347        }
 348
 349        spin_unlock(&opened_lock);
 350        return ret;
 351}
 352
 353
 354static void iss_net_timer(struct timer_list *t)
 355{
 356        struct iss_net_private *lp = from_timer(lp, t, timer);
 357
 358        iss_net_poll();
 359        spin_lock(&lp->lock);
 360        mod_timer(&lp->timer, jiffies + lp->timer_val);
 361        spin_unlock(&lp->lock);
 362}
 363
 364
 365static int iss_net_open(struct net_device *dev)
 366{
 367        struct iss_net_private *lp = netdev_priv(dev);
 368        int err;
 369
 370        spin_lock_bh(&lp->lock);
 371
 372        err = lp->tp.open(lp);
 373        if (err < 0)
 374                goto out;
 375
 376        netif_start_queue(dev);
 377
 378        /* clear buffer - it can happen that the host side of the interface
 379         * is full when we get here. In this case, new data is never queued,
 380         * SIGIOs never arrive, and the net never works.
 381         */
 382        while ((err = iss_net_rx(dev)) > 0)
 383                ;
 384
 385        spin_unlock_bh(&lp->lock);
 386        spin_lock_bh(&opened_lock);
 387        list_add(&lp->opened_list, &opened);
 388        spin_unlock_bh(&opened_lock);
 389        spin_lock_bh(&lp->lock);
 390
 391        timer_setup(&lp->timer, iss_net_timer, 0);
 392        lp->timer_val = ISS_NET_TIMER_VALUE;
 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                netif_trans_update(dev);
 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(struct timer_list *unused)
 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        timer_setup(&lp->tl, iss_net_user_timer_expire, 0);
 586
 587        return 0;
 588
 589errout:
 590        /* FIXME: unregister; free, etc.. */
 591        return -EIO;
 592}
 593
 594/* ------------------------------------------------------------------------- */
 595
 596/* Filled in during early boot */
 597
 598struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
 599
 600struct iss_net_init {
 601        struct list_head list;
 602        char *init;             /* init string */
 603        int index;
 604};
 605
 606/*
 607 * Parse the command line and look for 'ethX=...' fields, and register all
 608 * those fields. They will be later initialized in iss_net_init.
 609 */
 610
 611static int __init iss_net_setup(char *str)
 612{
 613        struct iss_net_private *device = NULL;
 614        struct iss_net_init *new;
 615        struct list_head *ele;
 616        char *end;
 617        int rc;
 618        unsigned n;
 619
 620        end = strchr(str, '=');
 621        if (!end) {
 622                pr_err("Expected '=' after device number\n");
 623                return 1;
 624        }
 625        *end = 0;
 626        rc = kstrtouint(str, 0, &n);
 627        *end = '=';
 628        if (rc < 0) {
 629                pr_err("Failed to parse '%s'\n", str);
 630                return 1;
 631        }
 632        str = end;
 633
 634        spin_lock(&devices_lock);
 635
 636        list_for_each(ele, &devices) {
 637                device = list_entry(ele, struct iss_net_private, device_list);
 638                if (device->index == n)
 639                        break;
 640        }
 641
 642        spin_unlock(&devices_lock);
 643
 644        if (device && device->index == n) {
 645                pr_err("Device %u already configured\n", n);
 646                return 1;
 647        }
 648
 649        new = memblock_alloc(sizeof(*new), SMP_CACHE_BYTES);
 650        if (new == NULL) {
 651                pr_err("Alloc_bootmem failed\n");
 652                return 1;
 653        }
 654
 655        INIT_LIST_HEAD(&new->list);
 656        new->index = n;
 657        new->init = str + 1;
 658
 659        list_add_tail(&new->list, &eth_cmd_line);
 660        return 1;
 661}
 662
 663__setup("eth", iss_net_setup);
 664
 665/*
 666 * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
 667 */
 668
 669static int iss_net_init(void)
 670{
 671        struct list_head *ele, *next;
 672
 673        /* Walk through all Ethernet devices specified in the command line. */
 674
 675        list_for_each_safe(ele, next, &eth_cmd_line) {
 676                struct iss_net_init *eth;
 677                eth = list_entry(ele, struct iss_net_init, list);
 678                iss_net_configure(eth->index, eth->init);
 679        }
 680
 681        return 1;
 682}
 683device_initcall(iss_net_init);
 684