diff options
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r-- | arch/tile/kernel/smp.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index d3c4ed780ce2..07e3ff5cc740 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/irq_work.h> | ||
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
22 | #include <asm/cacheflush.h> | 23 | #include <asm/cacheflush.h> |
23 | #include <asm/homecache.h> | 24 | #include <asm/homecache.h> |
@@ -33,6 +34,8 @@ EXPORT_SYMBOL(smp_topology); | |||
33 | static unsigned long __iomem *ipi_mappings[NR_CPUS]; | 34 | static unsigned long __iomem *ipi_mappings[NR_CPUS]; |
34 | #endif | 35 | #endif |
35 | 36 | ||
37 | /* Does messaging work correctly to the local cpu? */ | ||
38 | bool self_interrupt_ok; | ||
36 | 39 | ||
37 | /* | 40 | /* |
38 | * Top-level send_IPI*() functions to send messages to other cpus. | 41 | * Top-level send_IPI*() functions to send messages to other cpus. |
@@ -147,6 +150,10 @@ void evaluate_message(int tag) | |||
147 | generic_smp_call_function_single_interrupt(); | 150 | generic_smp_call_function_single_interrupt(); |
148 | break; | 151 | break; |
149 | 152 | ||
153 | case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */ | ||
154 | irq_work_run(); | ||
155 | break; | ||
156 | |||
150 | default: | 157 | default: |
151 | panic("Unknown IPI message tag %d", tag); | 158 | panic("Unknown IPI message tag %d", tag); |
152 | break; | 159 | break; |
@@ -186,6 +193,15 @@ void flush_icache_range(unsigned long start, unsigned long end) | |||
186 | EXPORT_SYMBOL(flush_icache_range); | 193 | EXPORT_SYMBOL(flush_icache_range); |
187 | 194 | ||
188 | 195 | ||
196 | #ifdef CONFIG_IRQ_WORK | ||
197 | void arch_irq_work_raise(void) | ||
198 | { | ||
199 | if (arch_irq_work_has_interrupt()) | ||
200 | send_IPI_single(smp_processor_id(), MSG_TAG_IRQ_WORK); | ||
201 | } | ||
202 | #endif | ||
203 | |||
204 | |||
189 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ | 205 | /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ |
190 | static irqreturn_t handle_reschedule_ipi(int irq, void *token) | 206 | static irqreturn_t handle_reschedule_ipi(int irq, void *token) |
191 | { | 207 | { |
@@ -203,8 +219,22 @@ static struct irqaction resched_action = { | |||
203 | 219 | ||
204 | void __init ipi_init(void) | 220 | void __init ipi_init(void) |
205 | { | 221 | { |
222 | int cpu = smp_processor_id(); | ||
223 | HV_Recipient recip = { .y = cpu_y(cpu), .x = cpu_x(cpu), | ||
224 | .state = HV_TO_BE_SENT }; | ||
225 | int tag = MSG_TAG_CALL_FUNCTION_SINGLE; | ||
226 | |||
227 | /* | ||
228 | * Test if we can message ourselves for arch_irq_work_raise. | ||
229 | * This functionality is only available in the Tilera hypervisor | ||
230 | * in versions 4.3.4 and following. | ||
231 | */ | ||
232 | if (hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag)) == 1) | ||
233 | self_interrupt_ok = true; | ||
234 | else | ||
235 | pr_warn("Older hypervisor: disabling fast irq_work_raise\n"); | ||
236 | |||
206 | #if CHIP_HAS_IPI() | 237 | #if CHIP_HAS_IPI() |
207 | int cpu; | ||
208 | /* Map IPI trigger MMIO addresses. */ | 238 | /* Map IPI trigger MMIO addresses. */ |
209 | for_each_possible_cpu(cpu) { | 239 | for_each_possible_cpu(cpu) { |
210 | HV_Coord tile; | 240 | HV_Coord tile; |