* [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
@ 2004-09-08 12:06 Ingo Molnar
2004-09-08 12:29 ` La Monte H.P. Yarroll
2004-09-08 12:34 ` Christoph Hellwig
0 siblings, 2 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 12:06 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 973 bytes --]
the attached patch moves generic hardirq handling bits to
kernel/hardirq.c. It is not a replacement for any of the existing IRQ
functions, so architectures can use their existing hardirq code in an
unmodified form. It is a library of generic functions that an
architecture can make use of optionally.
I've fully converted x86's irq.c to use the new functions, and Scott
Wood has done the same for ppc/ppc64 as well. (the arch-ppc* changes are
not included in this patch because i couldnt test them myself in the
current port of this patch - but the generic bits were tested on ppc.)
i have test-compiled and test-booted the patch on x86 and x64, on SMP &&
PREEMPT and !SMP && !PREEMPT kernels. x64 needed only a single change (a
setup_irq() prototype) to work fine, which makes me believe that the
patch will not break other architectures either.
(a more complex version of this patch has been tested for weeks as part
of the voluntary-preempt patches as well.)
Ingo
[-- Attachment #2: generic-hardirqs.patch --]
[-- Type: text/plain, Size: 31992 bytes --]
the attached patch moves generic hardirq handling bits into
kernel/hardirq.c. It is not a replacement for any of the existing IRQ
functions, so architectures can use their existing hardirq code in an
unmodified form. It is a library of generic functions that an
architecture can make use of optionally.
I've fully converted x86's irq.c to use the new functions - and Scott
Wood has done the same for ppc/ppc64 as well. (the arch-ppc* changes are
not included in this patch because i couldnt test them myself in the
current port of this patch - but the generic bits were tested on ppc)
i have test-compiled the patch on x86 and x64, on SMP && PREEMPT and
!SMP && !PREEMPT. x64 needed only a single change - a setup_irq()
prototype, to work fine, which makes me believe that the patch will not
break any other architectures either.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
--- linux/arch/i386/kernel/i386_ksyms.c.orig
+++ linux/arch/i386/kernel/i386_ksyms.c
@@ -77,9 +77,6 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
@@ -147,7 +144,6 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
/* Global SMP stuff */
-EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
/* TLB flushing */
--- linux/arch/i386/kernel/irq.c.orig
+++ linux/arch/i386/kernel/irq.c
@@ -71,8 +71,6 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
}
};
-static void register_irq_proc (unsigned int irq);
-
/*
* per-CPU IRQ handling stacks
*/
@@ -198,218 +196,6 @@ skip:
return 0;
}
-
-
-
-#ifdef CONFIG_SMP
-inline void synchronize_irq(unsigned int irq)
-{
- while (irq_desc[irq].status & IRQ_INPROGRESS)
- cpu_relax();
-}
-#endif
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-asmlinkage int handle_IRQ_event(unsigned int irq,
- struct pt_regs *regs, struct irqaction *action)
-{
- int status = 1; /* Force the "do bottom halves" bit */
- int ret, retval = 0;
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
- return retval;
-}
-
-static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- struct irqaction *action;
-
- if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
- printk(KERN_ERR "irq event %d: bogus return value %x\n",
- irq, action_ret);
- } else {
- printk(KERN_ERR "irq %d: nobody cared!\n", irq);
- }
- dump_stack();
- printk(KERN_ERR "handlers:\n");
- action = desc->action;
- do {
- printk(KERN_ERR "[<%p>]", action->handler);
- print_symbol(" (%s)",
- (unsigned long)action->handler);
- printk("\n");
- action = action->next;
- } while (action);
-}
-
-static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- static int count = 100;
-
- if (count) {
- count--;
- __report_bad_irq(irq, desc, action_ret);
- }
-}
-
-static int noirqdebug;
-
-static int __init noirqdebug_setup(char *str)
-{
- noirqdebug = 1;
- printk("IRQ lockup detection disabled\n");
- return 1;
-}
-
-__setup("noirqdebug", noirqdebug_setup);
-
-/*
- * 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 and try to
- * turn the IRQ off.
- *
- * (The other 100-of-100,000 interrupts may have been a correctly-functioning
- * device sharing an IRQ with the failing one)
- *
- * Called under desc->lock
- */
-static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- if (action_ret != IRQ_HANDLED) {
- desc->irqs_unhandled++;
- if (action_ret != IRQ_NONE)
- report_bad_irq(irq, desc, action_ret);
- }
-
- desc->irq_count++;
- if (desc->irq_count < 100000)
- return;
-
- desc->irq_count = 0;
- if (desc->irqs_unhandled > 99900) {
- /*
- * The interrupt is stuck
- */
- __report_bad_irq(irq, desc, action_ret);
- /*
- * Now kill the IRQ
- */
- printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- desc->irqs_unhandled = 0;
-}
-
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables and Enables are
- * nested.
- * Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-inline void disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Enables and Disables are
- * nested.
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- disable_irq_nosync(irq);
- if (desc->action)
- synchronize_irq(irq);
-}
-
-/**
- * enable_irq - enable handling of an irq
- * @irq: Interrupt to enable
- *
- * Undoes the effect of one call to disable_irq(). If this
- * matches the last disable, processing of interrupts on this
- * IRQ line is re-enabled.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
@@ -510,7 +296,7 @@ asmlinkage unsigned int do_IRQ(struct pt
*/
if (curctx == irqctx)
- action_ret = handle_IRQ_event(irq, ®s, action);
+ action_ret = generic_handle_IRQ_event(irq, ®s, action);
else {
/* build the stack frame on the IRQ stack */
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -523,7 +309,7 @@ asmlinkage unsigned int do_IRQ(struct pt
asm volatile(
" xchgl %%ebx,%%esp \n"
- " call handle_IRQ_event \n"
+ " call generic_handle_IRQ_event \n"
" xchgl %%ebx,%%esp \n"
: "=a"(action_ret)
: "b"(isp)
@@ -534,7 +320,7 @@ asmlinkage unsigned int do_IRQ(struct pt
}
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ generic_note_interrupt(irq, desc, action_ret);
if (curctx != irqctx)
irqctx->tinfo.task = NULL;
if (likely(!(desc->status & IRQ_PENDING)))
@@ -549,11 +335,11 @@ asmlinkage unsigned int do_IRQ(struct pt
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, ®s, action);
+ action_ret = generic_handle_IRQ_event(irq, ®s, action);
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ generic_note_interrupt(irq, desc, action_ret);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
@@ -659,7 +445,7 @@ int request_irq(unsigned int irq,
action->next = NULL;
action->dev_id = dev_id;
- retval = setup_irq(irq, action);
+ retval = generic_setup_irq(irq, action);
if (retval)
kfree(action);
return retval;
@@ -667,62 +453,6 @@ int request_irq(unsigned int irq,
EXPORT_SYMBOL(request_irq);
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- /* Wait to make sure it's not being used on another CPU */
- synchronize_irq(irq);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
/*
* IRQ autodetection code..
*
@@ -918,165 +648,6 @@ int probe_irq_off(unsigned long val)
EXPORT_SYMBOL(probe_irq_off);
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- if (desc->handler == &no_irq_type)
- return -ENOSYS;
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- register_irq_proc(irq);
- return 0;
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NR_IRQS];
-
-#ifdef CONFIG_SMP
-
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-static int irq_affinity_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
- if (count - len < 2)
- return -EINVAL;
- len += sprintf(page + len, "\n");
- return len;
-}
-
-static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int irq = (long)data, full_count = count, err;
- cpumask_t new_value, tmp;
-
- if (!irq_desc[irq].handler->set_affinity)
- return -EIO;
-
- err = cpumask_parse(buffer, count, new_value);
- if (err)
- return err;
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- cpus_and(tmp, new_value, cpu_online_map);
- if (cpus_empty(tmp))
- return -EINVAL;
-
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq,
- cpumask_of_cpu(first_cpu(new_value)));
-
- return full_count;
-}
-
-#endif
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
- irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%d", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#ifdef CONFIG_SMP
- {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
-
- smp_affinity_entry[irq] = entry;
- }
-#endif
-}
-
-void init_irq_proc (void)
-{
- int i;
-
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
- create_prof_cpu_mask(root_irq_dir);
- /*
- * Create entries for all existing IRQs.
- */
- for (i = 0; i < NR_IRQS; i++)
- register_irq_proc(i);
-}
-
-
#ifdef CONFIG_4KSTACKS
/*
* These should really be __section__(".bss.page_aligned") as well, but
--- linux/include/asm-x86_64/hardirq.h.orig
+++ linux/include/asm-x86_64/hardirq.h
@@ -25,8 +25,8 @@
* - ( bit 26 is the PREEMPT_ACTIVE flag. )
*
* PREEMPT_MASK: 0x000000ff
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x00ff0000
*/
#define PREEMPT_BITS 8
@@ -99,4 +99,6 @@ do { \
extern void synchronize_irq(unsigned int irq);
#endif /* CONFIG_SMP */
+extern int setup_irq(unsigned int irq, struct irqaction * new);
+
#endif /* __ASM_HARDIRQ_H */
--- linux/include/linux/irq.h.orig
+++ linux/include/linux/irq.h
@@ -10,12 +10,15 @@
*/
#include <linux/config.h>
+#include <linux/linkage.h>
#if !defined(CONFIG_ARCH_S390)
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -71,10 +74,21 @@ extern irq_desc_t irq_desc [NR_IRQS];
#include <asm/hw_irq.h> /* the arch dependent stuff */
-extern int setup_irq(unsigned int , struct irqaction * );
+
+extern asmlinkage int generic_handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
+extern void generic_synchronize_irq(unsigned int irq);
+extern int generic_setup_irq(unsigned int irq, struct irqaction * new);
+extern void generic_free_irq(unsigned int irq, void *dev_id);
+extern void generic_disable_irq_nosync(unsigned int irq);
+extern void generic_disable_irq(unsigned int irq);
+extern void generic_enable_irq(unsigned int irq);
+extern void generic_note_interrupt(int irq, irq_desc_t *desc, int action_ret);
+extern void generic_init_irq_proc(void);
extern hw_irq_controller no_irq_type; /* needed in every arch ? */
+extern int noirqdebug;
+
#endif
#endif /* __irq_h */
--- linux/include/linux/interrupt.h.orig
+++ linux/include/linux/interrupt.h
@@ -40,6 +40,8 @@ struct irqaction {
const char *name;
void *dev_id;
struct irqaction *next;
+ int irq;
+ struct proc_dir_entry *dir;
};
extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
--- linux/include/asm-i386/irq.h.orig
+++ linux/include/asm-i386/irq.h
@@ -21,9 +21,6 @@ static __inline__ int irq_canonicalize(i
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
extern void release_x86_irqs(struct task_struct *);
extern int can_request_irq(unsigned int, unsigned long flags);
--- linux/include/asm-i386/hardirq.h.orig
+++ linux/include/asm-i386/hardirq.h
@@ -68,10 +68,6 @@ typedef struct {
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
-
-#define hardirq_trylock() (!in_interrupt())
-#define hardirq_endlock() do { } while (0)
-
#define irq_enter() (preempt_count() += HARDIRQ_OFFSET)
#define nmi_enter() (irq_enter())
#define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET)
@@ -92,10 +88,39 @@ do { \
preempt_enable_no_resched(); \
} while (0)
-#ifndef CONFIG_SMP
-# define synchronize_irq(irq) barrier()
-#else
- extern void synchronize_irq(unsigned int irq);
-#endif /* CONFIG_SMP */
+static inline void synchronize_irq(unsigned int irq)
+{
+ generic_synchronize_irq(irq);
+}
+
+static inline void free_irq(unsigned int irq, void *dev_id)
+{
+ generic_free_irq(irq, dev_id);
+}
+
+static inline void disable_irq_nosync(unsigned int irq)
+{
+ generic_disable_irq_nosync(irq);
+}
+
+static inline void disable_irq(unsigned int irq)
+{
+ generic_disable_irq(irq);
+}
+
+static inline void enable_irq(unsigned int irq)
+{
+ generic_enable_irq(irq);
+}
+
+static inline int setup_irq(unsigned int irq, struct irqaction *new)
+{
+ return generic_setup_irq(irq, new);
+}
+
+static inline void init_irq_proc(void)
+{
+ generic_init_irq_proc();
+}
#endif /* __ASM_HARDIRQ_H */
--- linux/kernel/Makefile.orig
+++ linux/kernel/Makefile
@@ -3,7 +3,7 @@
#
obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
- exit.o itimer.o time.o softirq.o resource.o \
+ exit.o itimer.o time.o softirq.o hardirq.o resource.o \
sysctl.o capability.o ptrace.o timer.o user.o \
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o intermodule.o extable.o params.o posix-timers.o \
--- linux/kernel/hardirq.c.orig
+++ linux/kernel/hardirq.c
@@ -0,0 +1,529 @@
+/*
+ * linux/kernel/hardirq.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the generic code used by various IRQ handling
+ * routines.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kallsyms.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+int noirqdebug;
+
+extern struct irq_desc irq_desc[NR_IRQS];
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+static void register_irq_proc(unsigned int irq);
+static void register_handler_proc(unsigned int irq, struct irqaction *action);
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+asmlinkage int generic_handle_IRQ_event(unsigned int irq,
+ struct pt_regs *regs, struct irqaction *action)
+{
+ int status = 1; /* Force the "do bottom halves" bit */
+ int ret, retval = 0;
+
+ if (!(action->flags & SA_INTERRUPT))
+ local_irq_enable();
+
+ do {
+ ret = action->handler(irq, action->dev_id, regs);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ local_irq_disable();
+
+ return retval;
+}
+
+static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ struct irqaction *action;
+
+ if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+ printk(KERN_ERR "irq event %d: bogus return value %x\n",
+ irq, action_ret);
+ } else {
+ printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+ }
+ dump_stack();
+ printk(KERN_ERR "handlers:\n");
+ action = desc->action;
+ while (action) {
+ printk(KERN_ERR "[<%p>]", action->handler);
+ print_symbol(" (%s)",
+ (unsigned long)action->handler);
+ printk("\n");
+ action = action->next;
+ }
+}
+
+static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ static int count = 100;
+
+ if (count) {
+ count--;
+ __report_bad_irq(irq, desc, action_ret);
+ }
+}
+
+
+static int __init noirqdebug_setup(char *str)
+{
+ noirqdebug = 1;
+ printk("IRQ lockup detection disabled\n");
+ return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
+/*
+ * 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 and try to
+ * turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly-functioning
+ * device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+void generic_note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ if (action_ret != IRQ_HANDLED) {
+ desc->irqs_unhandled++;
+ if (action_ret != IRQ_NONE)
+ report_bad_irq(irq, desc, action_ret);
+ }
+
+ desc->irq_count++;
+ if (desc->irq_count < 100000)
+ return;
+
+ desc->irq_count = 0;
+ if (desc->irqs_unhandled > 99900) {
+ /*
+ * The interrupt is stuck
+ */
+ __report_bad_irq(irq, desc, action_ret);
+ /*
+ * Now kill the IRQ
+ */
+ printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ desc->irqs_unhandled = 0;
+}
+
+void generic_synchronize_irq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ while (desc->status & IRQ_INPROGRESS)
+ cpu_relax();
+}
+
+EXPORT_SYMBOL(generic_synchronize_irq);
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ * disable_irq_nosync - disable an irq without waiting
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Disables and Enables are
+ * nested.
+ * Unlike disable_irq(), this function does not ensure existing
+ * instances of the IRQ handler have completed before returning.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void generic_disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(generic_disable_irq_nosync);
+
+/**
+ * disable_irq - disable an irq and wait for completion
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Enables and Disables are
+ * nested.
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+
+void generic_disable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ generic_disable_irq_nosync(irq);
+ if (desc->action)
+ synchronize_irq(irq);
+}
+
+EXPORT_SYMBOL(generic_disable_irq);
+
+/**
+ * enable_irq - enable handling of an irq
+ * @irq: Interrupt to enable
+ *
+ * Undoes the effect of one call to disable_irq(). If this
+ * matches the last disable, processing of interrupts on this
+ * IRQ line is re-enabled.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void generic_enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(generic_enable_irq);
+
+int generic_setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (desc->handler == &no_irq_type)
+ return -ENOSYS;
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+ if (desc->handler->startup)
+ desc->handler->startup(irq);
+ else
+ desc->handler->enable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ new->irq = irq;
+ register_irq_proc(irq);
+ new->dir = NULL;
+ register_handler_proc(irq, new);
+
+ return 0;
+}
+
+/**
+ * generic_free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+
+void generic_free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ if (desc->handler->shutdown)
+ desc->handler->shutdown(irq);
+ else
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+ if (action->dir)
+ remove_proc_entry(action->dir->name, irq_dir[irq]);
+
+ /* Wait to make sure it's not being used on another CPU */
+ synchronize_irq(irq);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+EXPORT_SYMBOL(generic_free_irq);
+
+#ifdef CONFIG_SMP
+
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long)data, full_count = count, err;
+ cpumask_t new_value, tmp;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ cpus_and(tmp, new_value, cpu_online_map);
+ if (cpus_empty(tmp))
+ return -EINVAL;
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq,
+ cpumask_of_cpu(first_cpu(new_value)));
+
+ return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ cpumask_t *mask = (cpumask_t *)data;
+ unsigned long full_count = count, err;
+ cpumask_t new_value;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc(unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+ {
+ struct proc_dir_entry *entry;
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+#undef MAX_NAMELEN
+
+#define MAX_NAMELEN 128
+
+static void register_handler_proc(unsigned int irq, struct irqaction *action)
+{
+ char name [MAX_NAMELEN];
+
+ if (!irq_dir[irq] || action->dir || !action->name)
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ snprintf(name, MAX_NAMELEN, "%s", action->name);
+
+ /* create /proc/irq/1234/handler/ */
+ action->dir = proc_mkdir(name, irq_dir[irq]);
+}
+
+
+unsigned long prof_cpu_mask = -1;
+
+void generic_init_irq_proc(void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", NULL);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+ if (!entry)
+ return;
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ register_irq_proc(i);
+}
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:06 [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Ingo Molnar
@ 2004-09-08 12:29 ` La Monte H.P. Yarroll
2004-09-08 13:25 ` Christoph Hellwig
2004-09-08 12:34 ` Christoph Hellwig
1 sibling, 1 reply; 38+ messages in thread
From: La Monte H.P. Yarroll @ 2004-09-08 12:29 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Andrew Morton, linux-kernel, Scott Wood, Andrey Panin
Ingo Molnar wrote:
>the attached patch moves generic hardirq handling bits to
>kernel/hardirq.c. It is not a replacement for any of the existing IRQ
>functions, so architectures can use their existing hardirq code in an
>unmodified form. It is a library of generic functions that an
>architecture can make use of optionally.
>
>I've fully converted x86's irq.c to use the new functions, and Scott
>Wood has done the same for ppc/ppc64 as well. (the arch-ppc* changes are
>not included in this patch because i couldnt test them myself in the
>current port of this patch - but the generic bits were tested on ppc.)
>
>
In the interests of full provinence, the TimeSys patches are based on
work by Andrey Panin.
>i have test-compiled and test-booted the patch on x86 and x64, on SMP &&
>PREEMPT and !SMP && !PREEMPT kernels. x64 needed only a single change (a
>setup_irq() prototype) to work fine, which makes me believe that the
>patch will not break other architectures either.
>
>(a more complex version of this patch has been tested for weeks as part
>of the voluntary-preempt patches as well.)
>
> Ingo
>
>
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell's sig
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:06 [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Ingo Molnar
2004-09-08 12:29 ` La Monte H.P. Yarroll
@ 2004-09-08 12:34 ` Christoph Hellwig
2004-09-08 12:45 ` Ingo Molnar
1 sibling, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 12:34 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 02:06:13PM +0200, Ingo Molnar wrote:
>
> the attached patch moves generic hardirq handling bits to
> kernel/hardirq.c. It is not a replacement for any of the existing IRQ
> functions, so architectures can use their existing hardirq code in an
> unmodified form. It is a library of generic functions that an
> architecture can make use of optionally.
>
> I've fully converted x86's irq.c to use the new functions, and Scott
> Wood has done the same for ppc/ppc64 as well. (the arch-ppc* changes are
> not included in this patch because i couldnt test them myself in the
> current port of this patch - but the generic bits were tested on ppc.)
>
> i have test-compiled and test-booted the patch on x86 and x64, on SMP &&
> PREEMPT and !SMP && !PREEMPT kernels. x64 needed only a single change (a
> setup_irq() prototype) to work fine, which makes me believe that the
> patch will not break other architectures either.
>
> (a more complex version of this patch has been tested for weeks as part
> of the voluntary-preempt patches as well.)
> +++ linux/include/asm-x86_64/hardirq.h
> @@ -25,8 +25,8 @@
> * - ( bit 26 is the PREEMPT_ACTIVE flag. )
> *
> * PREEMPT_MASK: 0x000000ff
> - * HARDIRQ_MASK: 0x0000ff00
> - * SOFTIRQ_MASK: 0x00ff0000
> + * SOFTIRQ_MASK: 0x0000ff00
> + * HARDIRQ_MASK: 0x00ff0000
> */
>
> #define PREEMPT_BITS 8
> @@ -99,4 +99,6 @@ do { \
> extern void synchronize_irq(unsigned int irq);
> #endif /* CONFIG_SMP */
>
> +extern int setup_irq(unsigned int irq, struct irqaction * new);
This doesn't apply anymore because most of <asm/hardirq.h> moved
to linux/hardirq.h in -mm and a the patch is on it's way to Linus.
> @@ -71,10 +74,21 @@ extern irq_desc_t irq_desc [NR_IRQS];
>
> #include <asm/hw_irq.h> /* the arch dependent stuff */
>
> -extern int setup_irq(unsigned int , struct irqaction * );
> +
> +extern asmlinkage int generic_handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
> +extern void generic_synchronize_irq(unsigned int irq);
> +extern int generic_setup_irq(unsigned int irq, struct irqaction * new);
> +extern void generic_free_irq(unsigned int irq, void *dev_id);
> +extern void generic_disable_irq_nosync(unsigned int irq);
> +extern void generic_disable_irq(unsigned int irq);
> +extern void generic_enable_irq(unsigned int irq);
> +extern void generic_note_interrupt(int irq, irq_desc_t *desc, int action_ret);
Please don't introduce the generic_ names just to have every arch (in your
previous patches, that is) provide a wrapper with normal names again.
> --- linux/kernel/Makefile.orig
> +++ linux/kernel/Makefile
> @@ -3,7 +3,7 @@
> #
>
> obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
> - exit.o itimer.o time.o softirq.o resource.o \
> + exit.o itimer.o time.o softirq.o hardirq.o resource.o \
And make hardirq.o dependent on some symbols the architectures set.
Else arches that don't use it carry tons of useless baggage around (and
in fact I'm pretty sure it wouldn't even compie for many)
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:34 ` Christoph Hellwig
@ 2004-09-08 12:45 ` Ingo Molnar
2004-09-08 12:49 ` Christoph Hellwig
` (2 more replies)
0 siblings, 3 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 12:45 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
* Christoph Hellwig <hch@infradead.org> wrote:
> > @@ -99,4 +99,6 @@ do { \
> > extern void synchronize_irq(unsigned int irq);
> > #endif /* CONFIG_SMP */
> >
> > +extern int setup_irq(unsigned int irq, struct irqaction * new);
>
> This doesn't apply anymore because most of <asm/hardirq.h> moved to
> linux/hardirq.h in -mm and a the patch is on it's way to Linus.
(yeah. not a big issue - can happen in any order. this patch is against
BK-curr.)
> > +extern asmlinkage int generic_handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
> > +extern void generic_synchronize_irq(unsigned int irq);
> > +extern int generic_setup_irq(unsigned int irq, struct irqaction * new);
> > +extern void generic_free_irq(unsigned int irq, void *dev_id);
> > +extern void generic_disable_irq_nosync(unsigned int irq);
> > +extern void generic_disable_irq(unsigned int irq);
> > +extern void generic_enable_irq(unsigned int irq);
> > +extern void generic_note_interrupt(int irq, irq_desc_t *desc, int action_ret);
>
> Please don't introduce the generic_ names just to have every arch (in
> your previous patches, that is) provide a wrapper with normal names
> again.
some of the architectures dont want to (and cannot) use the generic
functions for one reason or another. So the proper approach i believe is
to provide these generic functions the architectures can plug in. I can
do an asm-generic/hardirq.h that adds all the definitions, for
architectures that dont need any special IRQ logic.
> > obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
> > - exit.o itimer.o time.o softirq.o resource.o \
> > + exit.o itimer.o time.o softirq.o hardirq.o resource.o \
>
> And make hardirq.o dependent on some symbols the architectures set.
> Else arches that don't use it carry tons of useless baggage around
> (and in fact I'm pretty sure it wouldn't even compie for many)
it compiles fine on x86, x64, ppc and ppc64. Why do you think it wont
compile on others?
wrt. unused generic functions - why dont we drop them link-time?
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:45 ` Ingo Molnar
@ 2004-09-08 12:49 ` Christoph Hellwig
2004-09-08 13:05 ` Ingo Molnar
2004-09-08 12:57 ` William Lee Irwin III
2004-09-08 13:03 ` [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Arjan van de Ven
2 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 12:49 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 02:45:47PM +0200, Ingo Molnar wrote:
> some of the architectures dont want to (and cannot) use the generic
> functions for one reason or another. So the proper approach i believe is
> to provide these generic functions the architectures can plug in. I can
> do an asm-generic/hardirq.h that adds all the definitions, for
> architectures that dont need any special IRQ logic.
Some architectures definitly can't use it. That's why the prototypes for
them arch in arch-headers. No need to introduce totally useless wrappers.
The asm-generic one sounds like a good idea, but I'd wait with that one
until the consolidation is mostly finished, aka all architectures that
currently use more or less a copy of the i386 irq.c are migrated over so
we can see it's scope.
> > > obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
> > > - exit.o itimer.o time.o softirq.o resource.o \
> > > + exit.o itimer.o time.o softirq.o hardirq.o resource.o \
> >
> > And make hardirq.o dependent on some symbols the architectures set.
> > Else arches that don't use it carry tons of useless baggage around
> > (and in fact I'm pretty sure it wouldn't even compie for many)
>
> it compiles fine on x86, x64, ppc and ppc64. Why do you think it wont
> compile on others?
linux/irq.h is despite it's name _not_ a public header but a misnamed
asm-generic/hw_irq.h. There's quite a few architectures with a completely
different interrupt architecture and for tose it won't compile.
> wrt. unused generic functions - why dont we drop them link-time?
make explicit what you can do easily instead of relying on the compiler.
It allows to get rid of your horrible generic_ hacks, cuts down compile
time and makes explicit to anyone looking at the code and Kconfig which
architectures use this.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:45 ` Ingo Molnar
2004-09-08 12:49 ` Christoph Hellwig
@ 2004-09-08 12:57 ` William Lee Irwin III
2004-09-08 13:01 ` Christoph Hellwig
2004-09-08 13:34 ` Zwane Mwaikambo
2004-09-08 13:03 ` [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Arjan van de Ven
2 siblings, 2 replies; 38+ messages in thread
From: William Lee Irwin III @ 2004-09-08 12:57 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
* Christoph Hellwig <hch@infradead.org> wrote:
>> And make hardirq.o dependent on some symbols the architectures set.
>> Else arches that don't use it carry tons of useless baggage around
>> (and in fact I'm pretty sure it wouldn't even compie for many)
On Wed, Sep 08, 2004 at 02:45:47PM +0200, Ingo Molnar wrote:
> it compiles fine on x86, x64, ppc and ppc64. Why do you think it wont
> compile on others?
> wrt. unused generic functions - why dont we drop them link-time?
It may be time for a __weak define to abbreviate __attribute__((weak));
we seem to use it in enough places.
-- wli
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:57 ` William Lee Irwin III
@ 2004-09-08 13:01 ` Christoph Hellwig
2004-09-08 13:09 ` William Lee Irwin III
2004-09-08 13:10 ` Ingo Molnar
2004-09-08 13:34 ` Zwane Mwaikambo
1 sibling, 2 replies; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:01 UTC (permalink / raw)
To: William Lee Irwin III, Ingo Molnar, Christoph Hellwig,
Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 05:57:55AM -0700, William Lee Irwin III wrote:
> * Christoph Hellwig <hch@infradead.org> wrote:
> >> And make hardirq.o dependent on some symbols the architectures set.
> >> Else arches that don't use it carry tons of useless baggage around
> >> (and in fact I'm pretty sure it wouldn't even compie for many)
>
> On Wed, Sep 08, 2004 at 02:45:47PM +0200, Ingo Molnar wrote:
> > it compiles fine on x86, x64, ppc and ppc64. Why do you think it wont
> > compile on others?
> > wrt. unused generic functions - why dont we drop them link-time?
>
> It may be time for a __weak define to abbreviate __attribute__((weak));
> we seem to use it in enough places.
Personally I'm extremly unhappy with that week model for things like
this. There's no reason why architectures could implement irq handling
as inlines. Or in case of s390 not at all.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:45 ` Ingo Molnar
2004-09-08 12:49 ` Christoph Hellwig
2004-09-08 12:57 ` William Lee Irwin III
@ 2004-09-08 13:03 ` Arjan van de Ven
2 siblings, 0 replies; 38+ messages in thread
From: Arjan van de Ven @ 2004-09-08 13:03 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 290 bytes --]
> wrt. unused generic functions - why dont we drop them link-time?
actually if nothing uses ANY function of a .o file then yes the entire
.o gets dropped.
(we should make the kernel use -ffunction-sections some day to make it
on a per function instead of on a per .o file basis)
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:49 ` Christoph Hellwig
@ 2004-09-08 13:05 ` Ingo Molnar
2004-09-08 13:12 ` Christoph Hellwig
0 siblings, 1 reply; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 13:05 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
* Christoph Hellwig <hch@infradead.org> wrote:
> > wrt. unused generic functions - why dont we drop them link-time?
>
> make explicit what you can do easily instead of relying on the
> compiler. It allows to get rid of your horrible generic_ hacks, cuts
> down compile time and makes explicit to anyone looking at the code and
> Kconfig which architectures use this.
i disagree. It's the same as the VFS model: we have generic_block_bmap()
which a filesystem might or might not make use of. It's still around
even if no filesystem makes use of it but do we care? I'd prefer fixing
our linking logic to get rid of unused functions than complicating code
and the architecture with conditionals.
is there any architecture that cannot make use of kernel/hardirq.c _at
all_?
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:01 ` Christoph Hellwig
@ 2004-09-08 13:09 ` William Lee Irwin III
2004-09-08 13:10 ` Ingo Molnar
1 sibling, 0 replies; 38+ messages in thread
From: William Lee Irwin III @ 2004-09-08 13:09 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: Ingo Molnar, Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 05:57:55AM -0700, William Lee Irwin III wrote:
>> It may be time for a __weak define to abbreviate __attribute__((weak));
>> we seem to use it in enough places.
On Wed, Sep 08, 2004 at 02:01:46PM +0100, Christoph Hellwig wrote:
> Personally I'm extremly unhappy with that week model for things like
> this. There's no reason why architectures could implement irq handling
> as inlines. Or in case of s390 not at all.
If there's a question of "not at all" that probably rules out weak
symbols as a method of handling it.
-- wli
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:01 ` Christoph Hellwig
2004-09-08 13:09 ` William Lee Irwin III
@ 2004-09-08 13:10 ` Ingo Molnar
1 sibling, 0 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 13:10 UTC (permalink / raw)
To: Christoph Hellwig, William Lee Irwin III, Andrew Morton,
linux-kernel, Scott Wood
* Christoph Hellwig <hch@infradead.org> wrote:
> Personally I'm extremly unhappy with that week model for things like
> this. There's no reason why architectures could implement irq
> handling as inlines. Or in case of s390 not at all.
s390 is a special case i agree - no IRQ handling is a special case. We
can exclude kernel/hardirq.o on s390 and all virtual-guest platforms.
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:05 ` Ingo Molnar
@ 2004-09-08 13:12 ` Christoph Hellwig
2004-09-08 13:17 ` Ingo Molnar
2004-09-09 17:56 ` Scott Wood
0 siblings, 2 replies; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:12 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 03:05:52PM +0200, Ingo Molnar wrote:
> i disagree. It's the same as the VFS model: we have generic_block_bmap()
> which a filesystem might or might not make use of. It's still around
> even if no filesystem makes use of it but do we care? I'd prefer fixing
> our linking logic to get rid of unused functions than complicating code
> and the architecture with conditionals.
Completley different model. VFS supports lots of filesystem implementation
with one interface. IRQ code is a a single implementation for each
architecture.
> is there any architecture that cannot make use of kernel/hardirq.c _at
> all_?
s390 doesn't need it at all because it doesn't have the concept of hardirqs.
At least arm{,26}, m68k{,nommu} and parisc and sparc{,64} use extremly
different models for irq handling
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:12 ` Christoph Hellwig
@ 2004-09-08 13:17 ` Ingo Molnar
2004-09-08 13:20 ` Christoph Hellwig
2004-09-09 17:56 ` Scott Wood
1 sibling, 1 reply; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 13:17 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
* Christoph Hellwig <hch@infradead.org> wrote:
> > i disagree. It's the same as the VFS model: we have generic_block_bmap()
> > which a filesystem might or might not make use of. It's still around
> > even if no filesystem makes use of it but do we care? I'd prefer fixing
> > our linking logic to get rid of unused functions than complicating code
> > and the architecture with conditionals.
>
> Completley different model. VFS supports lots of filesystem
> implementation with one interface. IRQ code is a a single
> implementation for each architecture.
not at all different model. 90% of the important drivers (no,
drivers/s390 doesnt count) are shared between multiple architectures
using the same interface: request_irq()/free_irq() and a handler with an
enumerated irq vector.
> > is there any architecture that cannot make use of kernel/hardirq.c _at
> > all_?
>
> s390 doesn't need it at all because it doesn't have the concept of hardirqs.
>
> At least arm{,26}, m68k{,nommu} and parisc and sparc{,64} use extremly
> different models for irq handling
it could be a bit like nommu - a noirq model.
i agree with enabling an architecture to exclude _all_ of hardirq.c, but
specifying per-function is excessive - if an architecture can make use
of some of them then weak symbols will get rid of the rest.
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:17 ` Ingo Molnar
@ 2004-09-08 13:20 ` Christoph Hellwig
2004-09-08 13:32 ` Ingo Molnar
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:20 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 03:17:20PM +0200, Ingo Molnar wrote:
> not at all different model. 90% of the important drivers (no,
> drivers/s390 doesnt count) are shared between multiple architectures
> using the same interface: request_irq()/free_irq() and a handler with an
> enumerated irq vector.
Sure, but that's not the level we're talking about. The function we talk
about compare to the vfs_* routines (when looking at the arches with
i386-style generic irq code)(
> > s390 doesn't need it at all because it doesn't have the concept of hardirqs.
> >
> > At least arm{,26}, m68k{,nommu} and parisc and sparc{,64} use extremly
> > different models for irq handling
>
> it could be a bit like nommu - a noirq model.
>
> i agree with enabling an architecture to exclude _all_ of hardirq.c, but
> specifying per-function is excessive - if an architecture can make use
> of some of them then weak symbols will get rid of the rest.
I never wanted to exclude individual functions. But when you look at
arch/*/kernel/irq.c I don't see a reason for doing it at all. It makes
sense to make this an all or nothing switch.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:29 ` La Monte H.P. Yarroll
@ 2004-09-08 13:25 ` Christoph Hellwig
2004-09-08 13:40 ` Ingo Molnar
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:25 UTC (permalink / raw)
To: La Monte H.P. Yarroll
Cc: Ingo Molnar, Andrew Morton, linux-kernel, Scott Wood,
Andrey Panin
On Wed, Sep 08, 2004 at 08:29:05AM -0400, La Monte H.P. Yarroll wrote:
> In the interests of full provinence, the TimeSys patches are based on
> work by Andrey Panin.
Btw, Andrey's patches got all the things right I complained about :)
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:34 ` Zwane Mwaikambo
@ 2004-09-08 13:31 ` Christoph Hellwig
2004-09-08 13:47 ` Zwane Mwaikambo
0 siblings, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:31 UTC (permalink / raw)
To: Zwane Mwaikambo
Cc: William Lee Irwin III, Ingo Molnar, Christoph Hellwig,
Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 09:34:03AM -0400, Zwane Mwaikambo wrote:
> Hmm, whenever i've brought up weak functions in a patch it's never well
> received. Frankly i prefer it to littering the architectures with similar
> functions.
That's what we have asm-generic for.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:20 ` Christoph Hellwig
@ 2004-09-08 13:32 ` Ingo Molnar
0 siblings, 0 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 13:32 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton, linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 879 bytes --]
* Christoph Hellwig <hch@infradead.org> wrote:
> > > s390 doesn't need it at all because it doesn't have the concept of hardirqs.
> > >
> > > At least arm{,26}, m68k{,nommu} and parisc and sparc{,64} use extremly
> > > different models for irq handling
> >
> > it could be a bit like nommu - a noirq model.
> >
> > i agree with enabling an architecture to exclude _all_ of hardirq.c, but
> > specifying per-function is excessive - if an architecture can make use
> > of some of them then weak symbols will get rid of the rest.
>
> I never wanted to exclude individual functions. But when you look at
> arch/*/kernel/irq.c I don't see a reason for doing it at all. It
> makes sense to make this an all or nothing switch.
ok, agreed. New patch attached. An architecture has to set
GENERIC_HARDIRQS in Kconfig to get it compiled by default. x86 does this
for now.
Ingo
[-- Attachment #2: generic-hardirqs-2.6.9-rc1-bk14-A5 --]
[-- Type: text/plain, Size: 31054 bytes --]
--- linux/arch/i386/kernel/i386_ksyms.c.orig
+++ linux/arch/i386/kernel/i386_ksyms.c
@@ -77,9 +77,6 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
@@ -147,7 +144,6 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
/* Global SMP stuff */
-EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
/* TLB flushing */
--- linux/arch/i386/kernel/irq.c.orig
+++ linux/arch/i386/kernel/irq.c
@@ -71,8 +71,6 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
}
};
-static void register_irq_proc (unsigned int irq);
-
/*
* per-CPU IRQ handling stacks
*/
@@ -198,218 +196,6 @@ skip:
return 0;
}
-
-
-
-#ifdef CONFIG_SMP
-inline void synchronize_irq(unsigned int irq)
-{
- while (irq_desc[irq].status & IRQ_INPROGRESS)
- cpu_relax();
-}
-#endif
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-asmlinkage int handle_IRQ_event(unsigned int irq,
- struct pt_regs *regs, struct irqaction *action)
-{
- int status = 1; /* Force the "do bottom halves" bit */
- int ret, retval = 0;
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
- return retval;
-}
-
-static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- struct irqaction *action;
-
- if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
- printk(KERN_ERR "irq event %d: bogus return value %x\n",
- irq, action_ret);
- } else {
- printk(KERN_ERR "irq %d: nobody cared!\n", irq);
- }
- dump_stack();
- printk(KERN_ERR "handlers:\n");
- action = desc->action;
- do {
- printk(KERN_ERR "[<%p>]", action->handler);
- print_symbol(" (%s)",
- (unsigned long)action->handler);
- printk("\n");
- action = action->next;
- } while (action);
-}
-
-static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- static int count = 100;
-
- if (count) {
- count--;
- __report_bad_irq(irq, desc, action_ret);
- }
-}
-
-static int noirqdebug;
-
-static int __init noirqdebug_setup(char *str)
-{
- noirqdebug = 1;
- printk("IRQ lockup detection disabled\n");
- return 1;
-}
-
-__setup("noirqdebug", noirqdebug_setup);
-
-/*
- * 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 and try to
- * turn the IRQ off.
- *
- * (The other 100-of-100,000 interrupts may have been a correctly-functioning
- * device sharing an IRQ with the failing one)
- *
- * Called under desc->lock
- */
-static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- if (action_ret != IRQ_HANDLED) {
- desc->irqs_unhandled++;
- if (action_ret != IRQ_NONE)
- report_bad_irq(irq, desc, action_ret);
- }
-
- desc->irq_count++;
- if (desc->irq_count < 100000)
- return;
-
- desc->irq_count = 0;
- if (desc->irqs_unhandled > 99900) {
- /*
- * The interrupt is stuck
- */
- __report_bad_irq(irq, desc, action_ret);
- /*
- * Now kill the IRQ
- */
- printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- desc->irqs_unhandled = 0;
-}
-
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables and Enables are
- * nested.
- * Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-inline void disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Enables and Disables are
- * nested.
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- disable_irq_nosync(irq);
- if (desc->action)
- synchronize_irq(irq);
-}
-
-/**
- * enable_irq - enable handling of an irq
- * @irq: Interrupt to enable
- *
- * Undoes the effect of one call to disable_irq(). If this
- * matches the last disable, processing of interrupts on this
- * IRQ line is re-enabled.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
@@ -510,7 +296,7 @@ asmlinkage unsigned int do_IRQ(struct pt
*/
if (curctx == irqctx)
- action_ret = handle_IRQ_event(irq, ®s, action);
+ action_ret = generic_handle_IRQ_event(irq, ®s, action);
else {
/* build the stack frame on the IRQ stack */
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -523,7 +309,7 @@ asmlinkage unsigned int do_IRQ(struct pt
asm volatile(
" xchgl %%ebx,%%esp \n"
- " call handle_IRQ_event \n"
+ " call generic_handle_IRQ_event \n"
" xchgl %%ebx,%%esp \n"
: "=a"(action_ret)
: "b"(isp)
@@ -534,7 +320,7 @@ asmlinkage unsigned int do_IRQ(struct pt
}
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ generic_note_interrupt(irq, desc, action_ret);
if (curctx != irqctx)
irqctx->tinfo.task = NULL;
if (likely(!(desc->status & IRQ_PENDING)))
@@ -549,11 +335,11 @@ asmlinkage unsigned int do_IRQ(struct pt
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, ®s, action);
+ action_ret = generic_handle_IRQ_event(irq, ®s, action);
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ generic_note_interrupt(irq, desc, action_ret);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
@@ -659,7 +445,7 @@ int request_irq(unsigned int irq,
action->next = NULL;
action->dev_id = dev_id;
- retval = setup_irq(irq, action);
+ retval = generic_setup_irq(irq, action);
if (retval)
kfree(action);
return retval;
@@ -667,62 +453,6 @@ int request_irq(unsigned int irq,
EXPORT_SYMBOL(request_irq);
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- /* Wait to make sure it's not being used on another CPU */
- synchronize_irq(irq);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
/*
* IRQ autodetection code..
*
@@ -918,165 +648,6 @@ int probe_irq_off(unsigned long val)
EXPORT_SYMBOL(probe_irq_off);
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- if (desc->handler == &no_irq_type)
- return -ENOSYS;
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- register_irq_proc(irq);
- return 0;
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NR_IRQS];
-
-#ifdef CONFIG_SMP
-
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-static int irq_affinity_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
- if (count - len < 2)
- return -EINVAL;
- len += sprintf(page + len, "\n");
- return len;
-}
-
-static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int irq = (long)data, full_count = count, err;
- cpumask_t new_value, tmp;
-
- if (!irq_desc[irq].handler->set_affinity)
- return -EIO;
-
- err = cpumask_parse(buffer, count, new_value);
- if (err)
- return err;
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- cpus_and(tmp, new_value, cpu_online_map);
- if (cpus_empty(tmp))
- return -EINVAL;
-
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq,
- cpumask_of_cpu(first_cpu(new_value)));
-
- return full_count;
-}
-
-#endif
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
- irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%d", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#ifdef CONFIG_SMP
- {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
-
- smp_affinity_entry[irq] = entry;
- }
-#endif
-}
-
-void init_irq_proc (void)
-{
- int i;
-
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
- create_prof_cpu_mask(root_irq_dir);
- /*
- * Create entries for all existing IRQs.
- */
- for (i = 0; i < NR_IRQS; i++)
- register_irq_proc(i);
-}
-
-
#ifdef CONFIG_4KSTACKS
/*
* These should really be __section__(".bss.page_aligned") as well, but
--- linux/arch/i386/Kconfig.orig
+++ linux/arch/i386/Kconfig
@@ -1190,6 +1190,10 @@ source "crypto/Kconfig"
source "lib/Kconfig"
+config GENERIC_HARDIRQS
+ bool
+ default y
+
config X86_SMP
bool
depends on SMP && !X86_VOYAGER
--- linux/include/asm-x86_64/hardirq.h.orig
+++ linux/include/asm-x86_64/hardirq.h
@@ -99,4 +99,6 @@ do { \
extern void synchronize_irq(unsigned int irq);
#endif /* CONFIG_SMP */
+extern int setup_irq(unsigned int irq, struct irqaction * new);
+
#endif /* __ASM_HARDIRQ_H */
--- linux/include/linux/irq.h.orig
+++ linux/include/linux/irq.h
@@ -10,12 +10,15 @@
*/
#include <linux/config.h>
+#include <linux/linkage.h>
#if !defined(CONFIG_ARCH_S390)
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -71,10 +74,21 @@ extern irq_desc_t irq_desc [NR_IRQS];
#include <asm/hw_irq.h> /* the arch dependent stuff */
-extern int setup_irq(unsigned int , struct irqaction * );
+
+extern asmlinkage int generic_handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
+extern void generic_synchronize_irq(unsigned int irq);
+extern int generic_setup_irq(unsigned int irq, struct irqaction * new);
+extern void generic_free_irq(unsigned int irq, void *dev_id);
+extern void generic_disable_irq_nosync(unsigned int irq);
+extern void generic_disable_irq(unsigned int irq);
+extern void generic_enable_irq(unsigned int irq);
+extern void generic_note_interrupt(int irq, irq_desc_t *desc, int action_ret);
+extern void generic_init_irq_proc(void);
extern hw_irq_controller no_irq_type; /* needed in every arch ? */
+extern int noirqdebug;
+
#endif
#endif /* __irq_h */
--- linux/include/linux/interrupt.h.orig
+++ linux/include/linux/interrupt.h
@@ -40,6 +40,8 @@ struct irqaction {
const char *name;
void *dev_id;
struct irqaction *next;
+ int irq;
+ struct proc_dir_entry *dir;
};
extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
--- linux/include/asm-i386/irq.h.orig
+++ linux/include/asm-i386/irq.h
@@ -21,9 +21,6 @@ static __inline__ int irq_canonicalize(i
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
extern void release_x86_irqs(struct task_struct *);
extern int can_request_irq(unsigned int, unsigned long flags);
--- linux/include/asm-i386/hardirq.h.orig
+++ linux/include/asm-i386/hardirq.h
@@ -68,10 +68,6 @@ typedef struct {
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
-
-#define hardirq_trylock() (!in_interrupt())
-#define hardirq_endlock() do { } while (0)
-
#define irq_enter() (preempt_count() += HARDIRQ_OFFSET)
#define nmi_enter() (irq_enter())
#define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET)
@@ -92,10 +88,39 @@ do { \
preempt_enable_no_resched(); \
} while (0)
-#ifndef CONFIG_SMP
-# define synchronize_irq(irq) barrier()
-#else
- extern void synchronize_irq(unsigned int irq);
-#endif /* CONFIG_SMP */
+static inline void synchronize_irq(unsigned int irq)
+{
+ generic_synchronize_irq(irq);
+}
+
+static inline void free_irq(unsigned int irq, void *dev_id)
+{
+ generic_free_irq(irq, dev_id);
+}
+
+static inline void disable_irq_nosync(unsigned int irq)
+{
+ generic_disable_irq_nosync(irq);
+}
+
+static inline void disable_irq(unsigned int irq)
+{
+ generic_disable_irq(irq);
+}
+
+static inline void enable_irq(unsigned int irq)
+{
+ generic_enable_irq(irq);
+}
+
+static inline int setup_irq(unsigned int irq, struct irqaction *new)
+{
+ return generic_setup_irq(irq, new);
+}
+
+static inline void init_irq_proc(void)
+{
+ generic_init_irq_proc();
+}
#endif /* __ASM_HARDIRQ_H */
--- linux/kernel/Makefile.orig
+++ linux/kernel/Makefile
@@ -12,6 +12,7 @@ obj-y = sched.o fork.o exec_domain.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o
+obj-$(CONFIG_GENERIC_HARDIRQS) += hardirq.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
--- linux/kernel/hardirq.c.orig
+++ linux/kernel/hardirq.c
@@ -0,0 +1,529 @@
+/*
+ * linux/kernel/hardirq.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the generic code used by various IRQ handling
+ * routines.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kallsyms.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+int noirqdebug;
+
+extern struct irq_desc irq_desc[NR_IRQS];
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+static void register_irq_proc(unsigned int irq);
+static void register_handler_proc(unsigned int irq, struct irqaction *action);
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+asmlinkage int generic_handle_IRQ_event(unsigned int irq,
+ struct pt_regs *regs, struct irqaction *action)
+{
+ int status = 1; /* Force the "do bottom halves" bit */
+ int ret, retval = 0;
+
+ if (!(action->flags & SA_INTERRUPT))
+ local_irq_enable();
+
+ do {
+ ret = action->handler(irq, action->dev_id, regs);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ local_irq_disable();
+
+ return retval;
+}
+
+static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ struct irqaction *action;
+
+ if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+ printk(KERN_ERR "irq event %d: bogus return value %x\n",
+ irq, action_ret);
+ } else {
+ printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+ }
+ dump_stack();
+ printk(KERN_ERR "handlers:\n");
+ action = desc->action;
+ while (action) {
+ printk(KERN_ERR "[<%p>]", action->handler);
+ print_symbol(" (%s)",
+ (unsigned long)action->handler);
+ printk("\n");
+ action = action->next;
+ }
+}
+
+static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ static int count = 100;
+
+ if (count) {
+ count--;
+ __report_bad_irq(irq, desc, action_ret);
+ }
+}
+
+
+static int __init noirqdebug_setup(char *str)
+{
+ noirqdebug = 1;
+ printk("IRQ lockup detection disabled\n");
+ return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
+/*
+ * 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 and try to
+ * turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly-functioning
+ * device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+void generic_note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ if (action_ret != IRQ_HANDLED) {
+ desc->irqs_unhandled++;
+ if (action_ret != IRQ_NONE)
+ report_bad_irq(irq, desc, action_ret);
+ }
+
+ desc->irq_count++;
+ if (desc->irq_count < 100000)
+ return;
+
+ desc->irq_count = 0;
+ if (desc->irqs_unhandled > 99900) {
+ /*
+ * The interrupt is stuck
+ */
+ __report_bad_irq(irq, desc, action_ret);
+ /*
+ * Now kill the IRQ
+ */
+ printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ desc->irqs_unhandled = 0;
+}
+
+void generic_synchronize_irq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ while (desc->status & IRQ_INPROGRESS)
+ cpu_relax();
+}
+
+EXPORT_SYMBOL(generic_synchronize_irq);
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ * disable_irq_nosync - disable an irq without waiting
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Disables and Enables are
+ * nested.
+ * Unlike disable_irq(), this function does not ensure existing
+ * instances of the IRQ handler have completed before returning.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void generic_disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(generic_disable_irq_nosync);
+
+/**
+ * disable_irq - disable an irq and wait for completion
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Enables and Disables are
+ * nested.
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+
+void generic_disable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ generic_disable_irq_nosync(irq);
+ if (desc->action)
+ synchronize_irq(irq);
+}
+
+EXPORT_SYMBOL(generic_disable_irq);
+
+/**
+ * enable_irq - enable handling of an irq
+ * @irq: Interrupt to enable
+ *
+ * Undoes the effect of one call to disable_irq(). If this
+ * matches the last disable, processing of interrupts on this
+ * IRQ line is re-enabled.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void generic_enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(generic_enable_irq);
+
+int generic_setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (desc->handler == &no_irq_type)
+ return -ENOSYS;
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+ if (desc->handler->startup)
+ desc->handler->startup(irq);
+ else
+ desc->handler->enable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ new->irq = irq;
+ register_irq_proc(irq);
+ new->dir = NULL;
+ register_handler_proc(irq, new);
+
+ return 0;
+}
+
+/**
+ * generic_free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+
+void generic_free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ if (desc->handler->shutdown)
+ desc->handler->shutdown(irq);
+ else
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+ if (action->dir)
+ remove_proc_entry(action->dir->name, irq_dir[irq]);
+
+ /* Wait to make sure it's not being used on another CPU */
+ synchronize_irq(irq);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+EXPORT_SYMBOL(generic_free_irq);
+
+#ifdef CONFIG_SMP
+
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long)data, full_count = count, err;
+ cpumask_t new_value, tmp;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ cpus_and(tmp, new_value, cpu_online_map);
+ if (cpus_empty(tmp))
+ return -EINVAL;
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq,
+ cpumask_of_cpu(first_cpu(new_value)));
+
+ return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ cpumask_t *mask = (cpumask_t *)data;
+ unsigned long full_count = count, err;
+ cpumask_t new_value;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc(unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+ {
+ struct proc_dir_entry *entry;
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+#undef MAX_NAMELEN
+
+#define MAX_NAMELEN 128
+
+static void register_handler_proc(unsigned int irq, struct irqaction *action)
+{
+ char name [MAX_NAMELEN];
+
+ if (!irq_dir[irq] || action->dir || !action->name)
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ snprintf(name, MAX_NAMELEN, "%s", action->name);
+
+ /* create /proc/irq/1234/handler/ */
+ action->dir = proc_mkdir(name, irq_dir[irq]);
+}
+
+
+unsigned long prof_cpu_mask = -1;
+
+void generic_init_irq_proc(void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", NULL);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+ if (!entry)
+ return;
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ register_irq_proc(i);
+}
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 12:57 ` William Lee Irwin III
2004-09-08 13:01 ` Christoph Hellwig
@ 2004-09-08 13:34 ` Zwane Mwaikambo
2004-09-08 13:31 ` Christoph Hellwig
1 sibling, 1 reply; 38+ messages in thread
From: Zwane Mwaikambo @ 2004-09-08 13:34 UTC (permalink / raw)
To: William Lee Irwin III
Cc: Ingo Molnar, Christoph Hellwig, Andrew Morton, linux-kernel,
Scott Wood
On Wed, 8 Sep 2004, William Lee Irwin III wrote:
> * Christoph Hellwig <hch@infradead.org> wrote:
> >> And make hardirq.o dependent on some symbols the architectures set.
> >> Else arches that don't use it carry tons of useless baggage around
> >> (and in fact I'm pretty sure it wouldn't even compie for many)
>
> On Wed, Sep 08, 2004 at 02:45:47PM +0200, Ingo Molnar wrote:
> > it compiles fine on x86, x64, ppc and ppc64. Why do you think it wont
> > compile on others?
> > wrt. unused generic functions - why dont we drop them link-time?
>
> It may be time for a __weak define to abbreviate __attribute__((weak));
> we seem to use it in enough places.
Hmm, whenever i've brought up weak functions in a patch it's never well
received. Frankly i prefer it to littering the architectures with similar
functions.
Zwane
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:25 ` Christoph Hellwig
@ 2004-09-08 13:40 ` Ingo Molnar
2004-09-08 13:47 ` Christoph Hellwig
0 siblings, 1 reply; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 13:40 UTC (permalink / raw)
To: Christoph Hellwig, La Monte H.P. Yarroll, Andrew Morton,
linux-kernel, Scott Wood, Andrey Panin
* Christoph Hellwig <hch@infradead.org> wrote:
> On Wed, Sep 08, 2004 at 08:29:05AM -0400, La Monte H.P. Yarroll wrote:
> > In the interests of full provinence, the TimeSys patches are based on
> > work by Andrey Panin.
>
> Btw, Andrey's patches got all the things right I complained about :)
do you mean the irq and softirq threading patches? Unfortunately, while
they were rather clean the generic bits were also quite substantially
broken semantically on SMP so while i carried them for a while in the
voluntary-preempt patch i had to drop and redo them all from scratch.
Scott Wood then sent ppc bits which might be based on the other code.
Anyway, it seems everyone wants roughly the same thing, it only has to
actually happen now ;-) Once we have kernel/hardirq.c then the
irq-threading patches become nicely local and maintainable.
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:31 ` Christoph Hellwig
@ 2004-09-08 13:47 ` Zwane Mwaikambo
2004-09-08 14:09 ` Arjan van de Ven
0 siblings, 1 reply; 38+ messages in thread
From: Zwane Mwaikambo @ 2004-09-08 13:47 UTC (permalink / raw)
To: Christoph Hellwig
Cc: William Lee Irwin III, Ingo Molnar, Andrew Morton, linux-kernel,
Scott Wood
On Wed, 8 Sep 2004, Christoph Hellwig wrote:
> On Wed, Sep 08, 2004 at 09:34:03AM -0400, Zwane Mwaikambo wrote:
> > Hmm, whenever i've brought up weak functions in a patch it's never well
> > received. Frankly i prefer it to littering the architectures with similar
> > functions.
>
> That's what we have asm-generic for.
So you have an inline function in a header and include it everywhere? How
is that better?
Zwane
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:40 ` Ingo Molnar
@ 2004-09-08 13:47 ` Christoph Hellwig
0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-08 13:47 UTC (permalink / raw)
To: Ingo Molnar
Cc: Christoph Hellwig, La Monte H.P. Yarroll, Andrew Morton,
linux-kernel, Scott Wood, Andrey Panin
On Wed, Sep 08, 2004 at 03:40:32PM +0200, Ingo Molnar wrote:
>
> * Christoph Hellwig <hch@infradead.org> wrote:
>
> > On Wed, Sep 08, 2004 at 08:29:05AM -0400, La Monte H.P. Yarroll wrote:
> > > In the interests of full provinence, the TimeSys patches are based on
> > > work by Andrey Panin.
> >
> > Btw, Andrey's patches got all the things right I complained about :)
>
> do you mean the irq and softirq threading patches?
No, irq.c consolidation.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:47 ` Zwane Mwaikambo
@ 2004-09-08 14:09 ` Arjan van de Ven
2004-09-08 18:25 ` Ingo Molnar
0 siblings, 1 reply; 38+ messages in thread
From: Arjan van de Ven @ 2004-09-08 14:09 UTC (permalink / raw)
To: Zwane Mwaikambo
Cc: Christoph Hellwig, William Lee Irwin III, Ingo Molnar,
Andrew Morton, linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 688 bytes --]
On Wed, 2004-09-08 at 15:47, Zwane Mwaikambo wrote:
> On Wed, 8 Sep 2004, Christoph Hellwig wrote:
>
> > On Wed, Sep 08, 2004 at 09:34:03AM -0400, Zwane Mwaikambo wrote:
> > > Hmm, whenever i've brought up weak functions in a patch it's never well
> > > received. Frankly i prefer it to littering the architectures with similar
> > > functions.
> >
> > That's what we have asm-generic for.
>
> So you have an inline function in a header and include it everywhere? How
> is that better?
the thing is, now with the config option, you don't need the generic_
wrapper thing, just use the full real name. And the prototypes can be
generic for the arch's that want it.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 14:09 ` Arjan van de Ven
@ 2004-09-08 18:25 ` Ingo Molnar
2004-09-08 18:42 ` Zwane Mwaikambo
2004-09-08 21:14 ` [patch] generic-hardirqs-2.6.9-rc1-mm4.patch Ingo Molnar
0 siblings, 2 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 18:25 UTC (permalink / raw)
To: Arjan van de Ven
Cc: Zwane Mwaikambo, Christoph Hellwig, William Lee Irwin III,
Andrew Morton, linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 415 bytes --]
* Arjan van de Ven <arjanv@redhat.com> wrote:
> the thing is, now with the config option, you don't need the generic_
> wrapper thing, just use the full real name. And the prototypes can be
> generic for the arch's that want it.
latest patch attached - this should compile on every architecture. It's
basically what Christoph suggested first time around :-) Compiles/boots
on x86. Any other observations?
Ingo
[-- Attachment #2: generic-hardirqs-2.6.9-rc1-bk14-A6 --]
[-- Type: text/plain, Size: 28310 bytes --]
--- linux/arch/i386/kernel/i386_ksyms.c.orig
+++ linux/arch/i386/kernel/i386_ksyms.c
@@ -77,9 +77,6 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
@@ -147,7 +144,6 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
/* Global SMP stuff */
-EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
/* TLB flushing */
--- linux/arch/i386/kernel/irq.c.orig
+++ linux/arch/i386/kernel/irq.c
@@ -71,8 +71,6 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
}
};
-static void register_irq_proc (unsigned int irq);
-
/*
* per-CPU IRQ handling stacks
*/
@@ -198,218 +196,6 @@ skip:
return 0;
}
-
-
-
-#ifdef CONFIG_SMP
-inline void synchronize_irq(unsigned int irq)
-{
- while (irq_desc[irq].status & IRQ_INPROGRESS)
- cpu_relax();
-}
-#endif
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-asmlinkage int handle_IRQ_event(unsigned int irq,
- struct pt_regs *regs, struct irqaction *action)
-{
- int status = 1; /* Force the "do bottom halves" bit */
- int ret, retval = 0;
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
- return retval;
-}
-
-static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- struct irqaction *action;
-
- if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
- printk(KERN_ERR "irq event %d: bogus return value %x\n",
- irq, action_ret);
- } else {
- printk(KERN_ERR "irq %d: nobody cared!\n", irq);
- }
- dump_stack();
- printk(KERN_ERR "handlers:\n");
- action = desc->action;
- do {
- printk(KERN_ERR "[<%p>]", action->handler);
- print_symbol(" (%s)",
- (unsigned long)action->handler);
- printk("\n");
- action = action->next;
- } while (action);
-}
-
-static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- static int count = 100;
-
- if (count) {
- count--;
- __report_bad_irq(irq, desc, action_ret);
- }
-}
-
-static int noirqdebug;
-
-static int __init noirqdebug_setup(char *str)
-{
- noirqdebug = 1;
- printk("IRQ lockup detection disabled\n");
- return 1;
-}
-
-__setup("noirqdebug", noirqdebug_setup);
-
-/*
- * 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 and try to
- * turn the IRQ off.
- *
- * (The other 100-of-100,000 interrupts may have been a correctly-functioning
- * device sharing an IRQ with the failing one)
- *
- * Called under desc->lock
- */
-static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- if (action_ret != IRQ_HANDLED) {
- desc->irqs_unhandled++;
- if (action_ret != IRQ_NONE)
- report_bad_irq(irq, desc, action_ret);
- }
-
- desc->irq_count++;
- if (desc->irq_count < 100000)
- return;
-
- desc->irq_count = 0;
- if (desc->irqs_unhandled > 99900) {
- /*
- * The interrupt is stuck
- */
- __report_bad_irq(irq, desc, action_ret);
- /*
- * Now kill the IRQ
- */
- printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- desc->irqs_unhandled = 0;
-}
-
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables and Enables are
- * nested.
- * Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-inline void disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Enables and Disables are
- * nested.
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- disable_irq_nosync(irq);
- if (desc->action)
- synchronize_irq(irq);
-}
-
-/**
- * enable_irq - enable handling of an irq
- * @irq: Interrupt to enable
- *
- * Undoes the effect of one call to disable_irq(). If this
- * matches the last disable, processing of interrupts on this
- * IRQ line is re-enabled.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
/*
* do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
@@ -667,62 +453,6 @@ int request_irq(unsigned int irq,
EXPORT_SYMBOL(request_irq);
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- /* Wait to make sure it's not being used on another CPU */
- synchronize_irq(irq);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
/*
* IRQ autodetection code..
*
@@ -918,165 +648,6 @@ int probe_irq_off(unsigned long val)
EXPORT_SYMBOL(probe_irq_off);
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- if (desc->handler == &no_irq_type)
- return -ENOSYS;
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- register_irq_proc(irq);
- return 0;
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NR_IRQS];
-
-#ifdef CONFIG_SMP
-
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-static int irq_affinity_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
- if (count - len < 2)
- return -EINVAL;
- len += sprintf(page + len, "\n");
- return len;
-}
-
-static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int irq = (long)data, full_count = count, err;
- cpumask_t new_value, tmp;
-
- if (!irq_desc[irq].handler->set_affinity)
- return -EIO;
-
- err = cpumask_parse(buffer, count, new_value);
- if (err)
- return err;
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- cpus_and(tmp, new_value, cpu_online_map);
- if (cpus_empty(tmp))
- return -EINVAL;
-
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq,
- cpumask_of_cpu(first_cpu(new_value)));
-
- return full_count;
-}
-
-#endif
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
- irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%d", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#ifdef CONFIG_SMP
- {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
-
- smp_affinity_entry[irq] = entry;
- }
-#endif
-}
-
-void init_irq_proc (void)
-{
- int i;
-
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
- create_prof_cpu_mask(root_irq_dir);
- /*
- * Create entries for all existing IRQs.
- */
- for (i = 0; i < NR_IRQS; i++)
- register_irq_proc(i);
-}
-
-
#ifdef CONFIG_4KSTACKS
/*
* These should really be __section__(".bss.page_aligned") as well, but
--- linux/arch/i386/Kconfig.orig
+++ linux/arch/i386/Kconfig
@@ -1190,6 +1190,10 @@ source "crypto/Kconfig"
source "lib/Kconfig"
+config GENERIC_HARDIRQS
+ bool
+ default y
+
config X86_SMP
bool
depends on SMP && !X86_VOYAGER
--- linux/include/linux/irq.h.orig
+++ linux/include/linux/irq.h
@@ -10,12 +10,15 @@
*/
#include <linux/config.h>
+#include <linux/linkage.h>
#if !defined(CONFIG_ARCH_S390)
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -71,7 +74,22 @@ extern irq_desc_t irq_desc [NR_IRQS];
#include <asm/hw_irq.h> /* the arch dependent stuff */
-extern int setup_irq(unsigned int , struct irqaction * );
+
+extern int setup_irq(unsigned int irq, struct irqaction * new);
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+extern asmlinkage int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
+extern void synchronize_irq(unsigned int irq);
+extern void free_irq(unsigned int irq, void *dev_id);
+extern void disable_irq_nosync(unsigned int irq);
+extern void disable_irq(unsigned int irq);
+extern void enable_irq(unsigned int irq);
+extern void note_interrupt(int irq, irq_desc_t *desc, int action_ret);
+extern void init_irq_proc(void);
+
+extern int noirqdebug;
+
+#endif
extern hw_irq_controller no_irq_type; /* needed in every arch ? */
--- linux/include/linux/interrupt.h.orig
+++ linux/include/linux/interrupt.h
@@ -40,6 +40,8 @@ struct irqaction {
const char *name;
void *dev_id;
struct irqaction *next;
+ int irq;
+ struct proc_dir_entry *dir;
};
extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
--- linux/include/asm-i386/irq.h.orig
+++ linux/include/asm-i386/irq.h
@@ -21,9 +21,6 @@ static __inline__ int irq_canonicalize(i
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
extern void release_x86_irqs(struct task_struct *);
extern int can_request_irq(unsigned int, unsigned long flags);
--- linux/include/asm-i386/hardirq.h.orig
+++ linux/include/asm-i386/hardirq.h
@@ -68,10 +68,6 @@ typedef struct {
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
-
-#define hardirq_trylock() (!in_interrupt())
-#define hardirq_endlock() do { } while (0)
-
#define irq_enter() (preempt_count() += HARDIRQ_OFFSET)
#define nmi_enter() (irq_enter())
#define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET)
@@ -92,10 +88,4 @@ do { \
preempt_enable_no_resched(); \
} while (0)
-#ifndef CONFIG_SMP
-# define synchronize_irq(irq) barrier()
-#else
- extern void synchronize_irq(unsigned int irq);
-#endif /* CONFIG_SMP */
-
#endif /* __ASM_HARDIRQ_H */
--- linux/kernel/Makefile.orig
+++ linux/kernel/Makefile
@@ -12,6 +12,7 @@ obj-y = sched.o fork.o exec_domain.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o
+obj-$(CONFIG_GENERIC_HARDIRQS) += hardirq.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
--- linux/kernel/hardirq.c.orig
+++ linux/kernel/hardirq.c
@@ -0,0 +1,529 @@
+/*
+ * linux/kernel/hardirq.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the generic code used by various IRQ handling
+ * routines.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kallsyms.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+int noirqdebug;
+
+extern struct irq_desc irq_desc[NR_IRQS];
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+static void register_irq_proc(unsigned int irq);
+static void register_handler_proc(unsigned int irq, struct irqaction *action);
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+asmlinkage int handle_IRQ_event(unsigned int irq,
+ struct pt_regs *regs, struct irqaction *action)
+{
+ int status = 1; /* Force the "do bottom halves" bit */
+ int ret, retval = 0;
+
+ if (!(action->flags & SA_INTERRUPT))
+ local_irq_enable();
+
+ do {
+ ret = action->handler(irq, action->dev_id, regs);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ local_irq_disable();
+
+ return retval;
+}
+
+static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ struct irqaction *action;
+
+ if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+ printk(KERN_ERR "irq event %d: bogus return value %x\n",
+ irq, action_ret);
+ } else {
+ printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+ }
+ dump_stack();
+ printk(KERN_ERR "handlers:\n");
+ action = desc->action;
+ while (action) {
+ printk(KERN_ERR "[<%p>]", action->handler);
+ print_symbol(" (%s)",
+ (unsigned long)action->handler);
+ printk("\n");
+ action = action->next;
+ }
+}
+
+static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ static int count = 100;
+
+ if (count) {
+ count--;
+ __report_bad_irq(irq, desc, action_ret);
+ }
+}
+
+
+static int __init noirqdebug_setup(char *str)
+{
+ noirqdebug = 1;
+ printk("IRQ lockup detection disabled\n");
+ return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
+/*
+ * 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 and try to
+ * turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly-functioning
+ * device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ if (action_ret != IRQ_HANDLED) {
+ desc->irqs_unhandled++;
+ if (action_ret != IRQ_NONE)
+ report_bad_irq(irq, desc, action_ret);
+ }
+
+ desc->irq_count++;
+ if (desc->irq_count < 100000)
+ return;
+
+ desc->irq_count = 0;
+ if (desc->irqs_unhandled > 99900) {
+ /*
+ * The interrupt is stuck
+ */
+ __report_bad_irq(irq, desc, action_ret);
+ /*
+ * Now kill the IRQ
+ */
+ printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ desc->irqs_unhandled = 0;
+}
+
+void synchronize_irq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ while (desc->status & IRQ_INPROGRESS)
+ cpu_relax();
+}
+
+EXPORT_SYMBOL(synchronize_irq);
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ * disable_irq_nosync - disable an irq without waiting
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Disables and Enables are
+ * nested.
+ * Unlike disable_irq(), this function does not ensure existing
+ * instances of the IRQ handler have completed before returning.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(disable_irq_nosync);
+
+/**
+ * disable_irq - disable an irq and wait for completion
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Enables and Disables are
+ * nested.
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+
+void disable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ disable_irq_nosync(irq);
+ if (desc->action)
+ synchronize_irq(irq);
+}
+
+EXPORT_SYMBOL(disable_irq);
+
+/**
+ * enable_irq - enable handling of an irq
+ * @irq: Interrupt to enable
+ *
+ * Undoes the effect of one call to disable_irq(). If this
+ * matches the last disable, processing of interrupts on this
+ * IRQ line is re-enabled.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (desc->handler == &no_irq_type)
+ return -ENOSYS;
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+ if (desc->handler->startup)
+ desc->handler->startup(irq);
+ else
+ desc->handler->enable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ new->irq = irq;
+ register_irq_proc(irq);
+ new->dir = NULL;
+ register_handler_proc(irq, new);
+
+ return 0;
+}
+
+/**
+ * free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ if (desc->handler->shutdown)
+ desc->handler->shutdown(irq);
+ else
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+ if (action->dir)
+ remove_proc_entry(action->dir->name, irq_dir[irq]);
+
+ /* Wait to make sure it's not being used on another CPU */
+ synchronize_irq(irq);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+EXPORT_SYMBOL(free_irq);
+
+#ifdef CONFIG_SMP
+
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long)data, full_count = count, err;
+ cpumask_t new_value, tmp;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ cpus_and(tmp, new_value, cpu_online_map);
+ if (cpus_empty(tmp))
+ return -EINVAL;
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq,
+ cpumask_of_cpu(first_cpu(new_value)));
+
+ return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ cpumask_t *mask = (cpumask_t *)data;
+ unsigned long full_count = count, err;
+ cpumask_t new_value;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc(unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+ {
+ struct proc_dir_entry *entry;
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+#undef MAX_NAMELEN
+
+#define MAX_NAMELEN 128
+
+static void register_handler_proc(unsigned int irq, struct irqaction *action)
+{
+ char name [MAX_NAMELEN];
+
+ if (!irq_dir[irq] || action->dir || !action->name)
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ snprintf(name, MAX_NAMELEN, "%s", action->name);
+
+ /* create /proc/irq/1234/handler/ */
+ action->dir = proc_mkdir(name, irq_dir[irq]);
+}
+
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc(void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", NULL);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+ if (!entry)
+ return;
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ register_irq_proc(i);
+}
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 18:25 ` Ingo Molnar
@ 2004-09-08 18:42 ` Zwane Mwaikambo
2004-09-08 21:14 ` [patch] generic-hardirqs-2.6.9-rc1-mm4.patch Ingo Molnar
1 sibling, 0 replies; 38+ messages in thread
From: Zwane Mwaikambo @ 2004-09-08 18:42 UTC (permalink / raw)
To: Ingo Molnar
Cc: Arjan van de Ven, Christoph Hellwig, William Lee Irwin III,
Andrew Morton, linux-kernel, Scott Wood
On Wed, 8 Sep 2004, Ingo Molnar wrote:
> latest patch attached - this should compile on every architecture. It's
> basically what Christoph suggested first time around :-) Compiles/boots
> on x86. Any other observations?
Apart from very nice? =) It's needed doing for a long time now.
Zwane
^ permalink raw reply [flat|nested] 38+ messages in thread
* [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-08 18:25 ` Ingo Molnar
2004-09-08 18:42 ` Zwane Mwaikambo
@ 2004-09-08 21:14 ` Ingo Molnar
2004-09-09 16:57 ` Christoph Hellwig
2004-09-09 20:24 ` Rafael J. Wysocki
1 sibling, 2 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-08 21:14 UTC (permalink / raw)
To: Andrew Morton
Cc: Zwane Mwaikambo, Christoph Hellwig, William Lee Irwin III,
linux-kernel, Scott Wood, Arjan van de Ven
[-- Attachment #1: Type: text/plain, Size: 439 bytes --]
* Ingo Molnar <mingo@elte.hu> wrote:
> latest patch attached - this should compile on every architecture.
> It's basically what Christoph suggested first time around :-)
> Compiles/boots on x86. Any other observations?
i've attached generic-hardirqs-2.6.9-rc1-mm4.patch which is a merge
against -mm4. x86 and x64 compiles & boots fine. Since there are zero
changes to non-x86 architectures it should build fine on all platforms.
Ingo
[-- Attachment #2: generic-hardirqs-2.6.9-rc1-mm4.patch --]
[-- Type: text/plain, Size: 27918 bytes --]
--- linux/arch/i386/kernel/irq.c.orig
+++ linux/arch/i386/kernel/irq.c
@@ -73,8 +73,6 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline
}
};
-static void register_irq_proc (unsigned int irq);
-
/*
* per-CPU IRQ handling stacks
*/
@@ -196,89 +194,6 @@ skip:
return 0;
}
-
-
-
-#ifdef CONFIG_SMP
-inline void synchronize_irq(unsigned int irq)
-{
- while (irq_desc[irq].status & IRQ_INPROGRESS)
- cpu_relax();
-}
-#endif
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-asmlinkage int handle_IRQ_event(unsigned int irq,
- struct pt_regs *regs, struct irqaction *action)
-{
- int status = 1; /* Force the "do bottom halves" bit */
- int ret, retval = 0;
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- retval |= ret;
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
- return retval;
-}
-
-static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- struct irqaction *action;
-
- if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
- printk(KERN_ERR "irq event %d: bogus return value %x\n",
- irq, action_ret);
- } else {
- printk(KERN_ERR "irq %d: nobody cared!\n", irq);
- }
- dump_stack();
- printk(KERN_ERR "handlers:\n");
- action = desc->action;
- do {
- printk(KERN_ERR "[<%p>]", action->handler);
- print_symbol(" (%s)",
- (unsigned long)action->handler);
- printk("\n");
- action = action->next;
- } while (action);
-}
-
-static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
-{
- static int count = 100;
-
- if (count) {
- count--;
- __report_bad_irq(irq, desc, action_ret);
- }
-}
-
-static int noirqdebug;
-
-static int __init noirqdebug_setup(char *str)
-{
- noirqdebug = 1;
- printk(KERN_INFO "IRQ lockup detection disabled\n");
- return 1;
-}
-
-__setup("noirqdebug", noirqdebug_setup);
-
static int irqfixup;
static int __init irqfixup_setup(char *str)
@@ -380,7 +295,7 @@ static asmlinkage int misrouted_irq(int
*
* Called under desc->lock
*/
-static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs)
+static void x86_note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs)
{
if (action_ret != IRQ_HANDLED) {
desc->irqs_unhandled++;
@@ -464,97 +379,6 @@ static void note_interrupt(int irq, irq_
desc->irqs_unhandled = 0;
}
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables and Enables are
- * nested.
- * Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-inline void disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Enables and Disables are
- * nested.
- * This function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- disable_irq_nosync(irq);
- if (desc->action)
- synchronize_irq(irq);
-}
-
-/**
- * enable_irq - enable handling of an irq
- * @irq: Interrupt to enable
- *
- * Undoes the effect of one call to disable_irq(). If this
- * matches the last disable, processing of interrupts on this
- * IRQ line is re-enabled.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
#ifdef CONFIG_HOTPLUG_CPU
static int irqs_stabilizing;
@@ -695,7 +519,7 @@ asmlinkage unsigned int do_IRQ(struct pt
}
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, ®s);
+ x86_note_interrupt(irq, desc, action_ret, ®s);
if (curctx != irqctx)
irqctx->tinfo.task = NULL;
if (likely(!(desc->status & IRQ_PENDING)))
@@ -714,7 +538,7 @@ asmlinkage unsigned int do_IRQ(struct pt
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, ®s);
+ x86_note_interrupt(irq, desc, action_ret, ®s);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
@@ -830,62 +654,6 @@ int request_irq(unsigned int irq,
EXPORT_SYMBOL(request_irq);
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function must not be called from interrupt context.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- /* Wait to make sure it's not being used on another CPU */
- synchronize_irq(irq);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
/*
* IRQ autodetection code..
*
@@ -1081,115 +849,6 @@ int probe_irq_off(unsigned long val)
EXPORT_SYMBOL(probe_irq_off);
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- if (desc->handler == &no_irq_type)
- return -ENOSYS;
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- register_irq_proc(irq);
- return 0;
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NR_IRQS];
-
-#ifdef CONFIG_SMP
-
-static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
-
-cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
-
-static int irq_affinity_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
- if (count - len < 2)
- return -EINVAL;
- len += sprintf(page + len, "\n");
- return len;
-}
-
-static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int irq = (long)data, full_count = count, err;
- cpumask_t new_value, tmp;
-
- if (!irq_desc[irq].handler->set_affinity)
- return -EIO;
-
- err = cpumask_parse(buffer, count, new_value);
- if (err)
- return err;
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- cpus_and(tmp, new_value, cpu_online_map);
- if (cpus_empty(tmp))
- return -EINVAL;
-
- irq_affinity[irq] = new_value;
- irq_desc[irq].handler->set_affinity(irq,
- cpumask_of_cpu(first_cpu(new_value)));
-
- return full_count;
-}
-#endif
-
#ifdef CONFIG_HOTPLUG_CPU
#include <mach_apic.h>
@@ -1234,55 +893,6 @@ void fixup_irqs(void)
#endif
}
#endif
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
- irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%d", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#ifdef CONFIG_SMP
- {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
-
- smp_affinity_entry[irq] = entry;
- }
-#endif
-}
-
-void init_irq_proc (void)
-{
- int i;
-
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
- create_prof_cpu_mask(root_irq_dir);
- /*
- * Create entries for all existing IRQs.
- */
- for (i = 0; i < NR_IRQS; i++)
- register_irq_proc(i);
-}
-
#ifdef CONFIG_4KSTACKS
/*
--- linux/arch/i386/kernel/i386_ksyms.c.orig
+++ linux/arch/i386/kernel/i386_ksyms.c
@@ -76,9 +76,6 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(ioremap_nocache);
EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
@@ -146,7 +143,6 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed
EXPORT_SYMBOL_NOVERS(__read_lock_failed);
/* Global SMP stuff */
-EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(smp_call_function);
/* TLB flushing */
--- linux/arch/i386/Kconfig.orig
+++ linux/arch/i386/Kconfig
@@ -1226,6 +1226,10 @@ source "crypto/Kconfig"
source "lib/Kconfig"
+config GENERIC_HARDIRQS
+ bool
+ default y
+
config X86_SMP
bool
depends on SMP && !X86_VOYAGER
--- linux/include/linux/irq.h.orig
+++ linux/include/linux/irq.h
@@ -10,12 +10,15 @@
*/
#include <linux/config.h>
+#include <linux/linkage.h>
#if !defined(CONFIG_ARCH_S390)
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -71,7 +74,24 @@ extern irq_desc_t irq_desc [NR_IRQS];
#include <asm/hw_irq.h> /* the arch dependent stuff */
-extern int setup_irq(unsigned int , struct irqaction * );
+
+extern int setup_irq(unsigned int irq, struct irqaction * new);
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+extern asmlinkage int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action);
+extern void synchronize_irq(unsigned int irq);
+extern void free_irq(unsigned int irq, void *dev_id);
+extern void disable_irq_nosync(unsigned int irq);
+extern void disable_irq(unsigned int irq);
+extern void enable_irq(unsigned int irq);
+extern void note_interrupt(int irq, irq_desc_t *desc, int action_ret);
+extern void __report_bad_irq(int irq, irq_desc_t *desc, int action_ret);
+extern void report_bad_irq(int irq, irq_desc_t *desc, int action_ret);
+extern void init_irq_proc(void);
+
+extern int noirqdebug;
+
+#endif
extern hw_irq_controller no_irq_type; /* needed in every arch ? */
--- linux/include/linux/interrupt.h.orig
+++ linux/include/linux/interrupt.h
@@ -40,6 +40,8 @@ struct irqaction {
const char *name;
void *dev_id;
struct irqaction *next;
+ int irq;
+ struct proc_dir_entry *dir;
};
extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
--- linux/include/asm-i386/irq.h.orig
+++ linux/include/asm-i386/irq.h
@@ -21,9 +21,6 @@ static __inline__ int irq_canonicalize(i
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
extern void release_x86_irqs(struct task_struct *);
extern int can_request_irq(unsigned int, unsigned long flags);
--- linux/kernel/Makefile.orig
+++ linux/kernel/Makefile
@@ -12,6 +12,7 @@ obj-y = sched.o fork.o exec_domain.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
obj-$(CONFIG_SMP) += cpu.o spinlock.o
+obj-$(CONFIG_GENERIC_HARDIRQS) += hardirq.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
--- linux/kernel/hardirq.c.orig
+++ linux/kernel/hardirq.c
@@ -0,0 +1,529 @@
+/*
+ * linux/kernel/hardirq.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the generic code used by various IRQ handling
+ * routines.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kallsyms.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+int noirqdebug;
+
+extern struct irq_desc irq_desc[NR_IRQS];
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+static void register_irq_proc(unsigned int irq);
+static void register_handler_proc(unsigned int irq, struct irqaction *action);
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+asmlinkage int handle_IRQ_event(unsigned int irq,
+ struct pt_regs *regs, struct irqaction *action)
+{
+ int status = 1; /* Force the "do bottom halves" bit */
+ int ret, retval = 0;
+
+ if (!(action->flags & SA_INTERRUPT))
+ local_irq_enable();
+
+ do {
+ ret = action->handler(irq, action->dev_id, regs);
+ if (ret == IRQ_HANDLED)
+ status |= action->flags;
+ retval |= ret;
+ action = action->next;
+ } while (action);
+
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ local_irq_disable();
+
+ return retval;
+}
+
+void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ struct irqaction *action;
+
+ if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+ printk(KERN_ERR "irq event %d: bogus return value %x\n",
+ irq, action_ret);
+ } else {
+ printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+ }
+ dump_stack();
+ printk(KERN_ERR "handlers:\n");
+ action = desc->action;
+ while (action) {
+ printk(KERN_ERR "[<%p>]", action->handler);
+ print_symbol(" (%s)",
+ (unsigned long)action->handler);
+ printk("\n");
+ action = action->next;
+ }
+}
+
+void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ static int count = 100;
+
+ if (count) {
+ count--;
+ __report_bad_irq(irq, desc, action_ret);
+ }
+}
+
+
+static int __init noirqdebug_setup(char *str)
+{
+ noirqdebug = 1;
+ printk("IRQ lockup detection disabled\n");
+ return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
+/*
+ * 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 and try to
+ * turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly-functioning
+ * device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+ if (action_ret != IRQ_HANDLED) {
+ desc->irqs_unhandled++;
+ if (action_ret != IRQ_NONE)
+ report_bad_irq(irq, desc, action_ret);
+ }
+
+ desc->irq_count++;
+ if (desc->irq_count < 100000)
+ return;
+
+ desc->irq_count = 0;
+ if (desc->irqs_unhandled > 99900) {
+ /*
+ * The interrupt is stuck
+ */
+ __report_bad_irq(irq, desc, action_ret);
+ /*
+ * Now kill the IRQ
+ */
+ printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ desc->irqs_unhandled = 0;
+}
+
+void synchronize_irq(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ while (desc->status & IRQ_INPROGRESS)
+ cpu_relax();
+}
+
+EXPORT_SYMBOL(synchronize_irq);
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ * disable_irq_nosync - disable an irq without waiting
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Disables and Enables are
+ * nested.
+ * Unlike disable_irq(), this function does not ensure existing
+ * instances of the IRQ handler have completed before returning.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void disable_irq_nosync(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(disable_irq_nosync);
+
+/**
+ * disable_irq - disable an irq and wait for completion
+ * @irq: Interrupt to disable
+ *
+ * Disable the selected interrupt line. Enables and Disables are
+ * nested.
+ * This function waits for any pending IRQ handlers for this interrupt
+ * to complete before returning. If you use this function while
+ * holding a resource the IRQ handler may need you will deadlock.
+ *
+ * This function may be called - with care - from IRQ context.
+ */
+
+void disable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ disable_irq_nosync(irq);
+ if (desc->action)
+ synchronize_irq(irq);
+}
+
+EXPORT_SYMBOL(disable_irq);
+
+/**
+ * enable_irq - enable handling of an irq
+ * @irq: Interrupt to enable
+ *
+ * Undoes the effect of one call to disable_irq(). If this
+ * matches the last disable, processing of interrupts on this
+ * IRQ line is re-enabled.
+ *
+ * This function may be called from IRQ context.
+ */
+
+void enable_irq(unsigned int irq)
+{
+ irq_desc_t *desc = irq_desc + irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ break;
+ case 0:
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (desc->handler == &no_irq_type)
+ return -ENOSYS;
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+ if (desc->handler->startup)
+ desc->handler->startup(irq);
+ else
+ desc->handler->enable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ new->irq = irq;
+ register_irq_proc(irq);
+ new->dir = NULL;
+ register_handler_proc(irq, new);
+
+ return 0;
+}
+
+/**
+ * free_irq - free an interrupt
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove an interrupt handler. The handler is removed and if the
+ * interrupt line is no longer in use by any driver it is disabled.
+ * On a shared IRQ the caller must ensure the interrupt is disabled
+ * on the card it drives before calling this function. The function
+ * does not return until any executing interrupts for this IRQ
+ * have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_desc *desc;
+ struct irqaction **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS)
+ return;
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ if (desc->handler->shutdown)
+ desc->handler->shutdown(irq);
+ else
+ desc->handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+ if (action->dir)
+ remove_proc_entry(action->dir->name, irq_dir[irq]);
+
+ /* Wait to make sure it's not being used on another CPU */
+ synchronize_irq(irq);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return;
+ }
+}
+
+EXPORT_SYMBOL(free_irq);
+
+#ifdef CONFIG_SMP
+
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long)data, full_count = count, err;
+ cpumask_t new_value, tmp;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ cpus_and(tmp, new_value, cpu_online_map);
+ if (cpus_empty(tmp))
+ return -EINVAL;
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq,
+ cpumask_of_cpu(first_cpu(new_value)));
+
+ return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
+ if (count - len < 2)
+ return -EINVAL;
+ len += sprintf(page + len, "\n");
+ return len;
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ cpumask_t *mask = (cpumask_t *)data;
+ unsigned long full_count = count, err;
+ cpumask_t new_value;
+
+ err = cpumask_parse(buffer, count, new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc(unsigned int irq)
+{
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+ irq_dir[irq])
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+ {
+ struct proc_dir_entry *entry;
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
+
+ smp_affinity_entry[irq] = entry;
+ }
+#endif
+}
+
+#undef MAX_NAMELEN
+
+#define MAX_NAMELEN 128
+
+static void register_handler_proc(unsigned int irq, struct irqaction *action)
+{
+ char name [MAX_NAMELEN];
+
+ if (!irq_dir[irq] || action->dir || !action->name)
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ snprintf(name, MAX_NAMELEN, "%s", action->name);
+
+ /* create /proc/irq/1234/handler/ */
+ action->dir = proc_mkdir(name, irq_dir[irq]);
+}
+
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc(void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", NULL);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+ if (!entry)
+ return;
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ register_irq_proc(i);
+}
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-08 21:14 ` [patch] generic-hardirqs-2.6.9-rc1-mm4.patch Ingo Molnar
@ 2004-09-09 16:57 ` Christoph Hellwig
2004-09-09 17:24 ` Ingo Molnar
2004-09-09 20:24 ` Rafael J. Wysocki
1 sibling, 1 reply; 38+ messages in thread
From: Christoph Hellwig @ 2004-09-09 16:57 UTC (permalink / raw)
To: Ingo Molnar
Cc: Andrew Morton, Zwane Mwaikambo, Christoph Hellwig,
William Lee Irwin III, linux-kernel, Scott Wood, Arjan van de Ven
On Wed, Sep 08, 2004 at 11:14:15PM +0200, Ingo Molnar wrote:
>
> * Ingo Molnar <mingo@elte.hu> wrote:
>
> > latest patch attached - this should compile on every architecture.
> > It's basically what Christoph suggested first time around :-)
> > Compiles/boots on x86. Any other observations?
>
> i've attached generic-hardirqs-2.6.9-rc1-mm4.patch which is a merge
> against -mm4. x86 and x64 compiles & boots fine. Since there are zero
> changes to non-x86 architectures it should build fine on all platforms.
Looks good to me. I no one else beats me I'll look into converting
ppc32/64 this weekend.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 16:57 ` Christoph Hellwig
@ 2004-09-09 17:24 ` Ingo Molnar
2004-09-09 17:53 ` William Lee Irwin III
0 siblings, 1 reply; 38+ messages in thread
From: Ingo Molnar @ 2004-09-09 17:24 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton, Zwane Mwaikambo,
William Lee Irwin III, linux-kernel, Scott Wood, Arjan van de Ven
* Christoph Hellwig <hch@infradead.org> wrote:
> > > latest patch attached - this should compile on every architecture.
> > > It's basically what Christoph suggested first time around :-)
> > > Compiles/boots on x86. Any other observations?
> >
> > i've attached generic-hardirqs-2.6.9-rc1-mm4.patch which is a merge
> > against -mm4. x86 and x64 compiles & boots fine. Since there are zero
> > changes to non-x86 architectures it should build fine on all platforms.
>
> Looks good to me. I no one else beats me I'll look into converting
> ppc32/64 this weekend.
you can find a pretty good approximation done by Scott Wood (and Andrey
Panin?) in the ppc/ppc64 portion of the VP patches:
http://redhat.com/~mingo/voluntary-preempt/voluntary-preempt-2.6.9-rc1-bk12-S0
basically you only have to zap some of the irq-threading changes such as
calls to redirect_hardirq(), do a s/generic_// and zap the PIC changes
(these are done for redirection too). Scott has tested those changes so
kernel/hardirq.c should work pretty well with ppc/ppc64.
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 17:24 ` Ingo Molnar
@ 2004-09-09 17:53 ` William Lee Irwin III
2004-09-09 17:54 ` Arjan van de Ven
0 siblings, 1 reply; 38+ messages in thread
From: William Lee Irwin III @ 2004-09-09 17:53 UTC (permalink / raw)
To: Ingo Molnar
Cc: Christoph Hellwig, Andrew Morton, Zwane Mwaikambo, linux-kernel,
Scott Wood, Arjan van de Ven
On Thu, Sep 09, 2004 at 07:24:01PM +0200, Ingo Molnar wrote:
> you can find a pretty good approximation done by Scott Wood (and Andrey
> Panin?) in the ppc/ppc64 portion of the VP patches:
> http://redhat.com/~mingo/voluntary-preempt/voluntary-preempt-2.6.9-rc1-bk12-S0
> basically you only have to zap some of the irq-threading changes such as
> calls to redirect_hardirq(), do a s/generic_// and zap the PIC changes
> (these are done for redirection too). Scott has tested those changes so
> kernel/hardirq.c should work pretty well with ppc/ppc64.
By any chance can the generic code be made not to be reliant on
irq_desc[] and/or irq_desc[] being an array?
-- wli
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 17:53 ` William Lee Irwin III
@ 2004-09-09 17:54 ` Arjan van de Ven
2004-09-09 17:56 ` William Lee Irwin III
2004-09-09 20:10 ` Russell King
0 siblings, 2 replies; 38+ messages in thread
From: Arjan van de Ven @ 2004-09-09 17:54 UTC (permalink / raw)
To: William Lee Irwin III, Ingo Molnar, Christoph Hellwig,
Andrew Morton, Zwane Mwaikambo, linux-kernel, Scott Wood
[-- Attachment #1: Type: text/plain, Size: 962 bytes --]
On Thu, Sep 09, 2004 at 10:53:14AM -0700, William Lee Irwin III wrote:
> On Thu, Sep 09, 2004 at 07:24:01PM +0200, Ingo Molnar wrote:
> > you can find a pretty good approximation done by Scott Wood (and Andrey
> > Panin?) in the ppc/ppc64 portion of the VP patches:
> > http://redhat.com/~mingo/voluntary-preempt/voluntary-preempt-2.6.9-rc1-bk12-S0
> > basically you only have to zap some of the irq-threading changes such as
> > calls to redirect_hardirq(), do a s/generic_// and zap the PIC changes
> > (these are done for redirection too). Scott has tested those changes so
> > kernel/hardirq.c should work pretty well with ppc/ppc64.
>
> By any chance can the generic code be made not to be reliant on
> irq_desc[] and/or irq_desc[] being an array?
I would say one step at a time.
First extract out the code that most arch's share already
only THEN start working on seeing if the few remaining ones can be moved in,
and if other cleanups are appropriate
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 17:54 ` Arjan van de Ven
@ 2004-09-09 17:56 ` William Lee Irwin III
2004-09-09 20:10 ` Russell King
1 sibling, 0 replies; 38+ messages in thread
From: William Lee Irwin III @ 2004-09-09 17:56 UTC (permalink / raw)
To: Arjan van de Ven
Cc: Ingo Molnar, Christoph Hellwig, Andrew Morton, Zwane Mwaikambo,
linux-kernel, Scott Wood
On Thu, Sep 09, 2004 at 10:53:14AM -0700, William Lee Irwin III wrote:
>> By any chance can the generic code be made not to be reliant on
>> irq_desc[] and/or irq_desc[] being an array?
On Thu, Sep 09, 2004 at 07:54:41PM +0200, Arjan van de Ven wrote:
> I would say one step at a time.
> First extract out the code that most arch's share already
> only THEN start working on seeing if the few remaining ones can be moved in,
> and if other cleanups are appropriate
I suppose that assumption can be swept for afterward.
-- wli
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14
2004-09-08 13:12 ` Christoph Hellwig
2004-09-08 13:17 ` Ingo Molnar
@ 2004-09-09 17:56 ` Scott Wood
1 sibling, 0 replies; 38+ messages in thread
From: Scott Wood @ 2004-09-09 17:56 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: Ingo Molnar, Andrew Morton, linux-kernel, Scott Wood
On Wed, Sep 08, 2004 at 02:12:17PM +0100, Christoph Hellwig wrote:
> On Wed, Sep 08, 2004 at 03:05:52PM +0200, Ingo Molnar wrote:
> > is there any architecture that cannot make use of kernel/hardirq.c _at
> > all_?
>
> s390 doesn't need it at all because it doesn't have the concept of hardirqs.
>
> At least arm{,26}, m68k{,nommu} and parisc and sparc{,64} use extremly
> different models for irq handling
They're not irreparably different, though (at least, not all of
them); we had generic IRQ code (with threads) running in our 2.4
kernel on arm and sparc64.
-Scott
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 17:54 ` Arjan van de Ven
2004-09-09 17:56 ` William Lee Irwin III
@ 2004-09-09 20:10 ` Russell King
2004-09-09 20:51 ` Scott Wood
1 sibling, 1 reply; 38+ messages in thread
From: Russell King @ 2004-09-09 20:10 UTC (permalink / raw)
To: Arjan van de Ven
Cc: William Lee Irwin III, Ingo Molnar, Christoph Hellwig,
Andrew Morton, Zwane Mwaikambo, linux-kernel, Scott Wood
On Thu, Sep 09, 2004 at 07:54:41PM +0200, Arjan van de Ven wrote:
>
> On Thu, Sep 09, 2004 at 10:53:14AM -0700, William Lee Irwin III wrote:
> > On Thu, Sep 09, 2004 at 07:24:01PM +0200, Ingo Molnar wrote:
> > > you can find a pretty good approximation done by Scott Wood (and Andrey
> > > Panin?) in the ppc/ppc64 portion of the VP patches:
> > > http://redhat.com/~mingo/voluntary-preempt/voluntary-preempt-2.6.9-rc1-bk12-S0
> > > basically you only have to zap some of the irq-threading changes such as
> > > calls to redirect_hardirq(), do a s/generic_// and zap the PIC changes
> > > (these are done for redirection too). Scott has tested those changes so
> > > kernel/hardirq.c should work pretty well with ppc/ppc64.
> >
> > By any chance can the generic code be made not to be reliant on
> > irq_desc[] and/or irq_desc[] being an array?
>
> I would say one step at a time.
> First extract out the code that most arch's share already
> only THEN start working on seeing if the few remaining ones can be moved in,
> and if other cleanups are appropriate
If it uses irq_desc then ARM won't use it. irq_desc is part of the
far-too-restrictive x86 IRQ handlign code which is unsuitable for
ARM platforms.
Sorry, try again.
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial core
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-08 21:14 ` [patch] generic-hardirqs-2.6.9-rc1-mm4.patch Ingo Molnar
2004-09-09 16:57 ` Christoph Hellwig
@ 2004-09-09 20:24 ` Rafael J. Wysocki
2004-09-09 20:40 ` Andrew Morton
1 sibling, 1 reply; 38+ messages in thread
From: Rafael J. Wysocki @ 2004-09-09 20:24 UTC (permalink / raw)
To: Ingo Molnar
Cc: Andrew Morton, Zwane Mwaikambo, Christoph Hellwig,
William Lee Irwin III, linux-kernel, Scott Wood, Arjan van de Ven
On Wednesday 08 of September 2004 23:14, Ingo Molnar wrote:
>
> * Ingo Molnar <mingo@elte.hu> wrote:
>
> > latest patch attached - this should compile on every architecture.
> > It's basically what Christoph suggested first time around :-)
> > Compiles/boots on x86. Any other observations?
>
> i've attached generic-hardirqs-2.6.9-rc1-mm4.patch which is a merge
> against -mm4. x86 and x64 compiles & boots fine. Since there are zero
> changes to non-x86 architectures it should build fine on all platforms.
I've got this trace (on x86-64):
general protection fault: 0000 [1] PREEMPT
CPU 0
Modules linked in: usbserial parport_pc lp parport joydev sg st sd_mod sr_mod
scsi_mod snd_seq_oss snd_seq_midi_evend
Pid: 694, comm: kjournald Not tainted 2.6.9-rc1-mm4
RIP: 0010:[<ffffffff802ac605>]
<ffffffff802ac605>{__journal_clean_checkpoint_list+389}
RSP: 0018:000001001f589b08 EFLAGS: 00010202
RAX: 0000000000000000 RBX: 6b6b6b6b6b6b6b6b RCX: 0000000000000000
RDX: 0000010001b2c4d8 RSI: 000001001fd2e150 RDI: 000001001fbab628
RBP: 00000100110c0708 R08: 000001001fd2e050 R09: 00000100110c0708
R10: 0000000000000000 R11: 0000000000000000 R12: 00000100110c0708
R13: 000001000b4345c8 R14: 000000000000007f R15: 0000010001ae8d70
FS: 0000002a9afefa80(0000) GS:ffffffff805f3580(0000) knlGS:0000000000000000
CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
CR2: 0000002a95654000 CR3: 0000000000101000 CR4: 00000000000006e0
Process kjournald (pid: 694, threadinfo 000001001f588000, task
0000010001ad9270)
Stack: 000001001f589b48 000001001fd2bc58 0000010001b2c4d8 0000010001b2c4d8
0000000000000001 0000000000000000 0000010001b2c4d8 000001000bc1f910
0000000000000000 ffffffff802a9039
Call Trace:<ffffffff802a9039>{journal_commit_transaction+2329}
<ffffffff8042f730>{thread_return+41} <ffffffff802b3465>{kjournald+725}
<ffffffff8015ece0>{autoremove_wake_function+0}
<ffffffff8015ece0>{autoremove_wake_function+0}
<ffffffff802b3a30>{commit_timeout+0} <ffffffff80111afb>{child_rip+8}
<ffffffff802b3190>{kjournald+0} <ffffffff80111af3>{child_rip+0}
Code: 48 8b 43 48 49 89 45 48 48 8b 54 24 10 4c 8b aa b8 00 00 00
RIP <ffffffff802ac605>{__journal_clean_checkpoint_list+389} RSP
<000001001f589b08>
with the patch applied. I don't know if the patch is the reason, but I
haven't got anything like that without it (please let me know if you
need .config etc.).
Greets,
RJW
--
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
-- Lewis Carroll "Alice's Adventures in Wonderland"
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 20:24 ` Rafael J. Wysocki
@ 2004-09-09 20:40 ` Andrew Morton
2004-09-09 20:49 ` Ingo Molnar
0 siblings, 1 reply; 38+ messages in thread
From: Andrew Morton @ 2004-09-09 20:40 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: mingo, zwane, hch, wli, linux-kernel, scott, arjanv
"Rafael J. Wysocki" <rjw@sisk.pl> wrote:
>
> I've got this trace (on x86-64):
>
> general protection fault: 0000 [1] PREEMPT
> CPU 0
> Modules linked in: usbserial parport_pc lp parport joydev sg st sd_mod sr_mod
> scsi_mod snd_seq_oss snd_seq_midi_evend
> Pid: 694, comm: kjournald Not tainted 2.6.9-rc1-mm4
> RIP: 0010:[<ffffffff802ac605>]
> <ffffffff802ac605>{__journal_clean_checkpoint_list+389}
You should revert
ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.9-rc1/2.6.9-rc1-mm4/broken-out/journal_clean_checkpoint_list-latency-fix.patch
- it seems to be sick.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 20:40 ` Andrew Morton
@ 2004-09-09 20:49 ` Ingo Molnar
0 siblings, 0 replies; 38+ messages in thread
From: Ingo Molnar @ 2004-09-09 20:49 UTC (permalink / raw)
To: Andrew Morton
Cc: Rafael J. Wysocki, zwane, hch, wli, linux-kernel, scott, arjanv
* Andrew Morton <akpm@osdl.org> wrote:
> "Rafael J. Wysocki" <rjw@sisk.pl> wrote:
> >
> > I've got this trace (on x86-64):
> >
> > general protection fault: 0000 [1] PREEMPT
> > CPU 0
> > Modules linked in: usbserial parport_pc lp parport joydev sg st sd_mod sr_mod
> > scsi_mod snd_seq_oss snd_seq_midi_evend
> > Pid: 694, comm: kjournald Not tainted 2.6.9-rc1-mm4
> > RIP: 0010:[<ffffffff802ac605>]
> > <ffffffff802ac605>{__journal_clean_checkpoint_list+389}
>
> You should revert
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.9-rc1/2.6.9-rc1-mm4/broken-out/journal_clean_checkpoint_list-latency-fix.patch
> - it seems to be sick.
the variant in the VP patch (for this latency) is pretty stable. Will
post splitups later.
Ingo
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 20:10 ` Russell King
@ 2004-09-09 20:51 ` Scott Wood
2004-09-09 21:00 ` Russell King
0 siblings, 1 reply; 38+ messages in thread
From: Scott Wood @ 2004-09-09 20:51 UTC (permalink / raw)
To: Russell King
Cc: Arjan van de Ven, William Lee Irwin III, Ingo Molnar,
Christoph Hellwig, Andrew Morton, Zwane Mwaikambo, linux-kernel,
Scott Wood
On Thu, Sep 09, 2004 at 09:10:38PM +0100, Russell King wrote:
> If it uses irq_desc then ARM won't use it. irq_desc is part of the
> far-too-restrictive x86 IRQ handlign code which is unsuitable for
> ARM platforms.
What does ARM need that irq_desc doesn't provide, and which could not
be added? IMHO, it'd be better to fix the generic code than maintain
completely separate implementations.
-Scott
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 20:51 ` Scott Wood
@ 2004-09-09 21:00 ` Russell King
2004-09-10 5:57 ` Arjan van de Ven
0 siblings, 1 reply; 38+ messages in thread
From: Russell King @ 2004-09-09 21:00 UTC (permalink / raw)
To: Scott Wood
Cc: Arjan van de Ven, William Lee Irwin III, Ingo Molnar,
Christoph Hellwig, Andrew Morton, Zwane Mwaikambo, linux-kernel
On Thu, Sep 09, 2004 at 04:51:53PM -0400, Scott Wood wrote:
> On Thu, Sep 09, 2004 at 09:10:38PM +0100, Russell King wrote:
> > If it uses irq_desc then ARM won't use it. irq_desc is part of the
> > far-too-restrictive x86 IRQ handlign code which is unsuitable for
> > ARM platforms.
>
> What does ARM need that irq_desc doesn't provide, and which could not
> be added? IMHO, it'd be better to fix the generic code than maintain
> completely separate implementations.
Unfortunately, to deal with this issue would mean breaking off from
planned work, so I'm not going to be in a position to do an element
by element comparison of the structures for some time.
Maybe I can look at it after the weekend though.
However, I think if you just compare:
linux/include/linux/irq.h
linux/include/asm-arm/mach/irq.h
you'll realise how inadequate the "generic" IRQ code is for ARM.
Note that IRQ handling on ARM is a multi-level affair where we have
multiple levels of interrupt controllers which need to be traversed
in software.
--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of: 2.6 PCMCIA - http://pcmcia.arm.linux.org.uk/
2.6 Serial core
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [patch] generic-hardirqs-2.6.9-rc1-mm4.patch
2004-09-09 21:00 ` Russell King
@ 2004-09-10 5:57 ` Arjan van de Ven
0 siblings, 0 replies; 38+ messages in thread
From: Arjan van de Ven @ 2004-09-10 5:57 UTC (permalink / raw)
To: Scott Wood, William Lee Irwin III, Ingo Molnar, Christoph Hellwig,
Andrew Morton, Zwane Mwaikambo, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 576 bytes --]
On Thu, Sep 09, 2004 at 10:00:04PM +0100, Russell King wrote:
> you'll realise how inadequate the "generic" IRQ code is for ARM.
>
> Note that IRQ handling on ARM is a multi-level affair where we have
> multiple levels of interrupt controllers which need to be traversed
> in software.
I still propose the plan of action that is to consolidate first all
architectures that CAN share the x86 one, and THEN look at making that more
generic. The reason is simple; right now there are 20-ish copies; after the
initial consolidation there will be 4 or 5. Far easier to work on.
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2004-09-10 5:58 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-08 12:06 [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Ingo Molnar
2004-09-08 12:29 ` La Monte H.P. Yarroll
2004-09-08 13:25 ` Christoph Hellwig
2004-09-08 13:40 ` Ingo Molnar
2004-09-08 13:47 ` Christoph Hellwig
2004-09-08 12:34 ` Christoph Hellwig
2004-09-08 12:45 ` Ingo Molnar
2004-09-08 12:49 ` Christoph Hellwig
2004-09-08 13:05 ` Ingo Molnar
2004-09-08 13:12 ` Christoph Hellwig
2004-09-08 13:17 ` Ingo Molnar
2004-09-08 13:20 ` Christoph Hellwig
2004-09-08 13:32 ` Ingo Molnar
2004-09-09 17:56 ` Scott Wood
2004-09-08 12:57 ` William Lee Irwin III
2004-09-08 13:01 ` Christoph Hellwig
2004-09-08 13:09 ` William Lee Irwin III
2004-09-08 13:10 ` Ingo Molnar
2004-09-08 13:34 ` Zwane Mwaikambo
2004-09-08 13:31 ` Christoph Hellwig
2004-09-08 13:47 ` Zwane Mwaikambo
2004-09-08 14:09 ` Arjan van de Ven
2004-09-08 18:25 ` Ingo Molnar
2004-09-08 18:42 ` Zwane Mwaikambo
2004-09-08 21:14 ` [patch] generic-hardirqs-2.6.9-rc1-mm4.patch Ingo Molnar
2004-09-09 16:57 ` Christoph Hellwig
2004-09-09 17:24 ` Ingo Molnar
2004-09-09 17:53 ` William Lee Irwin III
2004-09-09 17:54 ` Arjan van de Ven
2004-09-09 17:56 ` William Lee Irwin III
2004-09-09 20:10 ` Russell King
2004-09-09 20:51 ` Scott Wood
2004-09-09 21:00 ` Russell King
2004-09-10 5:57 ` Arjan van de Ven
2004-09-09 20:24 ` Rafael J. Wysocki
2004-09-09 20:40 ` Andrew Morton
2004-09-09 20:49 ` Ingo Molnar
2004-09-08 13:03 ` [patch] generic-hardirqs.patch, 2.6.9-rc1-bk14 Arjan van de Ven
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox