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