2000-12-08 18:32:43

by Matthew Galgoci

[permalink] [raw]
Subject: cardbus pirq conflict

Hi Folks,

I am running the 2.4.0test12pre7 kernel on my laptop computer, and
I'm having some rather interesting problems.

For the longest time, usb never worked on this machine. As of the
happy patch that enabled bus mastering for usb controllers, it
magically started working. I am really happy that it does work
now.

The usb controller and the pcmcia bridge both share the same
irq, irq 10.

Now, my cardbus cards have stopped working. When I insert a cardbus
nic, I get the following message: "IRQ routing conflict in pirq
table! Try 'pci=autoirq'"

The card fails to initialize, and upon issuing the halt command, the
system generates a kernel Oops. I tend to think that the Oops is a
symptom of having a half initialized device. If anyone is interested,
I'll catch the Oops, run it though ksymoops, and send it to them.

If I try as the kernel suggests, and give the kernel options
pci=autoirq, there seems to be no noticable change.

If I switch to a isa^H^H^H I mean 16 bit version of the same ethernet
card, the card works find, and the usb controller works. As a matter
of fact, I've had the 16 bit nic and a usb nic both active at the
same time.

So, beyond reporting this and waiting for the next prepatch from Linus,
I really don't know where to go next. If I can provide anyone with more
information about the hardware or this problem, please ask.

Cheers!

--Matt Galgoci



2000-12-09 02:26:22

by Andrew Morton

[permalink] [raw]
Subject: Re: cardbus pirq conflict

Matthew Galgoci wrote:
>
> Hi Folks,
>
> I am running the 2.4.0test12pre7 kernel on my laptop computer, and
> I'm having some rather interesting problems.
>
> For the longest time, usb never worked on this machine. As of the
> happy patch that enabled bus mastering for usb controllers, it
> magically started working. I am really happy that it does work
> now.
>
> The usb controller and the pcmcia bridge both share the same
> irq, irq 10.
>
> Now, my cardbus cards have stopped working. When I insert a cardbus
> nic, I get the following message: "IRQ routing conflict in pirq
> table! Try 'pci=autoirq'"
>
> The card fails to initialize, and upon issuing the halt command, the
> system generates a kernel Oops. I tend to think that the Oops is a
> symptom of having a half initialized device. If anyone is interested,
> I'll catch the Oops, run it though ksymoops, and send it to them.

test12-pre7 has a number of hotplug problems. I think what you're
seeing is a deadlock where keventd is waiting on itself in
call_usermodehelper() :(

And yes, when you shutdown the system in this state it oopses. I'm
not sure why it was doing that - it shouldn't have. hmmm...

Could you please test this stuff?



--- linux-2.4.0-test12-pre7/include/linux/sched.h Thu Dec 7 22:05:21 2000
+++ linux-akpm/include/linux/sched.h Sat Dec 9 01:36:19 2000
@@ -152,6 +152,7 @@
extern int schedule_task(struct tq_struct *task);
extern void run_schedule_tasks(void);
extern int start_context_thread(void);
+extern int current_is_keventd(void);

/*
* The default fd array needs to be at least BITS_PER_LONG,
--- linux-2.4.0-test12-pre7/include/linux/kernel.h Thu Dec 7 22:05:21 2000
+++ linux-akpm/include/linux/kernel.h Sat Dec 9 01:22:18 2000
@@ -63,6 +63,8 @@
extern int get_option(char **str, int *pint);
extern char *get_options(char *str, int nints, int *ints);
extern unsigned long memparse(char *ptr, char **retptr);
+extern void dev_probe_lock(void);
+extern void dev_probe_unlock(void);

extern int session_of_pgrp(int pgrp);

--- linux-2.4.0-test12-pre7/drivers/pci/pci.c Thu Dec 7 22:05:20 2000
+++ linux-akpm/drivers/pci/pci.c Sat Dec 9 01:24:46 2000
@@ -300,18 +300,25 @@
pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
{
const struct pci_device_id *id;
+ int ret = 0;

if (drv->id_table) {
id = pci_match_device(drv->id_table, dev);
- if (!id)
- return 0;
+ if (!id) {
+ ret = 0;
+ goto out;
+ }
} else
id = NULL;
+
+ dev_probe_lock();
if (drv->probe(dev, id) >= 0) {
dev->driver = drv;
- return 1;
+ ret = 1;
}
- return 0;
+ dev_probe_unlock();
+out:
+ return ret;
}

int
@@ -360,9 +367,9 @@
if (!hotplug_path[0])
return;

- sprintf(class_id, "PCI_CLASS=%X", pdev->class);
- sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
- sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
+ sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+ sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+ sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);

i = 0;
--- linux-2.4.0-test12-pre7/kernel/exit.c Thu Dec 7 22:05:21 2000
+++ linux-akpm/kernel/exit.c Fri Dec 8 22:38:30 2000
@@ -302,9 +302,9 @@
{
struct mm_struct * mm = tsk->mm;

+ mm_release();
if (mm) {
atomic_inc(&mm->mm_count);
- mm_release();
if (mm != tsk->active_mm) BUG();
/* more a memory barrier than a real lock */
task_lock(tsk);
--- linux-2.4.0-test12-pre7/kernel/kmod.c Thu Dec 7 22:05:21 2000
+++ linux-akpm/kernel/kmod.c Sat Dec 9 11:53:32 2000
@@ -256,21 +256,6 @@

#endif /* CONFIG_HOTPLUG */

-
-static int exec_helper (void *arg)
-{
- long ret;
- void **params = (void **) arg;
- char *path = (char *) params [0];
- char **argv = (char **) params [1];
- char **envp = (char **) params [2];
-
- ret = exec_usermodehelper (path, argv, envp);
- if (ret < 0)
- ret = -ret;
- do_exit(ret);
-}
-
struct subprocess_info {
struct semaphore *sem;
char *path;
@@ -279,73 +264,36 @@
int retval;
};

-/*
- * This is a standalone child of keventd. It forks off another thread which
- * is the desired usermode helper and then waits for the child to exit.
- * We return the usermode process's exit code, or some -ve error code.
- */
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
- struct task_struct *curtask = current;
- void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
- pid_t pid, pid2;
- mm_segment_t fs;
- int retval = 0;
+ int retval;

- if (!curtask->fs->root) {
- printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
- retval = -EPERM;
- goto up_and_out;
- }
- if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
- printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
- retval = pid;
- goto up_and_out;
- }
+ retval = -EPERM;
+ if (current->fs->root)
+ retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);

- if (retval >= 0) {
- /* Block everything but SIGKILL/SIGSTOP */
- spin_lock_irq(&curtask->sigmask_lock);
- siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
- recalc_sigpending(curtask);
- spin_unlock_irq(&curtask->sigmask_lock);
-
- /* Allow the system call to access kernel memory */
- fs = get_fs();
- set_fs(KERNEL_DS);
- pid2 = waitpid(pid, &retval, __WCLONE);
- if (pid2 == -1 && errno < 0)
- pid2 = errno;
- set_fs(fs);
-
- if (pid2 != pid) {
- printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
- retval = (pid2 < 0) ? pid2 : -1;
- }
- }
-
-up_and_out:
+ /* Exec failed? */
sub_info->retval = retval;
- curtask->exit_signal = SIGCHLD; /* Wake up parent */
- up_and_exit(sub_info->sem, retval);
+ do_exit(0);
}

/*
- * This is a schedule_task function, so we must not sleep for very long at all.
- * But the exec'ed process could do anything at all. So we launch another
- * kernel thread.
+ * This is run by keventd.
*/
static void __call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
pid_t pid;

- if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
- printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
+ /*
+ * CLONE_VFORK: wait until the usermode helper has execve'd successfully
+ * We need the data structures to stay around until that is done.
+ */
+ pid = kernel_thread (____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
+ if (pid < 0)
sub_info->retval = pid;
- up(sub_info->sem);
- }
+ up(sub_info->sem);
}

/*
@@ -358,22 +306,50 @@
{
DECLARE_MUTEX_LOCKED(sem);
struct subprocess_info sub_info = {
- sem: &sem,
- path: path,
- argv: argv,
- envp: envp,
- retval: 0,
- };
- struct tq_struct tqs = {
- next: 0,
- sync: 0,
- routine: __call_usermodehelper,
- data: &sub_info,
+ sem: &sem,
+ path: path,
+ argv: argv,
+ envp: envp,
+ retval: 0,
};
+ int retval = 0;
+
+ if (path[0] == '\0')
+ goto out;

- schedule_task(&tqs);
- down(&sem); /* Wait for an error or completion */
- return sub_info.retval;
+ if (current_is_keventd()) {
+ /* We can't wait on keventd! */
+ __call_usermodehelper(&sub_info);
+ } else {
+ struct tq_struct tqs = {
+ next: 0,
+ sync: 0,
+ routine: __call_usermodehelper,
+ data: &sub_info,
+ };
+
+ schedule_task(&tqs);
+ down(&sem); /* Wait for an error or completion */
+ }
+ retval = sub_info.retval;
+out:
+ return retval;
+}
+
+/*
+ * This is for the serialisation of device probe() functions
+ * against device open() functions
+ */
+static DECLARE_MUTEX(dev_probe_sem);
+
+void dev_probe_lock(void)
+{
+ down(&dev_probe_sem);
+}
+
+void dev_probe_unlock(void)
+{
+ up(&dev_probe_sem);
}

EXPORT_SYMBOL(exec_usermodehelper);
--- linux-2.4.0-test12-pre7/kernel/context.c Thu Dec 7 22:05:21 2000
+++ linux-akpm/kernel/context.c Fri Dec 8 22:38:30 2000
@@ -18,6 +18,17 @@
static DECLARE_TASK_QUEUE(tq_context);
static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
static int keventd_running;
+static struct task_struct *keventd_task;
+
+int current_is_keventd(void)
+{
+ int ret = 0;
+ if (keventd_running == 0)
+ printk(KERN_ERR "current_is_keventd(): keventd has not started\n");
+ else
+ ret = (current == keventd_task);
+ return ret;
+}

int schedule_task(struct tq_struct *task)
{
@@ -38,6 +49,7 @@
daemonize();
strcpy(curtask->comm, "keventd");
keventd_running = 1;
+ keventd_task = curtask;

spin_lock_irq(&curtask->sigmask_lock);
siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
--- linux-2.4.0-test12-pre7/net/core/dev.c Thu Dec 7 22:05:21 2000
+++ linux-akpm/net/core/dev.c Sat Dec 9 02:11:10 2000
@@ -154,6 +154,12 @@
static struct timer_list samp_timer = { function: sample_queue };
#endif

+#ifdef CONFIG_HOTPLUG
+static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+#else
+#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#endif
+
/*
* Our notifier list
*/
@@ -2196,9 +2202,11 @@
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
return ret;

case SIOCGIFMEM:
@@ -2217,9 +2225,11 @@
if (cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) {
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return ret;
@@ -2388,10 +2398,12 @@
if (ret)
return ret;
#endif /* CONFIG_NET_DIVERT */
-
+
/* Notify protocols, that a new device appeared. */
notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);

+ net_run_sbin_hotplug(dev, "register");
+
return 0;
}

@@ -2475,6 +2487,8 @@
/* Shutdown queueing discipline. */
dev_shutdown(dev);

+ net_run_sbin_hotplug(dev, "unregister");
+
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
*/
@@ -2714,29 +2728,15 @@
/* Notify userspace when a netdevice event occurs,
* by running '/sbin/hotplug net' with certain
* environment variables set.
- *
- * Currently reported events are listed in netdev_event_names[].
*/

-/* /sbin/hotplug ONLY executes for events named here */
-static char *netdev_event_names[] = {
- [NETDEV_REGISTER] = "register",
- [NETDEV_UNREGISTER] = "unregister",
-};
-
-static int run_sbin_hotplug(struct notifier_block *this,
- unsigned long event, void *ptr)
+static int net_run_sbin_hotplug(struct net_device *dev, char *action)
{
- struct net_device *dev = (struct net_device *) ptr;
- char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+ char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
int i;

- if ((event >= ARRAY_SIZE(netdev_event_names)) ||
- !netdev_event_names[event])
- return NOTIFY_DONE;
-
sprintf(ifname, "INTERFACE=%s", dev->name);
- sprintf(action, "ACTION=%s", netdev_event_names[event]);
+ sprintf(action_str, "ACTION=%s", action);

i = 0;
argv[i++] = hotplug_path;
@@ -2748,27 +2748,11 @@
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp [i++] = ifname;
- envp [i++] = action;
+ envp [i++] = action_str;
envp [i] = 0;

call_usermodehelper (argv [0], argv, envp);

return NOTIFY_DONE;
-}
-
-static struct notifier_block sbin_hotplug = {
- notifier_call: run_sbin_hotplug,
-};
-
-/*
- * called from init/main.c, -after- all the initcalls are complete.
- * Registers a hook that calls /sbin/hotplug on every netdev
- * addition and removal.
- */
-void __init net_notifier_init (void)
-{
- if (register_netdevice_notifier(&sbin_hotplug))
- printk (KERN_WARNING "unable to register netdev notifier\n"
- KERN_WARNING "/sbin/hotplug will not be run.\n");
}
#endif
--- linux-2.4.0-test12-pre7/net/ipv4/devinet.c Thu Aug 24 21:07:25 2000
+++ linux-akpm/net/ipv4/devinet.c Sat Dec 9 11:14:03 2000
@@ -519,6 +519,7 @@
return -EINVAL;
}

+ dev_probe_lock();
rtnl_lock();

if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
@@ -649,10 +650,12 @@
}
done:
rtnl_unlock();
+ dev_probe_unlock();
return ret;

rarok:
rtnl_unlock();
+ dev_probe_unlock();
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return 0;
--- linux-2.4.0-test12-pre7/init/main.c Thu Dec 7 22:05:21 2000
+++ linux-akpm/init/main.c Sat Dec 9 00:47:46 2000
@@ -716,14 +716,6 @@
/* Mount the root filesystem.. */
mount_root();

-#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
- /* do this after other 'do this last' stuff, because we want
- * to minimize spurious executions of /sbin/hotplug
- * during boot-up
- */
- net_notifier_init();
-#endif
-
mount_devfs_fs ();

#ifdef CONFIG_BLK_DEV_INITRD

2000-12-11 18:19:18

by Matthew Galgoci

[permalink] [raw]
Subject: Re: cardbus pirq conflict


Hello,

I tried this patch against test12-pre7, and all that I get is
"cs: socket c7604800 timed out during reset. Try increasing
setup_delay."

Performing cardctl reset yields the same message. I think that
cardctl reset takes away the possibility that increasing
setup_delay would actually help.

The Oops on shutdown no longer occurs, so I believe that you
have fixed the race contition you descdibed. The Oops was
also occuring on apm resume, but that has ceased as well.

I will try testing some other cardbus cards later today, and will
also experiment with an unpatch test12-pre8

Cheers!

--Matt Galgoci

>
> Could you please test this stuff?
>
>
>
> --- linux-2.4.0-test12-pre7/include/linux/sched.h Thu Dec 7 22:05:21 2000
> +++ linux-akpm/include/linux/sched.h Sat Dec 9 01:36:19 2000
> @@ -152,6 +152,7 @@
> extern int schedule_task(struct tq_struct *task);
> extern void run_schedule_tasks(void);
> extern int start_context_thread(void);
> +extern int current_is_keventd(void);
>
> /*
> * The default fd array needs to be at least BITS_PER_LONG,
> --- linux-2.4.0-test12-pre7/include/linux/kernel.h Thu Dec 7 22:05:21 2000
> +++ linux-akpm/include/linux/kernel.h Sat Dec 9 01:22:18 2000
> @@ -63,6 +63,8 @@
> extern int get_option(char **str, int *pint);
> extern char *get_options(char *str, int nints, int *ints);
> extern unsigned long memparse(char *ptr, char **retptr);
> +extern void dev_probe_lock(void);
> +extern void dev_probe_unlock(void);
>
> extern int session_of_pgrp(int pgrp);
>
> --- linux-2.4.0-test12-pre7/drivers/pci/pci.c Thu Dec 7 22:05:20 2000
> +++ linux-akpm/drivers/pci/pci.c Sat Dec 9 01:24:46 2000
> @@ -300,18 +300,25 @@
> pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
> {
> const struct pci_device_id *id;
> + int ret = 0;
>
> if (drv->id_table) {
> id = pci_match_device(drv->id_table, dev);
> - if (!id)
> - return 0;
> + if (!id) {
> + ret = 0;
> + goto out;
> + }
> } else
> id = NULL;
> +
> + dev_probe_lock();
> if (drv->probe(dev, id) >= 0) {
> dev->driver = drv;
> - return 1;
> + ret = 1;
> }
> - return 0;
> + dev_probe_unlock();
> +out:
> + return ret;
> }
>
> int
> @@ -360,9 +367,9 @@
> if (!hotplug_path[0])
> return;
>
> - sprintf(class_id, "PCI_CLASS=%X", pdev->class);
> - sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
> - sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
> + sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
> + sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
> + sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
> sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
>
> i = 0;
> --- linux-2.4.0-test12-pre7/kernel/exit.c Thu Dec 7 22:05:21 2000
> +++ linux-akpm/kernel/exit.c Fri Dec 8 22:38:30 2000
> @@ -302,9 +302,9 @@
> {
> struct mm_struct * mm = tsk->mm;
>
> + mm_release();
> if (mm) {
> atomic_inc(&mm->mm_count);
> - mm_release();
> if (mm != tsk->active_mm) BUG();
> /* more a memory barrier than a real lock */
> task_lock(tsk);
> --- linux-2.4.0-test12-pre7/kernel/kmod.c Thu Dec 7 22:05:21 2000
> +++ linux-akpm/kernel/kmod.c Sat Dec 9 11:53:32 2000
> @@ -256,21 +256,6 @@
>
> #endif /* CONFIG_HOTPLUG */
>
> -
> -static int exec_helper (void *arg)
> -{
> - long ret;
> - void **params = (void **) arg;
> - char *path = (char *) params [0];
> - char **argv = (char **) params [1];
> - char **envp = (char **) params [2];
> -
> - ret = exec_usermodehelper (path, argv, envp);
> - if (ret < 0)
> - ret = -ret;
> - do_exit(ret);
> -}
> -
> struct subprocess_info {
> struct semaphore *sem;
> char *path;
> @@ -279,73 +264,36 @@
> int retval;
> };
>
> -/*
> - * This is a standalone child of keventd. It forks off another thread which
> - * is the desired usermode helper and then waits for the child to exit.
> - * We return the usermode process's exit code, or some -ve error code.
> - */
> static int ____call_usermodehelper(void *data)
> {
> struct subprocess_info *sub_info = data;
> - struct task_struct *curtask = current;
> - void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
> - pid_t pid, pid2;
> - mm_segment_t fs;
> - int retval = 0;
> + int retval;
>
> - if (!curtask->fs->root) {
> - printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
> - retval = -EPERM;
> - goto up_and_out;
> - }
> - if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
> - printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
> - retval = pid;
> - goto up_and_out;
> - }
> + retval = -EPERM;
> + if (current->fs->root)
> + retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
>
> - if (retval >= 0) {
> - /* Block everything but SIGKILL/SIGSTOP */
> - spin_lock_irq(&curtask->sigmask_lock);
> - siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
> - recalc_sigpending(curtask);
> - spin_unlock_irq(&curtask->sigmask_lock);
> -
> - /* Allow the system call to access kernel memory */
> - fs = get_fs();
> - set_fs(KERNEL_DS);
> - pid2 = waitpid(pid, &retval, __WCLONE);
> - if (pid2 == -1 && errno < 0)
> - pid2 = errno;
> - set_fs(fs);
> -
> - if (pid2 != pid) {
> - printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
> - retval = (pid2 < 0) ? pid2 : -1;
> - }
> - }
> -
> -up_and_out:
> + /* Exec failed? */
> sub_info->retval = retval;
> - curtask->exit_signal = SIGCHLD; /* Wake up parent */
> - up_and_exit(sub_info->sem, retval);
> + do_exit(0);
> }
>
> /*
> - * This is a schedule_task function, so we must not sleep for very long at all.
> - * But the exec'ed process could do anything at all. So we launch another
> - * kernel thread.
> + * This is run by keventd.
> */
> static void __call_usermodehelper(void *data)
> {
> struct subprocess_info *sub_info = data;
> pid_t pid;
>
> - if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
> - printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
> + /*
> + * CLONE_VFORK: wait until the usermode helper has execve'd successfully
> + * We need the data structures to stay around until that is done.
> + */
> + pid = kernel_thread (____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
> + if (pid < 0)
> sub_info->retval = pid;
> - up(sub_info->sem);
> - }
> + up(sub_info->sem);
> }
>
> /*
> @@ -358,22 +306,50 @@
> {
> DECLARE_MUTEX_LOCKED(sem);
> struct subprocess_info sub_info = {
> - sem: &sem,
> - path: path,
> - argv: argv,
> - envp: envp,
> - retval: 0,
> - };
> - struct tq_struct tqs = {
> - next: 0,
> - sync: 0,
> - routine: __call_usermodehelper,
> - data: &sub_info,
> + sem: &sem,
> + path: path,
> + argv: argv,
> + envp: envp,
> + retval: 0,
> };
> + int retval = 0;
> +
> + if (path[0] == '\0')
> + goto out;
>
> - schedule_task(&tqs);
> - down(&sem); /* Wait for an error or completion */
> - return sub_info.retval;
> + if (current_is_keventd()) {
> + /* We can't wait on keventd! */
> + __call_usermodehelper(&sub_info);
> + } else {
> + struct tq_struct tqs = {
> + next: 0,
> + sync: 0,
> + routine: __call_usermodehelper,
> + data: &sub_info,
> + };
> +
> + schedule_task(&tqs);
> + down(&sem); /* Wait for an error or completion */
> + }
> + retval = sub_info.retval;
> +out:
> + return retval;
> +}
> +
> +/*
> + * This is for the serialisation of device probe() functions
> + * against device open() functions
> + */
> +static DECLARE_MUTEX(dev_probe_sem);
> +
> +void dev_probe_lock(void)
> +{
> + down(&dev_probe_sem);
> +}
> +
> +void dev_probe_unlock(void)
> +{
> + up(&dev_probe_sem);
> }
>
> EXPORT_SYMBOL(exec_usermodehelper);
> --- linux-2.4.0-test12-pre7/kernel/context.c Thu Dec 7 22:05:21 2000
> +++ linux-akpm/kernel/context.c Fri Dec 8 22:38:30 2000
> @@ -18,6 +18,17 @@
> static DECLARE_TASK_QUEUE(tq_context);
> static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
> static int keventd_running;
> +static struct task_struct *keventd_task;
> +
> +int current_is_keventd(void)
> +{
> + int ret = 0;
> + if (keventd_running == 0)
> + printk(KERN_ERR "current_is_keventd(): keventd has not started\n");
> + else
> + ret = (current == keventd_task);
> + return ret;
> +}
>
> int schedule_task(struct tq_struct *task)
> {
> @@ -38,6 +49,7 @@
> daemonize();
> strcpy(curtask->comm, "keventd");
> keventd_running = 1;
> + keventd_task = curtask;
>
> spin_lock_irq(&curtask->sigmask_lock);
> siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
> --- linux-2.4.0-test12-pre7/net/core/dev.c Thu Dec 7 22:05:21 2000
> +++ linux-akpm/net/core/dev.c Sat Dec 9 02:11:10 2000
> @@ -154,6 +154,12 @@
> static struct timer_list samp_timer = { function: sample_queue };
> #endif
>
> +#ifdef CONFIG_HOTPLUG
> +static int net_run_sbin_hotplug(struct net_device *dev, char *action);
> +#else
> +#define net_run_sbin_hotplug(dev, action) ({ 0; })
> +#endif
> +
> /*
> * Our notifier list
> */
> @@ -2196,9 +2202,11 @@
> if (!capable(CAP_NET_ADMIN))
> return -EPERM;
> dev_load(ifr.ifr_name);
> + dev_probe_lock();
> rtnl_lock();
> ret = dev_ifsioc(&ifr, cmd);
> rtnl_unlock();
> + dev_probe_unlock();
> return ret;
>
> case SIOCGIFMEM:
> @@ -2217,9 +2225,11 @@
> if (cmd >= SIOCDEVPRIVATE &&
> cmd <= SIOCDEVPRIVATE + 15) {
> dev_load(ifr.ifr_name);
> + dev_probe_lock();
> rtnl_lock();
> ret = dev_ifsioc(&ifr, cmd);
> rtnl_unlock();
> + dev_probe_unlock();
> if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
> return -EFAULT;
> return ret;
> @@ -2388,10 +2398,12 @@
> if (ret)
> return ret;
> #endif /* CONFIG_NET_DIVERT */
> -
> +
> /* Notify protocols, that a new device appeared. */
> notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
>
> + net_run_sbin_hotplug(dev, "register");
> +
> return 0;
> }
>
> @@ -2475,6 +2487,8 @@
> /* Shutdown queueing discipline. */
> dev_shutdown(dev);
>
> + net_run_sbin_hotplug(dev, "unregister");
> +
> /* Notify protocols, that we are about to destroy
> this device. They should clean all the things.
> */
> @@ -2714,29 +2728,15 @@
> /* Notify userspace when a netdevice event occurs,
> * by running '/sbin/hotplug net' with certain
> * environment variables set.
> - *
> - * Currently reported events are listed in netdev_event_names[].
> */
>
> -/* /sbin/hotplug ONLY executes for events named here */
> -static char *netdev_event_names[] = {
> - [NETDEV_REGISTER] = "register",
> - [NETDEV_UNREGISTER] = "unregister",
> -};
> -
> -static int run_sbin_hotplug(struct notifier_block *this,
> - unsigned long event, void *ptr)
> +static int net_run_sbin_hotplug(struct net_device *dev, char *action)
> {
> - struct net_device *dev = (struct net_device *) ptr;
> - char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
> + char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
> int i;
>
> - if ((event >= ARRAY_SIZE(netdev_event_names)) ||
> - !netdev_event_names[event])
> - return NOTIFY_DONE;
> -
> sprintf(ifname, "INTERFACE=%s", dev->name);
> - sprintf(action, "ACTION=%s", netdev_event_names[event]);
> + sprintf(action_str, "ACTION=%s", action);
>
> i = 0;
> argv[i++] = hotplug_path;
> @@ -2748,27 +2748,11 @@
> envp [i++] = "HOME=/";
> envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
> envp [i++] = ifname;
> - envp [i++] = action;
> + envp [i++] = action_str;
> envp [i] = 0;
>
> call_usermodehelper (argv [0], argv, envp);
>
> return NOTIFY_DONE;
> -}
> -
> -static struct notifier_block sbin_hotplug = {
> - notifier_call: run_sbin_hotplug,
> -};
> -
> -/*
> - * called from init/main.c, -after- all the initcalls are complete.
> - * Registers a hook that calls /sbin/hotplug on every netdev
> - * addition and removal.
> - */
> -void __init net_notifier_init (void)
> -{
> - if (register_netdevice_notifier(&sbin_hotplug))
> - printk (KERN_WARNING "unable to register netdev notifier\n"
> - KERN_WARNING "/sbin/hotplug will not be run.\n");
> }
> #endif
> --- linux-2.4.0-test12-pre7/net/ipv4/devinet.c Thu Aug 24 21:07:25 2000
> +++ linux-akpm/net/ipv4/devinet.c Sat Dec 9 11:14:03 2000
> @@ -519,6 +519,7 @@
> return -EINVAL;
> }
>
> + dev_probe_lock();
> rtnl_lock();
>
> if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
> @@ -649,10 +650,12 @@
> }
> done:
> rtnl_unlock();
> + dev_probe_unlock();
> return ret;
>
> rarok:
> rtnl_unlock();
> + dev_probe_unlock();
> if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
> return -EFAULT;
> return 0;
> --- linux-2.4.0-test12-pre7/init/main.c Thu Dec 7 22:05:21 2000
> +++ linux-akpm/init/main.c Sat Dec 9 00:47:46 2000
> @@ -716,14 +716,6 @@
> /* Mount the root filesystem.. */
> mount_root();
>
> -#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
> - /* do this after other 'do this last' stuff, because we want
> - * to minimize spurious executions of /sbin/hotplug
> - * during boot-up
> - */
> - net_notifier_init();
> -#endif
> -
> mount_devfs_fs ();
>
> #ifdef CONFIG_BLK_DEV_INITRD

--
"Hey Y'all, Watch this!" --Mike Wangsmo

2000-12-11 20:34:13

by Matthew Galgoci

[permalink] [raw]
Subject: Re: cardbus pirq conflict


I goofed in the report below. I had switched to the i82365
pcmcia driver to see if it was affected by the pirq problems
the night before, and forgotten to switch back to the yenta_socket.

Switching back to the yenta_socket, plus andrewm's keventd patch
allowed the collection of cardbus pcmcia cards to work. Apm suspend
and shutting down the machine do not cause an Oops either.

I do however still recieve a nasty message about a pirq table
conflict, but it does not seem to affect the operation of the
card.

The pirq conflict message seems a little harsh though, and perhaps
unnecessary.

Thank you all.

Cheer!

--Matt Galgoci


On Mon, Dec 11, 2000 at 12:48:16PM -0500, Matthew Galgoci wrote:
>
> Hello,
>
> I tried this patch against test12-pre7, and all that I get is
> "cs: socket c7604800 timed out during reset. Try increasing
> setup_delay."
>
> Performing cardctl reset yields the same message. I think that
> cardctl reset takes away the possibility that increasing
> setup_delay would actually help.
>
> The Oops on shutdown no longer occurs, so I believe that you
> have fixed the race contition you descdibed. The Oops was
> also occuring on apm resume, but that has ceased as well.
>
> I will try testing some other cardbus cards later today, and will
> also experiment with an unpatch test12-pre8
>

2000-12-11 21:02:15

by Linus Torvalds

[permalink] [raw]
Subject: Re: cardbus pirq conflict



On Mon, 11 Dec 2000, Matthew Galgoci wrote:
>
> I do however still recieve a nasty message about a pirq table
> conflict, but it does not seem to affect the operation of the
> card.

It doesn't.

> The pirq conflict message seems a little harsh though, and perhaps
> unnecessary.

It is a bit harsh, and while not unnecessary I'll have to do something
about it.

What is going on is that a lot of laptops appear to have a pirq routing
table for PCI bus #1 (and sometimes #2), even though that bus does not
actually exist in hardware at all. My suspicion is that the BIOS writers
just re-use the same pirq table over and over again, and that it's just a
remnant of the fact that some laptops have either a docking station bus or
an AGP bus as bus #1.

When Linux assigns bus #1 to the CardBus bridge, those bogus entries in
the pirq routing table will show up as conflicts. They'll be ignored, but
it's still a nasty message.

The problem is that the message probably _should_ be printed for the real
case of a misconfigured BIOS, if for no other reason than to try to track
down what the h*ll is going on.

My tentative fix for this would be to make Linux never assign bus #1 or #2
to a cardbus bridge, and start cardbus bridges at bus #8 or something like
that. That way we'd still catch any strangeness in the pirq table, but we
wouldn't get the message for this case which seems to be very common.

Linus

2000-12-11 21:26:49

by Martin Mares

[permalink] [raw]
Subject: Re: cardbus pirq conflict

Hi Linus!

> My tentative fix for this would be to make Linux never assign bus #1 or #2
> to a cardbus bridge, and start cardbus bridges at bus #8 or something like
> that. That way we'd still catch any strangeness in the pirq table, but we
> wouldn't get the message for this case which seems to be very common.

Agreed.

Have a nice fortnight
--
Martin `MJ' Mares <[email protected]> <[email protected]> http://atrey.karlin.mff.cuni.cz/~mj/
CChheecckk yyoouurr dduupplleexx sswwiittcchh..