1 /*
2 * Copyright (C) 2021-2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <errno.h>
8 #include <asm/lib/bits.h>
9 #include <irq.h>
10 #include <common/softirq.h>
11 #include <asm/irq.h>
12 #include <asm/per_cpu.h>
13
14 static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, };
15
16 uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE];
17 struct irq_desc irq_desc_array[NR_IRQS];
18 static uint64_t irq_rsvd_bitmap[IRQ_ALLOC_BITMAP_SIZE];
19
20 /*
21 * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned
22 * return: irq num on success, IRQ_INVALID on failure
23 */
alloc_irq_num(uint32_t req_irq,bool reserve)24 static uint32_t alloc_irq_num(uint32_t req_irq, bool reserve)
25 {
26 uint32_t irq = req_irq;
27 uint64_t rflags;
28 uint32_t ret;
29
30 if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) {
31 pr_err("[%s] invalid req_irq %u", __func__, req_irq);
32 ret = IRQ_INVALID;
33 } else {
34 spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
35 if (irq == IRQ_INVALID) {
36 /* if no valid irq num given, find a free one */
37 irq = (uint32_t)ffz64_ex(irq_alloc_bitmap, NR_IRQS);
38 }
39
40 if (irq >= NR_IRQS) {
41 irq = IRQ_INVALID;
42 } else {
43 bitmap_set_nolock((uint16_t)(irq & 0x3FU),
44 irq_alloc_bitmap + (irq >> 6U));
45 if (reserve) {
46 bitmap_set_nolock((uint16_t)(irq & 0x3FU),
47 irq_rsvd_bitmap + (irq >> 6U));
48 }
49 }
50 spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
51 ret = irq;
52 }
53 return ret;
54 }
55
reserve_irq_num(uint32_t irq)56 uint32_t reserve_irq_num(uint32_t irq)
57 {
58 return alloc_irq_num(irq, true);
59 }
60
61 /*
62 * @pre: irq is not in irq_static_mappings
63 * free irq num allocated via alloc_irq_num()
64 */
free_irq_num(uint32_t irq)65 static void free_irq_num(uint32_t irq)
66 {
67 uint64_t rflags;
68
69 if (irq < NR_IRQS) {
70 spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
71
72 if (bitmap_test((uint16_t)(irq & 0x3FU),
73 irq_rsvd_bitmap + (irq >> 6U)) == false) {
74 bitmap_clear_nolock((uint16_t)(irq & 0x3FU),
75 irq_alloc_bitmap + (irq >> 6U));
76 }
77 spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
78 }
79 }
80
free_irq(uint32_t irq)81 void free_irq(uint32_t irq)
82 {
83 uint64_t rflags;
84 struct irq_desc *desc;
85
86 if (irq < NR_IRQS) {
87 desc = &irq_desc_array[irq];
88
89 spinlock_irqsave_obtain(&desc->lock, &rflags);
90 desc->action = NULL;
91 desc->priv_data = NULL;
92 desc->flags = IRQF_NONE;
93 spinlock_irqrestore_release(&desc->lock, rflags);
94
95 free_irq_arch(irq);
96 free_irq_num(irq);
97 }
98 }
99
100 /*
101 * There are four cases as to irq/vector allocation:
102 * case 1: req_irq = IRQ_INVALID
103 * caller did not know which irq to use, and want system to
104 * allocate available irq for it. These irq are in range:
105 * nr_gsi ~ NR_IRQS
106 * an irq will be allocated and a vector will be assigned to this
107 * irq automatically.
108 * case 2: req_irq >= NR_LAGACY_IRQ and irq < nr_gsi
109 * caller want to add device ISR handler into ioapic pins.
110 * a vector will automatically assigned.
111 * case 3: req_irq >=0 and req_irq < NR_LEGACY_IRQ
112 * caller want to add device ISR handler into ioapic pins, which
113 * is a legacy irq, vector already reserved.
114 * Nothing to do in this case.
115 * case 4: irq with speical type (not from IOAPIC/MSI)
116 * These irq value are pre-defined for Timer, IPI, Spurious etc,
117 * which is listed in irq_static_mappings[].
118 * Nothing to do in this case.
119 *
120 * return value: valid irq (>=0) on success, otherwise errno (< 0).
121 */
request_irq(uint32_t req_irq,irq_action_t action_fn,void * priv_data,uint32_t flags)122 int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data,
123 uint32_t flags)
124 {
125 struct irq_desc *desc;
126 uint32_t irq;
127 uint64_t rflags;
128 int32_t ret;
129
130 irq = alloc_irq_num(req_irq, false);
131 if (irq == IRQ_INVALID) {
132 pr_err("[%s] invalid irq num", __func__);
133 ret = -EINVAL;
134 } else {
135 if (!request_irq_arch(irq)) {
136 pr_err("[%s] failed to alloc vector for irq %u",
137 __func__, irq);
138 free_irq_num(irq);
139 ret = -EINVAL;
140 } else {
141 desc = &irq_desc_array[irq];
142 if (desc->action == NULL) {
143 spinlock_irqsave_obtain(&desc->lock, &rflags);
144 desc->flags = flags;
145 desc->priv_data = priv_data;
146 desc->action = action_fn;
147 spinlock_irqrestore_release(&desc->lock, rflags);
148 ret = (int32_t)irq;
149 } else {
150 ret = -EBUSY;
151 pr_err("%s: request irq(%u) failed, already requested",
152 __func__, irq);
153 }
154 }
155 }
156
157 return ret;
158 }
159
set_irq_trigger_mode(uint32_t irq,bool is_level_triggered)160 void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered)
161 {
162 uint64_t rflags;
163 struct irq_desc *desc;
164
165 if (irq < NR_IRQS) {
166 desc = &irq_desc_array[irq];
167 spinlock_irqsave_obtain(&desc->lock, &rflags);
168 if (is_level_triggered) {
169 desc->flags |= IRQF_LEVEL;
170 } else {
171 desc->flags &= ~IRQF_LEVEL;
172 }
173 spinlock_irqrestore_release(&desc->lock, rflags);
174 }
175 }
176
handle_irq(const struct irq_desc * desc)177 static inline void handle_irq(const struct irq_desc *desc)
178 {
179 irq_action_t action = desc->action;
180
181 pre_irq_arch(desc);
182
183 if (action != NULL) {
184 action(desc->irq, desc->priv_data);
185 }
186
187 post_irq_arch(desc);
188 }
189
do_irq(const uint32_t irq)190 void do_irq(const uint32_t irq)
191 {
192 struct irq_desc *desc;
193
194 if (irq < NR_IRQS) {
195 desc = &irq_desc_array[irq];
196 per_cpu(irq_count, get_pcpu_id())[irq]++;
197
198 /* XXX irq_alloc_bitmap is used lockless here */
199 if (bitmap_test((uint16_t)(irq & 0x3FU), irq_alloc_bitmap + (irq >> 6U))) {
200 handle_irq(desc);
201 }
202 }
203
204 do_softirq();
205 }
206
init_irq_descs(void)207 static void init_irq_descs(void)
208 {
209 uint32_t i;
210
211 for (i = 0U; i < NR_IRQS; i++) {
212 struct irq_desc *desc = &irq_desc_array[i];
213 desc->irq = i;
214 spinlock_init(&desc->lock);
215 }
216
217 init_irq_descs_arch(irq_desc_array);
218 }
219
init_interrupt(uint16_t pcpu_id)220 void init_interrupt(uint16_t pcpu_id)
221 {
222 init_interrupt_arch(pcpu_id);
223
224 if (pcpu_id == BSP_CPU_ID) {
225 init_irq_descs();
226 setup_irqs_arch();
227 init_softirq();
228 }
229
230 CPU_IRQ_ENABLE_ON_CONFIG();
231 }
232