aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/sh4a/smp-shx3.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/sh4a/smp-shx3.c')
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c67
1 files changed, 25 insertions, 42 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
index e5e06845fa43..b8869aa20dec 100644
--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * SH-X3 SMP 2 * SH-X3 SMP
3 * 3 *
4 * Copyright (C) 2007 Paul Mundt 4 * Copyright (C) 2007 - 2008 Paul Mundt
5 * Copyright (C) 2007 Magnus Damm 5 * Copyright (C) 2007 Magnus Damm
6 * 6 *
7 * This file is subject to the terms and conditions of the GNU General Public 7 * This file is subject to the terms and conditions of the GNU General Public
@@ -14,6 +14,22 @@
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/io.h> 15#include <linux/io.h>
16 16
17static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
18{
19 unsigned int message = (unsigned int)(long)arg;
20 unsigned int cpu = hard_smp_processor_id();
21 unsigned int offs = 4 * cpu;
22 unsigned int x;
23
24 x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
25 x &= (1 << (message << 2));
26 ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
27
28 smp_message_recv(message);
29
30 return IRQ_HANDLED;
31}
32
17void __init plat_smp_setup(void) 33void __init plat_smp_setup(void)
18{ 34{
19 unsigned int cpu = 0; 35 unsigned int cpu = 0;
@@ -40,6 +56,13 @@ void __init plat_smp_setup(void)
40 56
41void __init plat_prepare_cpus(unsigned int max_cpus) 57void __init plat_prepare_cpus(unsigned int max_cpus)
42{ 58{
59 int i;
60
61 BUILD_BUG_ON(SMP_MSG_NR >= 8);
62
63 for (i = 0; i < SMP_MSG_NR; i++)
64 request_irq(104 + i, ipi_interrupt_handler, IRQF_DISABLED,
65 "IPI", (void *)(long)i);
43} 66}
44 67
45#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) 68#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
@@ -59,7 +82,7 @@ void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
59 ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); 82 ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
60 83
61 while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 84 while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
62 ; 85 cpu_relax();
63 86
64 /* Start up secondary processor by sending a reset */ 87 /* Start up secondary processor by sending a reset */
65 ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); 88 ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
@@ -75,46 +98,6 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
75 unsigned long addr = 0xfe410070 + (cpu * 4); 98 unsigned long addr = 0xfe410070 + (cpu * 4);
76 99
77 BUG_ON(cpu >= 4); 100 BUG_ON(cpu >= 4);
78 BUG_ON(message >= SMP_MSG_NR);
79 101
80 ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ 102 ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
81} 103}
82
83struct ipi_data {
84 void (*handler)(void *);
85 void *arg;
86 unsigned int message;
87};
88
89static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
90{
91 struct ipi_data *id = arg;
92 unsigned int cpu = hard_smp_processor_id();
93 unsigned int offs = 4 * cpu;
94 unsigned int x;
95
96 x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
97 x &= (1 << (id->message << 2));
98 ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
99
100 id->handler(id->arg);
101
102 return IRQ_HANDLED;
103}
104
105static struct ipi_data ipi_handlers[SMP_MSG_NR];
106
107int plat_register_ipi_handler(unsigned int message,
108 void (*handler)(void *), void *arg)
109{
110 struct ipi_data *id = &ipi_handlers[message];
111
112 BUG_ON(SMP_MSG_NR >= 8);
113 BUG_ON(message >= SMP_MSG_NR);
114
115 id->handler = handler;
116 id->arg = arg;
117 id->message = message;
118
119 return request_irq(104 + message, ipi_interrupt_handler, 0, "IPI", id);
120}