From 314b6a4d80a7a5217c86ffdca926b6f406da0e0e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 27 Jun 2005 22:29:33 -0700 Subject: [PATCH] kexec: fix sparse warnings Signed-off-by: Alexey Dobriyan Cc: Eric Biederman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kexec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/kexec.c b/kernel/kexec.c index 7843548cf2d9..cdd4dcd8fb63 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -241,7 +241,7 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, - struct kexec_segment *segments) + struct kexec_segment __user *segments) { int result; struct kimage *image; @@ -650,7 +650,7 @@ static kimage_entry_t *kimage_dst_used(struct kimage *image, } } - return 0; + return NULL; } static struct page *kimage_alloc_page(struct kimage *image, @@ -696,7 +696,7 @@ static struct page *kimage_alloc_page(struct kimage *image, /* Allocate a page, if we run out of memory give up */ page = kimage_alloc_pages(gfp_mask, 0); if (!page) - return 0; + return NULL; /* If the page cannot be used file it away */ if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { @@ -754,7 +754,7 @@ static int kimage_load_normal_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char *buf; + unsigned char __user *buf; result = 0; buf = segment->buf; @@ -818,7 +818,7 @@ static int kimage_load_crash_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char *buf; + unsigned char __user *buf; result = 0; buf = segment->buf; -- cgit v1.3-8-gc7d7 From f340c0d1a3f40fdcba69cd291530a4debc58748f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 28 Jun 2005 16:40:42 +0200 Subject: [PATCH] Tweak idle thread setup semantics This patch tweaks idle thread setup semantics a bit: instead of setting NEED_RESCHED in init_idle(), we do an explicit schedule() before calling into cpu_idle(). This patch, while having no negative side-effects, enables wider use of cond_resched()s. (which might happen in the stock kernel too, but it's particulary important for voluntary-preempt) Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/main.c | 7 +++++++ kernel/sched.c | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/init/main.c b/init/main.c index d324801729ba..b5e421e39ede 100644 --- a/init/main.c +++ b/init/main.c @@ -383,6 +383,13 @@ static void noinline rest_init(void) numa_default_policy(); unlock_kernel(); preempt_enable_no_resched(); + + /* + * The boot idle thread must execute schedule() + * at least one to get things moving: + */ + schedule(); + cpu_idle(); } diff --git a/kernel/sched.c b/kernel/sched.c index e2b0d3e4dd06..5f2182d42241 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4166,6 +4166,14 @@ void show_state(void) read_unlock(&tasklist_lock); } +/** + * init_idle - set up an idle thread for a given CPU + * @idle: task in question + * @cpu: cpu the idle task belongs to + * + * NOTE: this function does not set the idle thread's NEED_RESCHED + * flag, to make booting more robust. + */ void __devinit init_idle(task_t *idle, int cpu) { runqueue_t *rq = cpu_rq(cpu); @@ -4183,7 +4191,6 @@ void __devinit init_idle(task_t *idle, int cpu) #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) idle->oncpu = 1; #endif - set_tsk_need_resched(idle); spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ -- cgit v1.3-8-gc7d7 From 47f176fdaf8924bc83fddcf9658f2fd3ef60d573 Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Tue, 28 Jun 2005 20:44:42 -0700 Subject: [PATCH] Using msleep() instead of HZ Use msleep() in a few places. Signed-off-by: Luca Falavigna Acked-by: Ingo Molnar Acked-by: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/rtc.c | 16 ++++------------ kernel/irq/autoprobe.c | 9 ++++----- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'kernel') diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index ff4f09804865..d8f9e94ae475 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -894,7 +895,6 @@ static int __init rtc_init(void) struct proc_dir_entry *ent; #if defined(__alpha__) || defined(__mips__) unsigned int year, ctrl; - unsigned long uip_watchdog; char *guess = NULL; #endif #ifdef __sparc__ @@ -1000,12 +1000,8 @@ no_irq: /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -1213,7 +1209,6 @@ static int rtc_proc_open(struct inode *inode, struct file *file) void rtc_get_rtc_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char ctrl; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -1221,7 +1216,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) /* * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 10 to 20ms. There is no need to + * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable * periodic update complete interrupts, (via ioctl) and then @@ -1230,10 +1225,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) */ if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); /* * Only the values that we read from the RTC are set. We leave diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 98d62d8efeaf..3467097ca61a 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c @@ -9,6 +9,7 @@ #include #include #include +#include /* * Autodetection depends on the fact that any interrupt that @@ -26,7 +27,7 @@ static DECLARE_MUTEX(probe_sem); */ unsigned long probe_irq_on(void) { - unsigned long val, delay; + unsigned long val; irq_desc_t *desc; unsigned int i; @@ -45,8 +46,7 @@ unsigned long probe_irq_on(void) } /* Wait for longstanding interrupts to trigger. */ - for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ barrier(); + msleep(20); /* * enable any unassigned irqs @@ -68,8 +68,7 @@ unsigned long probe_irq_on(void) /* * Wait for spurious interrupts to trigger */ - for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ barrier(); + msleep(100); /* * Now filter out any obviously spurious interrupts -- cgit v1.3-8-gc7d7 From f01b1b0baa454825ed95c28d2a6a71bbf4510836 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 28 Jun 2005 20:44:47 -0700 Subject: [PATCH] ITIMER_REAL: fix possible deadlock and race As Steven Rostedt pointed out, there are 2 problems with ITIMER_REAL timers. 1. do_setitimer() does not call del_timer_sync() in case when the timer is not pending (it_real_value() returns 0). This is wrong, the timer may still be running, and it can rearm itself. 2. It calls del_timer_sync() with tsk->sighand->siglock held. This is deadlockable, because timer's handler needs this lock too. Signed-off-by: Oleg Nesterov Acked-by: Steven Rostedt Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/itimer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/itimer.c b/kernel/itimer.c index 1dc988e0d2c7..a72cb0e5aa4b 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -153,11 +153,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) switch (which) { case ITIMER_REAL: +again: spin_lock_irq(&tsk->sighand->siglock); interval = tsk->signal->it_real_incr; val = it_real_value(tsk->signal); - if (val) - del_timer_sync(&tsk->signal->real_timer); + /* We are sharing ->siglock with it_real_fn() */ + if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) { + spin_unlock_irq(&tsk->sighand->siglock); + goto again; + } tsk->signal->it_real_incr = timeval_to_jiffies(&value->it_interval); it_real_arm(tsk, timeval_to_jiffies(&value->it_value)); -- cgit v1.3-8-gc7d7 From 200803dfe4ff772740d63db725ab2f1b185ccf92 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 28 Jun 2005 20:45:18 -0700 Subject: [PATCH] irqpoll Anyone reporting a stuck IRQ should try these options. Its effectiveness varies we've found in the Fedora case. Quite a few systems with misdescribed IRQ routing just work when you use irqpoll. It also fixes up the VIA systems although thats now fixed with the VIA quirk (which we could just make default as its what Redmond OS does but Linus didn't like it historically). A small number of systems have jammed IRQ sources or misdescribes that cause an IRQ that we have no handler registered anywhere for. In those cases it doesn't help. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/kernel-parameters.txt | 15 +++++ arch/ppc64/kernel/irq.c | 2 +- include/linux/irq.h | 5 +- kernel/irq/handle.c | 2 +- kernel/irq/spurious.c | 113 +++++++++++++++++++++++++++++++++++- 5 files changed, 131 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0f71251f12b9..67e99f144199 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -437,6 +437,10 @@ running once the system is up. Format: {"of[f]" | "sk[ipmbr]"} See comment in arch/i386/boot/edd.S + edd [EDD] + Format: {"of[f]" | "sk[ipmbr]"} + See comment in arch/i386/boot/edd.S + eicon= [HW,ISDN] Format: ,, @@ -622,6 +626,17 @@ running once the system is up. ips= [HW,SCSI] Adaptec / IBM ServeRAID controller See header of drivers/scsi/ips.c. + irqfixup [HW] + When an interrupt is not handled search all handlers + for it. Intended to get systems with badly broken + firmware running. + + irqpoll [HW] + When an interrupt is not handled search all handlers + for it. Also check all handlers each timer + interrupt. Intended to get systems with badly broken + firmware running. + isapnp= [ISAPNP] Format: , , , diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 3defc8c33adf..ffe300611f00 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -245,7 +245,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff --git a/include/linux/irq.h b/include/linux/irq.h index 12277799c007..069d3b84d311 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -85,9 +85,10 @@ extern int no_irq_affinity; extern int noirqdebug_setup(char *str); extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action); + struct irqaction *action); extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); -extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret); +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, + int action_ret, struct pt_regs *regs); extern int can_request_irq(unsigned int irq, unsigned long irqflags); extern void init_irq_proc(void); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 436c7d93c00a..c29f83c16497 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -172,7 +172,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index ba039e827d58..7df9abd5ec86 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -11,6 +11,83 @@ #include #include +static int irqfixup; + +/* + * Recovery handler for misrouted interrupts. + */ + +static int misrouted_irq(int irq, struct pt_regs *regs) +{ + int i; + irq_desc_t *desc; + int ok = 0; + int work = 0; /* Did we do work for a real IRQ */ + + for(i = 1; i < NR_IRQS; i++) { + struct irqaction *action; + + if (i == irq) /* Already tried */ + continue; + desc = &irq_desc[i]; + spin_lock(&desc->lock); + action = desc->action; + /* Already running on another processor */ + if (desc->status & IRQ_INPROGRESS) { + /* + * Already running: If it is shared get the other + * CPU to go looking for our mystery interrupt too + */ + if (desc->action && (desc->action->flags & SA_SHIRQ)) + desc->status |= IRQ_PENDING; + spin_unlock(&desc->lock); + continue; + } + /* Honour the normal IRQ locking */ + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + while (action) { + /* Only shared IRQ handlers are safe to call */ + if (action->flags & SA_SHIRQ) { + if (action->handler(i, action->dev_id, regs) == + IRQ_HANDLED) + ok = 1; + } + action = action->next; + } + local_irq_disable(); + /* Now clean up the flags */ + spin_lock(&desc->lock); + action = desc->action; + + /* + * While we were looking for a fixup someone queued a real + * IRQ clashing with our walk + */ + + while ((desc->status & IRQ_PENDING) && action) { + /* + * Perform real IRQ processing for the IRQ we deferred + */ + work = 1; + spin_unlock(&desc->lock); + handle_IRQ_event(i, regs, action); + spin_lock(&desc->lock); + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + /* + * If we did actual work for the real IRQ line we must let the + * IRQ controller clean up too + */ + if(work) + desc->handler->end(i); + spin_unlock(&desc->lock); + } + /* So the caller can adjust the irq error counts */ + return ok; +} + /* * If 99,900 of the previous 100,000 interrupts have not been handled * then assume that the IRQ is stuck in some manner. Drop a diagnostic @@ -31,7 +108,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) printk(KERN_ERR "irq event %d: bogus return value %x\n", irq, action_ret); } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); + printk(KERN_ERR "irq %d: nobody cared (try booting with " + "the \"irqpoll\" option)\n", irq); } dump_stack(); printk(KERN_ERR "handlers:\n"); @@ -55,7 +133,8 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio } } -void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) +void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret, + struct pt_regs *regs) { if (action_ret != IRQ_HANDLED) { desc->irqs_unhandled++; @@ -63,6 +142,15 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) report_bad_irq(irq, desc, action_ret); } + if (unlikely(irqfixup)) { + /* Don't punish working computers */ + if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) { + int ok = misrouted_irq(irq, regs); + if (action_ret == IRQ_NONE) + desc->irqs_unhandled -= ok; + } + } + desc->irq_count++; if (desc->irq_count < 100000) return; @@ -94,3 +182,24 @@ int __init noirqdebug_setup(char *str) __setup("noirqdebug", noirqdebug_setup); +static int __init irqfixup_setup(char *str) +{ + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); + return 1; +} + +__setup("irqfixup", irqfixup_setup); + +static int __init irqpoll_setup(char *str) +{ + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support " + "enabled\n"); + printk(KERN_WARNING "This may significantly impact system " + "performance\n"); + return 1; +} + +__setup("irqpoll", irqpoll_setup); -- cgit v1.3-8-gc7d7