Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kernel/irq.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Based on arch/arm/kernel/irq.c
4
*
5
* Copyright (C) 1992 Linus Torvalds
6
* Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
7
* Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
8
* Dynamic Tick Timer written by Tony Lindgren <[email protected]> and
9
* Tuukka Tikkanen <[email protected]>.
10
* Copyright (C) 2012 ARM Ltd.
11
*/
12
13
#include <linux/hardirq.h>
14
#include <linux/init.h>
15
#include <linux/irq.h>
16
#include <linux/irqchip.h>
17
#include <linux/kprobes.h>
18
#include <linux/memory.h>
19
#include <linux/scs.h>
20
#include <linux/seq_file.h>
21
#include <linux/smp.h>
22
#include <linux/vmalloc.h>
23
#include <asm/daifflags.h>
24
#include <asm/exception.h>
25
#include <asm/numa.h>
26
#include <asm/softirq_stack.h>
27
#include <asm/stacktrace.h>
28
#include <asm/vmap_stack.h>
29
30
/* Only access this in an NMI enter/exit */
31
DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts);
32
33
DEFINE_PER_CPU(unsigned long *, irq_stack_ptr);
34
35
36
DECLARE_PER_CPU(unsigned long *, irq_shadow_call_stack_ptr);
37
38
#ifdef CONFIG_SHADOW_CALL_STACK
39
DEFINE_PER_CPU(unsigned long *, irq_shadow_call_stack_ptr);
40
#endif
41
42
static void init_irq_scs(void)
43
{
44
int cpu;
45
46
if (!scs_is_enabled())
47
return;
48
49
for_each_possible_cpu(cpu)
50
per_cpu(irq_shadow_call_stack_ptr, cpu) =
51
scs_alloc(early_cpu_to_node(cpu));
52
}
53
54
static void __init init_irq_stacks(void)
55
{
56
int cpu;
57
unsigned long *p;
58
59
for_each_possible_cpu(cpu) {
60
p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, early_cpu_to_node(cpu));
61
per_cpu(irq_stack_ptr, cpu) = p;
62
}
63
}
64
65
#ifndef CONFIG_PREEMPT_RT
66
static void ____do_softirq(struct pt_regs *regs)
67
{
68
__do_softirq();
69
}
70
71
void do_softirq_own_stack(void)
72
{
73
call_on_irq_stack(NULL, ____do_softirq);
74
}
75
#endif
76
77
static void default_handle_irq(struct pt_regs *regs)
78
{
79
panic("IRQ taken without a root IRQ handler\n");
80
}
81
82
static void default_handle_fiq(struct pt_regs *regs)
83
{
84
panic("FIQ taken without a root FIQ handler\n");
85
}
86
87
void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq;
88
void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq;
89
90
int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
91
{
92
if (handle_arch_irq != default_handle_irq)
93
return -EBUSY;
94
95
handle_arch_irq = handle_irq;
96
pr_info("Root IRQ handler: %ps\n", handle_irq);
97
return 0;
98
}
99
100
int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *))
101
{
102
if (handle_arch_fiq != default_handle_fiq)
103
return -EBUSY;
104
105
handle_arch_fiq = handle_fiq;
106
pr_info("Root FIQ handler: %ps\n", handle_fiq);
107
return 0;
108
}
109
110
void __init init_IRQ(void)
111
{
112
init_irq_stacks();
113
init_irq_scs();
114
irqchip_init();
115
116
if (system_uses_irq_prio_masking()) {
117
/*
118
* Now that we have a stack for our IRQ handler, set
119
* the PMR/PSR pair to a consistent state.
120
*/
121
WARN_ON(read_sysreg(daif) & PSR_A_BIT);
122
local_daif_restore(DAIF_PROCCTX_NOIRQ);
123
}
124
}
125
126