summaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/smp.c
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-06-25 16:41:11 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-07-06 13:34:01 -0400
commitfb702b942bf638baa6cbbbda9f76794db62921ef (patch)
treec065b0ab61cbb80b6209c725836a6864624b3c46 /arch/tile/kernel/smp.c
parentde5d9bf6541736dc7ad264d2b5cc99bc1b2ad958 (diff)
arch/tile: Enable more sophisticated IRQ model for 32-bit chips.
This model is based on the on-chip interrupt model used by the TILE-Gx next-generation hardware, and interacts much more cleanly with the Linux generic IRQ layer. The change includes modifications to the Tilera hypervisor, which are reflected in the hypervisor headers in arch/tile/include/arch/. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/tile/kernel/smp.c')
-rw-r--r--arch/tile/kernel/smp.c72
1 files changed, 63 insertions, 9 deletions
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index 782c1bfa6df..1cb5ec79de0 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -15,10 +15,18 @@
*/
#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/module.h>
#include <asm/cacheflush.h>
HV_Topology smp_topology __write_once;
+EXPORT_SYMBOL(smp_topology);
+
+#if CHIP_HAS_IPI()
+static unsigned long __iomem *ipi_mappings[NR_CPUS];
+#endif
/*
@@ -100,7 +108,6 @@ void on_each_cpu_mask(const struct cpumask *mask, void (*func)(void *),
/* Handler to start the current cpu. */
static void smp_start_cpu_interrupt(void)
{
- extern unsigned long start_cpu_function_addr;
get_irq_regs()->pc = start_cpu_function_addr;
}
@@ -174,12 +181,8 @@ void flush_icache_range(unsigned long start, unsigned long end)
}
-/*
- * The smp_send_reschedule() path does not use the hv_message_intr()
- * path but instead the faster tile_dev_intr() path for interrupts.
- */
-
-irqreturn_t handle_reschedule_ipi(int irq, void *token)
+/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
+static irqreturn_t handle_reschedule_ipi(int irq, void *token)
{
/*
* Nothing to do here; when we return from interrupt, the
@@ -191,12 +194,63 @@ irqreturn_t handle_reschedule_ipi(int irq, void *token)
return IRQ_HANDLED;
}
+static struct irqaction resched_action = {
+ .handler = handle_reschedule_ipi,
+ .name = "resched",
+ .dev_id = handle_reschedule_ipi /* unique token */,
+};
+
+void __init ipi_init(void)
+{
+#if CHIP_HAS_IPI()
+ int cpu;
+ /* Map IPI trigger MMIO addresses. */
+ for_each_possible_cpu(cpu) {
+ HV_Coord tile;
+ HV_PTE pte;
+ unsigned long offset;
+
+ tile.x = cpu_x(cpu);
+ tile.y = cpu_y(cpu);
+ if (hv_get_ipi_pte(tile, 1, &pte) != 0)
+ panic("Failed to initialize IPI for cpu %d\n", cpu);
+
+ offset = hv_pte_get_pfn(pte) << PAGE_SHIFT;
+ ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte);
+ }
+#endif
+
+ /* Bind handle_reschedule_ipi() to IRQ_RESCHEDULE. */
+ tile_irq_activate(IRQ_RESCHEDULE, TILE_IRQ_PERCPU);
+ BUG_ON(setup_irq(IRQ_RESCHEDULE, &resched_action));
+}
+
+#if CHIP_HAS_IPI()
+
+void smp_send_reschedule(int cpu)
+{
+ WARN_ON(cpu_is_offline(cpu));
+
+ /*
+ * We just want to do an MMIO store. The traditional writeq()
+ * functions aren't really correct here, since they're always
+ * directed at the PCI shim. For now, just do a raw store,
+ * casting away the __iomem attribute.
+ */
+ ((unsigned long __force *)ipi_mappings[cpu])[IRQ_RESCHEDULE] = 0;
+}
+
+#else
+
void smp_send_reschedule(int cpu)
{
HV_Coord coord;
WARN_ON(cpu_is_offline(cpu));
- coord.y = cpu / smp_width;
- coord.x = cpu % smp_width;
+
+ coord.y = cpu_y(cpu);
+ coord.x = cpu_x(cpu);
hv_trigger_ipi(coord, IRQ_RESCHEDULE);
}
+
+#endif /* CHIP_HAS_IPI() */