diff options
Diffstat (limited to 'arch/arc/kernel')
-rw-r--r-- | arch/arc/kernel/irq.c | 53 | ||||
-rw-r--r-- | arch/arc/kernel/signal.c | 47 | ||||
-rw-r--r-- | arch/arc/kernel/smp.c | 23 | ||||
-rw-r--r-- | arch/arc/kernel/time.c | 28 |
4 files changed, 72 insertions, 79 deletions
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 7d653c0d0773..620ec2fe32a9 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c | |||
@@ -19,21 +19,16 @@ | |||
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Early Hardware specific Interrupt setup | 21 | * Early Hardware specific Interrupt setup |
22 | * -Platform independent, needed for each CPU (not foldable into init_IRQ) | ||
22 | * -Called very early (start_kernel -> setup_arch -> setup_processor) | 23 | * -Called very early (start_kernel -> setup_arch -> setup_processor) |
23 | * -Platform Independent (must for any ARC700) | ||
24 | * -Needed for each CPU (hence not foldable into init_IRQ) | ||
25 | * | 24 | * |
26 | * what it does ? | 25 | * what it does ? |
27 | * -Disable all IRQs (on CPU side) | ||
28 | * -Optionally, setup the High priority Interrupts as Level 2 IRQs | 26 | * -Optionally, setup the High priority Interrupts as Level 2 IRQs |
29 | */ | 27 | */ |
30 | void arc_init_IRQ(void) | 28 | void arc_init_IRQ(void) |
31 | { | 29 | { |
32 | int level_mask = 0; | 30 | int level_mask = 0; |
33 | 31 | ||
34 | /* Disable all IRQs: enable them as devices request */ | ||
35 | write_aux_reg(AUX_IENABLE, 0); | ||
36 | |||
37 | /* setup any high priority Interrupts (Level2 in ARCompact jargon) */ | 32 | /* setup any high priority Interrupts (Level2 in ARCompact jargon) */ |
38 | level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3; | 33 | level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3; |
39 | level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5; | 34 | level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5; |
@@ -60,20 +55,28 @@ void arc_init_IRQ(void) | |||
60 | * below, per IRQ. | 55 | * below, per IRQ. |
61 | */ | 56 | */ |
62 | 57 | ||
63 | static void arc_mask_irq(struct irq_data *data) | 58 | static void arc_irq_mask(struct irq_data *data) |
64 | { | 59 | { |
65 | arch_mask_irq(data->irq); | 60 | unsigned int ienb; |
61 | |||
62 | ienb = read_aux_reg(AUX_IENABLE); | ||
63 | ienb &= ~(1 << data->irq); | ||
64 | write_aux_reg(AUX_IENABLE, ienb); | ||
66 | } | 65 | } |
67 | 66 | ||
68 | static void arc_unmask_irq(struct irq_data *data) | 67 | static void arc_irq_unmask(struct irq_data *data) |
69 | { | 68 | { |
70 | arch_unmask_irq(data->irq); | 69 | unsigned int ienb; |
70 | |||
71 | ienb = read_aux_reg(AUX_IENABLE); | ||
72 | ienb |= (1 << data->irq); | ||
73 | write_aux_reg(AUX_IENABLE, ienb); | ||
71 | } | 74 | } |
72 | 75 | ||
73 | static struct irq_chip onchip_intc = { | 76 | static struct irq_chip onchip_intc = { |
74 | .name = "ARC In-core Intc", | 77 | .name = "ARC In-core Intc", |
75 | .irq_mask = arc_mask_irq, | 78 | .irq_mask = arc_irq_mask, |
76 | .irq_unmask = arc_unmask_irq, | 79 | .irq_unmask = arc_irq_unmask, |
77 | }; | 80 | }; |
78 | 81 | ||
79 | static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, | 82 | static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq, |
@@ -150,6 +153,32 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs) | |||
150 | set_irq_regs(old_regs); | 153 | set_irq_regs(old_regs); |
151 | } | 154 | } |
152 | 155 | ||
156 | void arc_request_percpu_irq(int irq, int cpu, | ||
157 | irqreturn_t (*isr)(int irq, void *dev), | ||
158 | const char *irq_nm, | ||
159 | void *percpu_dev) | ||
160 | { | ||
161 | /* Boot cpu calls request, all call enable */ | ||
162 | if (!cpu) { | ||
163 | int rc; | ||
164 | |||
165 | /* | ||
166 | * These 2 calls are essential to making percpu IRQ APIs work | ||
167 | * Ideally these details could be hidden in irq chip map function | ||
168 | * but the issue is IPIs IRQs being static (non-DT) and platform | ||
169 | * specific, so we can't identify them there. | ||
170 | */ | ||
171 | irq_set_percpu_devid(irq); | ||
172 | irq_modify_status(irq, IRQ_NOAUTOEN, 0); /* @irq, @clr, @set */ | ||
173 | |||
174 | rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev); | ||
175 | if (rc) | ||
176 | panic("Percpu IRQ request failed for %d\n", irq); | ||
177 | } | ||
178 | |||
179 | enable_percpu_irq(irq, 0); | ||
180 | } | ||
181 | |||
153 | /* | 182 | /* |
154 | * arch_local_irq_enable - Enable interrupts. | 183 | * arch_local_irq_enable - Enable interrupts. |
155 | * | 184 | * |
diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 7e95e1a86510..cb3142a2d40b 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c | |||
@@ -141,17 +141,13 @@ badframe: | |||
141 | /* | 141 | /* |
142 | * Determine which stack to use.. | 142 | * Determine which stack to use.. |
143 | */ | 143 | */ |
144 | static inline void __user *get_sigframe(struct k_sigaction *ka, | 144 | static inline void __user *get_sigframe(struct ksignal *ksig, |
145 | struct pt_regs *regs, | 145 | struct pt_regs *regs, |
146 | unsigned long framesize) | 146 | unsigned long framesize) |
147 | { | 147 | { |
148 | unsigned long sp = regs->sp; | 148 | unsigned long sp = sigsp(regs->sp, ksig); |
149 | void __user *frame; | 149 | void __user *frame; |
150 | 150 | ||
151 | /* This is the X/Open sanctioned signal stack switching */ | ||
152 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | ||
153 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
154 | |||
155 | /* No matter what happens, 'sp' must be word | 151 | /* No matter what happens, 'sp' must be word |
156 | * aligned otherwise nasty things could happen | 152 | * aligned otherwise nasty things could happen |
157 | */ | 153 | */ |
@@ -179,14 +175,13 @@ static inline int map_sig(int sig) | |||
179 | } | 175 | } |
180 | 176 | ||
181 | static int | 177 | static int |
182 | setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info, | 178 | setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
183 | sigset_t *set, struct pt_regs *regs) | ||
184 | { | 179 | { |
185 | struct rt_sigframe __user *sf; | 180 | struct rt_sigframe __user *sf; |
186 | unsigned int magic = 0; | 181 | unsigned int magic = 0; |
187 | int err = 0; | 182 | int err = 0; |
188 | 183 | ||
189 | sf = get_sigframe(ka, regs, sizeof(struct rt_sigframe)); | 184 | sf = get_sigframe(ksig, regs, sizeof(struct rt_sigframe)); |
190 | if (!sf) | 185 | if (!sf) |
191 | return 1; | 186 | return 1; |
192 | 187 | ||
@@ -205,8 +200,8 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info, | |||
205 | * #2: struct siginfo | 200 | * #2: struct siginfo |
206 | * #3: struct ucontext (completely populated) | 201 | * #3: struct ucontext (completely populated) |
207 | */ | 202 | */ |
208 | if (unlikely(ka->sa.sa_flags & SA_SIGINFO)) { | 203 | if (unlikely(ksig->ka.sa.sa_flags & SA_SIGINFO)) { |
209 | err |= copy_siginfo_to_user(&sf->info, info); | 204 | err |= copy_siginfo_to_user(&sf->info, &ksig->info); |
210 | err |= __put_user(0, &sf->uc.uc_flags); | 205 | err |= __put_user(0, &sf->uc.uc_flags); |
211 | err |= __put_user(NULL, &sf->uc.uc_link); | 206 | err |= __put_user(NULL, &sf->uc.uc_link); |
212 | err |= __save_altstack(&sf->uc.uc_stack, regs->sp); | 207 | err |= __save_altstack(&sf->uc.uc_stack, regs->sp); |
@@ -227,16 +222,16 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info, | |||
227 | return err; | 222 | return err; |
228 | 223 | ||
229 | /* #1 arg to the user Signal handler */ | 224 | /* #1 arg to the user Signal handler */ |
230 | regs->r0 = map_sig(signo); | 225 | regs->r0 = map_sig(ksig->sig); |
231 | 226 | ||
232 | /* setup PC of user space signal handler */ | 227 | /* setup PC of user space signal handler */ |
233 | regs->ret = (unsigned long)ka->sa.sa_handler; | 228 | regs->ret = (unsigned long)ksig->ka.sa.sa_handler; |
234 | 229 | ||
235 | /* | 230 | /* |
236 | * handler returns using sigreturn stub provided already by userpsace | 231 | * handler returns using sigreturn stub provided already by userpsace |
237 | */ | 232 | */ |
238 | BUG_ON(!(ka->sa.sa_flags & SA_RESTORER)); | 233 | BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER)); |
239 | regs->blink = (unsigned long)ka->sa.sa_restorer; | 234 | regs->blink = (unsigned long)ksig->ka.sa.sa_restorer; |
240 | 235 | ||
241 | /* User Stack for signal handler will be above the frame just carved */ | 236 | /* User Stack for signal handler will be above the frame just carved */ |
242 | regs->sp = (unsigned long)sf; | 237 | regs->sp = (unsigned long)sf; |
@@ -298,38 +293,30 @@ static void arc_restart_syscall(struct k_sigaction *ka, struct pt_regs *regs) | |||
298 | * OK, we're invoking a handler | 293 | * OK, we're invoking a handler |
299 | */ | 294 | */ |
300 | static void | 295 | static void |
301 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 296 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
302 | struct pt_regs *regs) | ||
303 | { | 297 | { |
304 | sigset_t *oldset = sigmask_to_save(); | 298 | sigset_t *oldset = sigmask_to_save(); |
305 | int ret; | 299 | int ret; |
306 | 300 | ||
307 | /* Set up the stack frame */ | 301 | /* Set up the stack frame */ |
308 | ret = setup_rt_frame(sig, ka, info, oldset, regs); | 302 | ret = setup_rt_frame(ksig, oldset, regs); |
309 | 303 | ||
310 | if (ret) | 304 | signal_setup_done(ret, ksig, 0); |
311 | force_sigsegv(sig, current); | ||
312 | else | ||
313 | signal_delivered(sig, info, ka, regs, 0); | ||
314 | } | 305 | } |
315 | 306 | ||
316 | void do_signal(struct pt_regs *regs) | 307 | void do_signal(struct pt_regs *regs) |
317 | { | 308 | { |
318 | struct k_sigaction ka; | 309 | struct ksignal ksig; |
319 | siginfo_t info; | ||
320 | int signr; | ||
321 | int restart_scall; | 310 | int restart_scall; |
322 | 311 | ||
323 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
324 | |||
325 | restart_scall = in_syscall(regs) && syscall_restartable(regs); | 312 | restart_scall = in_syscall(regs) && syscall_restartable(regs); |
326 | 313 | ||
327 | if (signr > 0) { | 314 | if (get_signal(&ksig)) { |
328 | if (restart_scall) { | 315 | if (restart_scall) { |
329 | arc_restart_syscall(&ka, regs); | 316 | arc_restart_syscall(&ksig.ka, regs); |
330 | syscall_wont_restart(regs); /* No more restarts */ | 317 | syscall_wont_restart(regs); /* No more restarts */ |
331 | } | 318 | } |
332 | handle_signal(signr, &ka, &info, regs); | 319 | handle_signal(&ksig, regs); |
333 | return; | 320 | return; |
334 | } | 321 | } |
335 | 322 | ||
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index c802bb500602..dcd317c47d09 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c | |||
@@ -12,23 +12,15 @@ | |||
12 | * -- Initial Write (Borrowed heavily from ARM) | 12 | * -- Initial Write (Borrowed heavily from ARM) |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
18 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
19 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
20 | #include <linux/profile.h> | 18 | #include <linux/profile.h> |
21 | #include <linux/errno.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
24 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
25 | #include <linux/smp.h> | ||
26 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
27 | #include <linux/delay.h> | ||
28 | #include <linux/atomic.h> | 22 | #include <linux/atomic.h> |
29 | #include <linux/percpu.h> | ||
30 | #include <linux/cpumask.h> | 23 | #include <linux/cpumask.h> |
31 | #include <linux/spinlock_types.h> | ||
32 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
33 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
34 | #include <asm/setup.h> | 26 | #include <asm/setup.h> |
@@ -136,7 +128,7 @@ void start_kernel_secondary(void) | |||
136 | pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); | 128 | pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); |
137 | 129 | ||
138 | if (machine_desc->init_smp) | 130 | if (machine_desc->init_smp) |
139 | machine_desc->init_smp(smp_processor_id()); | 131 | machine_desc->init_smp(cpu); |
140 | 132 | ||
141 | arc_local_timer_setup(); | 133 | arc_local_timer_setup(); |
142 | 134 | ||
@@ -338,18 +330,11 @@ irqreturn_t do_IPI(int irq, void *dev_id) | |||
338 | */ | 330 | */ |
339 | static DEFINE_PER_CPU(int, ipi_dev); | 331 | static DEFINE_PER_CPU(int, ipi_dev); |
340 | 332 | ||
341 | static struct irqaction arc_ipi_irq = { | ||
342 | .name = "IPI Interrupt", | ||
343 | .flags = IRQF_PERCPU, | ||
344 | .handler = do_IPI, | ||
345 | }; | ||
346 | |||
347 | int smp_ipi_irq_setup(int cpu, int irq) | 333 | int smp_ipi_irq_setup(int cpu, int irq) |
348 | { | 334 | { |
349 | if (!cpu) | 335 | int *dev = per_cpu_ptr(&ipi_dev, cpu); |
350 | return setup_irq(irq, &arc_ipi_irq); | 336 | |
351 | else | 337 | arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev); |
352 | arch_unmask_irq(irq); | ||
353 | 338 | ||
354 | return 0; | 339 | return 0; |
355 | } | 340 | } |
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 36c2aa99436f..dbe74f418019 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c | |||
@@ -144,12 +144,12 @@ static struct clocksource arc_counter = { | |||
144 | /********** Clock Event Device *********/ | 144 | /********** Clock Event Device *********/ |
145 | 145 | ||
146 | /* | 146 | /* |
147 | * Arm the timer to interrupt after @limit cycles | 147 | * Arm the timer to interrupt after @cycles |
148 | * The distinction for oneshot/periodic is done in arc_event_timer_ack() below | 148 | * The distinction for oneshot/periodic is done in arc_event_timer_ack() below |
149 | */ | 149 | */ |
150 | static void arc_timer_event_setup(unsigned int limit) | 150 | static void arc_timer_event_setup(unsigned int cycles) |
151 | { | 151 | { |
152 | write_aux_reg(ARC_REG_TIMER0_LIMIT, limit); | 152 | write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); |
153 | write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ | 153 | write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ |
154 | 154 | ||
155 | write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); | 155 | write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); |
@@ -168,6 +168,10 @@ static void arc_clkevent_set_mode(enum clock_event_mode mode, | |||
168 | { | 168 | { |
169 | switch (mode) { | 169 | switch (mode) { |
170 | case CLOCK_EVT_MODE_PERIODIC: | 170 | case CLOCK_EVT_MODE_PERIODIC: |
171 | /* | ||
172 | * At X Hz, 1 sec = 1000ms -> X cycles; | ||
173 | * 10ms -> X / 100 cycles | ||
174 | */ | ||
171 | arc_timer_event_setup(arc_get_core_freq() / HZ); | 175 | arc_timer_event_setup(arc_get_core_freq() / HZ); |
172 | break; | 176 | break; |
173 | case CLOCK_EVT_MODE_ONESHOT: | 177 | case CLOCK_EVT_MODE_ONESHOT: |
@@ -210,12 +214,6 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id) | |||
210 | return IRQ_HANDLED; | 214 | return IRQ_HANDLED; |
211 | } | 215 | } |
212 | 216 | ||
213 | static struct irqaction arc_timer_irq = { | ||
214 | .name = "Timer0 (clock-evt-dev)", | ||
215 | .flags = IRQF_TIMER | IRQF_PERCPU, | ||
216 | .handler = timer_irq_handler, | ||
217 | }; | ||
218 | |||
219 | /* | 217 | /* |
220 | * Setup the local event timer for @cpu | 218 | * Setup the local event timer for @cpu |
221 | */ | 219 | */ |
@@ -228,15 +226,9 @@ void arc_local_timer_setup() | |||
228 | clockevents_config_and_register(evt, arc_get_core_freq(), | 226 | clockevents_config_and_register(evt, arc_get_core_freq(), |
229 | 0, ARC_TIMER_MAX); | 227 | 0, ARC_TIMER_MAX); |
230 | 228 | ||
231 | /* | 229 | /* setup the per-cpu timer IRQ handler - for all cpus */ |
232 | * setup the per-cpu timer IRQ handler - for all cpus | 230 | arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler, |
233 | * For non boot CPU explicitly unmask at intc | 231 | "Timer0 (per-cpu-tick)", evt); |
234 | * setup_irq() -> .. -> irq_startup() already does this on boot-cpu | ||
235 | */ | ||
236 | if (!cpu) | ||
237 | setup_irq(TIMER0_IRQ, &arc_timer_irq); | ||
238 | else | ||
239 | arch_unmask_irq(TIMER0_IRQ); | ||
240 | } | 232 | } |
241 | 233 | ||
242 | /* | 234 | /* |