Skip to contentSkip to conversation

sparse_irq aka dyn_irq

RFC PATCH In review Yinghai Lu 10 participants 66 messages Nov 9, 2008 – Nov 17, 2008 13 messages not in the archive

Subsystems (8)
x86 PCI x86 MM Proc filesystem +4 more subsystems
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

Yinghai Lu

author
#11 lore raw

RFC PATCH 1/1 sparse_irq aka dyn_irq

impact: new feature sparseirq

for sparse_irq, irq_desc, and irq_cfg is not using list_head to chain up also not add per_cpu_dyn_array... no user now

add some kind of hash table as Ingo suggesting.
remove dyna_array, and enable sparse_irq by default, use kzalloc_node to get it use desc->chip_data for x86 to store irq_cfg
make irq_desc to go with affinity aka irq_desc moving etc
only call move_irq_desc in irq_complete_move() --- but it seems not trigger that moving.

---
 arch/x86/Kconfig                   |    4 
 arch/x86/include/asm/io_apic.h     |    2 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/io_apic.c          |  384 ++++++++++++++++++++++++-------------
 arch/x86/kernel/irq.c              |   19 -
 arch/x86/kernel/irq_32.c           |    2 
 arch/x86/kernel/irq_64.c           |    2 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 ++
 drivers/pci/htirq.c                |   18 +
 drivers/pci/intr_remapping.c       |   65 ++++++
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   13 +
 fs/proc/stat.c                     |   17 +
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   60 +++++
 include/linux/irqnr.h              |   15 -
 include/linux/kernel_stat.h        |   14 +
 init/main.c                        |    2 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |    4 
 kernel/irq/handle.c                |  338 +++++++++++++++++++++++++++++++-
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 26 files changed, 839 insertions(+), 190 deletions(-)
arch/x86/Kconfig +4 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -236,6 +236,10 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config HAVE_SPARSE_IRQ
+	bool
+	default y
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +253 -131

816 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_HAVE_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_HAVE_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +18 -0
Index: linux-2.6/drivers/pci/htirq.c
===================================================================
@@ -82,6 +82,18 @@ void unmask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;
+}
+
 /**
  * __ht_create_irq - create an irq and attach it to a device.
  * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +110,7 @@ int __ht_create_irq(struct pci_dev *dev,
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)
@@ -125,7 +138,12 @@ int __ht_create_irq(struct pci_dev *dev,
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif
 
 	if (irq <= 0) {
 		kfree(cfg);
drivers/pci/intr_remapping.c +63 -2

89 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +12 -1
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -10,20 +10,31 @@
  */
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+#else
 	return (*pos <= nr_irqs) ? pos : NULL;
+#endif
 }
 
 static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
 {
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+	return seq_list_next(v, &sparse_irqs_head, pos);
+#else
 	(*pos)++;
 	if (*pos > nr_irqs)
 		return NULL;
 	return pos;
+#endif
 }
 
 static void int_seq_stop(struct seq_file *f, void *v)
 {
-	/* Nothing to do */
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+	rcu_read_unlock();
+#endif
 }
 
 static const struct seq_operations int_seq_ops = {
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +58 -2

84 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_HAVE_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_HAVE_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_HAVE_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +3 -1
Index: linux-2.6/kernel/irq/chip.c
===================================================================
@@ -24,9 +24,11 @@
  */
 void dynamic_irq_init(unsigned int irq)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc;
 	unsigned long flags;
 
+	/* first time to use this irq_desc */
+	desc = irq_to_desc_alloc(irq);
 	if (!desc) {
 		WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
 		return;
kernel/irq/handle.c +332 -6

370 lines not on this page · raw message

arch/x86/kernel/irq.c +9 -10
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,20 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
 
-	if (i > nr_irqs)
-		return 0;
-
-	if (i == nr_irqs)
-		return show_other_interrupts(p);
-
-	/* print header */
-	if (i == 0) {
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next) {
+		/* print header */
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +143,10 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init_work(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -254,7 +254,7 @@ void fixup_irqs(cpumask_t map)
 			desc->chip->set_affinity(irq, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -129,7 +129,7 @@ void fixup_irqs(cpumask_t map)
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@ void init_irq_proc(void)
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@ static int misrouted_irq(int irq)
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@ static void poll_spurious_irqs(unsigned
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +2 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -611,6 +611,8 @@ asmlinkage void __init start_kernel(void
 	sort_main_extable();
 	trap_init();
 	rcu_init();
+	/* init some list before init_ISA_irqs() */
+	early_sparse_irq_init_work();
 	init_IRQ();
 	pidhash_init();
 	init_timers();
arch/x86/include/asm/io_apic.h +1 -1
Index: linux-2.6/arch/x86/include/asm/io_apic.h
===================================================================
@@ -192,6 +192,7 @@ extern int io_apic_set_pci_routing(int i
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
+struct irq_desc;
 #ifdef CONFIG_X86_64
 extern int save_mask_IO_APIC_setup(void);
 extern void restore_IO_APIC_setup(void);
@@ -199,7 +200,6 @@ extern void reinit_intr_remapped_IO_APIC
 #endif
 
 extern int probe_nr_irqs(void);
-
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================
@@ -101,6 +101,8 @@
 #define LAST_VM86_IRQ		15
 #define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY		16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
#12 lore raw

General impression: very nice patch!

A lot of the structural problems have been addressed: the descriptor lookup is now hashed, the dynarray stuff got cleaned up / eliminated, the irq_desc->chip_data binding is very nice as well.

(And the patch needs to be split up like it was in the past, once all review feedback has been seen and addressed.)

arch/x86/Kconfig config X86_HAS_BOOT_CPU_ID · line 241

Quoted 3 lines
arch/x86/Kconfig +3 -0
+config HAVE_SPARSE_IRQ
+	bool
+	default y

i think it should be made user-configurable - at least initially. It should not cause extra complications, right?

Review

Quoted 1 line
(quoted diff) +1 -0
+	if (irq < NR_IRQS_LEGACY) {

please s/NR_IRQS_LEGACY/NR_IRQS_X86_LEGACY - this is never used outside of x86 code.

arch/x86/kernel/io_apic.c unsigned int create_irq_nr(unsigned int · line 3015

Quoted 1 line
arch/x86/kernel/io_apic.c +1 -0
+		cfg_new = desc_new->chip_data;

the chip_data binding is a nice touch.

Review

Quoted 2 lines
(quoted diff) +1 -1
-	irq_want = build_irq_for_pci_dev(dev) + 0x100;
+	irq_want = build_irq_for_pci_dev(dev) + 0xfff;

please replace magic constant with a properly named constant.

arch/x86/kernel/io_apic.c int __init probe_nr_irqs(void) · line 3615

Quoted 2 lines
arch/x86/kernel/io_apic.c +0 -2
-	if (WARN_ON(nr > NR_IRQS))
-		nr = NR_IRQS;

this will have to stay for the !SPARSE_IRQ case.

Quoted 10 lines

+++ linux-2.6/arch/x86/mm/init_32.c

arch/x86/mm/init_32.c +1 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 4 lines
arch/x86/mm/init_32.c +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

Review void __init mem_init(void) · line 992

Quoted 1 line
(quoted diff) +1 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ

i'd suggest s/HAVE_SPARSE_IRQ/SPARSE_IRQ - as the HAVE_* flags are for architecture code to signal the presence of a facility.

drivers/char/random.c void rand_initialize_irq(int irq) · line 968

Quoted 4 lines
drivers/char/random.c +2 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif

we should hide as many ugly #ifdefs as possible, and define nr_irqs to NR_IRQS in the !SPARSE_IRQ case.

Quoted 5 lines

+++ linux-2.6/drivers/pci/htirq.c

drivers/pci/htirq.c +0 -0
@@ -82,6 +82,18 @@ void unmask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 

drivers/pci/htirq.c void unmask_ht_irq(unsigned int irq) · line 94

Quoted 10 lines
drivers/pci/htirq.c +10 -0
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;

magic constants should be named.

drivers/pci/htirq.c int __ht_create_irq(struct pci_dev *dev, · line 146

Quoted 5 lines
drivers/pci/htirq.c +4 -0
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif

please eliminate this #ifdef by adding one new API:
create_irq_nr(idx), which just maps to the create_irq() API in the !SPARSE_IRQ case.

drivers/pci/intr_remapping.c struct irq_2_iommu { · line 46

Quoted 10 lines
drivers/pci/intr_remapping.c +7 -1
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
-	return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL;
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	BUG_ON(!desc);
+
+	return desc->irq_2_iommu;

the BUG_ON() is not too friendly, please do something like this instead:

	if (WARN_ON_ONCE(!desc))
		return NULL;

drivers/pci/intr_remapping.c int alloc_irte(struct intel_iommu *iommu · line 152

Quoted 5 lines
drivers/pci/intr_remapping.c +2 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ
 	/* protect irq_2_iommu_alloc later */
 	if (irq >= nr_irqs)
 		return -1;
+#endif

this #ifdef can be eliminated too and turned into straight code via the #define nr_irqs NR_IRQS trick in the !SPARSE_IRQ case.

drivers/xen/events.c static void init_evtchn_cpu_bindings(voi · line 146

Quoted 4 lines
drivers/xen/events.c +2 -1
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();

Sidenote: later on, once the patch is upstream, we should do a global rename:

s/for_each_irq_desc/do_each_irq_desc
s/end_for_each_irq_desc/while_each_irq_desc

as it's much harder to miss the "while" in a "do ..." loop, than it is to miss the "end" in a "for" loop.

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 70

Quoted 12 lines
kernel/irq/handle.c +12 -0
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+static struct irq_desc irq_desc_init = {
+	.irq = -1U,
+	.status = IRQ_DISABLED,
+	.chip = &no_irq_chip,
+	.handle_irq = handle_bad_irq,
+	.depth = 1,
+	.lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+	.affinity = CPU_MASK_ALL
+#endif
+};

please align structure fields vertically.

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 173

Quoted 13 lines
kernel/irq/handle.c +13 -0
+static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
+	[0 ... NR_IRQS_LEGACY-1] = {
+		.irq = -1U,
+		.status = IRQ_DISABLED,
+		.chip = &no_irq_chip,
+		.handle_irq = handle_bad_irq,
+		.depth = 1,
+		.lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+		.affinity = CPU_MASK_ALL
+#endif
+	}
+};

same here.

arch/x86/include/asm/io_apic.h extern void reinit_intr_remapped_IO_APIC · line 205

Quoted 8 lines
arch/x86/include/asm/io_apic.h +0 -1
@@ -199,7 +200,6 @@ extern void reinit_intr_remapped_IO_APIC
 #endif
 
 extern int probe_nr_irqs(void);
-
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;

that's a spurious removal of a newline.

all in one, i cannot see fundamental problems in this patch.

Ingo

author
#13 lore raw
Quoted 10 lines · Ingo Molnar

General impression: very nice patch!

A lot of the structural problems have been addressed: the descriptor lookup is now hashed, the dynarray stuff got cleaned up / eliminated, the irq_desc->chip_data binding is very nice as well.

(And the patch needs to be split up like it was in the past, once all review feedback has been seen and addressed.)

Quoted 6 lines

arch/x86/Kconfig config X86_HAS_BOOT_CPU_ID · line 241

Quoted 3 lines
arch/x86/Kconfig +3 -0
+config HAVE_SPARSE_IRQ
+     bool
+     default y

i think it should be made user-configurable - at least initially. It should not cause extra complications, right?

io_apic.c will get more complicated.

Quoted 5 lines
Quoted 2 lines

+ if (irq < NR_IRQS_LEGACY) {

please s/NR_IRQS_LEGACY/NR_IRQS_X86_LEGACY - this is never used outside of x86 code.

will use that in kernel/irq/handle.c too, because dyn_array is dumped.

Quoted 8 lines
Quoted 2 lines

+ cfg_new = desc_new->chip_data;

the chip_data binding is a nice touch.

Review

Quoted 2 lines
(quoted diff) +1 -1
-     irq_want = build_irq_for_pci_dev(dev) + 0x100;
+     irq_want = build_irq_for_pci_dev(dev) + 0xfff;
Quoted 6 lines

please replace magic constant with a properly named constant.

arch/x86/kernel/io_apic.c int __init probe_nr_irqs(void) · line 3615

Quoted 2 lines
arch/x86/kernel/io_apic.c +0 -2
-     if (WARN_ON(nr > NR_IRQS))
-             nr = NR_IRQS;

this will have to stay for the !SPARSE_IRQ case.

Yes

Quoted 12 lines
Quoted 12 lines

+++ linux-2.6/arch/x86/mm/init_32.c

arch/x86/mm/init_32.c +1 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
Quoted 6 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 3 lines
arch/x86/mm/init_32.c +1 -0
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch?
current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

Quoted 5 lines

Review void __init mem_init(void) · line 992

Quoted 2 lines
(quoted diff) +1 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ

i'd suggest s/HAVE_SPARSE_IRQ/SPARSE_IRQ - as the HAVE_* flags are for architecture code to signal the presence of a facility.

OK

Quoted 14 lines

drivers/char/random.c void rand_initialize_irq(int irq) · line 968

Quoted 5 lines
drivers/char/random.c +2 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ
      if (irq >= nr_irqs)
              return;
+#endif

we should hide as many ugly #ifdefs as possible, and define nr_irqs to NR_IRQS in the !SPARSE_IRQ case.

Quoted 5 lines

+++ linux-2.6/drivers/pci/htirq.c

drivers/pci/htirq.c +0 -0
@@ -82,6 +82,18 @@ void unmask_ht_irq(unsigned int irq)
      write_ht_irq_msg(irq, &msg);
 }
 
Quoted 12 lines

drivers/pci/htirq.c void unmask_ht_irq(unsigned int irq) · line 94

Quoted 10 lines
drivers/pci/htirq.c +10 -0
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+     unsigned int irq;
+
+     irq = dev->bus->number;
+     irq <<= 8;
+     irq |= dev->devfn;
+     irq <<= 12;
+
+     return irq;

magic constants should be named.

should add more comment here.

Quoted 85 lines

drivers/pci/htirq.c int __ht_create_irq(struct pci_dev *dev, · line 146

Quoted 6 lines
drivers/pci/htirq.c +4 -0
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+     irq = create_irq_nr(irq_want + idx);
+#else
      irq = create_irq();
+#endif

please eliminate this #ifdef by adding one new API:
create_irq_nr(idx), which just maps to the create_irq() API in the !SPARSE_IRQ case.

drivers/pci/intr_remapping.c struct irq_2_iommu { · line 46

Quoted 10 lines
drivers/pci/intr_remapping.c +7 -1
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
-     return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL;
+     struct irq_desc *desc;
+
+     desc = irq_to_desc(irq);
+
+     BUG_ON(!desc);
+
+     return desc->irq_2_iommu;

the BUG_ON() is not too friendly, please do something like this instead:

       if (WARN_ON_ONCE(!desc))
               return NULL;

drivers/pci/intr_remapping.c int alloc_irte(struct intel_iommu *iommu · line 152

Quoted 5 lines
drivers/pci/intr_remapping.c +2 -0
+#ifndef CONFIG_HAVE_SPARSE_IRQ
      /* protect irq_2_iommu_alloc later */
      if (irq >= nr_irqs)
              return -1;
+#endif

this #ifdef can be eliminated too and turned into straight code via the #define nr_irqs NR_IRQS trick in the !SPARSE_IRQ case.

drivers/xen/events.c static void init_evtchn_cpu_bindings(voi · line 146

Quoted 4 lines
drivers/xen/events.c +2 -1
-     for_each_irq_desc(i, desc)
+     for_each_irq_desc(i, desc) {
              desc->affinity = cpumask_of_cpu(0);
+     } end_for_each_irq_desc();

Sidenote: later on, once the patch is upstream, we should do a global rename:

s/for_each_irq_desc/do_each_irq_desc
s/end_for_each_irq_desc/while_each_irq_desc

as it's much harder to miss the "while" in a "do ..." loop, than it is to miss the "end" in a "for" loop.

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 70

Quoted 12 lines
kernel/irq/handle.c +12 -0
+#ifdef CONFIG_HAVE_SPARSE_IRQ
+static struct irq_desc irq_desc_init = {
+     .irq = -1U,
+     .status = IRQ_DISABLED,
+     .chip = &no_irq_chip,
+     .handle_irq = handle_bad_irq,
+     .depth = 1,
+     .lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+     .affinity = CPU_MASK_ALL
+#endif
+};

please align structure fields vertically.

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 173

Quoted 13 lines
kernel/irq/handle.c +13 -0
+static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
+     [0 ... NR_IRQS_LEGACY-1] = {
+             .irq = -1U,
+             .status = IRQ_DISABLED,
+             .chip = &no_irq_chip,
+             .handle_irq = handle_bad_irq,
+             .depth = 1,
+             .lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+             .affinity = CPU_MASK_ALL
+#endif
+     }
+};

same here.

Quoted 3 lines
(quoted diff) +0 -0
@@ -199,7 +200,6 @@ extern void reinit_intr_remapped_IO_APIC
 #endif
 
Quoted 7 lines

arch/x86/include/asm/io_apic.h extern void reinit_intr_remapped_IO_APIC · line 205

Quoted 5 lines
arch/x86/include/asm/io_apic.h +0 -1
 extern int probe_nr_irqs(void);
-
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;

that's a spurious removal of a newline.

.....

YH

#14 lore raw

(Andrew, please see the early_kzalloc() reference below)

Quoted 11 lines · Yinghai Lu
Quoted 10 lines · Ingo Molnar

General impression: very nice patch!

A lot of the structural problems have been addressed: the descriptor lookup is now hashed, the dynarray stuff got cleaned up / eliminated, the irq_desc->chip_data binding is very nice as well.

(And the patch needs to be split up like it was in the past, once all review feedback has been seen and addressed.)

Quoted 8 lines
Quoted 6 lines

arch/x86/Kconfig config X86_HAS_BOOT_CPU_ID · line 241

Quoted 3 lines
arch/x86/Kconfig +3 -0
+config HAVE_SPARSE_IRQ
+     bool
+     default y

i think it should be made user-configurable - at least initially. It should not cause extra complications, right?

io_apic.c will get more complicated.

yes, with such constructs:

+#ifdef CONFIG_SPARSE_IRQ
+ struct irq_desc *desc;
+
+ /* first time to refer irq_cfg, so with new */
+ desc = irq_to_desc_alloc_cpu(irq, cpu);
+ cfg = desc->chip_data;
+#else
+ cfg = irq_cfg(irq);
+#endif

please introduce a proper helper that eliminates such complications. Any reason why chip_data could not be used in the !SPARSE_IRQ case? irq_cfg_alloc() perhaps?

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

+ if (irq < NR_IRQS_LEGACY) {

please s/NR_IRQS_LEGACY/NR_IRQS_X86_LEGACY - this is never used outside of x86 code.

will use that in kernel/irq/handle.c too, because dyn_array is dumped.

ah, i missed that. Okay - lets keep NR_IRQS_LEGACY then.

Quoted 9 lines
Quoted 8 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 5 lines
arch/x86/mm/init_32.c +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

Quoted 4 lines

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Something like:

early_kzalloc()

?

Andrew, any preferences?

Ingo

author
#15 lore raw

PATCH 1/1 sparse_irq aka dyn_irq v10

getting closer, irq_desc can be moved according to smp_affinity.

it is getting some big now..., may split it to two patch: one only have sparse irq but don't move irq_desc second one will move irq_desc according to affinity.

YH

----------
From: Yinghai Lu <[email protected]>
Subject: sparseirq v10

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array
when sparse_irq is used, use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   11 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/i8259.c            |   24 +
 arch/x86/kernel/io_apic.c          |  510 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 +
 arch/x86/kernel/irq_32.c           |    2 
 arch/x86/kernel/irq_64.c           |    2 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   22 +
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 ++
 drivers/pci/htirq.c                |   19 +
 drivers/pci/intr_remapping.c       |   66 ++++
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   13 
 fs/proc/stat.c                     |   17 -
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   71 ++++-
 include/linux/irqnr.h              |   15 -
 include/linux/kernel_stat.h        |   14 -
 init/main.c                        |    2 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   51 ++-
 kernel/irq/handle.c                |  384 ++++++++++++++++++++++++++-
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 27 files changed, 1098 insertions(+), 219 deletions(-)
arch/x86/Kconfig +11 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -236,6 +236,17 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +365 -145

1,010 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +19 -0
Index: linux-2.6/drivers/pci/htirq.c
===================================================================
@@ -82,6 +82,19 @@ void unmask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	/* use 8bits (bus) + 8bits (devfn) + 12 bits */
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;
+}
+
 /**
  * __ht_create_irq - create an irq and attach it to a device.
  * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +111,7 @@ int __ht_create_irq(struct pci_dev *dev,
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)
@@ -125,7 +139,12 @@ int __ht_create_irq(struct pci_dev *dev,
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif
 
 	if (irq <= 0) {
 		kfree(cfg);
drivers/pci/intr_remapping.c +64 -2

90 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +12 -1
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -10,20 +10,31 @@
  */
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
+#ifdef CONFIG_SPARSE_IRQ
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+#else
 	return (*pos <= nr_irqs) ? pos : NULL;
+#endif
 }
 
 static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
 {
+#ifdef CONFIG_SPARSE_IRQ
+	return seq_list_next(v, &sparse_irqs_head, pos);
+#else
 	(*pos)++;
 	if (*pos > nr_irqs)
 		return NULL;
 	return pos;
+#endif
 }
 
 static void int_seq_stop(struct seq_file *f, void *v)
 {
-	/* Nothing to do */
+#ifdef CONFIG_SPARSE_IRQ
+	rcu_read_unlock();
+#endif
 }
 
 static const struct seq_operations int_seq_ops = {
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +67 -4

104 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +41 -10

113 lines not on this page · raw message

kernel/irq/handle.c +371 -13

457 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init_work(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -254,7 +254,7 @@ void fixup_irqs(cpumask_t map)
 			desc->chip->set_affinity(irq, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -129,7 +129,7 @@ void fixup_irqs(cpumask_t map)
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@ void init_irq_proc(void)
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@ static int misrouted_irq(int irq)
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@ static void poll_spurious_irqs(unsigned
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +2 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -611,6 +611,8 @@ asmlinkage void __init start_kernel(void
 	sort_main_extable();
 	trap_init();
 	rcu_init();
+	/* init some links before init_ISA_irqs() */
+	early_irq_init_work();
 	init_IRQ();
 	pidhash_init();
 	init_timers();
arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================
@@ -101,6 +101,8 @@
 #define LAST_VM86_IRQ		15
 #define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY		16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
arch/x86/kernel/i8259.c +21 -3
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================
@@ -36,12 +36,21 @@ static int i8259A_auto_eoi;
 DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
+#ifdef CONFIG_SPARSE_IRQ
+static void mask_and_ack_8259A_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void mask_and_ack_8259A_wrapper(unsigned int irq)
+#endif
+{
+	mask_and_ack_8259A(irq);
+}
+
 struct irq_chip i8259A_chip = {
 	.name		= "XT-PIC",
 	.mask		= disable_8259A_irq,
 	.disable	= disable_8259A_irq,
 	.unmask		= enable_8259A_irq,
-	.mask_ack	= mask_and_ack_8259A,
+	.mask_ack	= mask_and_ack_8259A_wrapper,
 };
 
 /*
@@ -78,6 +87,15 @@ void disable_8259A_irq(unsigned int irq)
 	spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void disable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void disable_8259A_irq_wrapper(unsigned int irq)
+#endif
+{
+	disable_8259A_irq(irq);
+}
+
 void enable_8259A_irq(unsigned int irq)
 {
 	unsigned int mask = ~(1 << irq);
@@ -348,9 +366,9 @@ void init_8259A(int auto_eoi)
 		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_chip.mask_ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq_wrapper;
 	else
-		i8259A_chip.mask_ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A_wrapper;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
arch/x86/kernel/uv_irq.c +20 -2
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================
@@ -18,6 +18,15 @@ static void uv_noop(unsigned int irq)
 {
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_noop_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_noop_wrapper(unsigned int irq)
+#endif
+{
+	uv_noop(irq);
+}
+
 static unsigned int uv_noop_ret(unsigned int irq)
 {
 	return 0;
@@ -28,16 +37,25 @@ static void uv_ack_apic(unsigned int irq
 	ack_APIC_irq();
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_ack_apic_wrapper(unsigned int irq)
+#endif
+{
+	uv_ack_apic(irq);
+}
+
 struct irq_chip uv_irq_chip = {
 	.name		= "UV-CORE",
 	.startup	= uv_noop_ret,
 	.shutdown	= uv_noop,
 	.enable		= uv_noop,
 	.disable	= uv_noop,
-	.ack		= uv_noop,
+	.ack		= uv_noop_wrapper,
 	.mask		= uv_noop,
 	.unmask		= uv_noop,
-	.eoi		= uv_ack_apic,
+	.eoi		= uv_ack_apic_wrapper,
 	.end		= uv_noop,
 };
 
#16 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v10

arch/x86/kernel/uv_irq.c static void uv_ack_apic(unsigned int irq · line 44

Quoted 5 lines · Yinghai Lu
arch/x86/kernel/uv_irq.c +5 -0
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_ack_apic_wrapper(unsigned int irq)
+#endif

hm, why not change it to the new prototype unconditionally? (just pass in NULL or so)

Ingo

author
#17 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v10

Quoted 10 lines · Ingo Molnar

arch/x86/kernel/uv_irq.c static void uv_ack_apic(unsigned int irq · line 44

Quoted 5 lines · Yinghai Lu
arch/x86/kernel/uv_irq.c +5 -0
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_ack_apic_wrapper(unsigned int irq)
+#endif

hm, why not change it to the new prototype unconditionally? (just pass in NULL or so)

that is sitting on irq_chip, and if change that, we need to go over all those kind of funcs and structure of other platforms.

YH

#18 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v10

Quoted 12 lines · Yinghai Lu
Quoted 10 lines · Ingo Molnar

arch/x86/kernel/uv_irq.c static void uv_ack_apic(unsigned int irq · line 44

Quoted 5 lines · Yinghai Lu
arch/x86/kernel/uv_irq.c +5 -0
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_ack_apic_wrapper(unsigned int irq)
+#endif

hm, why not change it to the new prototype unconditionally? (just pass in NULL or so)

Quoted 2 lines

that is sitting on irq_chip, and if change that, we need to go over all those kind of funcs and structure of other platforms.

okay, lets not go there just yet.

Ingo

#19 lore raw
In reply to Ingo Molnar
Quoted 17 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 9 lines
Quoted 8 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 5 lines
arch/x86/mm/init_32.c +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

Quoted 4 lines

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Quoted 7 lines

Something like:

early_kzalloc()

?

Andrew, any preferences?

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

So what's all this about?

author
#20 lore raw
Quoted 20 lines · Andrew Morton
Quoted 18 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines
Quoted 7 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 5 lines
arch/x86/mm/init_32.c +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Something like:

early_kzalloc()

Quoted 8 lines
Quoted 3 lines

?

Andrew, any preferences?

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

So what's all this about?

if i use alloc_bootmem to get some memory, and later after_bootmem, can I use kfree to free it?

YH

#21 lore raw
Quoted 25 lines · Yinghai Lu
Quoted 24 lines · Andrew Morton
Quoted 21 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines
Quoted 7 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 5 lines
arch/x86/mm/init_32.c +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Something like:

early_kzalloc()

?

Andrew, any preferences?

Quoted 7 lines
Quoted 4 lines

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

So what's all this about?

if i use alloc_bootmem to get some memory, and later after_bootmem, can I use kfree to free it?

hm, no. If we used alloc_bootmem(), then we must not free it after after_bootmem has been set.

Ingo

author
#22 lore raw
Quoted 29 lines · Ingo Molnar
Quoted 27 lines · Yinghai Lu
Quoted 26 lines · Andrew Morton
Quoted 14 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines
Quoted 7 lines

Review void __init mem_init(void) · line 991

Quoted 5 lines
(quoted diff) +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Quoted 7 lines

Something like:

early_kzalloc()

?

Andrew, any preferences?

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

So what's all this about?

if i use alloc_bootmem to get some memory, and later after_bootmem, can I use kfree to free it?

hm, no. If we used alloc_bootmem(), then we must not free it after after_bootmem has been set.

ok, let keep irq_desc for legacy irqs not movable...

YH

#23 lore raw
Quoted 30 lines · Yinghai Lu
Quoted 29 lines · Ingo Molnar
Quoted 27 lines · Yinghai Lu
Quoted 26 lines · Andrew Morton
Quoted 14 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines
Quoted 7 lines

Review void __init mem_init(void) · line 991

Quoted 5 lines
(quoted diff) +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Quoted 7 lines

Something like:

early_kzalloc()

?

Andrew, any preferences?

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
Quoted 1 line

So what's all this about?

if i use alloc_bootmem to get some memory, and later after_bootmem, can I use kfree to free it?

hm, no. If we used alloc_bootmem(), then we must not free it after after_bootmem has been set.

ok, let keep irq_desc for legacy irqs not movable...

most of them are movable right now, correct? If we restrict their movability now that might surprise existing usecases negatively.

Ingo

author
#24 lore raw
Quoted 37 lines · Ingo Molnar
Quoted 34 lines · Yinghai Lu
Quoted 33 lines · Ingo Molnar
Quoted 30 lines · Yinghai Lu
Quoted 20 lines · Andrew Morton
Quoted 18 lines · On Mon, 10 Nov 2008 10:40:33 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines
Quoted 7 lines

Review void __init mem_init(void) · line 991

Quoted 5 lines
(quoted diff) +1 -0
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
      set_highmem_pages_init();
 
+     after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

where is that fancy patch? current percpu_alloc(), will keep big pointer in array..., instead of put that pointer in percpu_area

64bit has that after_bootmem already.

or at least introduce a "bootmem agnostic" allocator instead of open-coding the after_bootmem flag.

Something like:

early_kzalloc()

Quoted 7 lines
Quoted 3 lines

?

Andrew, any preferences?

My mind reading ain't what it was, and this after_bootmem flag is write-only in this patch.

So what's all this about?

if i use alloc_bootmem to get some memory, and later after_bootmem, can I use kfree to free it?

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

hm, no. If we used alloc_bootmem(), then we must not free it after after_bootmem has been set.

ok, let keep irq_desc for legacy irqs not movable...

most of them are movable right now, correct? If we restrict their movability now that might surprise existing usecases negatively.

i mean irq_desc will not be allocated one one on new cpus...

YH

author
#25 lore raw

PATCH 1/1 sparse_irq aka dyn_irq v11

In reply to Ingo Molnar

done. please check it.
fix compiling problem on every config

---

From: Yinghai Lu <[email protected]>
Subject: sparseirq v11

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array
when sparse_irq is used, use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated try to pass desc cfg as more possible to avoid list look up.
legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.
	[ or we need to change domain definition to cpus on the same node ? ]

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   11 
 arch/x86/include/asm/hpet.h        |    5 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/hpet.c             |    8 
 arch/x86/kernel/i8259.c            |   37 +-
 arch/x86/kernel/io_apic.c          |  665 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 +
 arch/x86/kernel/irq_32.c           |    2 
 arch/x86/kernel/irq_64.c           |   16 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   26 +
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 +
 drivers/pci/htirq.c                |   27 +
 drivers/pci/intel-iommu.c          |    8 
 drivers/pci/intr_remapping.c       |   62 +++
 drivers/pci/msi.c                  |   42 +-
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   13 
 fs/proc/stat.c                     |   17 
 include/linux/dmar.h               |    5 
 include/linux/htirq.h              |    6 
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   78 ++++
 include/linux/irqnr.h              |   15 
 include/linux/kernel_stat.h        |   14 
 include/linux/msi.h                |    6 
 init/main.c                        |    2 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   82 +++-
 kernel/irq/handle.c                |  388 ++++++++++++++++++++-
 kernel/irq/migration.c             |   18 +
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 35 files changed, 1365 insertions(+), 282 deletions(-)
arch/x86/Kconfig +11 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -236,6 +236,17 @@
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +486 -186

1,331 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +27 -0
Index: linux-2.6/drivers/pci/htirq.c
===================================================================
@@ -58,7 +58,11 @@
 	*msg = cfg->msg;
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+void mask_ht_irq(unsigned int irq, struct irq_desc **descp)
+#else
 void mask_ht_irq(unsigned int irq)
+#endif
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -70,7 +74,11 @@
 	write_ht_irq_msg(irq, &msg);
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+void unmask_ht_irq(unsigned int irq, struct irq_desc **descp)
+#else
 void unmask_ht_irq(unsigned int irq)
+#endif
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -82,6 +90,19 @@
 	write_ht_irq_msg(irq, &msg);
 }
 
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	/* use 8bits (bus) + 8bits (devfn) + 12 bits */
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;
+}
+
 /**
  * __ht_create_irq - create an irq and attach it to a device.
  * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +119,7 @@
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)
@@ -125,7 +147,12 @@
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif
 
 	if (irq <= 0) {
 		kfree(cfg);
drivers/pci/intr_remapping.c +60 -2

86 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +12 -1
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -10,20 +10,31 @@
  */
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
+#ifdef CONFIG_SPARSE_IRQ
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+#else
 	return (*pos <= nr_irqs) ? pos : NULL;
+#endif
 }
 
 static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
 {
+#ifdef CONFIG_SPARSE_IRQ
+	return seq_list_next(v, &sparse_irqs_head, pos);
+#else
 	(*pos)++;
 	if (*pos > nr_irqs)
 		return NULL;
 	return pos;
+#endif
 }
 
 static void int_seq_stop(struct seq_file *f, void *v)
 {
-	/* Nothing to do */
+#ifdef CONFIG_SPARSE_IRQ
+	rcu_read_unlock();
+#endif
 }
 
 static const struct seq_operations int_seq_ops = {
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +71 -6

115 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +70 -12

186 lines not on this page · raw message

kernel/irq/handle.c +373 -15

461 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init_work(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -254,7 +254,7 @@
 			desc->chip->set_affinity(irq, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +13 -3
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -112,16 +112,26 @@
 			mask = map;
 		}
 
-		if (desc->chip->mask)
+		if (desc->chip->mask) {
+#ifdef CONFIG_SPARSE_IRQ
+			desc->chip->mask(irq, &desc);
+#else
 			desc->chip->mask(irq);
+#endif
+		}
 
 		if (desc->chip->set_affinity)
 			desc->chip->set_affinity(irq, mask);
 		else if (!(warned++))
 			set_affinity = 0;
 
-		if (desc->chip->unmask)
+		if (desc->chip->unmask) {
+#ifdef CONFIG_SPARSE_IRQ
+			desc->chip->unmask(irq, &desc);
+#else
 			desc->chip->unmask(irq);
+#endif
+		}
 
 		spin_unlock(&desc->lock);
 
@@ -129,7 +139,7 @@
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +11 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -541,6 +541,15 @@
 {
 }
 
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+void __init __attribute__((weak)) early_irq_init_work(void)
+{
+	arch_early_irq_init_work();
+}
+
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
@@ -611,6 +620,8 @@
 	sort_main_extable();
 	trap_init();
 	rcu_init();
+	/* init some links before init_ISA_irqs() */
+	early_irq_init_work();
 	init_IRQ();
 	pidhash_init();
 	init_timers();
arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================
@@ -101,6 +101,8 @@
 #define LAST_VM86_IRQ		15
 #define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY		16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
arch/x86/kernel/i8259.c +32 -5
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================
@@ -36,12 +36,39 @@
 DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
+#ifdef CONFIG_SPARSE_IRQ
+static void mask_and_ack_8259A_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void mask_and_ack_8259A_wrapper(unsigned int irq)
+#endif
+{
+	mask_and_ack_8259A(irq);
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+static void disable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void disable_8259A_irq_wrapper(unsigned int irq)
+#endif
+{
+	disable_8259A_irq(irq);
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+static void enable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void enable_8259A_irq_wrapper(unsigned int irq)
+#endif
+{
+	enable_8259A_irq(irq);
+}
+
 struct irq_chip i8259A_chip = {
 	.name		= "XT-PIC",
-	.mask		= disable_8259A_irq,
+	.mask		= disable_8259A_irq_wrapper,
 	.disable	= disable_8259A_irq,
-	.unmask		= enable_8259A_irq,
-	.mask_ack	= mask_and_ack_8259A,
+	.unmask		= enable_8259A_irq_wrapper,
+	.mask_ack	= mask_and_ack_8259A_wrapper,
 };
 
 /*
@@ -348,9 +375,9 @@
 		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_chip.mask_ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq_wrapper;
 	else
-		i8259A_chip.mask_ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A_wrapper;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
arch/x86/kernel/uv_irq.c +22 -4
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================
@@ -18,6 +18,15 @@
 {
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_noop_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_noop_wrapper(unsigned int irq)
+#endif
+{
+	uv_noop(irq);
+}
+
 static unsigned int uv_noop_ret(unsigned int irq)
 {
 	return 0;
@@ -28,16 +37,25 @@
 	ack_APIC_irq();
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+#else
+static void uv_ack_apic_wrapper(unsigned int irq)
+#endif
+{
+	uv_ack_apic(irq);
+}
+
 struct irq_chip uv_irq_chip = {
 	.name		= "UV-CORE",
 	.startup	= uv_noop_ret,
 	.shutdown	= uv_noop,
 	.enable		= uv_noop,
 	.disable	= uv_noop,
-	.ack		= uv_noop,
-	.mask		= uv_noop,
-	.unmask		= uv_noop,
-	.eoi		= uv_ack_apic,
+	.ack		= uv_noop_wrapper,
+	.mask		= uv_noop_wrapper,
+	.unmask		= uv_noop_wrapper,
+	.eoi		= uv_ack_apic_wrapper,
 	.end		= uv_noop,
 };
 
drivers/pci/msi.c +30 -12

92 lines not on this page · raw message

include/linux/msi.h +6 -0
Index: linux-2.6/include/linux/msi.h
===================================================================
@@ -10,8 +10,14 @@
 };
 
 /* Helper functions */
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+extern void mask_msi_irq(unsigned int irq, struct irq_desc **descp);
+extern void unmask_msi_irq(unsigned int irq, struct irq_desc **descp);
+#else
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
+#endif
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
arch/x86/include/asm/hpet.h +5 -0
Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================
@@ -72,8 +72,13 @@
 extern unsigned long hpet_readl(unsigned long a);
 extern void force_hpet_resume(void);
 
+#ifdef CONFIG_SPARSE_IRQ
+extern void hpet_msi_unmask(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_mask(unsigned int irq, struct irq_desc **descp);
+#else
 extern void hpet_msi_unmask(unsigned int irq);
 extern void hpet_msi_mask(unsigned int irq);
+#endif
 extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
 extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
 
arch/x86/kernel/hpet.c +8 -0
Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================
@@ -347,7 +347,11 @@
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev	*hpet_devs;
 
+#ifdef CONFIG_SPARSE_IRQ
+void hpet_msi_unmask(unsigned int irq, struct irq_desc **descp)
+#else
 void hpet_msi_unmask(unsigned int irq)
+#endif
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
 	unsigned long cfg;
@@ -358,7 +362,11 @@
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+void hpet_msi_mask(unsigned int irq, struct irq_desc **descp)
+#else
 void hpet_msi_mask(unsigned int irq)
+#endif
 {
 	unsigned long cfg;
 	struct hpet_dev *hdev = get_irq_data(irq);
include/linux/htirq.h +6 -0
Index: linux-2.6/include/linux/htirq.h
===================================================================
@@ -9,8 +9,14 @@
 /* Helper functions.. */
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+void mask_ht_irq(unsigned int irq, struct irq_desc **descp);
+void unmask_ht_irq(unsigned int irq, struct irq_desc **descp);
+#else
 void mask_ht_irq(unsigned int irq);
 void unmask_ht_irq(unsigned int irq);
+#endif
 
 /* The arch hook for getting things started */
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
kernel/irq/migration.c +18 -0
Index: linux-2.6/kernel/irq/migration.c
===================================================================
@@ -1,9 +1,15 @@
 
 #include <linux/irq.h>
 
+#ifdef CONFIG_SPARSE_IRQ
+void move_masked_irq(int irq, struct irq_desc **descp)
+{
+	struct irq_desc *desc = *descp;
+#else
 void move_masked_irq(int irq)
 {
 	struct irq_desc *desc = irq_to_desc(irq);
+#endif
 	cpumask_t tmp;
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
@@ -47,9 +53,15 @@
 	cpus_clear(desc->pending_mask);
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+void move_native_irq(int irq, struct irq_desc **descp)
+{
+	struct irq_desc *desc = *descp;
+#else
 void move_native_irq(int irq)
 {
 	struct irq_desc *desc = irq_to_desc(irq);
+#endif
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
 		return;
@@ -57,8 +69,14 @@
 	if (unlikely(desc->status & IRQ_DISABLED))
 		return;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc->chip->mask(irq, descp);
+	move_masked_irq(irq, descp);
+	desc->chip->unmask(irq, descp);
+#else
 	desc->chip->mask(irq);
 	move_masked_irq(irq);
 	desc->chip->unmask(irq);
+#endif
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/pci/intel-iommu.c +8 -0
Index: linux-2.6/drivers/pci/intel-iommu.c
===================================================================

Lines of this file are not shown. View the raw message.

include/linux/dmar.h +5 -0
Index: linux-2.6/include/linux/dmar.h
===================================================================

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#28 lore raw

PATCH 1/1 sparse_irq aka dyn_irq v13

reduce the #ifdef numbers

YH

---

From: Yinghai Lu <[email protected]>
Subject: sparseirq v13

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array

when sparse_irq is used (CONFIG_SPARSE_IRQ), use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg

if CONFIG_MOVE_IRQ_DESC is set
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated try to pass desc cfg as more as possible to avoid list looking up. legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.
	[ or we need to change domain definition to cpus on the same node ? ]

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   20 +
 arch/x86/include/asm/hpet.h        |    7 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/hpet.c             |   19 -
 arch/x86/kernel/i8259.c            |   29 +
 arch/x86/kernel/io_apic.c          |  688 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 +
 arch/x86/kernel/irq_32.c           |    2 
 arch/x86/kernel/irq_64.c           |    6 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   28 +
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 +
 drivers/pci/htirq.c                |   38 +-
 drivers/pci/intel-iommu.c          |   19 -
 drivers/pci/intr_remapping.c       |   62 +++
 drivers/pci/msi.c                  |   49 +-
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   18 
 fs/proc/stat.c                     |   17 
 include/linux/dmar.h               |    7 
 include/linux/htirq.h              |    8 
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   85 ++++
 include/linux/irqnr.h              |   15 
 include/linux/kernel_stat.h        |   14 
 include/linux/msi.h                |    8 
 init/main.c                        |   11 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   43 +-
 kernel/irq/handle.c                |  373 +++++++++++++++++++-
 kernel/irq/migration.c             |   29 +
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 35 files changed, 1377 insertions(+), 312 deletions(-)
arch/x86/Kconfig +20 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -240,6 +240,26 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+	bool "Move irq desc when changing irq smp_affinity"
+	depends on SPARSE_IRQ && SMP
+	default y
+	help
+	  This enables moving irq_desc to cpu/node that irq will use handled.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +490 -198

1,341 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +36 -2
Index: linux-2.6/drivers/pci/htirq.c
===================================================================
@@ -58,7 +58,7 @@ void fetch_ht_irq_msg(unsigned int irq,
 	*msg = cfg->msg;
 }
 
-void mask_ht_irq(unsigned int irq)
+void mask_ht_irqx(unsigned int irq, struct irq_desc **descp)
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -70,7 +70,7 @@ void mask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
-void unmask_ht_irq(unsigned int irq)
+void unmask_ht_irqx(unsigned int irq, struct irq_desc **descp)
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -82,6 +82,34 @@ void unmask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void mask_ht_irq(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	mask_ht_irqx(irq, &desc);
+}
+void unmask_ht_irq(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	unmask_ht_irqx(irq, &desc);
+}
+#endif
+
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	/* use 8bits (bus) + 8bits (devfn) + 12 bits */
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;
+}
+
 /**
  * __ht_create_irq - create an irq and attach it to a device.
  * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +126,7 @@ int __ht_create_irq(struct pci_dev *dev,
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)
@@ -125,7 +154,12 @@ int __ht_create_irq(struct pci_dev *dev,
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif
 
 	if (irq <= 0) {
 		kfree(cfg);
drivers/pci/intr_remapping.c +60 -2

86 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +18 -0
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -8,6 +8,23 @@
 /*
  * /proc/interrupts
  */
+#ifdef CONFIG_SPARSE_IRQ
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &sparse_irqs_head, pos);
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	rcu_read_unlock();
+}
+#else
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
 	return (*pos <= nr_irqs) ? pos : NULL;
@@ -25,6 +42,7 @@ static void int_seq_stop(struct seq_file
 {
 	/* Nothing to do */
 }
+#endif
 
 static const struct seq_operations int_seq_ops = {
 	.start = int_seq_start,
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +81 -4

125 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +24 -19

137 lines not on this page · raw message

kernel/irq/handle.c +360 -13

438 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init_work(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -254,7 +254,7 @@ void fixup_irqs(cpumask_t map)
 			desc->chip->set_affinity(irq, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +3 -3
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -113,7 +113,7 @@ void fixup_irqs(cpumask_t map)
 		}
 
 		if (desc->chip->mask)
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 
 		if (desc->chip->set_affinity)
 			desc->chip->set_affinity(irq, mask);
@@ -121,7 +121,7 @@ void fixup_irqs(cpumask_t map)
 			set_affinity = 0;
 
 		if (desc->chip->unmask)
-			desc->chip->unmask(irq);
+			desc_chip_unmask(irq, &desc);
 
 		spin_unlock(&desc->lock);
 
@@ -129,7 +129,7 @@ void fixup_irqs(cpumask_t map)
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@ void init_irq_proc(void)
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@ static int misrouted_irq(int irq)
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@ static void poll_spurious_irqs(unsigned
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +11 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini
 {
 }
 
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+void __init __attribute__((weak)) early_irq_init_work(void)
+{
+	arch_early_irq_init_work();
+}
+
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
@@ -612,6 +621,8 @@ asmlinkage void __init start_kernel(void
 	sort_main_extable();
 	trap_init();
 	rcu_init();
+	/* init some links before init_ISA_irqs() */
+	early_irq_init_work();
 	init_IRQ();
 	pidhash_init();
 	init_timers();
arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================
@@ -101,6 +101,8 @@
 #define LAST_VM86_IRQ		15
 #define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY		16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
arch/x86/kernel/i8259.c +24 -5
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================
@@ -36,12 +36,31 @@ static int i8259A_auto_eoi;
 DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
+#ifdef CONFIG_SPARSE_IRQ
+static void mask_and_ack_8259A_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	mask_and_ack_8259A(irq);
+}
+static void disable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	disable_8259A_irq(irq);
+}
+static void enable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	enable_8259A_irq(irq);
+}
+#else
+#define mask_and_ack_8259A_wrapper mask_and_ack_8259A
+#define disable_8259A_irq_wrapper disable_8259A_irq
+#define enable_8259A_irq_wrapper enable_8259A_irq
+#endif
+
 struct irq_chip i8259A_chip = {
 	.name		= "XT-PIC",
-	.mask		= disable_8259A_irq,
+	.mask		= disable_8259A_irq_wrapper,
 	.disable	= disable_8259A_irq,
-	.unmask		= enable_8259A_irq,
-	.mask_ack	= mask_and_ack_8259A,
+	.unmask		= enable_8259A_irq_wrapper,
+	.mask_ack	= mask_and_ack_8259A_wrapper,
 };
 
 /*
@@ -348,9 +367,9 @@ void init_8259A(int auto_eoi)
 		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_chip.mask_ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq_wrapper;
 	else
-		i8259A_chip.mask_ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A_wrapper;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
arch/x86/kernel/uv_irq.c +24 -4
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================
@@ -18,6 +18,16 @@ static void uv_noop(unsigned int irq)
 {
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_noop_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	uv_noop(irq);
+}
+
+#else
+#define uv_noop_wrapper uv_noop
+#endif
+
 static unsigned int uv_noop_ret(unsigned int irq)
 {
 	return 0;
@@ -28,16 +38,26 @@ static void uv_ack_apic(unsigned int irq
 	ack_APIC_irq();
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	uv_ack_apic(irq);
+}
+
+#else
+#define uv_ack_apic_wrapper uv_ack_apic
+#endif
+
 struct irq_chip uv_irq_chip = {
 	.name		= "UV-CORE",
 	.startup	= uv_noop_ret,
 	.shutdown	= uv_noop,
 	.enable		= uv_noop,
 	.disable	= uv_noop,
-	.ack		= uv_noop,
-	.mask		= uv_noop,
-	.unmask		= uv_noop,
-	.eoi		= uv_ack_apic,
+	.ack		= uv_noop_wrapper,
+	.mask		= uv_noop_wrapper,
+	.unmask		= uv_noop_wrapper,
+	.eoi		= uv_ack_apic_wrapper,
 	.end		= uv_noop,
 };
 
drivers/pci/msi.c +36 -13

99 lines not on this page · raw message

include/linux/msi.h +8 -0
Index: linux-2.6/include/linux/msi.h
===================================================================
@@ -10,8 +10,16 @@ struct msi_msg {
 };
 
 /* Helper functions */
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+extern void mask_msi_irqx(unsigned int irq, struct irq_desc **descp);
+extern void unmask_msi_irqx(unsigned int irq, struct irq_desc **descp);
+#define mask_msi_irq mask_msi_irqx
+#define unmask_msi_irq unmask_msi_irqx
+#else
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
+#endif
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
arch/x86/include/asm/hpet.h +7 -0
Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================
@@ -72,8 +72,15 @@ extern void hpet_disable(void);
 extern unsigned long hpet_readl(unsigned long a);
 extern void force_hpet_resume(void);
 
+#ifdef CONFIG_SPARSE_IRQ
+extern void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp);
+#define hpet_msi_unmask hpet_msi_unmaskx
+#define hpet_msi_mask hpet_msi_maskx
+#else
 extern void hpet_msi_unmask(unsigned int irq);
 extern void hpet_msi_mask(unsigned int irq);
+#endif
 extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
 extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
 
arch/x86/kernel/hpet.c +17 -2
Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================
@@ -347,7 +347,7 @@ static int hpet_legacy_next_event(unsign
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev	*hpet_devs;
 
-void hpet_msi_unmask(unsigned int irq)
+void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
 	unsigned long cfg;
@@ -358,7 +358,7 @@ void hpet_msi_unmask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_mask(unsigned int irq)
+void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp)
 {
 	unsigned long cfg;
 	struct hpet_dev *hdev = get_irq_data(irq);
@@ -369,6 +369,21 @@ void hpet_msi_mask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void hpet_msi_unmask(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_unmaskx(irq, &desc);
+}
+void hpet_msi_mask(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_maskx(irq, &desc);
+}
+#endif
+
 void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
include/linux/htirq.h +8 -0
Index: linux-2.6/include/linux/htirq.h
===================================================================
@@ -9,8 +9,16 @@ struct ht_irq_msg {
 /* Helper functions.. */
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+void mask_ht_irqx(unsigned int irq, struct irq_desc **descp);
+void unmask_ht_irqx(unsigned int irq, struct irq_desc **descp);
+#define mask_ht_irq mask_ht_irqx
+#define unmask_ht_irq unmask_ht_irqx
+#else
 void mask_ht_irq(unsigned int irq);
 void unmask_ht_irq(unsigned int irq);
+#endif
 
 /* The arch hook for getting things started */
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
kernel/irq/migration.c +22 -7
Index: linux-2.6/kernel/irq/migration.c
===================================================================
@@ -1,9 +1,9 @@
 
 #include <linux/irq.h>
 
-void move_masked_irq(int irq)
+void move_masked_irqx(int irq, struct irq_desc **descp)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc = *descp;
 	cpumask_t tmp;
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
@@ -47,9 +47,9 @@ void move_masked_irq(int irq)
 	cpus_clear(desc->pending_mask);
 }
 
-void move_native_irq(int irq)
+void move_native_irqx(int irq, struct irq_desc **descp)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc = *descp;
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
 		return;
@@ -57,8 +57,23 @@ void move_native_irq(int irq)
 	if (unlikely(desc->status & IRQ_DISABLED))
 		return;
 
-	desc->chip->mask(irq);
-	move_masked_irq(irq);
-	desc->chip->unmask(irq);
+	desc_chip_mask(irq, descp);
+	move_masked_irqx(irq, descp);
+	desc_chip_unmask(irq, descp);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void move_masked_irq(int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	move_masked_irqx(irq, &desc);
+}
+
+void move_native_irq(int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	move_native_irqx(irq, &desc);
+}
+#endif
drivers/pci/intel-iommu.c +17 -2
Index: linux-2.6/drivers/pci/intel-iommu.c
===================================================================
@@ -751,7 +751,7 @@ const char *dmar_get_fault_reason(u8 fau
 		return fault_reason_strings[fault_reason];
 }
 
-void dmar_msi_unmask(unsigned int irq)
+void dmar_msi_unmaskx(unsigned int irq, struct irq_desc **descp)
 {
 	struct intel_iommu *iommu = get_irq_data(irq);
 	unsigned long flag;
@@ -764,7 +764,7 @@ void dmar_msi_unmask(unsigned int irq)
 	spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
-void dmar_msi_mask(unsigned int irq)
+void dmar_msi_maskx(unsigned int irq, struct irq_desc **descp)
 {
 	unsigned long flag;
 	struct intel_iommu *iommu = get_irq_data(irq);
@@ -777,6 +777,21 @@ void dmar_msi_mask(unsigned int irq)
 	spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

include/linux/dmar.h +7 -0
Index: linux-2.6/include/linux/dmar.h
===================================================================

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#29 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 11 lines · Yinghai Lu

reduce the #ifdef numbers

Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================

arch/x86/include/asm/hpet.h +1 -0
@@ -72,8 +72,15 @@ extern void hpet_disable(void);
 extern unsigned long hpet_readl(unsigned long a);
 extern void force_hpet_resume(void);
 
+#ifdef CONFIG_SPARSE_IRQ

arch/x86/include/asm/hpet.h extern void hpet_disable(void); · line 85

Quoted 10 lines
arch/x86/include/asm/hpet.h +6 -0
+extern void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp);
+#define hpet_msi_unmask hpet_msi_unmaskx
+#define hpet_msi_mask hpet_msi_maskx
+#else
 extern void hpet_msi_unmask(unsigned int irq);
 extern void hpet_msi_mask(unsigned int irq);
+#endif
 extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
 extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);

please use inlines instead of #define's.

Quoted 14 lines

Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================

arch/x86/kernel/hpet.c +1 -1
@@ -347,7 +347,7 @@ static int hpet_legacy_next_event(unsign
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev	*hpet_devs;
 
-void hpet_msi_unmask(unsigned int irq)
+void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
 	unsigned long cfg;

arch/x86/kernel/hpet.c void hpet_msi_unmask(unsigned int irq) · line 361

Quoted 5 lines
arch/x86/kernel/hpet.c +1 -1
@@ -358,7 +358,7 @@ void hpet_msi_unmask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_mask(unsigned int irq)
+void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp)

please name it hpet_msi_mask_desc() - 'maskx' sounds quirky.

Quoted 15 lines
arch/x86/kernel/hpet.c +8 -0
 {
 	unsigned long cfg;
 	struct hpet_dev *hdev = get_irq_data(irq);
@@ -369,6 +369,21 @@ void hpet_msi_mask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void hpet_msi_unmask(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_unmaskx(irq, &desc);
+}
+void hpet_msi_mask(unsigned int irq)

arch/x86/kernel/hpet.c void hpet_msi_mask(unsigned int irq) · line 389

Quoted 10 lines
arch/x86/kernel/hpet.c +7 -0
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_maskx(irq, &desc);
+}
+#endif
+
 void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);

it still looks ugly to me: couldnt we make it completely #ifdef-free, by just adding the new API variants?

i.e. leave these present unconditionally:

Quoted 2 lines

extern void hpet_msi_unmask(unsigned int irq);
extern void hpet_msi_mask(unsigned int irq);

and just _add_ these (unconditionally):

arch/x86/kernel/hpet.c

Quoted 2 lines
arch/x86/kernel/hpet.c +2 -0
+extern void hpet_msi_unmask_desc(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_mask_desc(unsigned int irq, struct irq_desc **descp);

that gives us zero #ifdefs and much nicer to read patches. Am i missing something why this isnt possible?

Ingo

author
#30 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · Ingo Molnar

it still looks ugly to me: couldnt we make it completely #ifdef-free, by just adding the new API variants?

i.e. leave these present unconditionally:

Quoted 2 lines

extern void hpet_msi_unmask(unsigned int irq);
extern void hpet_msi_mask(unsigned int irq);

Quoted 7 lines

and just _add_ these (unconditionally):

Review

Quoted 2 lines
(quoted diff) +2 -0
+extern void hpet_msi_unmask_desc(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_mask_desc(unsigned int irq, struct irq_desc **descp);

that gives us zero #ifdefs and much nicer to read patches. Am i missing something why this isnt possible?

in io_apic.c

struct irq_chip hpet_msi_type = {
.name = "HPET_MSI",
.unmask = hpet_msi_unmask,
.mask = hpet_msi_mask,
.ack = ack_apic_edge,
#ifdef CONFIG_SMP
.set_affinity = hpet_msi_set_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};

so those ack, mask, unmak, eoi field will have different function prototype..when sparseirq is enabled or not.

if you want to remove those #ifdef, we need to go over all irq_chip definition to make all those field to take struct irq_desc *desc (or **descp) instead of unsigned int irq.

actually we only need to pass desc struct instead of irq, because we can get desc->irq in case.

YH

author
#31 lore raw

PATCH 1/1 sparse_irq aka dyn_irq v13

In reply to a message not in the archive

-- adding CC Mike

---------

reduce the #ifdef numbers

YH

---

From: Yinghai Lu <[email protected]>
Subject: sparseirq v13

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array

when sparse_irq is used (CONFIG_SPARSE_IRQ), use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg

if CONFIG_MOVE_IRQ_DESC is set
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated try to pass desc cfg as more as possible to avoid list looking up. legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.
	[ or we need to change domain definition to cpus on the same node ? ]

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   20 +
 arch/x86/include/asm/hpet.h        |    7 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/hpet.c             |   19 -
 arch/x86/kernel/i8259.c            |   29 +
 arch/x86/kernel/io_apic.c          |  688 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 +
 arch/x86/kernel/irq_32.c           |    2 
 arch/x86/kernel/irq_64.c           |    6 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   28 +
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 +
 drivers/pci/htirq.c                |   38 +-
 drivers/pci/intel-iommu.c          |   19 -
 drivers/pci/intr_remapping.c       |   62 +++
 drivers/pci/msi.c                  |   49 +-
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   18 
 fs/proc/stat.c                     |   17 
 include/linux/dmar.h               |    7 
 include/linux/htirq.h              |    8 
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   85 ++++
 include/linux/irqnr.h              |   15 
 include/linux/kernel_stat.h        |   14 
 include/linux/msi.h                |    8 
 init/main.c                        |   11 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   43 +-
 kernel/irq/handle.c                |  373 +++++++++++++++++++-
 kernel/irq/migration.c             |   29 +
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 35 files changed, 1377 insertions(+), 312 deletions(-)
arch/x86/Kconfig +20 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -240,6 +240,26 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+	bool "Move irq desc when changing irq smp_affinity"
+	depends on SPARSE_IRQ && SMP
+	default y
+	help
+	  This enables moving irq_desc to cpu/node that irq will use handled.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +490 -198

1,341 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +36 -2
Index: linux-2.6/drivers/pci/htirq.c
===================================================================
@@ -58,7 +58,7 @@ void fetch_ht_irq_msg(unsigned int irq,
 	*msg = cfg->msg;
 }
 
-void mask_ht_irq(unsigned int irq)
+void mask_ht_irqx(unsigned int irq, struct irq_desc **descp)
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -70,7 +70,7 @@ void mask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
-void unmask_ht_irq(unsigned int irq)
+void unmask_ht_irqx(unsigned int irq, struct irq_desc **descp)
 {
 	struct ht_irq_cfg *cfg;
 	struct ht_irq_msg msg;
@@ -82,6 +82,34 @@ void unmask_ht_irq(unsigned int irq)
 	write_ht_irq_msg(irq, &msg);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void mask_ht_irq(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	mask_ht_irqx(irq, &desc);
+}
+void unmask_ht_irq(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	unmask_ht_irqx(irq, &desc);
+}
+#endif
+
+static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
+{
+	unsigned int irq;
+
+	/* use 8bits (bus) + 8bits (devfn) + 12 bits */
+	irq = dev->bus->number;
+	irq <<= 8;
+	irq |= dev->devfn;
+	irq <<= 12;
+
+	return irq;
+}
+
 /**
  * __ht_create_irq - create an irq and attach it to a device.
  * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +126,7 @@ int __ht_create_irq(struct pci_dev *dev,
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)
@@ -125,7 +154,12 @@ int __ht_create_irq(struct pci_dev *dev,
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif
 
 	if (irq <= 0) {
 		kfree(cfg);
drivers/pci/intr_remapping.c +60 -2

86 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +18 -0
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -8,6 +8,23 @@
 /*
  * /proc/interrupts
  */
+#ifdef CONFIG_SPARSE_IRQ
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &sparse_irqs_head, pos);
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	rcu_read_unlock();
+}
+#else
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
 	return (*pos <= nr_irqs) ? pos : NULL;
@@ -25,6 +42,7 @@ static void int_seq_stop(struct seq_file
 {
 	/* Nothing to do */
 }
+#endif
 
 static const struct seq_operations int_seq_ops = {
 	.start = int_seq_start,
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +81 -4

125 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +24 -19

137 lines not on this page · raw message

kernel/irq/handle.c +360 -13

438 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init_work(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +1 -1
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -254,7 +254,7 @@ void fixup_irqs(cpumask_t map)
 			desc->chip->set_affinity(irq, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +3 -3
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -113,7 +113,7 @@ void fixup_irqs(cpumask_t map)
 		}
 
 		if (desc->chip->mask)
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 
 		if (desc->chip->set_affinity)
 			desc->chip->set_affinity(irq, mask);
@@ -121,7 +121,7 @@ void fixup_irqs(cpumask_t map)
 			set_affinity = 0;
 
 		if (desc->chip->unmask)
-			desc->chip->unmask(irq);
+			desc_chip_unmask(irq, &desc);
 
 		spin_unlock(&desc->lock);
 
@@ -129,7 +129,7 @@ void fixup_irqs(cpumask_t map)
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@ void init_irq_proc(void)
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@ static int misrouted_irq(int irq)
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@ static void poll_spurious_irqs(unsigned
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +11 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini
 {
 }
 
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+void __init __attribute__((weak)) early_irq_init_work(void)
+{
+	arch_early_irq_init_work();
+}
+
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
@@ -612,6 +621,8 @@ asmlinkage void __init start_kernel(void
 	sort_main_extable();
 	trap_init();
 	rcu_init();
+	/* init some links before init_ISA_irqs() */
+	early_irq_init_work();
 	init_IRQ();
 	pidhash_init();
 	init_timers();
arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================
@@ -101,6 +101,8 @@
 #define LAST_VM86_IRQ		15
 #define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY		16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
arch/x86/kernel/i8259.c +24 -5
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================
@@ -36,12 +36,31 @@ static int i8259A_auto_eoi;
 DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
+#ifdef CONFIG_SPARSE_IRQ
+static void mask_and_ack_8259A_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	mask_and_ack_8259A(irq);
+}
+static void disable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	disable_8259A_irq(irq);
+}
+static void enable_8259A_irq_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	enable_8259A_irq(irq);
+}
+#else
+#define mask_and_ack_8259A_wrapper mask_and_ack_8259A
+#define disable_8259A_irq_wrapper disable_8259A_irq
+#define enable_8259A_irq_wrapper enable_8259A_irq
+#endif
+
 struct irq_chip i8259A_chip = {
 	.name		= "XT-PIC",
-	.mask		= disable_8259A_irq,
+	.mask		= disable_8259A_irq_wrapper,
 	.disable	= disable_8259A_irq,
-	.unmask		= enable_8259A_irq,
-	.mask_ack	= mask_and_ack_8259A,
+	.unmask		= enable_8259A_irq_wrapper,
+	.mask_ack	= mask_and_ack_8259A_wrapper,
 };
 
 /*
@@ -348,9 +367,9 @@ void init_8259A(int auto_eoi)
 		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_chip.mask_ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq_wrapper;
 	else
-		i8259A_chip.mask_ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A_wrapper;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
arch/x86/kernel/uv_irq.c +24 -4
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================
@@ -18,6 +18,16 @@ static void uv_noop(unsigned int irq)
 {
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_noop_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	uv_noop(irq);
+}
+
+#else
+#define uv_noop_wrapper uv_noop
+#endif
+
 static unsigned int uv_noop_ret(unsigned int irq)
 {
 	return 0;
@@ -28,16 +38,26 @@ static void uv_ack_apic(unsigned int irq
 	ack_APIC_irq();
 }
 
+#ifdef CONFIG_SPARSE_IRQ
+static void uv_ack_apic_wrapper(unsigned int irq, struct irq_desc **descp)
+{
+	uv_ack_apic(irq);
+}
+
+#else
+#define uv_ack_apic_wrapper uv_ack_apic
+#endif
+
 struct irq_chip uv_irq_chip = {
 	.name		= "UV-CORE",
 	.startup	= uv_noop_ret,
 	.shutdown	= uv_noop,
 	.enable		= uv_noop,
 	.disable	= uv_noop,
-	.ack		= uv_noop,
-	.mask		= uv_noop,
-	.unmask		= uv_noop,
-	.eoi		= uv_ack_apic,
+	.ack		= uv_noop_wrapper,
+	.mask		= uv_noop_wrapper,
+	.unmask		= uv_noop_wrapper,
+	.eoi		= uv_ack_apic_wrapper,
 	.end		= uv_noop,
 };
 
drivers/pci/msi.c +36 -13

99 lines not on this page · raw message

include/linux/msi.h +8 -0
Index: linux-2.6/include/linux/msi.h
===================================================================
@@ -10,8 +10,16 @@ struct msi_msg {
 };
 
 /* Helper functions */
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+extern void mask_msi_irqx(unsigned int irq, struct irq_desc **descp);
+extern void unmask_msi_irqx(unsigned int irq, struct irq_desc **descp);
+#define mask_msi_irq mask_msi_irqx
+#define unmask_msi_irq unmask_msi_irqx
+#else
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
+#endif
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
arch/x86/include/asm/hpet.h +7 -0
Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================
@@ -72,8 +72,15 @@ extern void hpet_disable(void);
 extern unsigned long hpet_readl(unsigned long a);
 extern void force_hpet_resume(void);
 
+#ifdef CONFIG_SPARSE_IRQ
+extern void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp);
+extern void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp);
+#define hpet_msi_unmask hpet_msi_unmaskx
+#define hpet_msi_mask hpet_msi_maskx
+#else
 extern void hpet_msi_unmask(unsigned int irq);
 extern void hpet_msi_mask(unsigned int irq);
+#endif
 extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
 extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
 
arch/x86/kernel/hpet.c +17 -2
Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================
@@ -347,7 +347,7 @@ static int hpet_legacy_next_event(unsign
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev	*hpet_devs;
 
-void hpet_msi_unmask(unsigned int irq)
+void hpet_msi_unmaskx(unsigned int irq, struct irq_desc **descp)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
 	unsigned long cfg;
@@ -358,7 +358,7 @@ void hpet_msi_unmask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_mask(unsigned int irq)
+void hpet_msi_maskx(unsigned int irq, struct irq_desc **descp)
 {
 	unsigned long cfg;
 	struct hpet_dev *hdev = get_irq_data(irq);
@@ -369,6 +369,21 @@ void hpet_msi_mask(unsigned int irq)
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void hpet_msi_unmask(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_unmaskx(irq, &desc);
+}
+void hpet_msi_mask(unsigned int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	hpet_msi_maskx(irq, &desc);
+}
+#endif
+
 void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
 {
 	struct hpet_dev *hdev = get_irq_data(irq);
include/linux/htirq.h +8 -0
Index: linux-2.6/include/linux/htirq.h
===================================================================
@@ -9,8 +9,16 @@ struct ht_irq_msg {
 /* Helper functions.. */
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
+#ifdef CONFIG_SPARSE_IRQ
+struct irq_desc;
+void mask_ht_irqx(unsigned int irq, struct irq_desc **descp);
+void unmask_ht_irqx(unsigned int irq, struct irq_desc **descp);
+#define mask_ht_irq mask_ht_irqx
+#define unmask_ht_irq unmask_ht_irqx
+#else
 void mask_ht_irq(unsigned int irq);
 void unmask_ht_irq(unsigned int irq);
+#endif
 
 /* The arch hook for getting things started */
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
kernel/irq/migration.c +22 -7
Index: linux-2.6/kernel/irq/migration.c
===================================================================
@@ -1,9 +1,9 @@
 
 #include <linux/irq.h>
 
-void move_masked_irq(int irq)
+void move_masked_irqx(int irq, struct irq_desc **descp)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc = *descp;
 	cpumask_t tmp;
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
@@ -47,9 +47,9 @@ void move_masked_irq(int irq)
 	cpus_clear(desc->pending_mask);
 }
 
-void move_native_irq(int irq)
+void move_native_irqx(int irq, struct irq_desc **descp)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc = *descp;
 
 	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
 		return;
@@ -57,8 +57,23 @@ void move_native_irq(int irq)
 	if (unlikely(desc->status & IRQ_DISABLED))
 		return;
 
-	desc->chip->mask(irq);
-	move_masked_irq(irq);
-	desc->chip->unmask(irq);
+	desc_chip_mask(irq, descp);
+	move_masked_irqx(irq, descp);
+	desc_chip_unmask(irq, descp);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
+void move_masked_irq(int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	move_masked_irqx(irq, &desc);
+}
+
+void move_native_irq(int irq)
+{
+	struct irq_desc *desc = irq_to_desc(irq);
+
+	move_native_irqx(irq, &desc);
+}
+#endif
drivers/pci/intel-iommu.c +17 -2
Index: linux-2.6/drivers/pci/intel-iommu.c
===================================================================
@@ -751,7 +751,7 @@ const char *dmar_get_fault_reason(u8 fau
 		return fault_reason_strings[fault_reason];
 }
 
-void dmar_msi_unmask(unsigned int irq)
+void dmar_msi_unmaskx(unsigned int irq, struct irq_desc **descp)
 {
 	struct intel_iommu *iommu = get_irq_data(irq);
 	unsigned long flag;
@@ -764,7 +764,7 @@ void dmar_msi_unmask(unsigned int irq)
 	spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
-void dmar_msi_mask(unsigned int irq)
+void dmar_msi_maskx(unsigned int irq, struct irq_desc **descp)
 {
 	unsigned long flag;
 	struct intel_iommu *iommu = get_irq_data(irq);
@@ -777,6 +777,21 @@ void dmar_msi_mask(unsigned int irq)
 	spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
+#ifndef CONFIG_SPARSE_IRQ
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

include/linux/dmar.h +7 -0
Index: linux-2.6/include/linux/dmar.h
===================================================================

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#32 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 2 lines · On Thu, 13 Nov 2008 12:16:56 -0800 Yinghai Lu <[email protected]> wrote:

From: Yinghai Lu <[email protected]>
Subject: sparseirq v13

My overall view on this is that it takes some of the kernel's most fragile and most problem-dense code and makes it much more complex, and by adding new configuration options it significantly worsens our testing coverage.

The patch is HHHHHUUUUUUUUUUGGGGGEEE! Did it really need to be a single megapatch?

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

I don't have a clue what all this does. I hope those who will work on this code are sufficiently familiar with it all to be able to maintain it when there are close to zero comments in some of our most tricky and problem-prone code.

Quoted 12 lines

...

arch/x86/Kconfig +9 -0
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+

arch/x86/Kconfig config X86_HAS_BOOT_CPU_ID · line 261

Quoted 10 lines
arch/x86/Kconfig +10 -0
+	  If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+	bool "Move irq desc when changing irq smp_affinity"
+	depends on SPARSE_IRQ && SMP
+	default y
+	help
+	  This enables moving irq_desc to cpu/node that irq will use handled.
+
+	  If you don't know what to do here, say Y.

Do these reeeealy have to exist? How are users to know which to choose? Which option will distros choose and why did we make them have to decide?

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 133

Quoted 12 lines

...

arch/x86/kernel/io_apic.c +9 -0
+{
+	struct irq_pin_list *pin;
+	int node;
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	pin = kzalloc_node(sizeof(*pin), GFP_KERNEL, node);

It's a bug to call smp_processor_id() from preemptible code and it's a bug to use GFP_KERNEL in non-preemptible code. How can this be?

Quoted 10 lines
arch/x86/kernel/io_apic.c +5 -1
+	printk(KERN_DEBUG "  alloc irq_2_pin on cpu %d node %d\n", cpu, node);
+
+	return pin;
+}
 
 
...
 
-static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
+static struct irq_cfg *get_one_free_irq_cfg(int cpu)

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 220

Quoted 10 lines
arch/x86/kernel/io_apic.c +8 -1
 {
-	return irq_cfg(irq);
+	struct irq_cfg *cfg;
+	int node;
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);

See above.

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 224

Quoted 4 lines
arch/x86/kernel/io_apic.c +3 -0
+	printk(KERN_DEBUG "  alloc irq_cfg on cpu %d node %d\n", cpu, node);
+
+	return cfg;
 }

So all callers of this function must test the return value and if it is NULL, take appropriate action.

That is something which should have been documented in this function's interface description. Only that doesn't exist.

The one caller which I checked (arch_init_copy_chip_data()) fails to check for this and will oops.

Quoted 5 lines

...

arch/x86/kernel/io_apic.c +2 -0
+static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
+{

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 324

Quoted 10 lines
arch/x86/kernel/io_apic.c +10 -0
+	struct irq_cfg *cfg = desc->chip_data;
+
+	if (!cfg->move_in_progress) {
+		/* it means that domain is not changed */
+		cpumask_t tmp;
+
+		cpus_and(tmp, desc->affinity, mask);
+		if (cpus_empty(tmp))
+			cfg->move_desc_in_progress_in_same_domain = 1;
+	}

Aren't we trying to avoid on-stack cpumask_t's?

I'd have though that this one could be eliminated via the use of cpus_intersects()?

arch/x86/kernel/io_apic.c int timer_through_8259 __initdata; · line 2835

Quoted 11 lines

}

arch/x86/kernel/io_apic.c +1 -0
+#endif
 
...
 
 static struct irq_chip lapic_chip __read_mostly = {
 	.name		= "local-APIC",
 	.mask		= mask_lapic_irq,
@@ -2574,7 +2834,9 @@ int timer_through_8259 __initdata;
  */
 static inline void __init check_timer(void)

An inlined __init function makes little sense.

Review static void dmar_msi_set_affinity(unsign · line 3591

Quoted 6 lines

...

(quoted diff) +0 -0
@@ -3306,10 +3590,13 @@ static void dmar_msi_set_affinity(unsign
 	if (cpus_empty(tmp))
 		return;

`tmp' is always a bad choice of identifier.

arch/x86/mm/init_32.c static unsigned long __meminitdata table · line 69

Quoted 10 lines

...

arch/x86/mm/init_32.c +1 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;

This isn't a very well-chosen identifier for an x86-specific global.

Quoted 12 lines

...

arch/x86/mm/init_32.c +1 -0
@@ -98,6 +126,7 @@ int __ht_create_irq(struct pci_dev *dev,
 	int max_irq;
 	int pos;
 	int irq;
+	unsigned int irq_want;
 
 	pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
 	if (!pos)

arch/x86/mm/init_32.c int __ht_create_irq(struct pci_dev *dev, · line 162

Quoted 9 lines
arch/x86/mm/init_32.c +5 -0
@@ -125,7 +154,12 @@ int __ht_create_irq(struct pci_dev *dev,
 	cfg->msg.address_lo = 0xffffffff;
 	cfg->msg.address_hi = 0xffffffff;
 
+	irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+	irq = create_irq_nr(irq_want + idx);
+#else
 	irq = create_irq();
+#endif

irq_want is unused if CONFIG_SPARSE_IRQ=n.

Quoted 12 lines
arch/x86/mm/init_32.c +0 -0
 	if (irq <= 0) {
 		kfree(cfg);

Index: linux-2.6/drivers/pci/intr_remapping.c
===================================================================

drivers/pci/intr_remapping.c +1 -1
@@ -19,17 +19,73 @@ struct irq_2_iommu {
 	u8  irte_mask;
 };
 
-static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
+#ifdef CONFIG_SPARSE_IRQ

drivers/pci/intr_remapping.c struct irq_2_iommu { · line 32

Quoted 10 lines
drivers/pci/intr_remapping.c +10 -0
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+{
+	struct irq_2_iommu *iommu;
+	int node;
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	iommu = kzalloc_node(sizeof(*iommu), GFP_KERNEL, node);

See above.

Quoted 21 lines
drivers/pci/intr_remapping.c +4 -0
+	printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+
+	return iommu;
+}
 
 
...
fs/proc/stat.c +3 -0
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;

fs/proc/stat.c static int show_stat(struct seq_file *p, · line 50

Quoted 6 lines
fs/proc/stat.c +1 -2
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {

This won't compile if CONFIG_GENERIC_HARDIRQS=n, I suspect.

fs/proc/stat.c static int show_stat(struct seq_file *p, · line 95

Quoted 12 lines
fs/proc/stat.c +2 -2
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {

ditto.

fs/proc/stat.c

Quoted 11 lines

...

fs/proc/stat.c +8 -0
+#define end_for_each_irq_desc()
+#endif
+
+#define desc_chip_ack(irq, descp) desc->chip->ack(irq)
+#define desc_chip_mask(irq, descp) desc->chip->mask(irq)
+#define desc_chip_mask_ack(irq, descp) desc->chip->mask_ack(irq)
+#define desc_chip_unmask(irq, descp) desc->chip->unmask(irq)
+#define desc_chip_eoi(irq, descp) desc->chip->eoi(irq)

Was it necessary to implement these as macros?

Quoted 4 lines

...

fs/proc/stat.c void handle_bad_irq(unsigned int irq, st · line 65

Quoted 10 lines
fs/proc/stat.c +7 -0
@@ -49,6 +56,299 @@ void handle_bad_irq(unsigned int irq, st
 int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+static struct irq_desc irq_desc_init = {
+	.irq	    = -1U,

Plain old `-1' would be better here. It works in all cases and the reader doesn't need to go and check that this field really is an unsigned int and it won't need editing if that field gets changed to long.

Quoted 14 lines
fs/proc/stat.c +14 -0
+	.status	    = IRQ_DISABLED,
+	.chip	    = &no_irq_chip,
+	.handle_irq = handle_bad_irq,
+	.depth      = 1,
+	.lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+	.affinity   = CPU_MASK_ALL
+#endif
+};
+
+static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
+{
+	unsigned long bytes;
+	char *ptr;

fs/proc/stat.c void handle_bad_irq(unsigned int irq, st · line 89

Quoted 10 lines
fs/proc/stat.c +10 -0
+	int node;
+
+	/* Compute how many bytes we need per irq and allocate them */
+	bytes = nr * sizeof(unsigned int);
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+
+	node = cpu_to_node(cpu);
+	ptr = kzalloc_node(bytes, GFP_KERNEL, node);

See above.

Quoted 4 lines
fs/proc/stat.c +4 -0
+	printk(KERN_DEBUG "  alloc kstat_irqs on cpu %d node %d\n", cpu, node);
+
+	desc->kstat_irqs = (unsigned int *)ptr;
+}

fs/proc/stat.c void handle_bad_irq(unsigned int irq, st

Quoted 10 lines
fs/proc/stat.c +7 -0
+
 
...
 
+#endif
+/*
+ * Protect the sparse_irqs_free freelist:
+ */
+static DEFINE_SPINLOCK(sparse_irq_lock);
+LIST_HEAD(sparse_irqs_head);

It's strange that the list is global and is accessed from other .c files, but the lock which protects it is static.

fs/proc/stat.c

Quoted 7 lines
fs/proc/stat.c +7 -0
+/*
+ * The sparse irqs are in a hash-table as well, for fast lookup:
+ */
+#define SPARSEIRQHASH_BITS          (13 - 1)
+#define SPARSEIRQHASH_SIZE          (1UL << SPARSEIRQHASH_BITS)
+#define __sparseirqhashfn(key)      hash_long((unsigned long)key, SPARSEIRQHASH_BITS)
+#define sparseirqhashentry(key)     (sparseirqhash_table + __sparseirqhashfn((key)))

Why implement these via macros?

Quoted 8 lines
fs/proc/stat.c +8 -0
+static struct list_head sparseirqhash_table[SPARSEIRQHASH_SIZE];
+
+static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
+	[0 ... NR_IRQS_LEGACY-1] = {
+		.irq	    = -1U,
+		.status	    = IRQ_DISABLED,
+		.chip	    = &no_irq_chip,
+		.handle_irq = handle_bad_irq,

fs/proc/stat.c

Quoted 10 lines
fs/proc/stat.c +10 -0
+		.depth	    = 1,
+		.lock	    = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+		.affinity   = CPU_MASK_ALL
+#endif
+	}
+};
+
+/* FIXME: use bootmem alloc ...*/
+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

Quoted 1 line

+void __init early_irq_init_work(void)

The use of "_work" implies that this function is invoked by schedule_work(). But it isn't.

Quoted 46 lines
fs/proc/stat.c +43 -0
+{
+	struct irq_desc *desc;
+	int legacy_count;
+	int i;
+
+	/* init_work to init list for sparseirq */
+	for (i = 0; i < SPARSEIRQHASH_SIZE; i++)
+		INIT_LIST_HEAD(sparseirqhash_table + i);
+
+	desc = irq_desc_legacy;
+	legacy_count = ARRAY_SIZE(irq_desc_legacy);
+
+	for (i = 0; i < legacy_count; i++) {
+		struct list_head *hash_head;
+
+		hash_head = sparseirqhashentry(i);
+		desc[i].irq = i;
+		desc[i].kstat_irqs = kstat_irqs_legacy[i];
+		list_add_tail(&desc[i].hash_entry, hash_head);
+		list_add_tail(&desc[i].list, &sparse_irqs_head);
+	}
+
+	arch_early_irq_init_work();
+}
+
 
...
 
+struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+	struct irq_desc *desc;
+	struct list_head *hash_head;
+	unsigned long flags;
+	int node;
+
+	desc = irq_to_desc(irq);
+	if (desc)
+		return desc;
+
+	hash_head = sparseirqhashentry(irq);
+
+	spin_lock_irqsave(&sparse_irq_lock, flags);
+
+	/*
+	 * We have to do the hash-walk again, to avoid races
+	 * with another CPU:

fs/proc/stat.c

Quoted 10 lines
fs/proc/stat.c +10 -0
+	 */
+	list_for_each_entry(desc, hash_head, hash_entry)
+		if (desc->irq == irq)
+			goto out_unlock;
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+
+	node = cpu_to_node(cpu);
+	desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Oh for gawd's sake. PLEASE read Documentation/SubmitChecklist. Carefully. We've already discussed this.

You cannot do a GFP_KERNEL allocation under spin_lock_irqsave().

Quoted 43 lines
fs/proc/stat.c +43 -0
+	printk(KERN_DEBUG "  alloc irq_desc for %d aka %#x on cpu %d node %d\n",
+		 irq, irq, cpu, node);
+	init_one_irq_desc(irq, desc, cpu);
+
+	/*
+	 * We use RCU's safe list-add method to make
+	 * parallel walking of the hash-list safe:
+	 */
+	list_add_tail_rcu(&desc->hash_entry, hash_head);
+	/*
+	 * Add it to the global list:
+	 */
+	list_add_tail_rcu(&desc->list, &sparse_irqs_head);
+
+out_unlock:
+	spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+	return desc;
+}
+
+struct irq_desc *irq_to_desc_alloc(unsigned int irq)
+{
+	return irq_to_desc_alloc_cpu(irq, -1);
+}
+
+#ifdef CONFIG_MOVE_IRQ_DESC
+static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
+						int cpu)
+{
+	struct irq_desc *desc;
+	unsigned int irq;
+	struct list_head *hash_head;
+	unsigned long flags;
+	int node;
+
+	irq = old_desc->irq;
+
+	hash_head = sparseirqhashentry(irq);
+
+	spin_lock_irqsave(&sparse_irq_lock, flags);
+	/*
+	 * We have to do the hash-walk again, to avoid races
+	 * with another CPU:

fs/proc/stat.c

Quoted 10 lines
fs/proc/stat.c +10 -0
+	 */
+	list_for_each_entry(desc, hash_head, hash_entry)
+		if (desc->irq == irq && old_desc != desc)
+			goto out_unlock;
+
+	if (cpu < 0)
+		cpu = smp_processor_id();
+
+	node = cpu_to_node(cpu);
+	desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Ditto.

Also, the return value from the memory allocation attempt is not checked.

Quoted 25 lines
fs/proc/stat.c +18 -0
+	printk(KERN_DEBUG "  move irq_desc for %d aka %#x to cpu %d node %d\n",
+		 irq, irq, cpu, node);
+
+	init_copy_one_irq_desc(irq, old_desc, desc, cpu);
+
+	list_replace_rcu(&old_desc->hash_entry, &desc->hash_entry);
+	list_replace_rcu(&old_desc->list, &desc->list);
+
+	/* free the old one */
+	free_one_irq_desc(old_desc);
+	kfree(old_desc);
+
+out_unlock:
+	spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+	return desc;
+}
+
 
...
init/main.c +0 -0
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini
 {

init/main.c void __init __weak thread_info_cache_ini · line 552

Quoted 10 lines
init/main.c +8 -0
 }
 
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+void __init __attribute__((weak)) early_irq_init_work(void)
+{
+	arch_early_irq_init_work();
+}

Please use __weak

Quoted 3 lines

...

#33 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 2 lines · Andrew Morton

The patch is HHHHHUUUUUUUUUUGGGGGEEE! Did it really need to be a single megapatch?

i asked Yinghai to do that for now, instead of sending a 50-patch series 10 times over - so that we can see the overall structure.

Ingo

author
#34 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Andrew Morton
Quoted 40 lines · Andrew Morton
Quoted 2 lines · On Thu, 13 Nov 2008 12:16:56 -0800 Yinghai Lu <[email protected]> wrote:

From: Yinghai Lu <[email protected]>
Subject: sparseirq v13

My overall view on this is that it takes some of the kernel's most fragile and most problem-dense code and makes it much more complex, and by adding new configuration options it significantly worsens our testing coverage.

The patch is HHHHHUUUUUUUUUUGGGGGEEE! Did it really need to be a single megapatch?

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

I don't have a clue what all this does. I hope those who will work on this code are sufficiently familiar with it all to be able to maintain it when there are close to zero comments in some of our most tricky and problem-prone code.

Quoted 18 lines

...

arch/x86/Kconfig +15 -0
+config SPARSE_IRQ
+     bool "Support sparse irq numbering"
+     depends on PCI_MSI || HT_IRQ
+     default y
+     help
+       This enables support for sparse irq, esp for msi/msi-x. the irq
+       number will be bus/dev/fn + 12bit. You may need if you have lots of
+       cards supports msi-x installed.
+
+       If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+     bool "Move irq desc when changing irq smp_affinity"
+     depends on SPARSE_IRQ && SMP
+     default y
Quoted 8 lines

arch/x86/Kconfig config X86_HAS_BOOT_CPU_ID · line 261

Quoted 4 lines
arch/x86/Kconfig +4 -0
+     help
+       This enables moving irq_desc to cpu/node that irq will use handled.
+
+       If you don't know what to do here, say Y.

Do these reeeealy have to exist? How are users to know which to choose? Which option will distros choose and why did we make them have to decide?

want to use that as marker, so later could split the patch to small ones by enabling by steps.

Quoted 4 lines
Quoted 4 lines

...

Quoted 12 lines

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 133

Quoted 9 lines
arch/x86/kernel/io_apic.c +9 -0
+{
+     struct irq_pin_list *pin;
+     int node;
+
+     if (cpu < 0)
+             cpu = smp_processor_id();
+     node = cpu_to_node(cpu);
+
+     pin = kzalloc_node(sizeof(*pin), GFP_KERNEL, node);

It's a bug to call smp_processor_id() from preemptible code and it's a bug to use GFP_KERNEL in non-preemptible code. How can this be?

the could should be executed in boot stage, only bsp is running, or interrupt conext
via irq_complete_move

Quoted 29 lines
Quoted 11 lines
arch/x86/kernel/io_apic.c +5 -1
+     printk(KERN_DEBUG "  alloc irq_2_pin on cpu %d node %d\n", cpu, node);
+
+     return pin;
+}
 
 
...
 
-static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
+static struct irq_cfg *get_one_free_irq_cfg(int cpu)

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 220

Quoted 10 lines
arch/x86/kernel/io_apic.c +8 -1
 {
-     return irq_cfg(irq);
+     struct irq_cfg *cfg;
+     int node;
+
+     if (cpu < 0)
+             cpu = smp_processor_id();
+     node = cpu_to_node(cpu);
+
+     cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);

See above.

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 224

Quoted 4 lines
arch/x86/kernel/io_apic.c +3 -0
+     printk(KERN_DEBUG "  alloc irq_cfg on cpu %d node %d\n", cpu, node);
+
+     return cfg;
 }
Quoted 8 lines

So all callers of this function must test the return value and if it is NULL, take appropriate action.

That is something which should have been documented in this function's interface description. Only that doesn't exist.

The one caller which I checked (arch_init_copy_chip_data()) fails to check for this and will oops.

will add one function to wrap it.

Quoted 19 lines
Quoted 6 lines

...

arch/x86/kernel/io_apic.c +2 -0
+static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
+{

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 324

Quoted 10 lines
arch/x86/kernel/io_apic.c +10 -0
+     struct irq_cfg *cfg = desc->chip_data;
+
+     if (!cfg->move_in_progress) {
+             /* it means that domain is not changed */
+             cpumask_t tmp;
+
+             cpus_and(tmp, desc->affinity, mask);
+             if (cpus_empty(tmp))
+                     cfg->move_desc_in_progress_in_same_domain = 1;
+     }

Aren't we trying to avoid on-stack cpumask_t's?

Quoted 2 lines

I'd have though that this one could be eliminated via the use of cpus_intersects()?

will change to that.

there some other in __assign_irq_vector...

Quoted 6 lines
Quoted 6 lines

}
+#endif

...

Quoted 8 lines

arch/x86/kernel/io_apic.c int timer_through_8259 __initdata; · line 2835

Quoted 6 lines

static struct irq_chip lapic_chip __read_mostly = {
.name = "local-APIC",
.mask = mask_lapic_irq,

arch/x86/kernel/io_apic.c +0 -0
@@ -2574,7 +2834,9 @@ int timer_through_8259 __initdata;
  */
 static inline void __init check_timer(void)

An inlined __init function makes little sense.

should be done other patch...?

Quoted 9 lines

Review static void dmar_msi_set_affinity(unsign · line 3591

Quoted 7 lines

...

(quoted diff) +0 -0
@@ -3306,10 +3590,13 @@ static void dmar_msi_set_affinity(unsign
      if (cpus_empty(tmp))
              return;

`tmp' is always a bad choice of identifier.

other patch?

Quoted 9 lines
Quoted 9 lines

...

arch/x86/mm/init_32.c +0 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
Quoted 4 lines

arch/x86/mm/init_32.c static unsigned long __meminitdata table · line 69

Quoted 2 lines
arch/x86/mm/init_32.c +1 -0
 static int __initdata after_init_bootmem;
+int after_bootmem;

This isn't a very well-chosen identifier for an x86-specific global.

it is not used, will remove that.

Quoted 68 lines
Quoted 13 lines

...

arch/x86/mm/init_32.c +1 -0
@@ -98,6 +126,7 @@ int __ht_create_irq(struct pci_dev *dev,
      int max_irq;
      int pos;
      int irq;
+     unsigned int irq_want;
 
      pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
      if (!pos)

arch/x86/mm/init_32.c int __ht_create_irq(struct pci_dev *dev, · line 162

Quoted 9 lines
arch/x86/mm/init_32.c +5 -0
@@ -125,7 +154,12 @@ int __ht_create_irq(struct pci_dev *dev,
      cfg->msg.address_lo = 0xffffffff;
      cfg->msg.address_hi = 0xffffffff;
 
+     irq_want = build_irq_for_pci_dev(dev);
+#ifdef CONFIG_SPARSE_IRQ
+     irq = create_irq_nr(irq_want + idx);
+#else
      irq = create_irq();
+#endif

irq_want is unused if CONFIG_SPARSE_IRQ=n.

Quoted 12 lines
arch/x86/mm/init_32.c +0 -0
      if (irq <= 0) {
              kfree(cfg);

Index: linux-2.6/drivers/pci/intr_remapping.c
===================================================================

drivers/pci/intr_remapping.c +1 -1
@@ -19,17 +19,73 @@ struct irq_2_iommu {
      u8  irte_mask;
 };
 
-static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
+#ifdef CONFIG_SPARSE_IRQ

drivers/pci/intr_remapping.c struct irq_2_iommu { · line 32

Quoted 10 lines
drivers/pci/intr_remapping.c +10 -0
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+{
+     struct irq_2_iommu *iommu;
+     int node;
+
+     if (cpu < 0)
+             cpu = smp_processor_id();
+     node = cpu_to_node(cpu);
+
+     iommu = kzalloc_node(sizeof(*iommu), GFP_KERNEL, node);

See above.

Quoted 18 lines
drivers/pci/intr_remapping.c +4 -0
+     printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+
+     return iommu;
+}
 
 
...
fs/proc/stat.c +3 -0
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
      u64 sum = 0;
      struct timespec boottime;
      unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+     struct irq_desc *desc;
+#endif
 
Quoted 12 lines

fs/proc/stat.c static int show_stat(struct seq_file *p, · line 50

Quoted 9 lines
fs/proc/stat.c +1 -2
      user = nice = system = idle = iowait =
              irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
              softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
              steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
              guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-             for_each_irq_nr(j)
+             for_each_irq_desc(j, desc) {

This won't compile if CONFIG_GENERIC_HARDIRQS=n, I suspect.

we have

#ifndef CONFIG_GENERIC_HARDIRQS
#include <asm/irq.h>

# define nr_irqs                NR_IRQS
# define for_each_irq_desc(irq, desc)           \
        for (irq = 0; irq < nr_irqs; irq++)
# define end_for_each_irq_desc()
Quoted 18 lines

fs/proc/stat.c static int show_stat(struct seq_file *p, · line 95

Quoted 12 lines
fs/proc/stat.c +2 -2
                      sum += kstat_irqs_cpu(j, i);
-
+             } end_for_each_irq_desc();
              sum += arch_irq_stat_cpu(i);
      }
      sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
      seq_printf(p, "intr %llu", (unsigned long long)sum);
 
      /* sum again ? it could be updated? */
-     for_each_irq_nr(j) {
+     for_each_irq_desc(j, desc) {

ditto.

Quoted 3 lines

...

Quoted 10 lines

fs/proc/stat.c

Quoted 8 lines
fs/proc/stat.c +8 -0
+#define end_for_each_irq_desc()
+#endif
+
+#define desc_chip_ack(irq, descp) desc->chip->ack(irq)
+#define desc_chip_mask(irq, descp) desc->chip->mask(irq)
+#define desc_chip_mask_ack(irq, descp) desc->chip->mask_ack(irq)
+#define desc_chip_unmask(irq, descp) desc->chip->unmask(irq)
+#define desc_chip_eoi(irq, descp) desc->chip->eoi(irq)

Was it necessary to implement these as macros?

try to avoid bunch of #idef with different parameters that need to be passed.

Quoted 8 lines
Quoted 8 lines

...

fs/proc/stat.c +0 -0
@@ -49,6 +56,299 @@ void handle_bad_irq(unsigned int irq, st
 int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
Quoted 12 lines

fs/proc/stat.c void handle_bad_irq(unsigned int irq, st · line 65

Quoted 7 lines
fs/proc/stat.c +7 -0
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+static struct irq_desc irq_desc_init = {
+     .irq        = -1U,

Plain old `-1' would be better here. It works in all cases and the reader doesn't need to go and check that this field really is an unsigned int and it won't need editing if that field gets changed to long

.
ok.

Quoted 36 lines
Quoted 15 lines
fs/proc/stat.c +14 -0
+     .status     = IRQ_DISABLED,
+     .chip       = &no_irq_chip,
+     .handle_irq = handle_bad_irq,
+     .depth      = 1,
+     .lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+     .affinity   = CPU_MASK_ALL
+#endif
+};
+
+static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
+{
+     unsigned long bytes;
+     char *ptr;

fs/proc/stat.c void handle_bad_irq(unsigned int irq, st · line 89

Quoted 10 lines
fs/proc/stat.c +10 -0
+     int node;
+
+     /* Compute how many bytes we need per irq and allocate them */
+     bytes = nr * sizeof(unsigned int);
+
+     if (cpu < 0)
+             cpu = smp_processor_id();
+
+     node = cpu_to_node(cpu);
+     ptr = kzalloc_node(bytes, GFP_KERNEL, node);

See above.

Quoted 8 lines
fs/proc/stat.c +5 -0
+     printk(KERN_DEBUG "  alloc kstat_irqs on cpu %d node %d\n", cpu, node);
+
+     desc->kstat_irqs = (unsigned int *)ptr;
+}
+
 
...
Quoted 9 lines

fs/proc/stat.c

Quoted 6 lines
fs/proc/stat.c +6 -0
+#endif
+/*
+ * Protect the sparse_irqs_free freelist:
+ */
+static DEFINE_SPINLOCK(sparse_irq_lock);
+LIST_HEAD(sparse_irqs_head);

It's strange that the list is global and is accessed from other .c files, but the lock which protects it is static

.
only protect that when try to append the list. with rcu add tail.

Quoted 10 lines

fs/proc/stat.c

Quoted 8 lines
fs/proc/stat.c +7 -0
+/*
+ * The sparse irqs are in a hash-table as well, for fast lookup:
+ */
+#define SPARSEIRQHASH_BITS          (13 - 1)
+#define SPARSEIRQHASH_SIZE          (1UL << SPARSEIRQHASH_BITS)
+#define __sparseirqhashfn(key)      hash_long((unsigned long)key, SPARSEIRQHASH_BITS)
+#define sparseirqhashentry(key)     (sparseirqhash_table + __sparseirqhashfn((key)))

Why implement these via macros?

copied from sched.c

Quoted 13 lines
Quoted 13 lines
fs/proc/stat.c +12 -0
+static struct list_head sparseirqhash_table[SPARSEIRQHASH_SIZE];
+
+static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
+     [0 ... NR_IRQS_LEGACY-1] = {
+             .irq        = -1U,
+             .status     = IRQ_DISABLED,
+             .chip       = &no_irq_chip,
+             .handle_irq = handle_bad_irq,
+             .depth      = 1,
+             .lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+             .affinity   = CPU_MASK_ALL
Quoted 9 lines

fs/proc/stat.c

Quoted 6 lines
fs/proc/stat.c +6 -0
+#endif
+     }
+};
+
+/* FIXME: use bootmem alloc ...*/
+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

struct irq_desc {
        unsigned int            irq;
#ifdef CONFIG_SPARSE_IRQ
        struct list_head        list;
        struct list_head        hash_entry;
        struct timer_rand_state *timer_rand_state;
        unsigned int            *kstat_irqs;
Quoted 4 lines
Quoted 1 line

+void __init early_irq_init_work(void)

The use of "_work" implies that this function is invoked by schedule_work(). But it isn't

ok, will remove it.

Quoted 52 lines
Quoted 52 lines
fs/proc/stat.c +48 -0
+{
+     struct irq_desc *desc;
+     int legacy_count;
+     int i;
+
+     /* init_work to init list for sparseirq */
+     for (i = 0; i < SPARSEIRQHASH_SIZE; i++)
+             INIT_LIST_HEAD(sparseirqhash_table + i);
+
+     desc = irq_desc_legacy;
+     legacy_count = ARRAY_SIZE(irq_desc_legacy);
+
+     for (i = 0; i < legacy_count; i++) {
+             struct list_head *hash_head;
+
+             hash_head = sparseirqhashentry(i);
+             desc[i].irq = i;
+             desc[i].kstat_irqs = kstat_irqs_legacy[i];
+             list_add_tail(&desc[i].hash_entry, hash_head);
+             list_add_tail(&desc[i].list, &sparse_irqs_head);
+     }
+
+     arch_early_irq_init_work();
+}
+
 
...
 
+struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+     struct irq_desc *desc;
+     struct list_head *hash_head;
+     unsigned long flags;
+     int node;
+
+     desc = irq_to_desc(irq);
+     if (desc)
+             return desc;
+
+     hash_head = sparseirqhashentry(irq);
+
+     spin_lock_irqsave(&sparse_irq_lock, flags);
+
+     /*
+      * We have to do the hash-walk again, to avoid races
+      * with another CPU:
+      */
+     list_for_each_entry(desc, hash_head, hash_entry)
+             if (desc->irq == irq)
+                     goto out_unlock;
+
Quoted 8 lines

fs/proc/stat.c

Quoted 5 lines
fs/proc/stat.c +5 -0
+     if (cpu < 0)
+             cpu = smp_processor_id();
+
+     node = cpu_to_node(cpu);
+     desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Oh for gawd's sake. PLEASE read Documentation/SubmitChecklist. Carefully. We've already discussed this.

there are 13 errors with checkpatch scripts. seems all about macro definition.

Quoted 89 lines

You cannot do a GFP_KERNEL allocation under spin_lock_irqsave().

Quoted 43 lines
fs/proc/stat.c +43 -0
+     printk(KERN_DEBUG "  alloc irq_desc for %d aka %#x on cpu %d node %d\n",
+              irq, irq, cpu, node);
+     init_one_irq_desc(irq, desc, cpu);
+
+     /*
+      * We use RCU's safe list-add method to make
+      * parallel walking of the hash-list safe:
+      */
+     list_add_tail_rcu(&desc->hash_entry, hash_head);
+     /*
+      * Add it to the global list:
+      */
+     list_add_tail_rcu(&desc->list, &sparse_irqs_head);
+
+out_unlock:
+     spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+     return desc;
+}
+
+struct irq_desc *irq_to_desc_alloc(unsigned int irq)
+{
+     return irq_to_desc_alloc_cpu(irq, -1);
+}
+
+#ifdef CONFIG_MOVE_IRQ_DESC
+static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
+                                             int cpu)
+{
+     struct irq_desc *desc;
+     unsigned int irq;
+     struct list_head *hash_head;
+     unsigned long flags;
+     int node;
+
+     irq = old_desc->irq;
+
+     hash_head = sparseirqhashentry(irq);
+
+     spin_lock_irqsave(&sparse_irq_lock, flags);
+     /*
+      * We have to do the hash-walk again, to avoid races
+      * with another CPU:

fs/proc/stat.c

Quoted 10 lines
fs/proc/stat.c +10 -0
+      */
+     list_for_each_entry(desc, hash_head, hash_entry)
+             if (desc->irq == irq && old_desc != desc)
+                     goto out_unlock;
+
+     if (cpu < 0)
+             cpu = smp_processor_id();
+
+     node = cpu_to_node(cpu);
+     desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Ditto.

Also, the return value from the memory allocation attempt is not checked.

Quoted 27 lines
fs/proc/stat.c +18 -0
+     printk(KERN_DEBUG "  move irq_desc for %d aka %#x to cpu %d node %d\n",
+              irq, irq, cpu, node);
+
+     init_copy_one_irq_desc(irq, old_desc, desc, cpu);
+
+     list_replace_rcu(&old_desc->hash_entry, &desc->hash_entry);
+     list_replace_rcu(&old_desc->list, &desc->list);
+
+     /* free the old one */
+     free_one_irq_desc(old_desc);
+     kfree(old_desc);
+
+out_unlock:
+     spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+     return desc;
+}
+
 
...
init/main.c +0 -0
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini
 {
 }
 
Quoted 10 lines

init/main.c void __init __weak thread_info_cache_ini · line 552

Quoted 8 lines
init/main.c +8 -0
+void __init __attribute__((weak)) arch_early_irq_init_work(void)
+{
+}
+
+void __init __attribute__((weak)) early_irq_init_work(void)
+{
+     arch_early_irq_init_work();
+}

Please use __weak

ok

thanks for reviewing.

YH

#35 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 7 lines · Yinghai Lu
Quoted 7 lines

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 248

Quoted 7 lines
kernel/irq/handle.c +7 -0
+     /*
+      * We have to do the hash-walk again, to avoid races
+      * with another CPU:
+      */
+     list_for_each_entry(desc, hash_head, hash_entry)
+             if (desc->irq == irq)
+                     goto out_unlock;

should be:

Quoted 4 lines
Quoted 4 lines

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 273

Quoted 4 lines
kernel/irq/handle.c +4 -0
+     list_for_each_entry(desc, hash_head, hash_entry) {
+             if (desc->irq == irq)
+                     goto out_unlock;
+     }

and:

Quoted 6 lines
Quoted 6 lines
Quoted 1 line

+ desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Oh for gawd's sake. PLEASE read Documentation/SubmitChecklist. Carefully. We've already discussed this.

You cannot do a GFP_KERNEL allocation under spin_lock_irqsave().

yes.

Ingo

#36 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Yinghai Lu
Quoted 32 lines · On Thu, 13 Nov 2008 14:01:06 -0800 "Yinghai Lu" <[email protected]> wrote:
Quoted 22 lines · Andrew Morton
Quoted 2 lines · On Thu, 13 Nov 2008 12:16:56 -0800 Yinghai Lu <[email protected]> wrote:

From: Yinghai Lu <[email protected]>
Subject: sparseirq v13

My overall view on this is that it takes some of the kernel's most fragile and most problem-dense code and makes it much more complex, and by adding new configuration options it significantly worsens our testing coverage.

The patch is HHHHHUUUUUUUUUUGGGGGEEE! Did it really need to be a single megapatch?

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

I don't have a clue what all this does. I hope those who will work on this code are sufficiently familiar with it all to be able to maintain it when there are close to zero comments in some of our most tricky and problem-prone code.

...

Quoted 4 lines
Quoted 1 line

+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

Quoted 7 lines
struct irq_desc {
        unsigned int            irq;
#ifdef CONFIG_SPARSE_IRQ
        struct list_head        list;
        struct list_head        hash_entry;
        struct timer_rand_state *timer_rand_state;
        unsigned int            *kstat_irqs;

That doesn't address my question.

The above array can be very large. Can we halve its size by using 16-bit quantities? Will this code ever encounter IRQ numbers larger than 65536?

Quoted 31 lines
Quoted 23 lines
Quoted 23 lines
kernel/irq/handle.c +23 -0
+struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+     struct irq_desc *desc;
+     struct list_head *hash_head;
+     unsigned long flags;
+     int node;
+
+     desc = irq_to_desc(irq);
+     if (desc)
+             return desc;
+
+     hash_head = sparseirqhashentry(irq);
+
+     spin_lock_irqsave(&sparse_irq_lock, flags);
+
+     /*
+      * We have to do the hash-walk again, to avoid races
+      * with another CPU:
+      */
+     list_for_each_entry(desc, hash_head, hash_entry)
+             if (desc->irq == irq)
+                     goto out_unlock;
+
Quoted 8 lines

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 254

Quoted 5 lines
kernel/irq/handle.c +5 -0
+     if (cpu < 0)
+             cpu = smp_processor_id();
+
+     node = cpu_to_node(cpu);
+     desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);

Oh for gawd's sake. PLEASE read Documentation/SubmitChecklist. Carefully. We've already discussed this.

Quoted 1 line

there are 13 errors with checkpatch scripts. seems all about macro definition.

This has nothing to do with checkpatch. Documentation/SubmitChecklist covers much more than that. In particular it descripbes various steps which should be taken when runtime testing new code subissions.

Quoted 2 lines
Quoted 2 lines

You cannot do a GFP_KERNEL allocation under spin_lock_irqsave().

Steps which would have detected this bug.

author
#37 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 13 lines · Andrew Morton
Quoted 5 lines

...

Quoted 3 lines
Quoted 1 line

+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

Quoted 7 lines
struct irq_desc {
        unsigned int            irq;
#ifdef CONFIG_SPARSE_IRQ
        struct list_head        list;
        struct list_head        hash_entry;
        struct timer_rand_state *timer_rand_state;
        unsigned int            *kstat_irqs;
Quoted 6 lines

That doesn't address my question.

The above array can be very large. Can we halve its size by using 16-bit quantities? Will this code ever encounter IRQ numbers larger than 65536?

NR_CPUS=4096, NR_IRQS_LEGACY=16, and that array will be 256k bytes

later could change that alloc_bootmem, so NR_CPUS will be replaced to nr_cpu_ids

YH

#38 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 17 lines · On Thu, 13 Nov 2008 14:41:36 -0800 Yinghai Lu <[email protected]> wrote:
Quoted 15 lines · Andrew Morton
Quoted 5 lines

...

Quoted 3 lines
Quoted 1 line

+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

Quoted 7 lines
struct irq_desc {
        unsigned int            irq;
#ifdef CONFIG_SPARSE_IRQ
        struct list_head        list;
        struct list_head        hash_entry;
        struct timer_rand_state *timer_rand_state;
        unsigned int            *kstat_irqs;

That doesn't address my question.

Quoted 8 lines
Quoted 4 lines

The above array can be very large. Can we halve its size by using 16-bit quantities? Will this code ever encounter IRQ numbers larger than 65536?

NR_CPUS=4096, NR_IRQS_LEGACY=16, and that array will be 256k bytes

later could change that alloc_bootmem, so NR_CPUS will be replaced to nr_cpu_ids

Do the entries in that array need to be 32-bit?

#39 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 23 lines · Andrew Morton
Quoted 20 lines · On Thu, 13 Nov 2008 14:41:36 -0800 Yinghai Lu <[email protected]> wrote:
Quoted 18 lines · Andrew Morton
Quoted 5 lines

...

Quoted 3 lines
Quoted 1 line

+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];

Do these need to be 32-bit? Maybe they'll fit in 16-bit, dunno.

Quoted 7 lines
struct irq_desc {
        unsigned int            irq;
#ifdef CONFIG_SPARSE_IRQ
        struct list_head        list;
        struct list_head        hash_entry;
        struct timer_rand_state *timer_rand_state;
        unsigned int            *kstat_irqs;

That doesn't address my question.

The above array can be very large. Can we halve its size by using 16-bit quantities? Will this code ever encounter IRQ numbers larger than 65536?

Quoted 5 lines
Quoted 3 lines

NR_CPUS=4096, NR_IRQS_LEGACY=16, and that array will be 256k bytes

later could change that alloc_bootmem, so NR_CPUS will be replaced to nr_cpu_ids

Do the entries in that array need to be 32-bit?

That's a good question. If there are 4k or 16k cpus, would the number of irq's being "kstat'd" need to be > 64k? (I'm not exactly sure why there are NR_CPUS * NR_IRQS_LEGACY kstat entries per IRQ?)

author
#40 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · Mike Travis
Quoted 3 lines · Andrew Morton

On Thu, 13 Nov 2008 14:41:36 -0800
Yinghai Lu <[email protected]> wrote:

That's a good question. If there are 4k or 16k cpus, would the number of irq's being "kstat'd" need to be > 64k? (I'm not exactly sure why there are NR_CPUS * NR_IRQS_LEGACY kstat entries per IRQ?)

can be replaced with nr_cpu_ids * NR_IRQS_LEGACY...

YH

#41 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 5 lines · Yinghai Lu
Quoted 4 lines · Mike Travis
Quoted 3 lines · Andrew Morton

On Thu, 13 Nov 2008 14:41:36 -0800
Yinghai Lu <[email protected]> wrote:

Quoted 7 lines
Quoted 3 lines

That's a good question. If there are 4k or 16k cpus, would the number of irq's being "kstat'd" need to be > 64k? (I'm not exactly sure why there are NR_CPUS * NR_IRQS_LEGACY kstat entries per IRQ?)

can be replaced with nr_cpu_ids * NR_IRQS_LEGACY...

YH

Ok, but why does each irq need a list of all other irq's in the system? Can they be collapsed into one array or percpu list?

Thanks,
Mike

author
#42 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 9 lines · Mike Travis
Quoted 8 lines · Yinghai Lu
Quoted 7 lines · Mike Travis
Quoted 3 lines · Andrew Morton

On Thu, 13 Nov 2008 14:41:36 -0800
Yinghai Lu <[email protected]> wrote:

That's a good question. If there are 4k or 16k cpus, would the number of irq's being "kstat'd" need to be > 64k? (I'm not exactly sure why there are NR_CPUS * NR_IRQS_LEGACY kstat entries per IRQ?)

Quoted 6 lines
Quoted 3 lines

can be replaced with nr_cpu_ids * NR_IRQS_LEGACY...

YH

Ok, but why does each irq need a list of all other irq's in the system? Can they be collapsed into one array or percpu list?

use a big pointer array like struct irq_desc *desc[1<<32] ? that means 32g bytes... irq = bus/dev/fn/idx

or struct irq_desc *desc[NR_CPUS * NR_VECTORS] or per_cpu etc, it mean 4096*256*8 ... irq = cpu/idx

YH

author
#43 lore raw

PATCH 1/1 sparse_irq aka dyn_irq v14

In reply to Andrew Morton

address some Andrew's concerns.

also according to ingo, change _irqx to _irq_desc etc.

Thanks

Yinghai Lu

-----

From: Yinghai Lu <[email protected]>
Subject: sparseirq v14

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array

when sparse_irq is used (CONFIG_SPARSE_IRQ), use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg

if CONFIG_MOVE_IRQ_DESC is set
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated try to pass desc cfg as more as possible to avoid list looking up. legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.
	[ or we need to change domain definition to cpus on the same node ? ]

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   20 
 arch/x86/include/asm/hpet.h        |    7 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/hpet.c             |   23 -
 arch/x86/kernel/i8259.c            |   29 +
 arch/x86/kernel/io_apic.c          |  846 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 -
 arch/x86/kernel/irq_32.c           |    4 
 arch/x86/kernel/irq_64.c           |    8 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   27 +
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 +
 drivers/pci/htirq.c                |   44 +
 drivers/pci/intel-iommu.c          |   23 -
 drivers/pci/intr_remapping.c       |   60 ++
 drivers/pci/msi.c                  |   71 ++-
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   18 
 fs/proc/stat.c                     |   17 
 include/linux/dmar.h               |    7 
 include/linux/htirq.h              |    8 
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   95 +++-
 include/linux/irqnr.h              |   15 
 include/linux/kernel_stat.h        |   14 
 include/linux/msi.h                |   10 
 init/main.c                        |   11 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   40 -
 kernel/irq/handle.c                |  369 +++++++++++++++-
 kernel/irq/manage.c                |    6 
 kernel/irq/migration.c             |   34 +
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 36 files changed, 1527 insertions(+), 373 deletions(-)
arch/x86/Kconfig +20 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -240,6 +240,26 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+	bool "Move irq desc when changing irq smp_affinity"
+	depends on SPARSE_IRQ && SMP
+	default y
+	help
+	  This enables moving irq_desc to cpu/node that irq will use handled.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +603 -243

1,686 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +40 -4

77 lines not on this page · raw message

drivers/pci/intr_remapping.c +58 -2

84 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +18 -0
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -8,6 +8,23 @@
 /*
  * /proc/interrupts
  */
+#ifdef CONFIG_SPARSE_IRQ
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &sparse_irqs_head, pos);
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	rcu_read_unlock();
+}
+#else
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
 	return (*pos <= nr_irqs) ? pos : NULL;
@@ -25,6 +42,7 @@ static void int_seq_stop(struct seq_file
 {
 	/* Nothing to do */
 }
+#endif
 
 static const struct seq_operations int_seq_ops = {
 	.start = int_seq_start,
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +90 -5

143 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +22 -18
Index: linux-2.6/kernel/irq/chip.c
===================================================================
@@ -24,9 +24,11 @@
  */
 void dynamic_irq_init(unsigned int irq)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc;
 	unsigned long flags;
 
+	/* first time to use this irq_desc */
+	desc = irq_to_desc_alloc(irq);
 	if (!desc) {
 		WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
 		return;
@@ -223,7 +225,7 @@ static void default_enable(unsigned int
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 
-	desc->chip->unmask(irq);
+	desc_chip_unmask(irq, &desc);
 	desc->status &= ~IRQ_MASKED;
 }
 
@@ -252,7 +254,7 @@ static void default_shutdown(unsigned in
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 
-	desc->chip->mask(irq);
+	desc_chip_mask(irq, &desc);
 	desc->status |= IRQ_MASKED;
 }
 
@@ -282,13 +284,15 @@ void irq_chip_set_defaults(struct irq_ch
 		chip->end = dummy_irq_chip.end;
 }
 
-static inline void mask_ack_irq(struct irq_desc *desc, int irq)
+static inline void mask_ack_irq(struct irq_desc **descp, int irq)
 {
+	struct irq_desc *desc = *descp;
+
 	if (desc->chip->mask_ack)
-		desc->chip->mask_ack(irq);
+		desc_chip_mask_ack(irq, descp);
 	else {
-		desc->chip->mask(irq);
-		desc->chip->ack(irq);
+		desc_chip_mask(irq, descp);
+		desc_chip_ack(irq, descp);
 	}
 }
 
@@ -351,7 +355,7 @@ handle_level_irq(unsigned int irq, struc
 	irqreturn_t action_ret;
 
 	spin_lock(&desc->lock);
-	mask_ack_irq(desc, irq);
+	mask_ack_irq(&desc, irq);
 
 	if (unlikely(desc->status & IRQ_INPROGRESS))
 		goto out_unlock;
@@ -376,7 +380,7 @@ handle_level_irq(unsigned int irq, struc
 	spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
 	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
-		desc->chip->unmask(irq);
+		desc_chip_unmask(irq, &desc);
 out_unlock:
 	spin_unlock(&desc->lock);
 }
@@ -413,7 +417,7 @@ handle_fasteoi_irq(unsigned int irq, str
 	if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
 		desc->status |= IRQ_PENDING;
 		if (desc->chip->mask)
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 		goto out;
 	}
 
@@ -428,7 +432,7 @@ handle_fasteoi_irq(unsigned int irq, str
 	spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
 out:
-	desc->chip->eoi(irq);
+	desc_chip_eoi(irq, &desc);
 
 	spin_unlock(&desc->lock);
 }
@@ -464,13 +468,13 @@ handle_edge_irq(unsigned int irq, struct
 	if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
 		    !desc->action)) {
 		desc->status |= (IRQ_PENDING | IRQ_MASKED);
-		mask_ack_irq(desc, irq);
+		mask_ack_irq(&desc, irq);
 		goto out_unlock;
 	}
 	kstat_incr_irqs_this_cpu(irq, desc);
 
 	/* Start handling the irq */
-	desc->chip->ack(irq);
+	desc_chip_ack(irq, &desc);
 
 	/* Mark the IRQ currently in progress.*/
 	desc->status |= IRQ_INPROGRESS;
@@ -480,7 +484,7 @@ handle_edge_irq(unsigned int irq, struct
 		irqreturn_t action_ret;
 
 		if (unlikely(!action)) {
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 			goto out_unlock;
 		}
 
@@ -492,7 +496,7 @@ handle_edge_irq(unsigned int irq, struct
 		if (unlikely((desc->status &
 			       (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
 			      (IRQ_PENDING | IRQ_MASKED))) {
-			desc->chip->unmask(irq);
+			desc_chip_unmask(irq, &desc);
 			desc->status &= ~IRQ_MASKED;
 		}
 
@@ -525,14 +529,14 @@ handle_percpu_irq(unsigned int irq, stru
 	kstat_incr_irqs_this_cpu(irq, desc);
 
 	if (desc->chip->ack)
-		desc->chip->ack(irq);
+		desc_chip_ack(irq, &desc);
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
 		note_interrupt(irq, desc, action_ret);
 
 	if (desc->chip->eoi)
-		desc->chip->eoi(irq);
+		desc_chip_eoi(irq, &desc);
 }
 
 void
@@ -568,7 +572,7 @@ __set_irq_handler(unsigned int irq, irq_
 	/* Uninstall? */
 	if (handle == handle_bad_irq) {
 		if (desc->chip != &no_irq_chip)
-			mask_ack_irq(desc, irq);
+			mask_ack_irq(&desc, irq);
 		desc->status |= IRQ_DISABLED;
 		desc->depth = 1;
 	}
kernel/irq/handle.c +356 -13

434 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init(void)
+{
+}
 #endif
 
-#define for_each_irq_nr(irq)			\
-	for (irq = 0; irq < nr_irqs; irq++)
-
 #endif
arch/x86/kernel/irq_32.c +2 -2
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================
@@ -251,10 +251,10 @@ void fixup_irqs(cpumask_t map)
 			mask = map;
 		}
 		if (desc->chip->set_affinity)
-			desc->chip->set_affinity(irq, mask);
+			desc_chip_set_affinity(irq, desc, mask);
 		else if (desc->action && !(warned++))
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 #if 0
 	barrier();
arch/x86/kernel/irq_64.c +4 -4
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================
@@ -113,15 +113,15 @@ void fixup_irqs(cpumask_t map)
 		}
 
 		if (desc->chip->mask)
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 
 		if (desc->chip->set_affinity)
-			desc->chip->set_affinity(irq, mask);
+			desc_chip_set_affinity(irq, desc, mask);
 		else if (!(warned++))
 			set_affinity = 0;
 
 		if (desc->chip->unmask)
-			desc->chip->unmask(irq);
+			desc_chip_unmask(irq, &desc);
 
 		spin_unlock(&desc->lock);
 
@@ -129,7 +129,7 @@ void fixup_irqs(cpumask_t map)
 			printk("Broke affinity for irq %i\n", irq);
 		else if (!set_affinity)
 			printk("Cannot set affinity for irq %i\n", irq);
-	}
+	} end_for_each_irq_desc();
 
 	/* That doesn't seem sufficient.  Give it 1ms. */
 	local_irq_enable();
kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================
@@ -243,7 +243,8 @@ void init_irq_proc(void)
 	/*
 	 * Create entries for all existing IRQs.
 	 */
-	for_each_irq_desc(irq, desc)
+	for_each_irq_desc(irq, desc) {
 		register_irq_proc(irq, desc);
+	} end_for_each_irq_desc();
 }
 
kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================
@@ -99,7 +99,7 @@ static int misrouted_irq(int irq)
 
 		if (try_one_irq(i, desc))
 			ok = 1;
-	}
+	} end_for_each_irq_desc();
 	/* So the caller can adjust the irq error counts */
 	return ok;
 }
@@ -122,7 +122,7 @@ static void poll_spurious_irqs(unsigned
 			continue;
 
 		try_one_irq(i, desc);
-	}
+	} end_for_each_irq_desc();
 
 	mod_timer(&poll_spurious_irq_timer,
 		  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
init/main.c +11 -0
Index: linux-2.6/init/main.c
===================================================================
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini
 {
 }
 
+void __init __weak arch_early_irq_init(void)
+{
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/i8259.c +24 -5
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/uv_irq.c +23 -4
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================

Lines of this file are not shown. View the raw message.

drivers/pci/msi.c +54 -17

71 lines not on this page · raw message

include/linux/msi.h +10 -0
Index: linux-2.6/include/linux/msi.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/include/asm/hpet.h +7 -0
Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/hpet.c +19 -4
Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================

Lines of this file are not shown. View the raw message.

include/linux/htirq.h +8 -0
Index: linux-2.6/include/linux/htirq.h
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/migration.c +26 -8
Index: linux-2.6/kernel/irq/migration.c
===================================================================

Lines of this file are not shown. View the raw message.

drivers/pci/intel-iommu.c +19 -4
Index: linux-2.6/drivers/pci/intel-iommu.c
===================================================================

Lines of this file are not shown. View the raw message.

include/linux/dmar.h +7 -0
Index: linux-2.6/include/linux/dmar.h
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/manage.c +3 -3
Index: linux-2.6/kernel/irq/manage.c
===================================================================

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#44 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v14

Quoted 7 lines · On Thu, 13 Nov 2008 22:29:21 -0800 Yinghai Lu <[email protected]> wrote:

address some Andrew's concerns.

...

arch/x86/kernel/io_apic.c +3 -0
+static struct irq_pin_list *get_one_free_irq_2_pin(int cpu)
+{
+	struct irq_pin_list *pin;

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 136

Quoted 10 lines
arch/x86/kernel/io_apic.c +10 -0
+	int node;
+
+	node = cpu_to_node(cpu);
+
+	pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
+	printk(KERN_DEBUG "  alloc irq_2_pin on cpu %d node %d\n", cpu, node);
+	BUG_ON(!pin);
+
+	return pin;
+}

GFP_ATOMIC allocation attempts are unreliable - much more so than GFP_KERNEL. GFP_ATOMIC allocations can and do fail. With the above code, such a failure will crash the machine.

The code should handle this error and recover gracefully.

Quoted 6 lines

...

arch/x86/kernel/io_apic.c +3 -0
+static struct irq_cfg *get_one_free_irq_cfg(int cpu)
+{
+	struct irq_cfg *cfg;

arch/x86/kernel/io_apic.c static int __init parse_noapic(char *str · line 222

Quoted 10 lines
arch/x86/kernel/io_apic.c +9 -0
+	int node;
+
+	node = cpu_to_node(cpu);
+
+	cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
+	printk(KERN_DEBUG "  alloc irq_cfg on cpu %d node %d\n", cpu, node);
+	BUG_ON(!cfg);
+
+	return cfg;
 }

Ditto

Quoted 4 lines

...

drivers/pci/intr_remapping.c +2 -0
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+{

drivers/pci/intr_remapping.c struct irq_2_iommu { · line 34

Quoted 10 lines
drivers/pci/intr_remapping.c +10 -0
+	struct irq_2_iommu *iommu;
+	int node;
+
+	node = cpu_to_node(cpu);
+
+	iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
+	printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+
+	return iommu;
+}

I spent some time trying to work out whether the callers handle failure here but I got lost in a twisty maze.

Quoted 8 lines

...

kernel/irq/handle.c +6 -0
+static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
+{
+	unsigned long bytes;
+	char *ptr;
+	int node;
+

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 91

Quoted 10 lines
kernel/irq/handle.c +10 -0
+	/* Compute how many bytes we need per irq and allocate them */
+	bytes = nr * sizeof(unsigned int);
+
+	node = cpu_to_node(cpu);
+	ptr = kzalloc_node(bytes, GFP_ATOMIC, node);
+	printk(KERN_DEBUG "  alloc kstat_irqs on cpu %d node %d\n", cpu, node);
+	BUG_ON(!ptr);
+
+	desc->kstat_irqs = (unsigned int *)ptr;
+}

Ditto.

Quoted 22 lines

...

kernel/irq/handle.c +19 -0
+struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+	struct irq_desc *desc;
+	struct list_head *hash_head;
+	unsigned long flags;
+	int node;
+
+	desc = irq_to_desc(irq);
+	if (desc)
+		return desc;
+
+	hash_head = sparseirqhashentry(irq);
+
+	spin_lock_irqsave(&sparse_irq_lock, flags);
+
+	/*
+	 * We have to do the hash-walk again, to avoid races
+	 * with another CPU:
+	 */

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 253

Quoted 10 lines
kernel/irq/handle.c +10 -0
+	list_for_each_entry(desc, hash_head, hash_entry) {
+		if (desc->irq == irq)
+			goto out_unlock;
+	}
+
+	node = cpu_to_node(cpu);
+	desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+	printk(KERN_DEBUG "  alloc irq_desc for %d aka %#x on cpu %d node %d\n",
+		 irq, irq, cpu, node);
+	BUG_ON(!desc);

Ditto.

Quoted 39 lines
kernel/irq/handle.c +36 -0
+	init_one_irq_desc(irq, desc, cpu);
+
+	/*
+	 * We use RCU's safe list-add method to make
+	 * parallel walking of the hash-list safe:
+	 */
+	list_add_tail_rcu(&desc->hash_entry, hash_head);
+	/*
+	 * Add it to the global list:
+	 */
+	list_add_tail_rcu(&desc->list, &sparse_irqs_head);
+
+out_unlock:
+	spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+	return desc;
+}
+
 
...
 
+static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
+						int cpu)
+{
+	struct irq_desc *desc;
+	unsigned int irq;
+	struct list_head *hash_head;
+	unsigned long flags;
+	int node;
+
+	irq = old_desc->irq;
+
+	hash_head = sparseirqhashentry(irq);
+
+	spin_lock_irqsave(&sparse_irq_lock, flags);
+	/*
+	 * We have to do the hash-walk again, to avoid races
+	 * with another CPU:
+	 */

kernel/irq/handle.c void handle_bad_irq(unsigned int irq, st · line 305

Quoted 10 lines
kernel/irq/handle.c +10 -0
+	list_for_each_entry(desc, hash_head, hash_entry) {
+		if (desc->irq == irq && old_desc != desc)
+			goto out_unlock;
+	}
+
+	node = cpu_to_node(cpu);
+	desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+	printk(KERN_DEBUG "  move irq_desc for %d aka %#x to cpu %d node %d\n",
+		 irq, irq, cpu, node);
+	BUG_ON(!desc);

Ditto.

Quoted 15 lines
kernel/irq/handle.c +15 -0
+	init_copy_one_irq_desc(irq, old_desc, desc, cpu);
+
+	list_replace_rcu(&old_desc->hash_entry, &desc->hash_entry);
+	list_replace_rcu(&old_desc->list, &desc->list);
+
+	/* free the old one */
+	free_one_irq_desc(old_desc);
+	kfree(old_desc);
+
+out_unlock:
+	spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+	return desc;
+}
+
author
#45 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v14

please check it. address kzalloc_node return handling.

YH

---

From: Yinghai Lu <[email protected]>
Subject: sparseirq v15

impact: new feature sparseirq

add some kind of hash table as Ingo suggesting.
remove dyna_array

when sparse_irq is used (CONFIG_SPARSE_IRQ), use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg

if CONFIG_MOVE_IRQ_DESC is set
make irq_desc to go with affinity aka irq_desc moving etc
call move_irq_desc in irq_complete_move()
need to add struct (irq_desc **descp) to ack_edge/level to make sure desc get updated try to pass desc cfg as more as possible to avoid list looking up. legacy irq_desc is not moved, because they are allocated via static array

for logical apic mode, need to add move_desc_in_progress_in_same_domain. otherwise it will not get moved. ==> also could need two phase to get irq_desc moved.

	for example: 0xff is old affinity, and need to set 0xf, and then set to 0xf0.
	[ or we need to change domain definition to cpus on the same node ? ]

LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,000000ff
LBSuse:~ # echo f > /proc/irq/22/smp_affinity
LBSuse:~ # cat /proc/irq/22/smp_affinity
00000000,00000000,00000000,0000000f
LBSuse:~ # tail /var/log/messages
...

Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
LBSuse:~ # echo f0 > /proc/irq/22/smp_affinity
LBSuse:~ # tail /var/log/messages
Oct 27 12:35:34 LBSuse kernel: klogd 1.4.1, log source = /proc/kmsg started.
Oct 27 12:35:34 LBSuse kernel: eth0: no IPv6 routers present
Oct 27 12:36:46 LBSuse kernel:   move irq_desc for 22 aka 0x16 to cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc kstat_irqs on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_cfg on cpu 7 node 1
Oct 27 12:36:46 LBSuse kernel:   alloc irq_2_pin on cpu 7 node 1

so assume the user space program should update /proc/irq/XX/smp_affinity to 03 or 0f at first on boot or we change irq_default_affinity ?

for physical apic is much simple
on 4 sockets 16 cores system
irq_desc is moving..
when

# echo 10 > /proc/irq/134483967/smp_affinity
# echo 100 > /proc/irq/134483967/smp_affinity
# echo 1000 > /proc/irq/134483967/smp_affinity
got
Nov  9 21:39:51 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc kstat_irqs on cpu 4 node 1
Nov  9 21:39:51 LBSuse kernel:   alloc irq_cfg on cpu 4 node 1
Nov  9 21:40:05 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc kstat_irqs on cpu 8 node 2
Nov  9 21:40:05 LBSuse kernel:   alloc irq_cfg on cpu 8 node 2
Nov  9 21:40:18 LBSuse kernel:   move irq_desc for 134483967 aka 0x8040fff to cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc kstat_irqs on cpu 12 node 3
Nov  9 21:40:18 LBSuse kernel:   alloc irq_cfg on cpu 12 node 3
---
 arch/x86/Kconfig                   |   20 
 arch/x86/include/asm/hpet.h        |    7 
 arch/x86/include/asm/irq_vectors.h |    2 
 arch/x86/kernel/hpet.c             |   23 
 arch/x86/kernel/i8259.c            |   29 +
 arch/x86/kernel/io_apic.c          |  880 ++++++++++++++++++++++++++-----------
 arch/x86/kernel/irq.c              |   24 -
 arch/x86/kernel/irq_32.c           |    4 
 arch/x86/kernel/irq_64.c           |    8 
 arch/x86/kernel/irqinit_32.c       |    3 
 arch/x86/kernel/irqinit_64.c       |    3 
 arch/x86/kernel/uv_irq.c           |   27 -
 arch/x86/mm/init_32.c              |    3 
 drivers/char/random.c              |   31 +
 drivers/pci/htirq.c                |   44 +
 drivers/pci/intel-iommu.c          |   23 
 drivers/pci/intr_remapping.c       |   72 ++-
 drivers/pci/msi.c                  |   71 ++
 drivers/xen/events.c               |    9 
 fs/proc/interrupts.c               |   18 
 fs/proc/stat.c                     |   17 
 include/linux/dmar.h               |    7 
 include/linux/htirq.h              |    8 
 include/linux/interrupt.h          |    2 
 include/linux/irq.h                |   95 +++
 include/linux/irqnr.h              |   15 
 include/linux/kernel_stat.h        |   14 
 include/linux/msi.h                |   10 
 init/main.c                        |   11 
 kernel/irq/autoprobe.c             |   10 
 kernel/irq/chip.c                  |   40 -
 kernel/irq/handle.c                |  386 +++++++++++++++-
 kernel/irq/manage.c                |    6 
 kernel/irq/migration.c             |   34 +
 kernel/irq/proc.c                  |    3 
 kernel/irq/spurious.c              |    4 
 36 files changed, 1590 insertions(+), 373 deletions(-)
arch/x86/Kconfig +20 -0
Index: linux-2.6/arch/x86/Kconfig
===================================================================
@@ -240,6 +240,26 @@ config X86_HAS_BOOT_CPU_ID
 	def_bool y
 	depends on X86_VOYAGER
 
+config SPARSE_IRQ
+	bool "Support sparse irq numbering"
+	depends on PCI_MSI || HT_IRQ
+	default y
+	help
+	  This enables support for sparse irq, esp for msi/msi-x. the irq
+	  number will be bus/dev/fn + 12bit. You may need if you have lots of
+	  cards supports msi-x installed.
+
+	  If you don't know what to do here, say Y.
+
+config MOVE_IRQ_DESC
+	bool "Move irq desc when changing irq smp_affinity"
+	depends on SPARSE_IRQ && SMP
+	default y
+	help
+	  This enables moving irq_desc to cpu/node that irq will use handled.
+
+	  If you don't know what to do here, say Y.
+
 config X86_FIND_SMP_CONFIG
 	def_bool y
 	depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +637 -243

1,720 lines not on this page · raw message

arch/x86/kernel/irqinit_32.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
 	/*
 	 * 16 old-style INTA-cycle interrupts:
 	 */
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/kernel/irqinit_64.c +1 -2
Index: linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
 	init_bsp_APIC();
 	init_8259A(0);
 
-	for (i = 0; i < 16; i++) {
-		/* first time call this irq_desc */
+	for (i = 0; i < NR_IRQS_LEGACY; i++) {
 		struct irq_desc *desc = irq_to_desc(i);
 
 		desc->status = IRQ_DISABLED;
arch/x86/mm/init_32.c +3 -0
Index: linux-2.6/arch/x86/mm/init_32.c
===================================================================
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
 	set_highmem_pages_init();
 
+	after_bootmem = 1;
+
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
drivers/char/random.c +31 -0
Index: linux-2.6/drivers/char/random.c
===================================================================
@@ -558,6 +558,8 @@ struct timer_rand_state {
 	unsigned dont_count_entropy:1;
 };
 
+#ifndef CONFIG_SPARSE_IRQ
+
 static struct timer_rand_state *irq_timer_state[NR_IRQS];
 
 static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne
 	irq_timer_state[irq] = state;
 }
 
+#else
+
+static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return NULL;
+
+	return desc->timer_rand_state;
+}
+
+static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+
+	if (!desc)
+		return;
+
+	desc->timer_rand_state = state;
+}
+#endif
+
 static struct timer_rand_state input_timer_state;
 
 /*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq)
 {
 	struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
 	if (irq >= nr_irqs)
 		return;
+#endif
 
 	state = get_timer_rand_state(irq);
 
drivers/pci/htirq.c +40 -4

77 lines not on this page · raw message

drivers/pci/intr_remapping.c +70 -2

108 lines not on this page · raw message

drivers/xen/events.c +5 -4
Index: linux-2.6/drivers/xen/events.c
===================================================================
@@ -141,8 +141,9 @@ static void init_evtchn_cpu_bindings(voi
 	int i;
 
 	/* By default all event channels notify CPU#0. */
-	for_each_irq_desc(i, desc)
+	for_each_irq_desc(i, desc) {
 		desc->affinity = cpumask_of_cpu(0);
+	} end_for_each_irq_desc();
 #endif
 
 	memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)
 	int irq;
 
 	/* Only allocate from dynirq range */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		if (irq_bindcount[irq] == 0)
 			break;
 
@@ -792,7 +793,7 @@ void xen_irq_resume(void)
 		mask_evtchn(evtchn);
 
 	/* No IRQ <-> event-channel mappings. */
-	for_each_irq_nr(irq)
+	for (irq = 0; irq < nr_irqs; irq++)
 		irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
 	for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)
 		mask_evtchn(i);
 
 	/* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-	for_each_irq_nr(i)
+	for (i = 0; i < nr_irqs; i++)
 		irq_bindcount[i] = 0;
 
 	irq_ctx_init(smp_processor_id());
fs/proc/stat.c +11 -6
Index: linux-2.6/fs/proc/stat.c
===================================================================
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,
 	u64 sum = 0;
 	struct timespec boottime;
 	unsigned int per_irq_sum;
+#ifdef CONFIG_GENERIC_HARDIRQS
+	struct irq_desc *desc;
+#endif
 
 	user = nice = system = idle = iowait =
 		irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p,
 		softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
 		steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
 		guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-		for_each_irq_nr(j)
+		for_each_irq_desc(j, desc) {
 			sum += kstat_irqs_cpu(j, i);
-
+		} end_for_each_irq_desc();
 		sum += arch_irq_stat_cpu(i);
 	}
 	sum += arch_irq_stat();
@@ -90,14 +92,17 @@ static int show_stat(struct seq_file *p,
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
 	/* sum again ? it could be updated? */
-	for_each_irq_nr(j) {
+	for_each_irq_desc(j, desc) {
 		per_irq_sum = 0;
-
 		for_each_possible_cpu(i)
 			per_irq_sum += kstat_irqs_cpu(j, i);
 
+#ifdef CONFIG_SPARSE_IRQ
+		seq_printf(p, " %#x:%u", j, per_irq_sum);
+#else
 		seq_printf(p, " %u", per_irq_sum);
-	}
+#endif
+	} end_for_each_irq_desc();
 
 	seq_printf(p,
 		"\nctxt %llu\n"
fs/proc/interrupts.c +18 -0
Index: linux-2.6/fs/proc/interrupts.c
===================================================================
@@ -8,6 +8,23 @@
 /*
  * /proc/interrupts
  */
+#ifdef CONFIG_SPARSE_IRQ
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	rcu_read_lock();
+	return seq_list_start(&sparse_irqs_head, *pos);
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	return seq_list_next(v, &sparse_irqs_head, pos);
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	rcu_read_unlock();
+}
+#else
 static void *int_seq_start(struct seq_file *f, loff_t *pos)
 {
 	return (*pos <= nr_irqs) ? pos : NULL;
@@ -25,6 +42,7 @@ static void int_seq_stop(struct seq_file
 {
 	/* Nothing to do */
 }
+#endif
 
 static const struct seq_operations int_seq_ops = {
 	.start = int_seq_start,
include/linux/interrupt.h +2 -0
Index: linux-2.6/include/linux/interrupt.h
===================================================================
@@ -18,6 +18,8 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
+extern int nr_irqs;
+
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
  * linux/ioport.h to select the interrupt line behaviour.  When
include/linux/irq.h +90 -5

143 lines not on this page · raw message

include/linux/kernel_stat.h +13 -1
Index: linux-2.6/include/linux/kernel_stat.h
===================================================================
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
 	struct cpu_usage_stat	cpustat;
-	unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, ksta
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+	(kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_
 {
 	kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -5
Index: linux-2.6/kernel/irq/autoprobe.c
===================================================================
@@ -57,7 +57,7 @@ unsigned long probe_irq_on(void)
 			desc->chip->startup(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/* Wait for longstanding interrupts to trigger. */
 	msleep(20);
@@ -75,7 +75,7 @@ unsigned long probe_irq_on(void)
 				desc->status |= IRQ_PENDING;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -99,7 +99,7 @@ unsigned long probe_irq_on(void)
 					mask |= 1 << i;
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 
 	return mask;
 }
@@ -135,7 +135,7 @@ unsigned int probe_irq_mask(unsigned lon
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	return mask & val;
@@ -179,7 +179,7 @@ int probe_irq_off(unsigned long val)
 			desc->chip->shutdown(i);
 		}
 		spin_unlock_irq(&desc->lock);
-	}
+	} end_for_each_irq_desc();
 	mutex_unlock(&probing_active);
 
 	if (nr_of_irqs > 1)
kernel/irq/chip.c +22 -18
Index: linux-2.6/kernel/irq/chip.c
===================================================================
@@ -24,9 +24,11 @@
  */
 void dynamic_irq_init(unsigned int irq)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_desc *desc;
 	unsigned long flags;
 
+	/* first time to use this irq_desc */
+	desc = irq_to_desc_alloc(irq);
 	if (!desc) {
 		WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
 		return;
@@ -223,7 +225,7 @@ static void default_enable(unsigned int
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 
-	desc->chip->unmask(irq);
+	desc_chip_unmask(irq, &desc);
 	desc->status &= ~IRQ_MASKED;
 }
 
@@ -252,7 +254,7 @@ static void default_shutdown(unsigned in
 {
 	struct irq_desc *desc = irq_to_desc(irq);
 
-	desc->chip->mask(irq);
+	desc_chip_mask(irq, &desc);
 	desc->status |= IRQ_MASKED;
 }
 
@@ -282,13 +284,15 @@ void irq_chip_set_defaults(struct irq_ch
 		chip->end = dummy_irq_chip.end;
 }
 
-static inline void mask_ack_irq(struct irq_desc *desc, int irq)
+static inline void mask_ack_irq(struct irq_desc **descp, int irq)
 {
+	struct irq_desc *desc = *descp;
+
 	if (desc->chip->mask_ack)
-		desc->chip->mask_ack(irq);
+		desc_chip_mask_ack(irq, descp);
 	else {
-		desc->chip->mask(irq);
-		desc->chip->ack(irq);
+		desc_chip_mask(irq, descp);
+		desc_chip_ack(irq, descp);
 	}
 }
 
@@ -351,7 +355,7 @@ handle_level_irq(unsigned int irq, struc
 	irqreturn_t action_ret;
 
 	spin_lock(&desc->lock);
-	mask_ack_irq(desc, irq);
+	mask_ack_irq(&desc, irq);
 
 	if (unlikely(desc->status & IRQ_INPROGRESS))
 		goto out_unlock;
@@ -376,7 +380,7 @@ handle_level_irq(unsigned int irq, struc
 	spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
 	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
-		desc->chip->unmask(irq);
+		desc_chip_unmask(irq, &desc);
 out_unlock:
 	spin_unlock(&desc->lock);
 }
@@ -413,7 +417,7 @@ handle_fasteoi_irq(unsigned int irq, str
 	if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
 		desc->status |= IRQ_PENDING;
 		if (desc->chip->mask)
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 		goto out;
 	}
 
@@ -428,7 +432,7 @@ handle_fasteoi_irq(unsigned int irq, str
 	spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
 out:
-	desc->chip->eoi(irq);
+	desc_chip_eoi(irq, &desc);
 
 	spin_unlock(&desc->lock);
 }
@@ -464,13 +468,13 @@ handle_edge_irq(unsigned int irq, struct
 	if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
 		    !desc->action)) {
 		desc->status |= (IRQ_PENDING | IRQ_MASKED);
-		mask_ack_irq(desc, irq);
+		mask_ack_irq(&desc, irq);
 		goto out_unlock;
 	}
 	kstat_incr_irqs_this_cpu(irq, desc);
 
 	/* Start handling the irq */
-	desc->chip->ack(irq);
+	desc_chip_ack(irq, &desc);
 
 	/* Mark the IRQ currently in progress.*/
 	desc->status |= IRQ_INPROGRESS;
@@ -480,7 +484,7 @@ handle_edge_irq(unsigned int irq, struct
 		irqreturn_t action_ret;
 
 		if (unlikely(!action)) {
-			desc->chip->mask(irq);
+			desc_chip_mask(irq, &desc);
 			goto out_unlock;
 		}
 
@@ -492,7 +496,7 @@ handle_edge_irq(unsigned int irq, struct
 		if (unlikely((desc->status &
 			       (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
 			      (IRQ_PENDING | IRQ_MASKED))) {
-			desc->chip->unmask(irq);
+			desc_chip_unmask(irq, &desc);
 			desc->status &= ~IRQ_MASKED;
 		}
 
@@ -525,14 +529,14 @@ handle_percpu_irq(unsigned int irq, stru
 	kstat_incr_irqs_this_cpu(irq, desc);
 
 	if (desc->chip->ack)
-		desc->chip->ack(irq);
+		desc_chip_ack(irq, &desc);
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
 		note_interrupt(irq, desc, action_ret);
 
 	if (desc->chip->eoi)
-		desc->chip->eoi(irq);
+		desc_chip_eoi(irq, &desc);
 }
 
 void
@@ -568,7 +572,7 @@ __set_irq_handler(unsigned int irq, irq_
 	/* Uninstall? */
 	if (handle == handle_bad_irq) {
 		if (desc->chip != &no_irq_chip)
-			mask_ack_irq(desc, irq);
+			mask_ack_irq(&desc, irq);
 		desc->status |= IRQ_DISABLED;
 		desc->depth = 1;
 	}
kernel/irq/handle.c +373 -13

451 lines not on this page · raw message

arch/x86/kernel/irq.c +21 -3
Index: linux-2.6/arch/x86/kernel/irq.c
===================================================================
@@ -99,25 +99,37 @@ static int show_other_interrupts(struct
 int show_interrupts(struct seq_file *p, void *v)
 {
 	unsigned long flags, any_count = 0;
-	int i = *(loff_t *) v, j;
+	int i, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	int head = 0;
 
+#ifdef CONFIG_SPARSE_IRQ
+	desc = list_entry(v, struct irq_desc, list);
+	i = desc->irq;
+	if (&desc->list == sparse_irqs_head.next)
+		head = 1;
+#else
+	i = *(loff_t *) v;
 	if (i > nr_irqs)
 		return 0;
 
 	if (i == nr_irqs)
 		return show_other_interrupts(p);
+	if (i == 0)
+		head = 1;
+
+	desc = irq_to_desc(i);
+#endif
 
 	/* print header */
-	if (i == 0) {
+	if (head) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
 			seq_printf(p, "CPU%-8d", j);
 		seq_putc(p, '\n');
 	}
 
-	desc = irq_to_desc(i);
 	spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
 	any_count = kstat_irqs(i);
@@ -148,6 +160,12 @@ int show_interrupts(struct seq_file *p,
 	seq_putc(p, '\n');
 out:
 	spin_unlock_irqrestore(&desc->lock, flags);
+
+#ifdef CONFIG_SPARSE_IRQ
+	if (&desc->list == sparse_irqs_head.prev)
+		show_other_interrupts(p);
+#endif
+
 	return 0;
 }
 
include/linux/irqnr.h +4 -11
Index: linux-2.6/include/linux/irqnr.h
===================================================================
@@ -7,18 +7,11 @@
 
 # define for_each_irq_desc(irq, desc)		\
 	for (irq = 0; irq < nr_irqs; irq++)
-#else
-extern int nr_irqs;
+# define end_for_each_irq_desc()
 
-# define for_each_irq_desc(irq, desc)		\
-	for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)				\
-	for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);	\
-	     irq >= 0; irq--, desc--)
+static inline early_sparse_irq_init(void)
+{
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

arch/x86/kernel/irq_32.c +2 -2
Index: linux-2.6/arch/x86/kernel/irq_32.c
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/irq_64.c +4 -4
Index: linux-2.6/arch/x86/kernel/irq_64.c
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/proc.c +2 -1
Index: linux-2.6/kernel/irq/proc.c
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/spurious.c +2 -2
Index: linux-2.6/kernel/irq/spurious.c
===================================================================

Lines of this file are not shown. View the raw message.

init/main.c +11 -0
Index: linux-2.6/init/main.c
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/include/asm/irq_vectors.h +2 -0
Index: linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/i8259.c +24 -5
Index: linux-2.6/arch/x86/kernel/i8259.c
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/uv_irq.c +23 -4
Index: linux-2.6/arch/x86/kernel/uv_irq.c
===================================================================

Lines of this file are not shown. View the raw message.

drivers/pci/msi.c +54 -17

71 lines not on this page · raw message

include/linux/msi.h +10 -0
Index: linux-2.6/include/linux/msi.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/include/asm/hpet.h +7 -0
Index: linux-2.6/arch/x86/include/asm/hpet.h
===================================================================

Lines of this file are not shown. View the raw message.

arch/x86/kernel/hpet.c +19 -4
Index: linux-2.6/arch/x86/kernel/hpet.c
===================================================================

Lines of this file are not shown. View the raw message.

include/linux/htirq.h +8 -0
Index: linux-2.6/include/linux/htirq.h
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/migration.c +26 -8
Index: linux-2.6/kernel/irq/migration.c
===================================================================

Lines of this file are not shown. View the raw message.

drivers/pci/intel-iommu.c +19 -4
Index: linux-2.6/drivers/pci/intel-iommu.c
===================================================================

Lines of this file are not shown. View the raw message.

include/linux/dmar.h +7 -0
Index: linux-2.6/include/linux/dmar.h
===================================================================

Lines of this file are not shown. View the raw message.

kernel/irq/manage.c +3 -3
Index: linux-2.6/kernel/irq/manage.c
===================================================================

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#46 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Andrew Morton
Quoted 2 lines · Andrew Morton

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

On powerpc we have a mapping from virtual irq numbers (in the range 0 to NR_IRQS-1) to physical irq numbers (which can be anything) and back again. I think our approach is simpler than what's being proposed here, though we don't try to keep the irqdescs node-local as this patch seems to (fortunately our big systems aren't so NUMA-ish as to make that necessary).

Paul.

#47 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

From: Paul Mackerras <[email protected]>
Date: Fri, 14 Nov 2008 09:19:13 +1100

Quoted 11 lines
Quoted 2 lines · Andrew Morton

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

On powerpc we have a mapping from virtual irq numbers (in the range 0 to NR_IRQS-1) to physical irq numbers (which can be anything) and back again. I think our approach is simpler than what's being proposed here, though we don't try to keep the irqdescs node-local as this patch seems to (fortunately our big systems aren't so NUMA-ish as to make that necessary).

This is exactly what sparc64 does as well, same as powerpc, and as Paul said it's so much incredibly simpler than the dyn_irq stuff.

#48 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 14 lines · David Miller

From: Paul Mackerras <[email protected]>
Date: Fri, 14 Nov 2008 09:19:13 +1100

Quoted 10 lines
Quoted 2 lines · Andrew Morton

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

On powerpc we have a mapping from virtual irq numbers (in the range 0 to NR_IRQS-1) to physical irq numbers (which can be anything) and back again. I think our approach is simpler than what's being proposed here, though we don't try to keep the irqdescs node-local as this patch seems to (fortunately our big systems aren't so NUMA-ish as to make that necessary).

Quoted 2 lines

This is exactly what sparc64 does as well, same as powerpc, and as Paul said it's so much incredibly simpler than the dyn_irq stuff.

One problem is that pre-defining a static NR_IRQ count is almost always wrong when the NR_CPUS count is large, and should be adjusted as resources require.

Large UV systems will take a performance hit from off-node accesses when the CPU count (or more likely the NODE count) reaches some threshold. So keeping as much interrupt context close to the interrupting source is a good thing.

#49 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 15:11:29 -0800

Quoted 15 lines
Quoted 14 lines · David Miller

From: Paul Mackerras <[email protected]>
Date: Fri, 14 Nov 2008 09:19:13 +1100

Quoted 10 lines
Quoted 2 lines · Andrew Morton

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

On powerpc we have a mapping from virtual irq numbers (in the range 0 to NR_IRQS-1) to physical irq numbers (which can be anything) and back again. I think our approach is simpler than what's being proposed here, though we don't try to keep the irqdescs node-local as this patch seems to (fortunately our big systems aren't so NUMA-ish as to make that necessary).

Quoted 6 lines
Quoted 2 lines

This is exactly what sparc64 does as well, same as powerpc, and as Paul said it's so much incredibly simpler than the dyn_irq stuff.

One problem is that pre-defining a static NR_IRQ count is almost always wrong when the NR_CPUS count is large, and should be adjusted as resources require.

We use a value of 256 and I've been booting linux on 128 cpu sparc64 systems with lots of PCI-E host controllers (and others have booted it on even larger ones). All of which have several NUMA domains.

It's not an issue.

Quoted 4 lines

Large UV systems will take a performance hit from off-node accesses when the CPU count (or more likely the NODE count) reaches some threshold. So keeping as much interrupt context close to the interrupting source is a good thing.

Just because the same piece of information is repeated over and over again doesn't mean it really matters.

#50 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 25 lines · David Miller

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 15:11:29 -0800

Quoted 14 lines
Quoted 13 lines · David Miller

From: Paul Mackerras <[email protected]>
Date: Fri, 14 Nov 2008 09:19:13 +1100

Quoted 10 lines
Quoted 2 lines · Andrew Morton

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

On powerpc we have a mapping from virtual irq numbers (in the range 0 to NR_IRQS-1) to physical irq numbers (which can be anything) and back again. I think our approach is simpler than what's being proposed here, though we don't try to keep the irqdescs node-local as this patch seems to (fortunately our big systems aren't so NUMA-ish as to make that necessary).

Quoted 7 lines
Quoted 2 lines

This is exactly what sparc64 does as well, same as powerpc, and as Paul said it's so much incredibly simpler than the dyn_irq stuff.

One problem is that pre-defining a static NR_IRQ count is almost always wrong when the NR_CPUS count is large, and should be adjusted as resources require.

Quoted 5 lines

We use a value of 256 and I've been booting linux on 128 cpu sparc64 systems with lots of PCI-E host controllers (and others have booted it on even larger ones). All of which have several NUMA domains.

It's not an issue.

Are you saying that having a fixed count of IRQ's is not an issue? With NR_CPUS=4096 what would you fix it to? (Currently it's NR_CPUS * 32 but that might not be sufficient.) Would NR_CPUS=16384 make it an issue?

Quoted 8 lines
Quoted 5 lines

Large UV systems will take a performance hit from off-node accesses when the CPU count (or more likely the NODE count) reaches some threshold. So keeping as much interrupt context close to the interrupting source is a good thing.

Just because the same piece of information is repeated over and over again doesn't mean it really matters.

Which information is repeated over and over? I was under the impression that each and every interrupt writes to the irq_desc entry for that irq? If this is in a big list on node 0, that is data passing over the system bus.

Or am I missing what you're getting at?

Thanks,
Mike

#51 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 16:15:12 -0800

Quoted 8 lines
Quoted 7 lines · David Miller

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 15:11:29 -0800

We use a value of 256 and I've been booting linux on 128 cpu sparc64 systems with lots of PCI-E host controllers (and others have booted it on even larger ones). All of which have several NUMA domains.

Quoted 5 lines
Quoted 1 line

It's not an issue.

Are you saying that having a fixed count of IRQ's is not an issue? With NR_CPUS=4096 what would you fix it to? (Currently it's NR_CPUS * 32 but that might not be sufficient.) Would NR_CPUS=16384 make it an issue?

Nope, and nope. I frequently run kernels with NR_CPUS set to huge values.

It seems that the issue of x86 is that it has it's IRQ count tied to the number of cpus, that's not very intelligent. Perhaps that part should be rearranged somehow?

#52 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 16 lines · David Miller

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 16:15:12 -0800

Quoted 4 lines
Quoted 3 lines · David Miller

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 15:11:29 -0800

Quoted 8 lines
Quoted 5 lines

We use a value of 256 and I've been booting linux on 128 cpu sparc64 systems with lots of PCI-E host controllers (and others have booted it on even larger ones). All of which have several NUMA domains.

It's not an issue.

Are you saying that having a fixed count of IRQ's is not an issue? With NR_CPUS=4096 what would you fix it to? (Currently it's NR_CPUS * 32 but that might not be sufficient.) Would NR_CPUS=16384 make it an issue?

Quoted 6 lines

Nope, and nope. I frequently run kernels with NR_CPUS set to huge values.

It seems that the issue of x86 is that it has it's IRQ count tied to the number of cpus, that's not very intelligent. Perhaps that part should be rearranged somehow?

Yes, you're probably right but it is what it is. Most of the irq vectors have more to do with cpus than with i/o devices (the system vectors, ipi, kdb and gru [a uv thing] interrupt vectors come first to mind.) These do by necessity need to grow with NR_CPUS, if you're fixing the total IRQ count.

There's been a couple of different proposals to attempt to disassociate i/o and system vectors though even attempting to guess at the number of i/o devices is tricky. Every one of the 512 nodes on a UV system *may* have a number of i/o devices attached to them though practically this will be rare.

#53 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

From: Mike Travis <[email protected]>
Date: Thu, 13 Nov 2008 16:39:51 -0800

Quoted 5 lines

There's been a couple of different proposals to attempt to disassociate i/o and system vectors though even attempting to guess at the number of i/o devices is tricky. Every one of the 512 nodes on a UV system *may* have a number of i/o devices attached to them though practically this will be rare.

Practicality is what really matters.

We can even make the constant number a config option, so that if someone has a system that actually triggers past this limit even dist vendors can simply bump the config option value.

#54 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 5 lines · David Miller

Practicality is what really matters.

We can even make the constant number a config option, so that if someone has a system that actually triggers past this limit even dist vendors can simply bump the config option value.

Unfortunately the reality is that distros spend months certifying the base kernel for both application and security conformance. And many (most?) of the large system customers will only run this kernel. Even changing root startup options is considered invalidating the conformance testing. That means the kernel has to adapt to the resource needs of the system being serviced.

Ideally, linux shouldn't have any fixed resources. A system built to run on a massively parallel system should also boot and run on a smart phone (not well perhaps... ;-)

#55 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Andrew Morton
Quoted 8 lines

Other architectures want (or have) sparse interrupts. Are those guys paying attention here?

I don't have a clue what all this does. I hope those who will work on this code are sufficiently familiar with it all to be able to maintain it when there are close to zero comments in some of our most tricky and problem-prone code.

Indeed, I'm a bit scared by the patch as it is ...

On powerpc, we have a nice an simple virtual irq layer that also probably better fits the need of architecture that can have multiple PICs with different number space cascaded in various ways in a single machine too.

We provide a basic construct that defines an HW IRQ domain (we call it irq_host, it can have a 1:1 relationship to a HW irq_chip but not always), and when HW IRQs are discovered and made available to linux, they are "mapped" to virtual irq numbers by mapping them to a tuple (irq_hose, hw_number).

The HW numbering can be arbitrarily anything for that controller unrelated to the "linux" virtual number, so all the problems of making IRQ 0 invalid and reserving 1...15 for legacy 8259 etc... are taken care of.

For fast mapping of HW->Linux numbers, we provide various schemes that a given IRQ host implementation can choose (from no translation, some HW PICs or hypervisor can be directly given the linux number and pass it back to us) to linear mapping to a lockless radix tree for large sparse irq domains.

At this stage, I don't feel like changing to this sparse_irq which I haven't fully understood, is complicated, and doesn't seem to provide the features I need anyway.

The only thing that I see possibly of interest is getting rid of the irq_desc array itself, toward something more dynamically resizeable, in which case our powerpc remapping scheme could probably also benefit by also getting rid in a similar way of our equivalent array used for mapping the virq's to host,hw_number tuples.

The irq_desc per-cpu also seem to be an interesting idea.

In any case, the patch is too big and unless I missed something, totally under-documented in what it does, why it does it, how it does it, etc... with a bit more of that, I might take more time to look closely and find out that indeed it's something I can make use of, maybe with a few tweaks.

Cheers,
Ben.

author
#56 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 6 lines · Benjamin Herrenschmidt

In any case, the patch is too big and unless I missed something, totally under-documented in what it does, why it does it, how it does it, etc... with a bit more of that, I might take more time to look closely and find out that indeed it's something I can make use of, maybe with a few tweaks.

will cut it to smaller ones. try to have one big one to make review more easy.

starting case
1. IBM x3950 have io apic pins > 224?
2. SGI big box need 8192 irqs

want to make same kernel with NR_CPUS = 4096 can be used with regular sized system.

points are
1. removing irq_desc array and NR_IRQS. for small system will have less wasting ram in that array, and for big system will get more irqs like system have 8 pcie cards and every card need 40 MSI vector or a lot of IO apic controllers etc.
2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.
3. irq_desc is going with /proc/irq/xxx/smp_affinity.

YH

#57 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

-hpa

author
#58 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

you want to u64 instead of unsigned int for irq?

YH

#59 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 11 lines · Yinghai Lu
Quoted 7 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

you want to u64 instead of unsigned int for irq?

No, I think the whole notion of a static *numeric* identifier for an IRQ when it's something like MSI-X is simply pointless. I think we should assign IRQ numbers beyond the legacy range dynamically.

I really don't think anyone gives a hoot about the IRQ number for any IRQ above the 0-15 legacy range, even including the "APIC" numbers 16+.

-hpa

author
#60 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 12 lines · H. Peter Anvin
Quoted 10 lines · Yinghai Lu
Quoted 7 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

you want to u64 instead of unsigned int for irq?

Quoted 6 lines

No, I think the whole notion of a static *numeric* identifier for an IRQ when it's something like MSI-X is simply pointless. I think we should assign IRQ numbers beyond the legacy range dynamically.

I really don't think anyone gives a hoot about the IRQ number for any IRQ above the 0-15 legacy range, even including the "APIC" numbers 16+.

you want to change ioapic/pin to irq mapping too?

so INTx and MSI will call create_irq_nr to get one irq for 16, and following first come and first serve rule.

YH

#61 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 7 lines · Yinghai Lu
Quoted 3 lines

I really don't think anyone gives a hoot about the IRQ number for any IRQ above the 0-15 legacy range, even including the "APIC" numbers 16+.

you want to change ioapic/pin to irq mapping too?
so INTx and MSI will call create_irq_nr to get one irq for 16, and following first come and first serve rule.

I personally don't think there is any issue with changing ioapic/pin to IRQ mapping. Other people may disagree. My opinion is that IRQ numbers 16-23 are somewhat useful when you're dealing with a single IOAPIC, but after that it's all a blur.

It would, however, be a good idea if IOAPICs had their numbers assigned at detection time, as opposed to when the interrupt is registered, thus making it a stable number for a single boot, at least. The same is probably true for MSI(-X); we could assign it a range of numbers when the device is enumerated (as opposed to when a driver is activated), but I don't know to what extent that is likely to cause more troubles than it solves.

-hpa

author
#62 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · H. Peter Anvin

It would, however, be a good idea if IOAPICs had their numbers assigned at detection time, as opposed to when the interrupt is registered, thus making it a stable number for a single boot, at least. The same is probably true for MSI(-X); we could assign it a range of numbers when the device is enumerated (as opposed to when a driver is activated), but I don't know to what extent that is likely to cause more troubles than it solves.

how to find the range for MSIX, one device/func may need a lot. for example, niu driver could use 20 MSI-X for one port. (one dev/func) some could use 256. we only know that when driver is loaded.
So as Eric said, just try to use 12bits (4k range) for them.

YH

#63 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 9 lines · Yinghai Lu
Quoted 7 lines · H. Peter Anvin

It would, however, be a good idea if IOAPICs had their numbers assigned at detection time, as opposed to when the interrupt is registered, thus making it a stable number for a single boot, at least. The same is probably true for MSI(-X); we could assign it a range of numbers when the device is enumerated (as opposed to when a driver is activated), but I don't know to what extent that is likely to cause more troubles than it solves.

Quoted 4 lines

how to find the range for MSIX, one device/func may need a lot. for example, niu driver could use 20 MSI-X for one port. (one dev/func) some could use 256. we only know that when driver is loaded.
So as Eric said, just try to use 12bits (4k range) for them.

You can know how many vectors are exported in generic code. However, using 4k per should be fine.

-hpa

author
#64 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 9 lines · H. Peter Anvin
Quoted 8 lines · Yinghai Lu
Quoted 7 lines · H. Peter Anvin

It would, however, be a good idea if IOAPICs had their numbers assigned at detection time, as opposed to when the interrupt is registered, thus making it a stable number for a single boot, at least. The same is probably true for MSI(-X); we could assign it a range of numbers when the device is enumerated (as opposed to when a driver is activated), but I don't know to what extent that is likely to cause more troubles than it solves.

Quoted 7 lines
Quoted 4 lines

how to find the range for MSIX, one device/func may need a lot. for example, niu driver could use 20 MSI-X for one port. (one dev/func) some could use 256. we only know that when driver is loaded.
So as Eric said, just try to use 12bits (4k range) for them.

You can know how many vectors are exported in generic code. However, using 4k per should be fine.

so we have one list to map domain/bus/dev/func to bits [31,12] in irq ?

YH

#65 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 3 lines · Yinghai Lu

so we have one list to map domain/bus/dev/func to bits [31,12] in irq ?

That works, although having a more generic allocation mechanism which isn't so tied to MSI-X would make more sense.

-hpa

#66 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · H. Peter Anvin
Quoted 2 lines · Yinghai Lu

so we have one list to map domain/bus/dev/func to bits [31,12] in irq ?

That works, although having a more generic allocation mechanism which isn't so tied to MSI-X would make more sense.

-hpa

Hmm, I see I picked up this conversation quite late. I would agree that trying to map any set of fixed bit fields to domain/bus/device/function would be problematic (esp. since I don't understand how MSI's figure into the deal.)

Is there some reason why we need that?

Thanks,
Mike

#67 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to H. Peter Anvin
Quoted 7 lines · H. Peter Anvin
Quoted 3 lines · Yinghai Lu

so we have one list to map domain/bus/dev/func to bits [31,12] in irq ?

That works, although having a more generic allocation mechanism which isn't so tied to MSI-X would make more sense.

None of that should be related to the linux interrupt number.

Ben.

#68 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to H. Peter Anvin
Quoted 7 lines · H. Peter Anvin

It would, however, be a good idea if IOAPICs had their numbers assigned at detection time, as opposed to when the interrupt is registered, thus making it a stable number for a single boot, at least. The same is probably true for MSI(-X); we could assign it a range of numbers when the device is enumerated (as opposed to when a driver is activated), but I don't know to what extent that is likely to cause more troubles than it solves.

On powerpc, we establish the mapping at PCI probe time so it's reasonably stable. In fact, we even try to use virq == hwirq number if the hwirq number fits and is available though I'm tempted to remove that "feature" as it can make things more confusing in the end with some interrupts having matching HW numbers and some not.

Cheers,
Ben.

#69 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Yinghai Lu
Quoted 23 lines · Yinghai Lu
Quoted 21 lines · H. Peter Anvin
Quoted 6 lines · Yinghai Lu
Quoted 4 lines · H. Peter Anvin
Quoted 2 lines · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

Quoted 9 lines
Quoted 6 lines

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

you want to u64 instead of unsigned int for irq?

No, I think the whole notion of a static *numeric* identifier for an IRQ when it's something like MSI-X is simply pointless. I think we should assign IRQ numbers beyond the legacy range dynamically.

Quoted 6 lines
Quoted 3 lines

I really don't think anyone gives a hoot about the IRQ number for any IRQ above the 0-15 legacy range, even including the "APIC" numbers 16+.

you want to change ioapic/pin to irq mapping too?

I would like to see that. I'm already doing this in the Xen dom0 code interrupt code that I posted the other day.

J

#70 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to H. Peter Anvin
Quoted 4 lines · H. Peter Anvin

No, I think the whole notion of a static *numeric* identifier for an IRQ when it's something like MSI-X is simply pointless. I think we should assign IRQ numbers beyond the legacy range dynamically.

Yup, exactly. Which is what we do on other platforms :-)

I think there is some value in getting rid of the irq_desc static array, and to a certain extend having the ability to have irq_desc's be per-cpu allocated but I think that patch tries to mix up way too many different things, including a dubious attempt at tying the interrupt subsystem into a specific implementation choice of x86 platforms for numbering.

Linux interrupts should just be a dynamically allocated number space, with an exception for the 16 first ones (0 = illegal, 1...15 = legacy) and that should be -separate- from the actual HW number of one on a given PIC. In fact, powerpc handles multiple HW interrupt domain numbers just fine that way which is very useful for embedded platforms with funky cascaded PIC setups..

Ben.

#71 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to Yinghai Lu
Quoted 6 lines
Quoted 4 lines

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

you want to u64 instead of unsigned int for irq?

No, separate HW number from linux logic number. The later can remain u32 or even u16 if you want :-)

Ben.

#72 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to H. Peter Anvin
Quoted 10 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

-hpa

Hmm, I was going to bring this up as well... ;-)

X was changed quite a while ago to domain/bus/dev/func, which was a lot easier to deal with than trying to "offset" the bus with domain * some large number + bus. Currently max nodes is 512 so it deserves it's own field. ;-)

Btw, are you suggesting combining device and function? That might be inadvertently squeezing something that shouldn't be.

Thanks,
Mike

#73 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · Mike Travis

X was changed quite a while ago to domain/bus/dev/func, which was a lot easier to deal with than trying to "offset" the bus with domain * some large number + bus. Currently max nodes is 512 so it deserves it's own field. ;-)

Btw, are you suggesting combining device and function? That might be inadvertently squeezing something that shouldn't be.

devfn = (device << 3) + function

It's a standard construct inside Linux.

-hpa

#74 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

In reply to H. Peter Anvin
Quoted 8 lines · H. Peter Anvin
Quoted 1 line · Yinghai Lu

2. make irq number is bus/devfn/idx, and every dev func will use 12bit range, irq number is relatively fixed not like current MSI irq creating is some kind of floating from NR_IRQS too.

2 is *STILL WRONG*, dammit!

You keep bringing this one up, but our PCI addressing is *DOMAIN*/bus/devfn -- it falls flat on its face when you have more than 16 PCI domains. CAN WE PLEASE STOP WITH THIS FOOLISHNESS NOW!

Besides, the relationship between PCI location and IRQ numbers seems to be an x86 thingy ... don't bring that into the generic code please !

IRQ numbers are arbitrary, some platforms make up numbers out of the blue, or they can be hypervisor internal tokens etc...

The only sane way to handle this generically IMHO is to do what we do on powerpc (and I think sparc64) which is to totally disconnect the HW number from the "linux" number.

Ben.

#75 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 8 lines · Benjamin Herrenschmidt

IRQ numbers are arbitrary, some platforms make up numbers out of the blue, or they can be hypervisor internal tokens etc...

The only sane way to handle this generically IMHO is to do what we do on powerpc (and I think sparc64) which is to totally disconnect the HW number from the "linux" number.

Yes, that's what I want to see, too. On x86, it's important to preserve the first 16 (BIOS-compatible, XT-PIC) numbers, as they are widely used as a user interface, but for the rest, there is no point.

It is probably desirable to do that by overlaying the first (primary, south bridge) IO-APIC, which also takes care of the "semi-legacy" IRQ 16-23 numbers.

-hpa

#76 lore raw

Re: [PATCH] sparse_irq aka dyn_irq v13

Quoted 5 lines · H. Peter Anvin
Quoted 4 lines · Benjamin Herrenschmidt

IRQ numbers are arbitrary, some platforms make up numbers out of the blue, or they can be hypervisor internal tokens etc...

Quoted 8 lines
Quoted 4 lines

The only sane way to handle this generically IMHO is to do what we do on powerpc (and I think sparc64) which is to totally disconnect the HW number from the "linux" number.

Yes, that's what I want to see, too. On x86, it's important to preserve the first 16 (BIOS-compatible, XT-PIC) numbers, as they are widely used as a user interface, but for the rest, there is no point.

Right, and I do that on powerpc by reserving those numbers so they get automatically assigned to and only to the PIC that comes up as claiming the legacy number space (if any, if none, then they remain unassigned to avoid problems with old crappy modules hard coding IRQ numbers and trying to request them).

Quoted 3 lines

It is probably desirable to do that by overlaying the first (primary, south bridge) IO-APIC, which also takes care of the "semi-legacy" IRQ 16-23 numbers.

Would make sense indeed to treat those numbers specifically.

Ben.

#77 lore raw
In reply to Ingo Molnar
Quoted 12 lines · Ingo Molnar
Quoted 12 lines

+++ linux-2.6/arch/x86/mm/init_32.c

arch/x86/mm/init_32.c +1 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata table
 static unsigned long __meminitdata table_top;
 
 static int __initdata after_init_bootmem;
+int after_bootmem;
 
 static __init void *alloc_low_page(unsigned long *phys)
 {
@@ -987,6 +988,8 @@ void __init mem_init(void)
 
Quoted 7 lines

arch/x86/mm/init_32.c void __init mem_init(void) · line 991

Quoted 3 lines
arch/x86/mm/init_32.c +1 -0
 	set_highmem_pages_init();
 
+	after_bootmem = 1;

this hack can go away once we have a proper percpu_alloc() that can be used early enough.

Also, flags should be "bool". We're not aggressively going after old code to convert it, but new code should use "bool".

-hpa

#78 lore raw
In reply to Yinghai Lu

[Yinghai Lu - Sat, Nov 08, 2008 at 11:05:55PM -0800]

| 
| impact: new feature sparseirq
| 
| for sparse_irq, irq_desc, and irq_cfg is not using list_head to chain up
| also not add per_cpu_dyn_array... no user now
| 
| add some kind of hash table as Ingo suggesting.
| remove dyna_array, and enable sparse_irq by default, use kzalloc_node to get it
| use desc->chip_data for x86 to store irq_cfg
| make irq_desc to go with affinity aka irq_desc moving etc
| only call move_irq_desc in irq_complete_move() --- but it seems not trigger that moving.
| 
| Signed-off-by: Yinghai Lu <[email protected]>
| 
| ---

Hi Yinghai,

from a glance view (didn't read the whole patch)

...

|  
| -static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
| +static struct irq_cfg *get_one_free_irq_cfg(int cpu)
|  {
| -	return irq_cfg(irq);
| +	struct irq_cfg *cfg;
| +	int node;
| +
| +	if (cpu < 0)
| +		cpu = smp_processor_id();
| +	node = cpu_to_node(cpu);
| +
| +	cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
| +	printk(KERN_DEBUG "  alloc irq_cfg on cpu %d node %d\n", cpu, node);
| +
| +	return cfg;
|  }
|  
| -/*
| - * Rough estimation of how many shared IRQs there are, can be changed
| - * anytime.
| - */
| -#define MAX_PLUS_SHARED_IRQS NR_IRQS
| -#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
| +static void free_irq_cfg(struct irq_cfg *cfg)
| +{
| +	kfree(cfg);
| +}
| +
| +void arch_init_chip_data(struct irq_desc *desc, int cpu)
| +{
| +	struct irq_cfg *cfg;
| +
| +	cfg = desc->chip_data;
| +	if (!cfg)
| +		desc->chip_data = get_one_free_irq_cfg(cpu);
| +}
| +
| +static void init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg,
| +				 int cpu);
| +
| +void arch_init_copy_chip_data(struct irq_desc *old_desc,
| +				 struct irq_desc *desc, int cpu)
| +{
| +	struct irq_cfg *cfg;
| +	struct irq_cfg *old_cfg;
| +
| +	cfg = get_one_free_irq_cfg(cpu);
| +	desc->chip_data = cfg;
| +
| +	old_cfg = old_desc->chip_data;
| +
| +	memcpy(cfg, old_cfg, sizeof(struct irq_cfg));

If cfg gets NULL here we will be NULL-dereferring
(cause of possible kzalloc_node fails).

| +
| +	init_copy_irq_2_pin(old_cfg, cfg, cpu);
| +}
| +

...

Am I missgin something?

- Cyrill -