diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2010-06-25 16:41:11 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2010-07-06 13:34:01 -0400 |
commit | fb702b942bf638baa6cbbbda9f76794db62921ef (patch) | |
tree | c065b0ab61cbb80b6209c725836a6864624b3c46 /arch/tile/kernel/smp.c | |
parent | de5d9bf6541736dc7ad264d2b5cc99bc1b2ad958 (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.c | 72 |
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() */ |