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 <[EMAIL PROTECTED]>

---
 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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to