]> Pileus Git - ~andy/linux/blob - arch/xtensa/platforms/iss/network.c
Merge tag 'for-v3.8' of git://git.infradead.org/users/cbou/linux-pstore
[~andy/linux] / arch / xtensa / platforms / iss / network.c
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 (2 * HZ)
42
43
44 static DEFINE_SPINLOCK(opened_lock);
45 static LIST_HEAD(opened);
46
47 static DEFINE_SPINLOCK(devices_lock);
48 static 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
57 struct tuntap_info {
58         char dev_name[IFNAMSIZ];
59         int fixed_config;
60         unsigned char gw[ETH_ALEN];
61         int fd;
62 };
63
64 /* ------------------------------------------------------------------------- */
65
66
67 /* This structure contains out private information for the driver. */
68
69 struct iss_net_private {
70
71         struct list_head device_list;
72         struct list_head opened_list;
73
74         spinlock_t lock;
75         struct net_device *dev;
76         struct platform_device pdev;
77         struct timer_list tl;
78         struct net_device_stats stats;
79
80         struct timer_list timer;
81         unsigned int timer_val;
82
83         int index;
84         int mtu;
85
86         unsigned char mac[ETH_ALEN];
87         int have_mac;
88
89         struct {
90                 union {
91                         struct tuntap_info tuntap;
92                 } info;
93
94                 int (*open)(struct iss_net_private *lp);
95                 void (*close)(struct iss_net_private *lp);
96                 int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
97                 int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
98                 unsigned short (*protocol)(struct sk_buff *skb);
99                 int (*poll)(struct iss_net_private *lp);
100         } tp;
101
102 };
103
104 /* ================================ HELPERS ================================ */
105
106
107 static char *split_if_spec(char *str, ...)
108 {
109         char **arg, *end;
110         va_list ap;
111
112         va_start(ap, str);
113         while ((arg = va_arg(ap, char**)) != NULL) {
114                 if (*str == '\0')
115                         return NULL;
116                 end = strchr(str, ',');
117                 if (end != str)
118                         *arg = str;
119                 if (end == NULL)
120                         return NULL;
121                 *end ++ = '\0';
122                 str = end;
123         }
124         va_end(ap);
125         return str;
126 }
127
128
129 #if 0
130 /* Adjust SKB. */
131
132 struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
133 {
134         if ((skb != NULL) && (skb_tailroom(skb) < extra)) {
135                 struct sk_buff *skb2;
136
137                 skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
138                 dev_kfree_skb(skb);
139                 skb = skb2;
140         }
141         if (skb != NULL)
142                 skb_put(skb, extra);
143
144         return skb;
145 }
146 #endif
147
148 /* Return the IP address as a string for a given device. */
149
150 static void dev_ip_addr(void *d, char *buf, char *bin_buf)
151 {
152         struct net_device *dev = d;
153         struct in_device *ip = dev->ip_ptr;
154         struct in_ifaddr *in;
155         __be32 addr;
156
157         if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
158                 printk(KERN_WARNING "Device not assigned an IP address!\n");
159                 return;
160         }
161
162         addr = in->ifa_address;
163         sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
164                 (addr >> 16) & 0xff, addr >> 24);
165
166         if (bin_buf) {
167                 bin_buf[0] = addr & 0xff;
168                 bin_buf[1] = (addr >> 8) & 0xff;
169                 bin_buf[2] = (addr >> 16) & 0xff;
170                 bin_buf[3] = addr >> 24;
171         }
172 }
173
174 /* Set Ethernet address of the specified device. */
175
176 static void inline set_ether_mac(void *d, unsigned char *addr)
177 {
178         struct net_device *dev = d;
179         memcpy(dev->dev_addr, addr, ETH_ALEN);
180 }
181
182
183 /* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
184
185 static int tuntap_open(struct iss_net_private *lp)
186 {
187         struct ifreq ifr;
188         char *dev_name = lp->tp.info.tuntap.dev_name;
189         int err = -EINVAL;
190         int fd;
191
192         /* We currently only support a fixed configuration. */
193
194         if (!lp->tp.info.tuntap.fixed_config)
195                 return -EINVAL;
196
197         if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) {      /* O_RDWR */
198                 printk("Failed to open /dev/net/tun, returned %d "
199                        "(errno = %d)\n", fd, errno);
200                 return fd;
201         }
202
203         memset(&ifr, 0, sizeof ifr);
204         ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
205         strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name);
206
207         if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
208                 printk("Failed to set interface, returned %d "
209                        "(errno = %d)\n", err, errno);
210                 simc_close(fd);
211                 return err;
212         }
213
214         lp->tp.info.tuntap.fd = fd;
215         return err;
216 }
217
218 static void tuntap_close(struct iss_net_private *lp)
219 {
220 #if 0
221         if (lp->tp.info.tuntap.fixed_config)
222                 iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);
223 #endif
224         simc_close(lp->tp.info.tuntap.fd);
225         lp->tp.info.tuntap.fd = -1;
226 }
227
228 static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb)
229 {
230 #if 0
231         *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
232         if (*skb == NULL)
233                 return -ENOMEM;
234 #endif
235
236         return simc_read(lp->tp.info.tuntap.fd,
237                         (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
238 }
239
240 static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb)
241 {
242         return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
243 }
244
245 unsigned short tuntap_protocol(struct sk_buff *skb)
246 {
247         return eth_type_trans(skb, skb->dev);
248 }
249
250 static int tuntap_poll(struct iss_net_private *lp)
251 {
252         return simc_poll(lp->tp.info.tuntap.fd);
253 }
254
255 /*
256  * Currently only a device name is supported.
257  * ethX=tuntap[,[mac address][,[device name]]]
258  */
259
260 static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
261 {
262         const int len = strlen(TRANSPORT_TUNTAP_NAME);
263         char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
264
265         /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
266
267         if (strncmp(init, TRANSPORT_TUNTAP_NAME, len))
268                 return 0;
269
270         if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') {
271                 if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) {
272                         printk("Extra garbage on specification : '%s'\n", rem);
273                         return 0;
274                 }
275         } else if (*init != '\0') {
276                 printk("Invalid argument: %s. Skipping device!\n", init);
277                 return 0;
278         }
279
280         if (dev_name) {
281                 strncpy(lp->tp.info.tuntap.dev_name, dev_name,
282                          sizeof lp->tp.info.tuntap.dev_name);
283                 lp->tp.info.tuntap.fixed_config = 1;
284         } else
285                 strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);
286
287
288 #if 0
289         if (setup_etheraddr(mac_str, lp->mac))
290                 lp->have_mac = 1;
291 #endif
292         lp->mtu = TRANSPORT_TUNTAP_MTU;
293
294         //lp->info.tuntap.gate_addr = gate_addr;
295
296         lp->tp.info.tuntap.fd = -1;
297
298         lp->tp.open = tuntap_open;
299         lp->tp.close = tuntap_close;
300         lp->tp.read = tuntap_read;
301         lp->tp.write = tuntap_write;
302         lp->tp.protocol = tuntap_protocol;
303         lp->tp.poll = tuntap_poll;
304
305         printk("TUN/TAP backend - ");
306 #if 0
307         if (lp->host.gate_addr != NULL)
308                 printk("IP = %s", lp->host.gate_addr);
309 #endif
310         printk("\n");
311
312         return 1;
313 }
314
315 /* ================================ ISS NET ================================ */
316
317 static int iss_net_rx(struct net_device *dev)
318 {
319         struct iss_net_private *lp = netdev_priv(dev);
320         int pkt_len;
321         struct sk_buff *skb;
322
323         /* Check if there is any new data. */
324
325         if (lp->tp.poll(lp) == 0)
326                 return 0;
327
328         /* Try to allocate memory, if it fails, try again next round. */
329
330         if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) {
331                 lp->stats.rx_dropped++;
332                 return 0;
333         }
334
335         skb_reserve(skb, 2);
336
337         /* Setup skb */
338
339         skb->dev = dev;
340         skb_reset_mac_header(skb);
341         pkt_len = lp->tp.read(lp, &skb);
342         skb_put(skb, pkt_len);
343
344         if (pkt_len > 0) {
345                 skb_trim(skb, pkt_len);
346                 skb->protocol = lp->tp.protocol(skb);
347
348                 lp->stats.rx_bytes += skb->len;
349                 lp->stats.rx_packets++;
350         //      netif_rx(skb);
351                 netif_rx_ni(skb);
352                 return pkt_len;
353         }
354         kfree_skb(skb);
355         return pkt_len;
356 }
357
358 static int iss_net_poll(void)
359 {
360         struct list_head *ele;
361         int err, ret = 0;
362
363         spin_lock(&opened_lock);
364
365         list_for_each(ele, &opened) {
366                 struct iss_net_private *lp;
367
368                 lp = list_entry(ele, struct iss_net_private, opened_list);
369
370                 if (!netif_running(lp->dev))
371                         break;
372
373                 spin_lock(&lp->lock);
374
375                 while ((err = iss_net_rx(lp->dev)) > 0)
376                         ret++;
377
378                 spin_unlock(&lp->lock);
379
380                 if (err < 0) {
381                         printk(KERN_ERR "Device '%s' read returned %d, "
382                                "shutting it down\n", lp->dev->name, err);
383                         dev_close(lp->dev);
384                 } else {
385                         // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ);
386                 }
387         }
388
389         spin_unlock(&opened_lock);
390         return ret;
391 }
392
393
394 static void iss_net_timer(unsigned long priv)
395 {
396         struct iss_net_private* lp = (struct iss_net_private*) priv;
397
398         spin_lock(&lp->lock);
399
400         iss_net_poll();
401
402         mod_timer(&lp->timer, jiffies + lp->timer_val);
403
404         spin_unlock(&lp->lock);
405 }
406
407
408 static int iss_net_open(struct net_device *dev)
409 {
410         struct iss_net_private *lp = netdev_priv(dev);
411         char addr[sizeof "255.255.255.255\0"];
412         int err;
413
414         spin_lock(&lp->lock);
415
416         if ((err = lp->tp.open(lp)) < 0)
417                 goto out;
418
419         if (!lp->have_mac) {
420                 dev_ip_addr(dev, addr, &lp->mac[2]);
421                 set_ether_mac(dev, lp->mac);
422         }
423
424         netif_start_queue(dev);
425
426         /* clear buffer - it can happen that the host side of the interface
427          * is full when we get here. In this case, new data is never queued,
428          * SIGIOs never arrive, and the net never works.
429          */
430         while ((err = iss_net_rx(dev)) > 0)
431                 ;
432
433         spin_lock(&opened_lock);
434         list_add(&lp->opened_list, &opened);
435         spin_unlock(&opened_lock);
436
437         init_timer(&lp->timer);
438         lp->timer_val = ISS_NET_TIMER_VALUE;
439         lp->timer.data = (unsigned long) lp;
440         lp->timer.function = iss_net_timer;
441         mod_timer(&lp->timer, jiffies + lp->timer_val);
442
443 out:
444         spin_unlock(&lp->lock);
445         return err;
446 }
447
448 static int iss_net_close(struct net_device *dev)
449 {
450         struct iss_net_private *lp = netdev_priv(dev);
451 printk("iss_net_close!\n");
452         netif_stop_queue(dev);
453         spin_lock(&lp->lock);
454
455         spin_lock(&opened_lock);
456         list_del(&opened);
457         spin_unlock(&opened_lock);
458
459         del_timer_sync(&lp->timer);
460
461         lp->tp.close(lp);
462
463         spin_unlock(&lp->lock);
464         return 0;
465 }
466
467 static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
468 {
469         struct iss_net_private *lp = netdev_priv(dev);
470         unsigned long flags;
471         int len;
472
473         netif_stop_queue(dev);
474         spin_lock_irqsave(&lp->lock, flags);
475
476         len = lp->tp.write(lp, &skb);
477
478         if (len == skb->len) {
479                 lp->stats.tx_packets++;
480                 lp->stats.tx_bytes += skb->len;
481                 dev->trans_start = jiffies;
482                 netif_start_queue(dev);
483
484                 /* this is normally done in the interrupt when tx finishes */
485                 netif_wake_queue(dev);
486
487         } else if (len == 0) {
488                 netif_start_queue(dev);
489                 lp->stats.tx_dropped++;
490
491         } else {
492                 netif_start_queue(dev);
493                 printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len);
494         }
495
496         spin_unlock_irqrestore(&lp->lock, flags);
497
498         dev_kfree_skb(skb);
499         return NETDEV_TX_OK;
500 }
501
502
503 static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
504 {
505         struct iss_net_private *lp = netdev_priv(dev);
506         return &lp->stats;
507 }
508
509 static void iss_net_set_multicast_list(struct net_device *dev)
510 {
511 #if 0
512         if (dev->flags & IFF_PROMISC)
513                 return;
514         else if (!netdev_mc_empty(dev))
515                 dev->flags |= IFF_ALLMULTI;
516         else
517                 dev->flags &= ~IFF_ALLMULTI;
518 #endif
519 }
520
521 static void iss_net_tx_timeout(struct net_device *dev)
522 {
523 #if 0
524         dev->trans_start = jiffies;
525         netif_wake_queue(dev);
526 #endif
527 }
528
529 static int iss_net_set_mac(struct net_device *dev, void *addr)
530 {
531 #if 0
532         struct iss_net_private *lp = netdev_priv(dev);
533         struct sockaddr *hwaddr = addr;
534
535         spin_lock(&lp->lock);
536         memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
537         spin_unlock(&lp->lock);
538 #endif
539
540         return 0;
541 }
542
543 static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
544 {
545 #if 0
546         struct iss_net_private *lp = netdev_priv(dev);
547         int err = 0;
548
549         spin_lock(&lp->lock);
550
551         // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user);
552
553         if (new_mtu < 0)
554                 err = new_mtu;
555         else
556                 dev->mtu = new_mtu;
557
558         spin_unlock(&lp->lock);
559         return err;
560 #endif
561         return -EINVAL;
562 }
563
564 void iss_net_user_timer_expire(unsigned long _conn)
565 {
566 }
567
568
569 static struct platform_driver iss_net_driver = {
570         .driver = {
571                 .name  = DRIVER_NAME,
572         },
573 };
574
575 static int driver_registered;
576
577 static const struct net_device_ops iss_netdev_ops = {
578         .ndo_open               = iss_net_open,
579         .ndo_stop               = iss_net_close,
580         .ndo_get_stats          = iss_net_get_stats,
581         .ndo_start_xmit         = iss_net_start_xmit,
582         .ndo_validate_addr      = eth_validate_addr,
583         .ndo_change_mtu         = iss_net_change_mtu,
584         .ndo_set_mac_address    = iss_net_set_mac,
585         //.ndo_do_ioctl         = iss_net_ioctl,
586         .ndo_tx_timeout         = iss_net_tx_timeout,
587         .ndo_set_rx_mode        = iss_net_set_multicast_list,
588 };
589
590 static int iss_net_configure(int index, char *init)
591 {
592         struct net_device *dev;
593         struct iss_net_private *lp;
594         int err;
595
596         if ((dev = alloc_etherdev(sizeof *lp)) == NULL) {
597                 printk(KERN_ERR "eth_configure: failed to allocate device\n");
598                 return 1;
599         }
600
601         /* Initialize private element. */
602
603         lp = netdev_priv(dev);
604         *lp = ((struct iss_net_private) {
605                 .device_list            = LIST_HEAD_INIT(lp->device_list),
606                 .opened_list            = LIST_HEAD_INIT(lp->opened_list),
607                 .lock                   = __SPIN_LOCK_UNLOCKED(lp.lock),
608                 .dev                    = dev,
609                 .index                  = index,
610                 //.fd                   = -1,
611                 .mac                    = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
612                 .have_mac               = 0,
613                 });
614
615         /*
616          * Try all transport protocols.
617          * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
618          */
619
620         if (!tuntap_probe(lp, index, init)) {
621                 printk("Invalid arguments. Skipping device!\n");
622                 goto errout;
623         }
624
625         printk(KERN_INFO "Netdevice %d ", index);
626         if (lp->have_mac)
627                 printk("(%pM) ", lp->mac);
628         printk(": ");
629
630         /* sysfs register */
631
632         if (!driver_registered) {
633                 platform_driver_register(&iss_net_driver);
634                 driver_registered = 1;
635         }
636
637         spin_lock(&devices_lock);
638         list_add(&lp->device_list, &devices);
639         spin_unlock(&devices_lock);
640
641         lp->pdev.id = index;
642         lp->pdev.name = DRIVER_NAME;
643         platform_device_register(&lp->pdev);
644         SET_NETDEV_DEV(dev,&lp->pdev.dev);
645
646         /*
647          * If this name ends up conflicting with an existing registered
648          * netdevice, that is OK, register_netdev{,ice}() will notice this
649          * and fail.
650          */
651         snprintf(dev->name, sizeof dev->name, "eth%d", index);
652
653         dev->netdev_ops = &iss_netdev_ops;
654         dev->mtu = lp->mtu;
655         dev->watchdog_timeo = (HZ >> 1);
656         dev->irq = -1;
657
658         rtnl_lock();
659         err = register_netdevice(dev);
660         rtnl_unlock();
661
662         if (err) {
663                 printk("Error registering net device!\n");
664                 /* XXX: should we call ->remove() here? */
665                 free_netdev(dev);
666                 return 1;
667         }
668
669         init_timer(&lp->tl);
670         lp->tl.function = iss_net_user_timer_expire;
671
672 #if 0
673         if (lp->have_mac)
674                 set_ether_mac(dev, lp->mac);
675 #endif
676         return 0;
677
678 errout:
679         // FIXME: unregister; free, etc..
680         return -EIO;
681
682 }
683
684 /* ------------------------------------------------------------------------- */
685
686 /* Filled in during early boot */
687
688 struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
689
690 struct iss_net_init {
691         struct list_head list;
692         char *init;             /* init string */
693         int index;
694 };
695
696 /*
697  * Parse the command line and look for 'ethX=...' fields, and register all
698  * those fields. They will be later initialized in iss_net_init.
699  */
700
701 #define ERR KERN_ERR "iss_net_setup: "
702
703 static int iss_net_setup(char *str)
704 {
705         struct iss_net_private *device = NULL;
706         struct iss_net_init *new;
707         struct list_head *ele;
708         char *end;
709         int n;
710
711         n = simple_strtoul(str, &end, 0);
712         if (end == str) {
713                 printk(ERR "Failed to parse '%s'\n", str);
714                 return 1;
715         }
716         if (n < 0) {
717                 printk(ERR "Device %d is negative\n", n);
718                 return 1;
719         }
720         if (*(str = end) != '=') {
721                 printk(ERR "Expected '=' after device number\n");
722                 return 1;
723         }
724
725         spin_lock(&devices_lock);
726
727         list_for_each(ele, &devices) {
728                 device = list_entry(ele, struct iss_net_private, device_list);
729                 if (device->index == n)
730                         break;
731         }
732
733         spin_unlock(&devices_lock);
734
735         if (device && device->index == n) {
736                 printk(ERR "Device %d already configured\n", n);
737                 return 1;
738         }
739
740         if ((new = alloc_bootmem(sizeof new)) == NULL) {
741                 printk("Alloc_bootmem failed\n");
742                 return 1;
743         }
744
745         INIT_LIST_HEAD(&new->list);
746         new->index = n;
747         new->init = str + 1;
748
749         list_add_tail(&new->list, &eth_cmd_line);
750         return 1;
751 }
752
753 #undef ERR
754
755 __setup("eth=", iss_net_setup);
756
757 /*
758  * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
759  */
760
761 static int iss_net_init(void)
762 {
763         struct list_head *ele, *next;
764
765         /* Walk through all Ethernet devices specified in the command line. */
766
767         list_for_each_safe(ele, next, &eth_cmd_line) {
768                 struct iss_net_init *eth;
769                 eth = list_entry(ele, struct iss_net_init, list);
770                 iss_net_configure(eth->index, eth->init);
771         }
772
773         return 1;
774 }
775
776 module_init(iss_net_init);
777