Re: [Bug 7505] Linux-2.6.18 fails to boot on AMD64 machine

From: Ard -kwaak- van Breemen
Date: Fri Dec 29 2006 - 09:11:55 EST


On Fri, Dec 29, 2006 at 02:27:59PM +0100, Ard -kwaak- van Breemen wrote:
> I will clean up the patches found on this list to fix and detect this.

Preliminary patches:
- pci fix of Andrews patches
- parse-one detection of Yanmin
- start_kernel detection and workaround (disable them again)

These are the patches that I am about to test in the next 2
hours... :-)
Anyway: I think it is possible that other drivers are also
potential irq enablers as soon as they are called from parse_one.
Usually I compile network drivers as modules, but in diskless
setups this might not be the case :-).
--
program signature;
begin { telegraaf.com
} writeln("<ard@xxxxxxxxxxxxxxx> TEM2");
end
.
--- linux-2.6.19.vanilla/drivers/pci/search.c 2006-11-29 21:57:37.000000000 +0000
+++ linux-2.6.19/drivers/pci/search.c 2006-12-29 13:58:51.000000000 +0000
@@ -193,6 +193,17 @@
struct pci_dev *dev;

WARN_ON(in_interrupt());
+
+ /*
+ * pci_find_subsys() can be called on the ide_setup() path, super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if(unlikely(list_empty(&pci_devices))) {
+ printk(KERN_INFO "pci_find_subsys() called while pci_devices is still empty\n");
+ return NULL;
+ }
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;

@@ -259,6 +270,16 @@
struct pci_dev *dev;

WARN_ON(in_interrupt());
+ /*
+ * pci_get_subsys() can potentially be called by drivers super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if(unlikely(list_empty(&pci_devices))) {
+ printk(KERN_NOTICE "pci_get_subsys() called while pci_devices is still empty\n");
+ return NULL;
+ }
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;

--- linux-2.6.19.vanilla/kernel/params.c 2006-11-29 21:57:37.000000000 +0000
+++ linux-2.6.19/kernel/params.c 2006-12-29 14:02:48.000000000 +0000
@@ -53,13 +53,20 @@
int (*handle_unknown)(char *param, char *val))
{
unsigned int i;
+ int result;
+ int irq_was_disabled;

/* Find parameter */
for (i = 0; i < num_params; i++) {
if (parameq(param, params[i].name)) {
DEBUGP("They are equal! Calling %p\n",
params[i].set);
- return params[i].set(val, &params[i]);
+ irq_was_disabled = irqs_disabled();
+ result=params[i].set(val, &params[i]);
+ if (irq_was_disabled && !irqs_disabled()) {
+ printk(KERN_WARNING "[BUG] parse_one: kerneloption '%s' enabled irq!\n",param);
+ }
+ return result;
}
}

--- linux-2.6.19.vanilla/init/main.c 2006-11-29 21:57:37.000000000 +0000
+++ linux-2.6.19/init/main.c 2006-12-29 13:58:37.000000000 +0000
@@ -525,6 +525,10 @@
parse_args("Booting kernel", command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
+ if (!irqs_disabled()) {
+ printk(KERN_WARNING "start_kernel(): bug: interrupts were enabled *very* early, fixing it\n");
+ local_irq_disable();
+ }
sort_main_extable();
trap_init();
rcu_init();