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