public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Dean Nelson <dcn@sgi.com>
To: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alan Mayer <ajm@sgi.com>, Ingo Molnar <mingo@elte.hu>,
	jeremy@goop.org, rusty@rustcorp.com.au,
	suresh.b.siddha@intel.com, torvalds@linux-foundation.org,
	linux-kernel@vger.kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Yinghai Lu <Yinghai.lu@amd.com>
Subject: [RFC 2/4] introduce dynamically allocated system vectors
Date: Thu, 11 Sep 2008 10:27:32 -0500	[thread overview]
Message-ID: <20080911152732.GC13655@sgi.com> (raw)
In-Reply-To: <20080911152304.GA13655@sgi.com>

Introduce the dynamic allocation and deallocation of system vectors which
are mapped to irq numbers allowing the use of request_irq()/free_irq().

Signed-off-by: Dean Nelson <dcn@sgi.com>

---

 arch/x86/kernel/apic.c        |    3 
 arch/x86/kernel/io_apic.c     |  264 +++++++++++++++++++++++++++++++++-----
 arch/x86/kernel/irqinit_64.c  |    4 
 include/asm-x86/desc.h        |   13 +
 include/asm-x86/irq_vectors.h |    1 
 include/linux/irq.h           |   13 +
 6 files changed, 258 insertions(+), 40 deletions(-)

Index: linux/arch/x86/kernel/io_apic.c
===================================================================
--- linux.orig/arch/x86/kernel/io_apic.c	2008-09-10 12:08:46.000000000 -0500
+++ linux/arch/x86/kernel/io_apic.c	2008-09-11 07:17:33.000000000 -0500
@@ -1205,7 +1205,34 @@ void unlock_vector_lock(void)
 	spin_unlock(&vector_lock);
 }
 
-static int __assign_irq_vector(int irq, cpumask_t mask)
+bool __grab_irq_vector(struct irq_desc *desc, unsigned int vector,
+		       cpumask_t *new_domain_mask)
+{
+	/* Must be called with vector lock */
+	struct irq_cfg *cfg;
+	int cpu;
+
+	for_each_cpu_mask_nr(cpu, *new_domain_mask) {
+		if (per_cpu(vector_irq, cpu)[vector] != NULL)
+			return false;
+	}
+
+	/* Available reserve it */
+	for_each_cpu_mask_nr(cpu, *new_domain_mask)
+		per_cpu(vector_irq, cpu)[vector] = desc;
+
+	cfg = irq_cfg(desc->irq);
+	if (cfg->vector) {
+		cfg->move_in_progress = 1;
+		cfg->old_domain = cfg->domain;
+	}
+	cfg->vector = vector;
+	cfg->domain = *new_domain_mask;
+
+	return true;
+}
+
+static int __assign_irq_vector(int irq, cpumask_t *mask)
 {
 	/*
 	 * NOTE! The local APIC isn't very good at handling
@@ -1219,42 +1246,40 @@ static int __assign_irq_vector(int irq, 
 	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
 	 */
 	static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
-	unsigned int old_vector;
+	cpumask_t target_cpus_mask;
 	int cpu;
 	struct irq_cfg *cfg;
 	struct irq_desc *desc;
 
 	cfg = irq_cfg(irq);
 
-	/* Only try and allocate irqs on cpus that are present */
-	cpus_and(mask, mask, cpu_online_map);
-
 	if ((cfg->move_in_progress) || cfg->move_cleanup_count)
 		return -EBUSY;
 
-	old_vector = cfg->vector;
-	if (old_vector) {
+	/* Only try and allocate irqs on cpus that are present */
+	cpus_and(target_cpus_mask, *mask, cpu_online_map);
+
+	if (cfg->vector) {
 		cpumask_t tmp;
-		cpus_and(tmp, cfg->domain, mask);
+		cpus_and(tmp, cfg->domain, target_cpus_mask);
 		if (!cpus_empty(tmp))
 			return 0;
 	}
 
 	desc = irq_to_desc_alloc(irq);
 
-	for_each_cpu_mask_nr(cpu, mask) {
-		cpumask_t domain, new_mask;
-		int new_cpu;
+	for_each_cpu_mask_nr(cpu, target_cpus_mask) {
+		cpumask_t domain, new_domain_mask;
 		int vector, offset;
 
 		domain = vector_allocation_domain(cpu);
-		cpus_and(new_mask, domain, cpu_online_map);
+		cpus_and(new_domain_mask, domain, cpu_online_map);
 
 		vector = current_vector;
 		offset = current_offset;
 next:
 		vector += 8;
-		if (vector >= first_system_vector) {
+		if (vector > last_device_vector) {
 			/* If we run out of vectors on large boxen, must share them. */
 			offset = (offset + 1) % 8;
 			vector = FIRST_DEVICE_VECTOR + offset;
@@ -1268,20 +1293,12 @@ next:
 		if (vector == SYSCALL_VECTOR)
 			goto next;
 #endif
-		for_each_cpu_mask_nr(new_cpu, new_mask)
-			if (per_cpu(vector_irq, new_cpu)[vector] != NULL)
-				goto next;
+		if (!__grab_irq_vector(desc, vector, &new_domain_mask))
+			goto next;
+
 		/* Found one! */
 		current_vector = vector;
 		current_offset = offset;
-		if (old_vector) {
-			cfg->move_in_progress = 1;
-			cfg->old_domain = cfg->domain;
-		}
-		for_each_cpu_mask_nr(new_cpu, new_mask)
-			per_cpu(vector_irq, new_cpu)[vector] = desc;
-		cfg->vector = vector;
-		cfg->domain = domain;
 		return 0;
 	}
 	return -ENOSPC;
@@ -1293,11 +1310,51 @@ static int assign_irq_vector(int irq, cp
 	unsigned long flags;
 
 	spin_lock_irqsave(&vector_lock, flags);
-	err = __assign_irq_vector(irq, mask);
+	err = __assign_irq_vector(irq, &mask);
 	spin_unlock_irqrestore(&vector_lock, flags);
 	return err;
 }
 
+static int __assign_irq_system_vector(int irq, cpumask_t *mask, int priority)
+{
+	int vector;
+	cpumask_t target_cpus_mask;
+	int cpu;
+	cpumask_t domain;
+	cpumask_t new_domain_mask = CPU_MASK_NONE;
+	struct irq_desc *desc;
+
+	if (priority == IRQ_PRIORITY_HIGH)
+		vector = first_static_system_vector;
+	else if (priority == IRQ_PRIORITY_LOW)
+		vector = FIRST_DEVICE_VECTOR - 1;
+	else
+		BUG();
+
+	cpus_and(target_cpus_mask, *mask, cpu_possible_map);
+	for_each_cpu_mask_nr(cpu, target_cpus_mask) {
+		domain = vector_allocation_domain(cpu);
+		cpus_and(domain, domain, cpu_possible_map);
+		cpus_or(new_domain_mask, new_domain_mask, domain);
+	}
+
+	desc = irq_to_desc_alloc(irq);
+
+	do {
+		if (priority == IRQ_PRIORITY_HIGH) {
+			if (--vector < FIRST_DEVICE_VECTOR)
+				return -ENOSPC;
+		} else {	/* IRQ_PRIORITY_LOW */
+			if (++vector == first_static_system_vector)
+				return -ENOSPC;
+		}
+
+	} while (!__grab_irq_vector(desc, vector, &new_domain_mask));
+
+	/* found one */
+	return 0;
+}
+
 static void __clear_irq_vector(int irq)
 {
 	struct irq_cfg *cfg;
@@ -3045,21 +3102,22 @@ static int __init ioapic_init_sysfs(void
 
 device_initcall(ioapic_init_sysfs);
 
-/*
- * Dynamic irq allocate and deallocation
- */
-unsigned int create_irq_nr(unsigned int irq_want)
+#define DEVICE_VECTOR	1
+#define SYSTEM_VECTOR	2
+
+static unsigned int __create_irq_nr(int vector_type, unsigned int irq_want,
+				    cpumask_t *mask, int priority)
 {
 	/* Allocate an unused irq */
 	unsigned int irq;
 	unsigned int new;
 	unsigned long flags;
 	struct irq_cfg *cfg_new;
+	int ret;
 
 #ifndef CONFIG_HAVE_SPARSE_IRQ
 	irq_want = nr_irqs - 1;
 #endif
-
 	irq = 0;
 	spin_lock_irqsave(&vector_lock, flags);
 	for (new = irq_want; new > 0; new--) {
@@ -3071,18 +3129,34 @@ unsigned int create_irq_nr(unsigned int 
 		/* check if need to create one */
 		if (!cfg_new)
 			cfg_new = irq_cfg_alloc(new);
-		if (__assign_irq_vector(new, TARGET_CPUS) == 0)
+		if (vector_type == DEVICE_VECTOR)
+			ret = __assign_irq_vector(new, mask);
+		else
+			ret = __assign_irq_system_vector(new, mask, priority);
+
+		if (ret == 0)
 			irq = new;
 		break;
 	}
 	spin_unlock_irqrestore(&vector_lock, flags);
 
-	if (irq > 0) {
+	if (irq > 0)
 		dynamic_irq_init(irq);
-	}
+
 	return irq;
 }
 
+unsigned int create_irq_nr(unsigned int irq_want)
+{
+	cpumask_t mask = TARGET_CPUS;
+
+	return __create_irq_nr(DEVICE_VECTOR, irq_want, &mask,
+			       IRQ_PRIORITY_LOW);
+}
+
+/*
+ * Dynamic irq device vector allocation.
+ */
 int create_irq(void)
 {
 	int irq;
@@ -3095,6 +3169,9 @@ int create_irq(void)
 	return irq;
 }
 
+/*
+ * Dynamic irq device vector deallocation.
+ */
 void destroy_irq(unsigned int irq)
 {
 	unsigned long flags;
@@ -3109,6 +3186,127 @@ void destroy_irq(unsigned int irq)
 	spin_unlock_irqrestore(&vector_lock, flags);
 }
 
+static void noop(unsigned int irq)
+{
+}
+
+static unsigned int noop_ret(unsigned int irq)
+{
+	return 0;
+}
+
+static void ack_apic(unsigned int irq)
+{
+	ack_APIC_irq();
+}
+
+static struct irq_chip ack_apic_chip = {
+	.name		= "ack_apic",
+	.startup	= noop_ret,
+	.shutdown	= noop,
+	.enable		= noop,
+	.disable	= noop,
+	.ack		= noop,
+	.mask		= noop,
+	.unmask		= noop,
+	.eoi		= ack_apic,
+	.end		= noop,
+};
+
+unsigned int create_irq_system_vector_nr(unsigned int irq_want, cpumask_t *mask,
+					 int priority)
+{
+	return __create_irq_nr(SYSTEM_VECTOR, irq_want, mask, priority);
+}
+
+/*
+ * Dynamic irq system vector allocation.
+ */
+unsigned int create_irq_system_vector(cpumask_t *mask, int priority,
+				      char *irq_name, int *assigned_vector)
+{
+	unsigned long flags;
+	struct irq_cfg *cfg;
+	int irq;
+
+	/* allocate an available irq and vector mapping */
+	irq = create_irq_system_vector_nr(nr_irqs - 1, mask, priority);
+	if (irq == 0)
+		return -1;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	set_irq_chip_and_handler_name(irq, &ack_apic_chip, handle_percpu_irq,
+				      irq_name);
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	cfg = irq_cfg(irq);
+	*assigned_vector = cfg->vector;
+	return irq;
+}
+EXPORT_SYMBOL(create_irq_system_vector);
+
+/*
+ * Dynamic irq system vector deallocation.
+ */
+void destroy_irq_system_vector(unsigned int irq)
+{
+	unsigned long flags;
+	struct irq_cfg *cfg;
+	int cpu;
+
+	if (irq >= nr_irqs)
+		return;
+	cfg = irq_cfg(irq);
+	if (cfg->vector == 0)
+		return;
+
+#ifdef CONFIG_SMP
+	synchronize_irq(irq);
+#endif
+	dynamic_irq_cleanup(irq);
+	disable_irq(irq);
+
+	spin_lock_irqsave(&vector_lock, flags);
+
+	for_each_cpu_mask_nr(cpu, cfg->domain)
+		per_cpu(vector_irq, cpu)[cfg->vector] = NULL;
+
+	cfg->vector = 0;
+	cpus_clear(cfg->domain);
+
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
+EXPORT_SYMBOL(destroy_irq_system_vector);
+
+int reserve_system_vectors(int number)
+{
+	unsigned long flags;
+	int new_last_device_vector;
+	int vector;
+	int cpu;
+	int ret = -EBUSY;
+
+	spin_lock_irqsave(&vector_lock, flags);
+
+	new_last_device_vector = last_device_vector - number;
+	if (new_last_device_vector < MIN_LAST_DEVICE_VECTOR)
+		goto out;
+
+	for (vector = last_device_vector; vector > new_last_device_vector;
+	     vector--) {
+		for_each_cpu_mask_nr(cpu, cpu_possible_map) {
+			if (per_cpu(vector_irq, cpu)[vector] != NULL)
+				goto out;
+		}
+	}
+
+	last_device_vector = new_last_device_vector;
+	ret = 0;
+out:
+	spin_unlock_irqrestore(&vector_lock, flags);
+	return ret;
+}
+
 /*
  * MSI message composition
  */
Index: linux/include/linux/irq.h
===================================================================
--- linux.orig/include/linux/irq.h	2008-09-10 12:08:46.000000000 -0500
+++ linux/include/linux/irq.h	2008-09-11 06:53:16.000000000 -0500
@@ -390,11 +390,22 @@ set_irq_chained_handler(unsigned int irq
 extern void set_irq_noprobe(unsigned int irq);
 extern void set_irq_probe(unsigned int irq);
 
-/* Handle dynamic irq creation and destruction */
+/* Handle dynamic irq device vector allocation and deallocation */
 extern unsigned int create_irq_nr(unsigned int irq_want);
 extern int create_irq(void);
 extern void destroy_irq(unsigned int irq);
 
+/* Handle dynamic irq system vector allocation and deallocation */
+extern unsigned int create_irq_system_vector(cpumask_t *mask, int priority,
+					     char *irq_name,
+					     int *assigned_vector);
+#define IRQ_PRIORITY_LOW	1
+#define IRQ_PRIORITY_HIGH	2
+
+extern void destroy_irq_system_vector(unsigned int irq);
+
+extern int reserve_system_vectors(int number);
+
 /* Test to see if a driver has successfully requested an irq */
 static inline int irq_has_action(unsigned int irq)
 {
Index: linux/arch/x86/kernel/apic.c
===================================================================
--- linux.orig/arch/x86/kernel/apic.c	2008-09-10 12:08:46.000000000 -0500
+++ linux/arch/x86/kernel/apic.c	2008-09-11 06:42:34.000000000 -0500
@@ -116,7 +116,8 @@ static int disable_apic_timer __cpuinitd
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 
-int first_system_vector = 0xfe;
+int first_static_system_vector = 0xfe;
+int last_device_vector = 0xfd;
 
 char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
 
Index: linux/include/asm-x86/desc.h
===================================================================
--- linux.orig/include/asm-x86/desc.h	2008-09-10 12:08:46.000000000 -0500
+++ linux/include/asm-x86/desc.h	2008-09-11 06:42:34.000000000 -0500
@@ -323,22 +323,25 @@ static inline void set_intr_gate(unsigne
 #define SYS_VECTOR_FREE		0
 #define SYS_VECTOR_ALLOCED	1
 
-extern int first_system_vector;
+extern int first_static_system_vector;
+extern int last_device_vector;
 extern char system_vectors[];
 
-static inline void alloc_system_vector(int vector)
+static inline void alloc_static_system_vector(int vector)
 {
 	if (system_vectors[vector] == SYS_VECTOR_FREE) {
 		system_vectors[vector] = SYS_VECTOR_ALLOCED;
-		if (first_system_vector > vector)
-			first_system_vector = vector;
+		if (first_static_system_vector > vector)
+			first_static_system_vector = vector;
+		if (last_device_vector > vector - 1)
+			last_device_vector = vector - 1;
 	} else
 		BUG();
 }
 
 static inline void alloc_intr_gate(unsigned int n, void *addr)
 {
-	alloc_system_vector(n);
+	alloc_static_system_vector(n);
 	set_intr_gate(n, addr);
 }
 
Index: linux/include/asm-x86/irq_vectors.h
===================================================================
--- linux.orig/include/asm-x86/irq_vectors.h	2008-09-05 08:38:48.000000000 -0500
+++ linux/include/asm-x86/irq_vectors.h	2008-09-11 07:14:54.000000000 -0500
@@ -92,6 +92,7 @@
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	(IRQ15_VECTOR + 2)
+#define MIN_LAST_DEVICE_VECTOR	(LOCAL_TIMER_VECTOR - 16)
 
 #define NR_VECTORS		256
 
Index: linux/arch/x86/kernel/irqinit_64.c
===================================================================
--- linux.orig/arch/x86/kernel/irqinit_64.c	2008-09-09 12:57:13.000000000 -0500
+++ linux/arch/x86/kernel/irqinit_64.c	2008-09-11 07:21:41.000000000 -0500
@@ -22,6 +22,7 @@
 #include <asm/desc.h>
 #include <asm/apic.h>
 #include <asm/i8259.h>
+#include <asm/genapic.h>
 
 /*
  * Common place to define all x86 IRQ vectors
@@ -202,6 +203,9 @@ void __init native_init_IRQ(void)
 	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
 	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
+	if (is_uv_system())
+		reserve_system_vectors(8);
+
 	if (!acpi_ioapic)
 		setup_irq(2, &irq2);
 }

  parent reply	other threads:[~2008-09-11 15:27 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-08 15:37 [Fwd: [PATCH] x86_64: (NEW) Dynamically allocate arch specific system vectors] Alan Mayer
2008-08-11 16:59 ` [PATCH] x86_64: (NEW) Dynamically allocate arch specific system vectors Ingo Molnar
2008-08-11 17:14   ` Alan Mayer
2008-08-11 19:39     ` Eric W. Biederman
2008-08-11 19:51       ` Ingo Molnar
2008-08-11 19:55         ` Jeremy Fitzhardinge
2008-08-11 20:10         ` Eric W. Biederman
2008-08-11 20:02       ` Alan Mayer
2008-09-11 15:23       ` [RFC 0/4] dynamically " Dean Nelson
2008-09-11 15:25         ` [RFC 1/4] switch vector_irq[] from irq number to irq_desc pointer Dean Nelson
2008-09-11 15:27         ` Dean Nelson [this message]
2008-09-14 15:39           ` [RFC 2/4] introduce dynamically allocated system vectors Ingo Molnar
2008-09-14 15:46           ` Ingo Molnar
2008-09-11 15:28         ` [RFC 3/4] switch static system vector allocation to use vector_irq[] Dean Nelson
2008-09-11 15:29         ` [RFC 4/4] switch non-standard SYSCALL_VECTOR " Dean Nelson
2008-09-14 15:40           ` Ingo Molnar
2008-09-14 15:42           ` Ingo Molnar
2008-09-11 20:04         ` [RFC 0/4] dynamically allocate arch specific system vectors H. Peter Anvin
2008-09-12 11:46           ` Dean Nelson
2008-09-14 15:35         ` Ingo Molnar
2008-09-14 15:48           ` Ingo Molnar
2008-09-15 21:50           ` Dean Nelson
2008-09-16  8:24             ` Ingo Molnar
2008-09-16 20:46               ` Dean Nelson
2008-09-17 17:30                 ` Dimitri Sivanich
2008-09-17 18:59                   ` Eric W. Biederman
2008-09-18 13:37                     ` Dean Nelson
2008-09-18 19:18                       ` H. Peter Anvin
2008-09-17 19:15                 ` H. Peter Anvin
2008-09-17 20:21                   ` Jack Steiner
2008-09-17 22:15                     ` Eric W. Biederman
2008-09-18  1:09                       ` H. Peter Anvin
2008-09-18 19:10                       ` Jack Steiner
2008-09-19  0:28                         ` Eric W. Biederman
2008-09-19  8:48                           ` Ingo Molnar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080911152732.GC13655@sgi.com \
    --to=dcn@sgi.com \
    --cc=Yinghai.lu@amd.com \
    --cc=ajm@sgi.com \
    --cc=ebiederm@xmission.com \
    --cc=hpa@zytor.com \
    --cc=jeremy@goop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=rusty@rustcorp.com.au \
    --cc=suresh.b.siddha@intel.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox