|
@@ -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 */
|
|
|
|
|
@@ -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)
|
|
@@ -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);
|
|
|
}
|