- patches.suse/slab-handle-memoryless-nodes-v2a.patch: Refresh.
[linux-flexiantxendom0-3.2.10.git] / arch / powerpc / platforms / pseries / xics.c
index b9bf0ee..d80f193 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/cpu.h>
 #include <linux/msi.h>
 #include <linux/of.h>
+#include <linux/percpu.h>
 
 #include <asm/firmware.h>
 #include <asm/io.h>
@@ -46,6 +47,12 @@ static struct irq_host *xics_host;
  */
 #define IPI_PRIORITY           4
 
+/* The least favored priority */
+#define LOWEST_PRIORITY                0xFF
+
+/* The number of priorities defined above */
+#define MAX_NUM_PRIORITIES     3
+
 static unsigned int default_server = 0xFF;
 static unsigned int default_distrib_server = 0;
 static unsigned int interrupt_server_size = 8;
@@ -56,6 +63,12 @@ static int ibm_set_xive;
 static int ibm_int_on;
 static int ibm_int_off;
 
+struct xics_cppr {
+       unsigned char stack[MAX_NUM_PRIORITIES];
+       int index;
+};
+
+static DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
 
 /* Direct hardware low level accessors */
 
@@ -150,14 +163,13 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
 /* Interface to generic irq subsystem */
 
 #ifdef CONFIG_SMP
-static int get_irq_server(unsigned int virq, unsigned int strict_check)
+static int get_irq_server(unsigned int virq, cpumask_t cpumask,
+                         unsigned int strict_check)
 {
        int server;
        /* For the moment only implement delivery to all cpus or one cpu */
-       cpumask_t cpumask;
        cpumask_t tmp = CPU_MASK_NONE;
 
-       cpumask_copy(&cpumask, irq_desc[virq].affinity);
        if (!distribute_irqs)
                return default_server;
 
@@ -179,7 +191,8 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
        return default_server;
 }
 #else
-static int get_irq_server(unsigned int virq, unsigned int strict_check)
+static int get_irq_server(unsigned int virq, cpumask_t cpumask,
+                         unsigned int strict_check)
 {
        return default_server;
 }
@@ -198,7 +211,7 @@ static void xics_unmask_irq(unsigned int virq)
        if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
                return;
 
-       server = get_irq_server(virq, 0);
+       server = get_irq_server(virq, *(irq_to_desc(virq)->affinity), 0);
 
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
                                DEFAULT_PRIORITY);
@@ -284,6 +297,19 @@ static inline unsigned int xics_xirr_vector(unsigned int xirr)
        return xirr & 0x00ffffff;
 }
 
+static void push_cppr(unsigned int vec)
+{
+       struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+       if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1))
+               return;
+
+       if (vec == XICS_IPI)
+               os_cppr->stack[++os_cppr->index] = IPI_PRIORITY;
+       else
+               os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY;
+}
+
 static unsigned int xics_get_irq_direct(void)
 {
        unsigned int xirr = direct_xirr_info_get();
@@ -294,8 +320,10 @@ static unsigned int xics_get_irq_direct(void)
                return NO_IRQ;
 
        irq = irq_radix_revmap_lookup(xics_host, vec);
-       if (likely(irq != NO_IRQ))
+       if (likely(irq != NO_IRQ)) {
+               push_cppr(vec);
                return irq;
+       }
 
        /* We don't have a linux mapping, so have rtas mask it. */
        xics_mask_unknown_vec(vec);
@@ -315,8 +343,10 @@ static unsigned int xics_get_irq_lpar(void)
                return NO_IRQ;
 
        irq = irq_radix_revmap_lookup(xics_host, vec);
-       if (likely(irq != NO_IRQ))
+       if (likely(irq != NO_IRQ)) {
+               push_cppr(vec);
                return irq;
+       }
 
        /* We don't have a linux mapping, so have RTAS mask it. */
        xics_mask_unknown_vec(vec);
@@ -326,12 +356,22 @@ static unsigned int xics_get_irq_lpar(void)
        return NO_IRQ;
 }
 
+static unsigned char pop_cppr(void)
+{
+       struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+       if (WARN_ON(os_cppr->index < 1))
+               return LOWEST_PRIORITY;
+
+       return os_cppr->stack[--os_cppr->index];
+}
+
 static void xics_eoi_direct(unsigned int virq)
 {
        unsigned int irq = (unsigned int)irq_map[virq].hwirq;
 
        iosync();
-       direct_xirr_info_set((0xff << 24) | irq);
+       direct_xirr_info_set((pop_cppr() << 24) | irq);
 }
 
 static void xics_eoi_lpar(unsigned int virq)
@@ -339,7 +379,7 @@ static void xics_eoi_lpar(unsigned int virq)
        unsigned int irq = (unsigned int)irq_map[virq].hwirq;
 
        iosync();
-       lpar_xirr_info_set((0xff << 24) | irq);
+       lpar_xirr_info_set((pop_cppr() << 24) | irq);
 }
 
 static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
@@ -365,7 +405,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
         * For the moment only implement delivery to all cpus or one cpu.
         * Get current irq_server for the given irq
         */
-       irq_server = get_irq_server(virq, 1);
+       irq_server = get_irq_server(virq, *cpumask, 1);
        if (irq_server == -1) {
                char cpulist[128];
                cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
@@ -388,7 +428,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
 }
 
 static struct irq_chip xics_pic_direct = {
-       .typename = " XICS     ",
+       .name = " XICS     ",
        .startup = xics_startup,
        .mask = xics_mask_irq,
        .unmask = xics_unmask_irq,
@@ -397,7 +437,7 @@ static struct irq_chip xics_pic_direct = {
 };
 
 static struct irq_chip xics_pic_lpar = {
-       .typename = " XICS     ",
+       .name = " XICS     ",
        .startup = xics_startup,
        .mask = xics_mask_irq,
        .unmask = xics_unmask_irq,
@@ -428,13 +468,13 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
        /* Insert the interrupt mapping into the radix tree for fast lookup */
        irq_radix_revmap_insert(xics_host, virq, hw);
 
-       get_irq_desc(virq)->status |= IRQ_LEVEL;
+       irq_to_desc(virq)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq);
        return 0;
 }
 
 static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
-                          u32 *intspec, unsigned int intsize,
+                          const u32 *intspec, unsigned int intsize,
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
 {
@@ -746,6 +786,12 @@ void __init xics_init_IRQ(void)
 
 static void xics_set_cpu_priority(unsigned char cppr)
 {
+       struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+       BUG_ON(os_cppr->index != 0);
+
+       os_cppr->stack[os_cppr->index] = cppr;
+
        if (firmware_has_feature(FW_FEATURE_LPAR))
                lpar_cppr_info(cppr);
        else
@@ -772,7 +818,7 @@ static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
 
 void xics_setup_cpu(void)
 {
-       xics_set_cpu_priority(0xff);
+       xics_set_cpu_priority(LOWEST_PRIORITY);
 
        xics_set_cpu_giq(default_distrib_server, 1);
 }
@@ -852,7 +898,7 @@ void xics_migrate_irqs_away(void)
                /* We need to get IPIs still. */
                if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
                        continue;
-               desc = get_irq_desc(virq);
+               desc = irq_to_desc(virq);
 
                /* We only need to migrate enabled IRQS */
                if (desc == NULL || desc->chip == NULL
@@ -860,7 +906,7 @@ void xics_migrate_irqs_away(void)
                    || desc->chip->set_affinity == NULL)
                        continue;
 
-               spin_lock_irqsave(&desc->lock, flags);
+               raw_spin_lock_irqsave(&desc->lock, flags);
 
                status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
                if (status) {
@@ -881,10 +927,10 @@ void xics_migrate_irqs_away(void)
                       virq, cpu);
 
                /* Reset affinity to all cpus */
-               cpumask_setall(irq_desc[virq].affinity);
+               cpumask_setall(irq_to_desc(virq)->affinity);
                desc->chip->set_affinity(virq, cpu_all_mask);
 unlock:
-               spin_unlock_irqrestore(&desc->lock, flags);
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
        }
 }
 #endif