[PATCH take2 13/13] Bind gsi to irq

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When pci drivers enabled/disabled devices dynamically, its irq number is
changed to the different one. Therefore, suspend/resume code may happen problem.

To fix this problem, I bound gsi to irq.

Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@xxxxxxxxxxxxxx>

---
 arch/ia64/kernel/iosapic.c  |   34 +++++++++++++++++----------
 arch/ia64/kernel/irq_ia64.c |   54 +++++++++++++++++++++++++++++++++++++-------
 include/asm-ia64/irq.h      |    2 +
 3 files changed, 69 insertions(+), 21 deletions(-)

Index: linux-2.6.22-rc5/arch/ia64/kernel/iosapic.c
===================================================================
--- linux-2.6.22-rc5.orig/arch/ia64/kernel/iosapic.c	2007-06-19 15:33:47.000000000 +0900
+++ linux-2.6.22-rc5/arch/ia64/kernel/iosapic.c	2007-06-19 15:34:05.000000000 +0900
@@ -113,6 +113,8 @@

 static DEFINE_SPINLOCK(iosapic_lock);

+#define GSI_IRQ_UNASSIGNED	(-1)
+
 /*
  * These tables map IA-64 vectors to the IOSAPIC pin that generates this
  * vector.
@@ -139,6 +141,7 @@ struct iosapic_rte_info {
 static struct iosapic_intr_info {
 	struct list_head rtes;		/* RTEs using this vector (empty =>
 					 * not an IOSAPIC interrupt) */
+	unsigned int	gsi;
 	int		count;		/* # of RTEs that shares this vector */
 	u32		low32;		/* current value of low word of
 					 * Redirection table entry */
@@ -184,15 +187,12 @@ find_iosapic (unsigned int gsi)
 static inline int __gsi_to_irq(unsigned int gsi)
 {
 	int irq;
-	struct iosapic_intr_info *info;
-	struct iosapic_rte_info *rte;

-	for (irq = 0; irq < NR_IRQS; irq++) {
-		info = &iosapic_intr_info[irq];
-		list_for_each_entry(rte, &info->rtes, rte_list)
-			if (rte->iosapic->gsi_base + rte->rte_index == gsi)
-				return irq;
+	for(irq = 0; irq < NR_IRQS; irq++) {
+		if(iosapic_intr_info[irq].gsi == gsi)
+			return irq;
 	}
+
 	return -1;
 }

@@ -645,6 +645,7 @@ register_intr (unsigned int gsi, int irq
 		}
 	}

+	iosapic_intr_info[irq].gsi = gsi;
 	iosapic_intr_info[irq].polarity = polarity;
 	iosapic_intr_info[irq].dmode    = delivery;
 	iosapic_intr_info[irq].trigger  = trigger;
@@ -772,13 +773,18 @@ iosapic_register_intr (unsigned int gsi,
 	spin_lock_irqsave(&iosapic_lock, flags);
 	irq = __gsi_to_irq(gsi);
 	if (irq > 0) {
-		rte = find_rte(irq, gsi);
-		rte->refcnt++;
-		goto unlock_iosapic_lock;
-	}
+		if(list_empty(&iosapic_intr_info[irq].rtes)) {
+			assign_irq_vector(irq);
+			dynamic_irq_init(irq);
+		} else {
+			rte = find_rte(irq, gsi);
+			rte->refcnt++;
+			goto unlock_iosapic_lock;
+		}
+	} else
+		irq = create_irq();

 	/* If vector is running out, we try to find a sharable vector */
-	irq = create_irq();
 	if (irq < 0) {
 		irq = iosapic_find_sharable_irq(trigger, polarity);
   		if (irq < 0)
@@ -885,10 +891,11 @@ iosapic_unregister_intr (unsigned int gs
 		memset(&iosapic_intr_info[irq], 0,
 		       sizeof(struct iosapic_intr_info));
 		iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+		iosapic_intr_info[irq].gsi = gsi;
 		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);

 		/* Destroy IRQ */
-		destroy_irq(irq);
+		destroy_and_reserve_irq(irq);
 	}
  out:
 	spin_unlock_irqrestore(&iosapic_lock, flags);
@@ -980,6 +987,7 @@ iosapic_system_init (int system_pcat_com
 	int irq;

 	for (irq = 0; irq < NR_IRQS; ++irq) {
+		iosapic_intr_info[irq].gsi = GSI_IRQ_UNASSIGNED;
 		iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
 		/* mark as unused */
 		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
Index: linux-2.6.22-rc5/arch/ia64/kernel/irq_ia64.c
===================================================================
--- linux-2.6.22-rc5.orig/arch/ia64/kernel/irq_ia64.c	2007-06-19 15:33:52.000000000 +0900
+++ linux-2.6.22-rc5/arch/ia64/kernel/irq_ia64.c	2007-06-19 15:34:05.000000000 +0900
@@ -49,6 +49,10 @@
 #define IRQ_VECTOR_UNASSIGNED	(0)
 #define VECTOR_IRQ_UNASSIGNED	(-1)

+#define IRQ_UNUSED		(0)
+#define IRQ_USED		(1)
+#define IRQ_RSVD 		(2)
+
 /* These can be overridden in platform_irq_init */
 int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
 int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -57,6 +61,8 @@ int ia64_last_device_vector = IA64_DEF_L
 void __iomem *ipi_base_addr = ((void __iomem *)
 			       (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));

+static cpumask_t vector_allocation_domain(int cpu);
+
 /*
  * Legacy IRQ to IA-64 vector translation table.
  */
@@ -84,12 +90,16 @@ static cpumask_t vector_table[IA64_MAX_D
 	[0 ... IA64_MAX_DEVICE_VECTORS - 1] = CPU_MASK_NONE
 };

+static int irq_status[NR_IRQS] = {
+	[0 ... NR_IRQS -1] = IRQ_UNUSED
+};
+
 static inline int find_unassigned_irq(void)
 {
 	int irq;

 	for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
-		if (irq_cfg[irq].vector == IRQ_VECTOR_UNASSIGNED)
+		if (irq_status[irq] == IRQ_UNUSED)
 			return irq;
 	return -ENOSPC;
 }
@@ -125,6 +135,7 @@ static int __bind_irq_vector(int irq, in
 		return 0;
 	if (cfg->vector != IRQ_VECTOR_UNASSIGNED)
 		return -EBUSY;
+	irq_status[irq] = IRQ_USED;
 	for_each_cpu_mask(cpu, mask)
 		per_cpu(vector_irq, cpu)[vector] = irq;
 	cfg->vector = vector;
@@ -160,6 +171,7 @@ static void __clear_irq_vector(int irq)
 		per_cpu(vector_irq, cpu)[vector] = VECTOR_IRQ_UNASSIGNED;
 	irq_cfg[irq].vector = IRQ_VECTOR_UNASSIGNED;
 	irq_cfg[irq].domain = CPU_MASK_NONE;
+	irq_status[irq] = IRQ_UNUSED;
 	pos = vector - IA64_FIRST_DEVICE_VECTOR;
 	cpus_andnot(vector_table[pos], vector_table[pos], domain);
 }
@@ -177,17 +189,26 @@ int
 assign_irq_vector (int irq)
 {
 	unsigned long flags;
-	int vector;
-
+	int vector, cpu;
+	cpumask_t domain;
+	vector = -ENOSPC;
 	spin_lock_irqsave(&vector_lock, flags);
-	vector = find_unassigned_vector(CPU_MASK_ALL);
+	if (irq < 0) {
+		goto out;
+	}
+	for_each_online_cpu(cpu) {
+		domain = vector_allocation_domain(cpu);
+		vector = find_unassigned_vector(domain);
+		if (vector >= 0)
+			break;
+	}
 	if (vector < 0)
 		goto out;
-	BUG_ON(__bind_irq_vector(vector, vector, CPU_MASK_ALL));
-	spin_unlock_irqrestore(&vector_lock, flags);
+	BUG_ON(__bind_irq_vector(irq, vector, domain));
  out:
-	return vector;
-}
+	spin_unlock_irqrestore(&vector_lock, flags);
+ 	return vector;
+ }

 void
 free_irq_vector (int vector)
@@ -288,6 +309,23 @@ int reassign_irq_vector(int irq, int cpu
 	return ret;
 }

+static void reserve_irq(unsigned int irq)
+{
+	irq_status[irq] = IRQ_RSVD;
+}
+
+void destroy_and_reserve_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	dynamic_irq_cleanup(irq);
+
+	spin_lock_irqsave(&vector_lock, flags);
+	__clear_irq_vector(irq);
+	reserve_irq(irq);
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
+
 /*
  * Dynamic irq allocate and deallocation for MSI
  */
Index: linux-2.6.22-rc5/include/asm-ia64/irq.h
===================================================================
--- linux-2.6.22-rc5.orig/include/asm-ia64/irq.h	2007-06-19 15:33:44.000000000 +0900
+++ linux-2.6.22-rc5/include/asm-ia64/irq.h	2007-06-19 15:34:05.000000000 +0900
@@ -35,6 +35,8 @@ extern void disable_irq_nosync (unsigned
 extern void enable_irq (unsigned int);
 extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
 bool is_affinity_mask_valid(cpumask_t cpumask);
+extern void destroy_and_reserve_irq(unsigned int irq);
+extern int assign_irq_vector(int irq);

 #define is_affinity_mask_valid is_affinity_mask_valid


-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Sparc Linux]     [DCCP]     [Linux ARM]     [Yosemite News]     [Linux SCSI]     [Linux x86_64]     [Linux for Ham Radio]

  Powered by Linux