~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/xtensa/platforms/iss/network.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 __init 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 
778 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp