network.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. /*
  2. *
  3. * arch/xtensa/platform-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. #include <linux/list.h>
  19. #include <linux/irq.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/slab.h>
  22. #include <linux/timer.h>
  23. #include <linux/if_ether.h>
  24. #include <linux/inetdevice.h>
  25. #include <linux/init.h>
  26. #include <linux/if_tun.h>
  27. #include <linux/etherdevice.h>
  28. #include <linux/interrupt.h>
  29. #include <linux/ioctl.h>
  30. #include <linux/bootmem.h>
  31. #include <linux/ethtool.h>
  32. #include <linux/rtnetlink.h>
  33. #include <linux/platform_device.h>
  34. #include <asm/platform/simcall.h>
  35. #define DRIVER_NAME "iss-netdev"
  36. #define ETH_MAX_PACKET 1500
  37. #define ETH_HEADER_OTHER 14
  38. #define ISS_NET_TIMER_VALUE (2 * HZ)
  39. static DEFINE_SPINLOCK(opened_lock);
  40. static LIST_HEAD(opened);
  41. static DEFINE_SPINLOCK(devices_lock);
  42. static LIST_HEAD(devices);
  43. /* ------------------------------------------------------------------------- */
  44. /* We currently only support the TUNTAP transport protocol. */
  45. #define TRANSPORT_TUNTAP_NAME "tuntap"
  46. #define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
  47. struct tuntap_info {
  48. char dev_name[IFNAMSIZ];
  49. int fixed_config;
  50. unsigned char gw[ETH_ALEN];
  51. int fd;
  52. };
  53. /* ------------------------------------------------------------------------- */
  54. /* This structure contains out private information for the driver. */
  55. struct iss_net_private {
  56. struct list_head device_list;
  57. struct list_head opened_list;
  58. spinlock_t lock;
  59. struct net_device *dev;
  60. struct platform_device pdev;
  61. struct timer_list tl;
  62. struct net_device_stats stats;
  63. struct timer_list timer;
  64. unsigned int timer_val;
  65. int index;
  66. int mtu;
  67. unsigned char mac[ETH_ALEN];
  68. int have_mac;
  69. struct {
  70. union {
  71. struct tuntap_info tuntap;
  72. } info;
  73. int (*open)(struct iss_net_private *lp);
  74. void (*close)(struct iss_net_private *lp);
  75. int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
  76. int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
  77. unsigned short (*protocol)(struct sk_buff *skb);
  78. int (*poll)(struct iss_net_private *lp);
  79. } tp;
  80. };
  81. /* ======================= ISS SIMCALL INTERFACE =========================== */
  82. /* Note: __simc must _not_ be declared inline! */
  83. static int errno;
  84. static int __simc (int a, int b, int c, int d, int e, int f)
  85. {
  86. int ret;
  87. __asm__ __volatile__ ("simcall\n"
  88. "mov %0, a2\n"
  89. "mov %1, a3\n" : "=a" (ret), "=a" (errno)
  90. : : "a2", "a3");
  91. return ret;
  92. }
  93. static int inline simc_open(char *file, int flags, int mode)
  94. {
  95. return __simc(SYS_open, (int) file, flags, mode, 0, 0);
  96. }
  97. static int inline simc_close(int fd)
  98. {
  99. return __simc(SYS_close, fd, 0, 0, 0, 0);
  100. }
  101. static int inline simc_ioctl(int fd, int request, void *arg)
  102. {
  103. return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);
  104. }
  105. static int inline simc_read(int fd, void *buf, size_t count)
  106. {
  107. return __simc(SYS_read, fd, (int) buf, count, 0, 0);
  108. }
  109. static int inline simc_write(int fd, void *buf, size_t count)
  110. {
  111. return __simc(SYS_write, fd, (int) buf, count, 0, 0);
  112. }
  113. static int inline simc_poll(int fd)
  114. {
  115. struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
  116. return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0);
  117. }
  118. /* ================================ HELPERS ================================ */
  119. static char *split_if_spec(char *str, ...)
  120. {
  121. char **arg, *end;
  122. va_list ap;
  123. va_start(ap, str);
  124. while ((arg = va_arg(ap, char**)) != NULL) {
  125. if (*str == '\0')
  126. return NULL;
  127. end = strchr(str, ',');
  128. if (end != str)
  129. *arg = str;
  130. if (end == NULL)
  131. return NULL;
  132. *end ++ = '\0';
  133. str = end;
  134. }
  135. va_end(ap);
  136. return str;
  137. }
  138. #if 0
  139. /* Adjust SKB. */
  140. struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
  141. {
  142. if ((skb != NULL) && (skb_tailroom(skb) < extra)) {
  143. struct sk_buff *skb2;
  144. skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
  145. dev_kfree_skb(skb);
  146. skb = skb2;
  147. }
  148. if (skb != NULL)
  149. skb_put(skb, extra);
  150. return skb;
  151. }
  152. #endif
  153. /* Return the IP address as a string for a given device. */
  154. static void dev_ip_addr(void *d, char *buf, char *bin_buf)
  155. {
  156. struct net_device *dev = d;
  157. struct in_device *ip = dev->ip_ptr;
  158. struct in_ifaddr *in;
  159. __be32 addr;
  160. if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
  161. printk(KERN_WARNING "Device not assigned an IP address!\n");
  162. return;
  163. }
  164. addr = in->ifa_address;
  165. sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
  166. (addr >> 16) & 0xff, addr >> 24);
  167. if (bin_buf) {
  168. bin_buf[0] = addr & 0xff;
  169. bin_buf[1] = (addr >> 8) & 0xff;
  170. bin_buf[2] = (addr >> 16) & 0xff;
  171. bin_buf[3] = addr >> 24;
  172. }
  173. }
  174. /* Set Ethernet address of the specified device. */
  175. static void inline set_ether_mac(void *d, unsigned char *addr)
  176. {
  177. struct net_device *dev = d;
  178. memcpy(dev->dev_addr, addr, ETH_ALEN);
  179. }
  180. /* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
  181. static int tuntap_open(struct iss_net_private *lp)
  182. {
  183. struct ifreq ifr;
  184. char *dev_name = lp->tp.info.tuntap.dev_name;
  185. int err = -EINVAL;
  186. int fd;
  187. /* We currently only support a fixed configuration. */
  188. if (!lp->tp.info.tuntap.fixed_config)
  189. return -EINVAL;
  190. if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */
  191. printk("Failed to open /dev/net/tun, returned %d "
  192. "(errno = %d)\n", fd, errno);
  193. return fd;
  194. }
  195. memset(&ifr, 0, sizeof ifr);
  196. ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
  197. strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name);
  198. if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
  199. printk("Failed to set interface, returned %d "
  200. "(errno = %d)\n", err, errno);
  201. simc_close(fd);
  202. return err;
  203. }
  204. lp->tp.info.tuntap.fd = fd;
  205. return err;
  206. }
  207. static void tuntap_close(struct iss_net_private *lp)
  208. {
  209. #if 0
  210. if (lp->tp.info.tuntap.fixed_config)
  211. iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);
  212. #endif
  213. simc_close(lp->tp.info.tuntap.fd);
  214. lp->tp.info.tuntap.fd = -1;
  215. }
  216. static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb)
  217. {
  218. #if 0
  219. *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
  220. if (*skb == NULL)
  221. return -ENOMEM;
  222. #endif
  223. return simc_read(lp->tp.info.tuntap.fd,
  224. (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
  225. }
  226. static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb)
  227. {
  228. return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
  229. }
  230. unsigned short tuntap_protocol(struct sk_buff *skb)
  231. {
  232. return eth_type_trans(skb, skb->dev);
  233. }
  234. static int tuntap_poll(struct iss_net_private *lp)
  235. {
  236. return simc_poll(lp->tp.info.tuntap.fd);
  237. }
  238. /*
  239. * Currently only a device name is supported.
  240. * ethX=tuntap[,[mac address][,[device name]]]
  241. */
  242. static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
  243. {
  244. const int len = strlen(TRANSPORT_TUNTAP_NAME);
  245. char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
  246. /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
  247. if (strncmp(init, TRANSPORT_TUNTAP_NAME, len))
  248. return 0;
  249. if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') {
  250. if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) {
  251. printk("Extra garbage on specification : '%s'\n", rem);
  252. return 0;
  253. }
  254. } else if (*init != '\0') {
  255. printk("Invalid argument: %s. Skipping device!\n", init);
  256. return 0;
  257. }
  258. if (dev_name) {
  259. strncpy(lp->tp.info.tuntap.dev_name, dev_name,
  260. sizeof lp->tp.info.tuntap.dev_name);
  261. lp->tp.info.tuntap.fixed_config = 1;
  262. } else
  263. strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);
  264. #if 0
  265. if (setup_etheraddr(mac_str, lp->mac))
  266. lp->have_mac = 1;
  267. #endif
  268. lp->mtu = TRANSPORT_TUNTAP_MTU;
  269. //lp->info.tuntap.gate_addr = gate_addr;
  270. lp->tp.info.tuntap.fd = -1;
  271. lp->tp.open = tuntap_open;
  272. lp->tp.close = tuntap_close;
  273. lp->tp.read = tuntap_read;
  274. lp->tp.write = tuntap_write;
  275. lp->tp.protocol = tuntap_protocol;
  276. lp->tp.poll = tuntap_poll;
  277. printk("TUN/TAP backend - ");
  278. #if 0
  279. if (lp->host.gate_addr != NULL)
  280. printk("IP = %s", lp->host.gate_addr);
  281. #endif
  282. printk("\n");
  283. return 1;
  284. }
  285. /* ================================ ISS NET ================================ */
  286. static int iss_net_rx(struct net_device *dev)
  287. {
  288. struct iss_net_private *lp = dev->priv;
  289. int pkt_len;
  290. struct sk_buff *skb;
  291. /* Check if there is any new data. */
  292. if (lp->tp.poll(lp) == 0)
  293. return 0;
  294. /* Try to allocate memory, if it fails, try again next round. */
  295. if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) {
  296. lp->stats.rx_dropped++;
  297. return 0;
  298. }
  299. skb_reserve(skb, 2);
  300. /* Setup skb */
  301. skb->dev = dev;
  302. skb_reset_mac_header(skb);
  303. pkt_len = lp->tp.read(lp, &skb);
  304. skb_put(skb, pkt_len);
  305. if (pkt_len > 0) {
  306. skb_trim(skb, pkt_len);
  307. skb->protocol = lp->tp.protocol(skb);
  308. lp->stats.rx_bytes += skb->len;
  309. lp->stats.rx_packets++;
  310. // netif_rx(skb);
  311. netif_rx_ni(skb);
  312. return pkt_len;
  313. }
  314. kfree_skb(skb);
  315. return pkt_len;
  316. }
  317. static int iss_net_poll(void)
  318. {
  319. struct list_head *ele;
  320. int err, ret = 0;
  321. spin_lock(&opened_lock);
  322. list_for_each(ele, &opened) {
  323. struct iss_net_private *lp;
  324. lp = list_entry(ele, struct iss_net_private, opened_list);
  325. if (!netif_running(lp->dev))
  326. break;
  327. spin_lock(&lp->lock);
  328. while ((err = iss_net_rx(lp->dev)) > 0)
  329. ret++;
  330. spin_unlock(&lp->lock);
  331. if (err < 0) {
  332. printk(KERN_ERR "Device '%s' read returned %d, "
  333. "shutting it down\n", lp->dev->name, err);
  334. dev_close(lp->dev);
  335. } else {
  336. // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ);
  337. }
  338. }
  339. spin_unlock(&opened_lock);
  340. return ret;
  341. }
  342. static void iss_net_timer(unsigned long priv)
  343. {
  344. struct iss_net_private* lp = (struct iss_net_private*) priv;
  345. spin_lock(&lp->lock);
  346. iss_net_poll();
  347. mod_timer(&lp->timer, jiffies + lp->timer_val);
  348. spin_unlock(&lp->lock);
  349. }
  350. static int iss_net_open(struct net_device *dev)
  351. {
  352. struct iss_net_private *lp = dev->priv;
  353. char addr[sizeof "255.255.255.255\0"];
  354. int err;
  355. spin_lock(&lp->lock);
  356. if ((err = lp->tp.open(lp)) < 0)
  357. goto out;
  358. if (!lp->have_mac) {
  359. dev_ip_addr(dev, addr, &lp->mac[2]);
  360. set_ether_mac(dev, lp->mac);
  361. }
  362. netif_start_queue(dev);
  363. /* clear buffer - it can happen that the host side of the interface
  364. * is full when we get here. In this case, new data is never queued,
  365. * SIGIOs never arrive, and the net never works.
  366. */
  367. while ((err = iss_net_rx(dev)) > 0)
  368. ;
  369. spin_lock(&opened_lock);
  370. list_add(&lp->opened_list, &opened);
  371. spin_unlock(&opened_lock);
  372. init_timer(&lp->timer);
  373. lp->timer_val = ISS_NET_TIMER_VALUE;
  374. lp->timer.data = (unsigned long) lp;
  375. lp->timer.function = iss_net_timer;
  376. mod_timer(&lp->timer, jiffies + lp->timer_val);
  377. out:
  378. spin_unlock(&lp->lock);
  379. return err;
  380. }
  381. static int iss_net_close(struct net_device *dev)
  382. {
  383. struct iss_net_private *lp = dev->priv;
  384. printk("iss_net_close!\n");
  385. netif_stop_queue(dev);
  386. spin_lock(&lp->lock);
  387. spin_lock(&opened_lock);
  388. list_del(&opened);
  389. spin_unlock(&opened_lock);
  390. del_timer_sync(&lp->timer);
  391. lp->tp.close(lp);
  392. spin_unlock(&lp->lock);
  393. return 0;
  394. }
  395. static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
  396. {
  397. struct iss_net_private *lp = dev->priv;
  398. unsigned long flags;
  399. int len;
  400. netif_stop_queue(dev);
  401. spin_lock_irqsave(&lp->lock, flags);
  402. len = lp->tp.write(lp, &skb);
  403. if (len == skb->len) {
  404. lp->stats.tx_packets++;
  405. lp->stats.tx_bytes += skb->len;
  406. dev->trans_start = jiffies;
  407. netif_start_queue(dev);
  408. /* this is normally done in the interrupt when tx finishes */
  409. netif_wake_queue(dev);
  410. } else if (len == 0) {
  411. netif_start_queue(dev);
  412. lp->stats.tx_dropped++;
  413. } else {
  414. netif_start_queue(dev);
  415. printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len);
  416. }
  417. spin_unlock_irqrestore(&lp->lock, flags);
  418. dev_kfree_skb(skb);
  419. return 0;
  420. }
  421. static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
  422. {
  423. struct iss_net_private *lp = dev->priv;
  424. return &lp->stats;
  425. }
  426. static void iss_net_set_multicast_list(struct net_device *dev)
  427. {
  428. #if 0
  429. if (dev->flags & IFF_PROMISC)
  430. return;
  431. else if (dev->mc_count)
  432. dev->flags |= IFF_ALLMULTI;
  433. else
  434. dev->flags &= ~IFF_ALLMULTI;
  435. #endif
  436. }
  437. static void iss_net_tx_timeout(struct net_device *dev)
  438. {
  439. #if 0
  440. dev->trans_start = jiffies;
  441. netif_wake_queue(dev);
  442. #endif
  443. }
  444. static int iss_net_set_mac(struct net_device *dev, void *addr)
  445. {
  446. #if 0
  447. struct iss_net_private *lp = dev->priv;
  448. struct sockaddr *hwaddr = addr;
  449. spin_lock(&lp->lock);
  450. memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
  451. spin_unlock(&lp->lock);
  452. #endif
  453. return 0;
  454. }
  455. static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
  456. {
  457. #if 0
  458. struct iss_net_private *lp = dev->priv;
  459. int err = 0;
  460. spin_lock(&lp->lock);
  461. // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user);
  462. if (new_mtu < 0)
  463. err = new_mtu;
  464. else
  465. dev->mtu = new_mtu;
  466. spin_unlock(&lp->lock);
  467. return err;
  468. #endif
  469. return -EINVAL;
  470. }
  471. void iss_net_user_timer_expire(unsigned long _conn)
  472. {
  473. }
  474. static struct platform_driver iss_net_driver = {
  475. .driver = {
  476. .name = DRIVER_NAME,
  477. },
  478. };
  479. static int driver_registered;
  480. static int iss_net_configure(int index, char *init)
  481. {
  482. struct net_device *dev;
  483. struct iss_net_private *lp;
  484. int err;
  485. if ((dev = alloc_etherdev(sizeof *lp)) == NULL) {
  486. printk(KERN_ERR "eth_configure: failed to allocate device\n");
  487. return 1;
  488. }
  489. /* Initialize private element. */
  490. lp = dev->priv;
  491. *lp = ((struct iss_net_private) {
  492. .device_list = LIST_HEAD_INIT(lp->device_list),
  493. .opened_list = LIST_HEAD_INIT(lp->opened_list),
  494. .lock = SPIN_LOCK_UNLOCKED,
  495. .dev = dev,
  496. .index = index,
  497. //.fd = -1,
  498. .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
  499. .have_mac = 0,
  500. });
  501. /*
  502. * Try all transport protocols.
  503. * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
  504. */
  505. if (!tuntap_probe(lp, index, init)) {
  506. printk("Invalid arguments. Skipping device!\n");
  507. goto errout;
  508. }
  509. printk(KERN_INFO "Netdevice %d ", index);
  510. if (lp->have_mac)
  511. printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
  512. lp->mac[0], lp->mac[1],
  513. lp->mac[2], lp->mac[3],
  514. lp->mac[4], lp->mac[5]);
  515. printk(": ");
  516. /* sysfs register */
  517. if (!driver_registered) {
  518. platform_driver_register(&iss_net_driver);
  519. driver_registered = 1;
  520. }
  521. spin_lock(&devices_lock);
  522. list_add(&lp->device_list, &devices);
  523. spin_unlock(&devices_lock);
  524. lp->pdev.id = index;
  525. lp->pdev.name = DRIVER_NAME;
  526. platform_device_register(&lp->pdev);
  527. SET_NETDEV_DEV(dev,&lp->pdev.dev);
  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. dev->mtu = lp->mtu;
  535. dev->open = iss_net_open;
  536. dev->hard_start_xmit = iss_net_start_xmit;
  537. dev->stop = iss_net_close;
  538. dev->get_stats = iss_net_get_stats;
  539. dev->set_multicast_list = iss_net_set_multicast_list;
  540. dev->tx_timeout = iss_net_tx_timeout;
  541. dev->set_mac_address = iss_net_set_mac;
  542. dev->change_mtu = iss_net_change_mtu;
  543. dev->watchdog_timeo = (HZ >> 1);
  544. dev->irq = -1;
  545. rtnl_lock();
  546. err = register_netdevice(dev);
  547. rtnl_unlock();
  548. if (err) {
  549. printk("Error registering net device!\n");
  550. /* XXX: should we call ->remove() here? */
  551. free_netdev(dev);
  552. return 1;
  553. }
  554. init_timer(&lp->tl);
  555. lp->tl.function = iss_net_user_timer_expire;
  556. #if 0
  557. if (lp->have_mac)
  558. set_ether_mac(dev, lp->mac);
  559. #endif
  560. return 0;
  561. errout:
  562. // FIXME: unregister; free, etc..
  563. return -EIO;
  564. }
  565. /* ------------------------------------------------------------------------- */
  566. /* Filled in during early boot */
  567. struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
  568. struct iss_net_init {
  569. struct list_head list;
  570. char *init; /* init string */
  571. int index;
  572. };
  573. /*
  574. * Parse the command line and look for 'ethX=...' fields, and register all
  575. * those fields. They will be later initialized in iss_net_init.
  576. */
  577. #define ERR KERN_ERR "iss_net_setup: "
  578. static int iss_net_setup(char *str)
  579. {
  580. struct iss_net_private *device = NULL;
  581. struct iss_net_init *new;
  582. struct list_head *ele;
  583. char *end;
  584. int n;
  585. n = simple_strtoul(str, &end, 0);
  586. if (end == str) {
  587. printk(ERR "Failed to parse '%s'\n", str);
  588. return 1;
  589. }
  590. if (n < 0) {
  591. printk(ERR "Device %d is negative\n", n);
  592. return 1;
  593. }
  594. if (*(str = end) != '=') {
  595. printk(ERR "Expected '=' after device number\n");
  596. return 1;
  597. }
  598. spin_lock(&devices_lock);
  599. list_for_each(ele, &devices) {
  600. device = list_entry(ele, struct iss_net_private, device_list);
  601. if (device->index == n)
  602. break;
  603. }
  604. spin_unlock(&devices_lock);
  605. if (device && device->index == n) {
  606. printk(ERR "Device %d already configured\n", n);
  607. return 1;
  608. }
  609. if ((new = alloc_bootmem(sizeof new)) == NULL) {
  610. printk("Alloc_bootmem failed\n");
  611. return 1;
  612. }
  613. INIT_LIST_HEAD(&new->list);
  614. new->index = n;
  615. new->init = str + 1;
  616. list_add_tail(&new->list, &eth_cmd_line);
  617. return 1;
  618. }
  619. #undef ERR
  620. __setup("eth=", iss_net_setup);
  621. /*
  622. * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
  623. */
  624. static int iss_net_init(void)
  625. {
  626. struct list_head *ele, *next;
  627. /* Walk through all Ethernet devices specified in the command line. */
  628. list_for_each_safe(ele, next, &eth_cmd_line) {
  629. struct iss_net_init *eth;
  630. eth = list_entry(ele, struct iss_net_init, list);
  631. iss_net_configure(eth->index, eth->init);
  632. }
  633. return 1;
  634. }
  635. module_init(iss_net_init);