summary refs log tree commit diff
path: root/arch/ia64/kernel/iosapic.c
diff options
context:
space:
mode:
authorYasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>2007-07-17 21:22:23 +0900
committerTony Luck <tony.luck@intel.com>2007-07-17 09:51:49 -0700
commite1b30a392835e92581db09a4e8b4b2ad53a0c370 (patch)
tree1a0dacd37e682dc4c2222f415f8035057d6bbc30 /arch/ia64/kernel/iosapic.c
parentf8c087f31e1d3fbf1f7d0b3ea5e643f535e7de04 (diff)
downloadlinux-e1b30a392835e92581db09a4e8b4b2ad53a0c370.tar.gz
[IA64] Add mapping table between irq and vector
Add mapping tables between irqs and vectors, and its management code.
This is necessary for supporting multiple vector domain because 1:1
mapping between irq and vector will be changed to n:1.

The irq == vector relationship between irqs and vectors is explicitly
remained for percpu interrupts, platform interrupts, isa IRQs and
vectors assigned using assign_irq_vector() because some programs might
depend on it.

And I should consider the following problem.

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: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/kernel/iosapic.c')
-rw-r--r--arch/ia64/kernel/iosapic.c61
1 files changed, 35 insertions, 26 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index cffb443a557c..cf27cfb4d165 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -117,6 +117,9 @@ static DEFINE_SPINLOCK(iosapic_lock);
  * These tables map IA-64 vectors to the IOSAPIC pin that generates this
  * vector.
  */
+
+#define NO_REF_RTE	0
+
 static struct iosapic {
 	char __iomem	*addr;		/* base address of IOSAPIC */
 	unsigned int	gsi_base;	/* GSI base */
@@ -204,7 +207,7 @@ inline int
 gsi_to_vector (unsigned int gsi)
 {
 	int irq = __gsi_to_irq(gsi);
-	if (irq < 0)
+	if (check_irq_used(irq) < 0)
 		return -1;
 	return irq_to_vector(irq);
 }
@@ -619,14 +622,18 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
 		iosapic_intr_info[irq].count++;
 		iosapic_lists[index].rtes_inuse++;
 	}
-	else if (irq_is_shared(irq)) {
+	else if (rte->refcnt == NO_REF_RTE) {
 		struct iosapic_intr_info *info = &iosapic_intr_info[irq];
-		if (info->trigger != trigger || info->polarity != polarity) {
+		if (info->count > 0 &&
+		    (info->trigger != trigger || info->polarity != polarity)){
 			printk (KERN_WARNING
 				"%s: cannot override the interrupt\n",
 				__FUNCTION__);
 			return -EINVAL;
 		}
+		rte->refcnt++;
+		iosapic_intr_info[irq].count++;
+		iosapic_lists[index].rtes_inuse++;
 	}
 
 	iosapic_intr_info[irq].polarity = polarity;
@@ -756,12 +763,17 @@ iosapic_register_intr (unsigned int gsi,
 	irq = __gsi_to_irq(gsi);
 	if (irq > 0) {
 		rte = find_rte(irq, gsi);
-		rte->refcnt++;
-		goto unlock_iosapic_lock;
-	}
+		if(iosapic_intr_info[irq].count == 0) {
+			assign_irq_vector(irq);
+			dynamic_irq_init(irq);
+		} else if (rte->refcnt != NO_REF_RTE) {
+			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)
@@ -832,18 +844,14 @@ iosapic_unregister_intr (unsigned int gsi)
 	if (--rte->refcnt > 0)
 		goto out;
 
-	/* Remove the rte entry from the list */
 	idesc = irq_desc + irq;
-	spin_lock(&idesc->lock);
-	list_del(&rte->rte_list);
-	spin_unlock(&idesc->lock);
+	rte->refcnt = NO_REF_RTE;
 
 	/* Mask the interrupt */
 	low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
 	iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
 
 	iosapic_intr_info[irq].count--;
-	iosapic_free_rte(rte);
 	index = find_iosapic(gsi);
 	iosapic_lists[index].rtes_inuse--;
 	WARN_ON(iosapic_lists[index].rtes_inuse < 0);
@@ -857,21 +865,20 @@ iosapic_unregister_intr (unsigned int gsi)
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 	       cpu_logical_id(dest), dest, irq_to_vector(irq));
 
-	if (list_empty(&iosapic_intr_info[irq].rtes)) {
-		/* Sanity check */
-		BUG_ON(iosapic_intr_info[irq].count);
+	if (iosapic_intr_info[irq].count == 0) {
 #ifdef CONFIG_SMP
 		/* Clear affinity */
 		cpus_setall(idesc->affinity);
 #endif
 		/* Clear the interrupt information */
-		memset(&iosapic_intr_info[irq], 0,
-		       sizeof(struct iosapic_intr_info));
+		iosapic_intr_info[irq].dest = 0;
+		iosapic_intr_info[irq].dmode = 0;
+		iosapic_intr_info[irq].polarity = 0;
+		iosapic_intr_info[irq].trigger = 0;
 		iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
-		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
 
-		/* Destroy IRQ */
-		destroy_irq(irq);
+		/* Destroy and reserve IRQ */
+		destroy_and_reserve_irq(irq);
 	}
  out:
 	spin_unlock_irqrestore(&iosapic_lock, flags);
@@ -892,8 +899,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 
 	switch (int_type) {
 	      case ACPI_INTERRUPT_PMI:
-		vector = iosapic_vector;
-		irq = vector;		/* FIXME */
+		irq = vector = iosapic_vector;
+		bind_irq_vector(irq, vector);
 		/*
 		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
 		 * we need to make sure the vector is available
@@ -909,8 +916,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 		delivery = IOSAPIC_INIT;
 		break;
 	      case ACPI_INTERRUPT_CPEI:
-		vector = IA64_CPE_VECTOR;
-		irq = vector;		/* FIXME */
+		irq = vector = IA64_CPE_VECTOR;
+		BUG_ON(bind_irq_vector(irq, vector));
 		delivery = IOSAPIC_LOWEST_PRIORITY;
 		mask = 1;
 		break;
@@ -945,8 +952,8 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
 	int vector, irq;
 	unsigned int dest = cpu_physical_id(smp_processor_id());
 
-	vector = isa_irq_to_vector(isa_irq);
-	irq = vector;	/* FIXME */
+	irq = vector = isa_irq_to_vector(isa_irq);
+	BUG_ON(bind_irq_vector(irq, vector));
 	register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
 	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
@@ -966,6 +973,8 @@ iosapic_system_init (int system_pcat_compat)
 		iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
 		/* mark as unused */
 		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
+
+		iosapic_intr_info[irq].count = 0;
 	}
 
 	pcat_compat = system_pcat_compat;