Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 964ad81c authored by David S. Miller's avatar David S. Miller
Browse files

ipconfig: Handle devices which take some time to come up.



Some network devices, particularly USB ones, take several seconds to
fully init and appear in the device list.

If the user turned ipconfig on, they are using it for NFS root or some
other early booting purpose.  So it makes no sense to just flat out
fail immediately if the device isn't found.

It also doesn't make sense to just jack up the initial wait to
something crazy like 10 seconds.

Instead, poll immediately, and then periodically once a second,
waiting for a usable device to appear.  Fail after 12 seconds.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Tested-by: default avatarChristian Pellegrin <chripell@fsfe.org>
parent 717ea4b3
Loading
Loading
Loading
Loading
+47 −10
Original line number Diff line number Diff line
@@ -187,6 +187,16 @@ struct ic_device {
static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
static struct net_device *ic_dev __initdata = NULL;	/* Selected device */

static bool __init ic_device_match(struct net_device *dev)
{
	if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
	    (!(dev->flags & IFF_LOOPBACK) &&
	     (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
	     strncmp(dev->name, "dummy", 5)))
		return true;
	return false;
}

static int __init ic_open_devs(void)
{
	struct ic_device *d, **last;
@@ -207,10 +217,7 @@ static int __init ic_open_devs(void)
	for_each_netdev(&init_net, dev) {
		if (dev->flags & IFF_LOOPBACK)
			continue;
		if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
		    (!(dev->flags & IFF_LOOPBACK) &&
		     (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
		     strncmp(dev->name, "dummy", 5))) {
		if (ic_device_match(dev)) {
			int able = 0;
			if (dev->mtu >= 364)
				able |= IC_BOOTP;
@@ -228,7 +235,7 @@ static int __init ic_open_devs(void)
			}
			if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
				rtnl_unlock();
				return -1;
				return -ENOMEM;
			}
			d->dev = dev;
			*last = d;
@@ -253,7 +260,7 @@ static int __init ic_open_devs(void)
			printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
		else
			printk(KERN_ERR "IP-Config: No network devices available.\n");
		return -1;
		return -ENODEV;
	}
	return 0;
}
@@ -1303,6 +1310,32 @@ __be32 __init root_nfs_parse_addr(char *name)
	return addr;
}

#define DEVICE_WAIT_MAX		12 /* 12 seconds */

static int __init wait_for_devices(void)
{
	int i;

	msleep(CONF_PRE_OPEN);
	for (i = 0; i < DEVICE_WAIT_MAX; i++) {
		struct net_device *dev;
		int found = 0;

		rtnl_lock();
		for_each_netdev(&init_net, dev) {
			if (ic_device_match(dev)) {
				found = 1;
				break;
			}
		}
		rtnl_unlock();
		if (found)
			return 0;
		ssleep(1);
	}
	return -ENODEV;
}

/*
 *	IP Autoconfig dispatcher.
 */
@@ -1313,6 +1346,7 @@ static int __init ip_auto_config(void)
#ifdef IPCONFIG_DYNAMIC
	int retries = CONF_OPEN_RETRIES;
#endif
	int err;

#ifdef CONFIG_PROC_FS
	proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops);
@@ -1325,12 +1359,15 @@ static int __init ip_auto_config(void)
#ifdef IPCONFIG_DYNAMIC
 try_try_again:
#endif
	/* Give hardware a chance to settle */
	msleep(CONF_PRE_OPEN);
	/* Wait for devices to appear */
	err = wait_for_devices();
	if (err)
		return err;

	/* Setup all network devices */
	if (ic_open_devs() < 0)
		return -1;
	err = ic_open_devs();
	if (err)
		return err;

	/* Give drivers a chance to settle */
	ssleep(CONF_POST_OPEN);