Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

qm_interrupt.c
1 /*
2 * {% copyright %}
3 */
4
5 #include "qm_common.h"
6 #include "qm_interrupt.h"
7 #include "idt.h"
8
9 #if (HAS_APIC)
10 #include "apic.h"
11
12 #elif(HAS_MVIC)
13 #include "mvic.h"
14
15 #elif(QM_SENSOR)
16 #include "qm_ss_interrupt.h"
17 #include "qm_sensor_regs.h"
18 extern qm_ss_isr_t __ivt_vect_table[];
19
20 static void ss_register_irq(unsigned int vector);
21
22 #else
23 #error "Unsupported / unspecified processor detected."
24 #endif
25
26 /* x86 CPU FLAGS.IF register field (Interrupt enable Flag, bit 9), indicating
27 * whether or not CPU interrupts are enabled.
28 */
29 #define X86_FLAGS_IF BIT(9)
30
31 void qm_irq_disable(void)
32 {
33 #if (QM_SENSOR)
34 qm_ss_irq_disable();
35 #else
36 __asm__ __volatile__("cli");
37 #endif
38 }
39
40 void qm_irq_enable(void)
41 {
42 #if (QM_SENSOR)
43 qm_ss_irq_enable();
44 #else
45 __asm__ __volatile__("sti");
46 #endif
47 }
48
49 #if (QM_SENSOR)
50 unsigned int qm_irq_lock(void)
51 {
52 unsigned int key = 0;
53
54 /*
55 * Store the ARC STATUS32 register fields relating to interrupts into
56 * the variable `key' and disable interrupt delivery to the core.
57 */
58 __asm__ __volatile__("clri %0" : "=r"(key));
59
60 return key;
61 }
62
63 void qm_irq_unlock(unsigned int key)
64 {
65 /*
66 * Restore the ARC STATUS32 register fields relating to interrupts based
67 * on the variable `key' populated by qm_irq_lock().
68 */
69 __asm__ __volatile__("seti %0" : : "ir"(key));
70 }
71
72 #else /* x86 */
73
74 unsigned int qm_irq_lock(void)
75 {
76 unsigned int key = 0;
77
78 /*
79 * Store the CPU FLAGS register into the variable `key' and disable
80 * interrupt delivery to the core.
81 */
82 __asm__ __volatile__("pushfl;\n\t"
83 "cli;\n\t"
84 "popl %0;\n\t"
85 : "=g"(key)
86 :
87 : "memory");
88
89 return key;
90 }
91
92 void qm_irq_unlock(unsigned int key)
93 {
94 /*
95 * `key' holds the CPU FLAGS register content at the time when
96 * qm_irq_lock() was called.
97 */
98 if (!(key & X86_FLAGS_IF)) {
99 /*
100 * Interrupts were disabled when qm_irq_lock() was invoked:
101 * do not re-enable interrupts.
102 */
103 return;
104 }
105
106 /* Enable interrupts */
107 __asm__ __volatile__("sti;\n\t" : :);
108 }
109 #endif /* QM_SENSOR */
110
111 void qm_irq_mask(uint32_t irq)
112 {
113 #if (HAS_APIC)
114 ioapic_mask_irq(irq);
115
116 #elif(HAS_MVIC)
117 mvic_mask_irq(irq);
118
119 #elif(QM_SENSOR)
120 qm_ss_irq_mask(irq);
121
122 #endif
123 }
124
125 void qm_irq_unmask(uint32_t irq)
126 {
127 #if (HAS_APIC)
128 ioapic_unmask_irq(irq);
129
130 #elif(HAS_MVIC)
131 mvic_unmask_irq(irq);
132
133 #elif(QM_SENSOR)
134 qm_ss_irq_unmask(irq);
135
136 #endif
137 }
138
139 #if (ENABLE_RESTORE_CONTEXT)
140 #if (HAS_APIC)
141 int qm_irq_save_context(qm_irq_context_t *const ctx)
142 {
143 uint32_t rte_low;
144 uint8_t irq;
145
146 QM_CHECK(ctx != NULL, -EINVAL);
147
148 for (irq = 0; irq < QM_IOAPIC_NUM_RTES; irq++) {
149 rte_low = _ioapic_get_redtbl_entry_lo(irq);
150 ctx->redtbl_entries[irq] = rte_low;
151 }
152
153 return 0;
154 }
155
156 int qm_irq_restore_context(const qm_irq_context_t *const ctx)
157 {
158 uint32_t rte_low;
159 uint8_t irq;
160
161 QM_CHECK(ctx != NULL, -EINVAL);
162
163 apic_init();
164
165 for (irq = 0; irq < QM_IOAPIC_NUM_RTES; irq++) {
166 rte_low = ctx->redtbl_entries[irq];
167 _ioapic_set_redtbl_entry_lo(irq, rte_low);
168 }
169
170 return 0;
171 }
172 #elif(QM_SENSOR) /* HAS_APIC */
173 int qm_irq_save_context(qm_irq_context_t *const ctx)
174 {
175 uint8_t i;
176 uint32_t status32;
177
178 QM_CHECK(ctx != NULL, -EINVAL);
179
180 /* Interrupts from 0 to 15 are exceptions and they are ignored
181 * by IRQ auxiliary registers. For that reason we skip those
182 * values in this loop.
183 */
184 for (i = 0; i < (QM_SS_INT_VECTOR_NUM - QM_SS_EXCEPTION_NUM); i++) {
185 __builtin_arc_sr(i + QM_SS_EXCEPTION_NUM, QM_SS_AUX_IRQ_SELECT);
186
187 ctx->irq_config[i] = __builtin_arc_lr(QM_SS_AUX_IRQ_PRIORITY)
188 << 2;
189 ctx->irq_config[i] |= __builtin_arc_lr(QM_SS_AUX_IRQ_TRIGGER)
190 << 1;
191 ctx->irq_config[i] |= __builtin_arc_lr(QM_SS_AUX_IRQ_ENABLE);
192 }
193
194 status32 = __builtin_arc_lr(QM_SS_AUX_STATUS32);
195
196 ctx->status32_irq_threshold = status32 & QM_SS_STATUS32_E_MASK;
197 ctx->status32_irq_enable = status32 & QM_SS_STATUS32_IE_MASK;
198 ctx->irq_ctrl = __builtin_arc_lr(QM_SS_AUX_IRQ_CTRL);
199
200 return 0;
201 }
202
203 int qm_irq_restore_context(const qm_irq_context_t *const ctx)
204 {
205 uint8_t i;
206 uint32_t reg;
207
208 QM_CHECK(ctx != NULL, -EINVAL);
209
210 for (i = 0; i < (QM_SS_INT_VECTOR_NUM - QM_SS_EXCEPTION_NUM); i++) {
211 __builtin_arc_sr(i + QM_SS_EXCEPTION_NUM, QM_SS_AUX_IRQ_SELECT);
212
213 __builtin_arc_sr(ctx->irq_config[i] >> 2,
214 QM_SS_AUX_IRQ_PRIORITY);
215 __builtin_arc_sr((ctx->irq_config[i] >> 1) & BIT(0),
216 QM_SS_AUX_IRQ_TRIGGER);
217 __builtin_arc_sr(ctx->irq_config[i] & BIT(0),
218 QM_SS_AUX_IRQ_ENABLE);
219 }
220
221 __builtin_arc_sr(ctx->irq_ctrl, QM_SS_AUX_IRQ_CTRL);
222
223 /* Setting an interrupt priority threshold. */
224 reg = __builtin_arc_lr(QM_SS_AUX_STATUS32);
225 reg |= (ctx->status32_irq_threshold & QM_SS_STATUS32_E_MASK);
226 reg |= (ctx->status32_irq_enable & QM_SS_STATUS32_IE_MASK);
227
228 /* This one has to be a kernel operation. */
229 __builtin_arc_kflag(reg);
230
231 return 0;
232 }
233 #endif /* QM_SENSOR */
234 #else /* !ENABLE_RESTORE_CONTEXT */
235 int qm_irq_save_context(qm_irq_context_t *const ctx)
236 {
237 (void)ctx;
238
239 return 0;
240 }
241
242 int qm_irq_restore_context(const qm_irq_context_t *const ctx)
243 {
244 (void)ctx;
245
246 return 0;
247 }
248 #endif /* ENABLE_RESTORE_CONTEXT */
249
250 void _qm_irq_setup(uint32_t irq)
251 {
252 #if (HAS_APIC)
253 /*
254 * Quark SE SOC has an APIC. Other SoCs uses a simple, fixed-vector
255 * non-8259 PIC that requires no configuration.
256 */
257 ioapic_register_irq(irq, QM_IRQ_TO_VECTOR(irq));
258 ioapic_unmask_irq(irq);
259 #elif(HAS_MVIC)
260 mvic_register_irq(irq);
261 mvic_unmask_irq(irq);
262 #elif(QM_SENSOR)
263 ss_register_irq(QM_IRQ_TO_VECTOR(irq));
264 qm_ss_irq_unmask(QM_IRQ_TO_VECTOR(irq));
265 #endif
266 }
267
268 /*
269 * Register an Interrupt Service Routine to a given interrupt vector.
270 *
271 * @param[in] vector Interrupt Vector number.
272 * @param[in] isr ISR to register to given vector. Must be a valid x86 ISR.
273 * If this can't be provided, QM_IRQ_REQUEST() or
274 * qm_int_vector_request() should be used instead.
275 */
276 void _qm_register_isr(uint32_t vector, qm_isr_t isr)
277 {
278 #if (QM_SENSOR)
279 /* Invalidate the i-cache line which contains the IRQ vector. This
280 * will bypass i-cache and set vector with the good ISR. */
281 __builtin_arc_sr((uint32_t)&__ivt_vect_table[0] + (vector * 4),
282 QM_SS_AUX_IC_IVIL);
283 /* All SR accesses to the IC_IVIL register must be followed by three
284 * NOP instructions, see chapter 3.3.59 in the datasheet
285 * "ARC_V2_ProgrammersReference.pdf" */
286 __builtin_arc_nop();
287 __builtin_arc_nop();
288 __builtin_arc_nop();
289 __ivt_vect_table[vector] = isr;
290 #else
291 idt_set_intr_gate_desc(vector, (uint32_t)isr);
292 #endif
293 }
294
295 #if (QM_SENSOR)
296 static void ss_register_irq(unsigned int vector)
297 {
298 /*
299 * By hardware power-on default, SS interrupts are level triggered.
300 * The following switch statement sets some of the peripherals to edge
301 * triggered.
302 */
303 switch (vector) {
304 case QM_SS_IRQ_ADC_0_PWR_INT_VECTOR:
305 case QM_IRQ_RTC_0_INT_VECTOR:
306 case QM_IRQ_AONPT_0_INT_VECTOR:
307 case QM_IRQ_WDT_0_INT_VECTOR:
308 /* Edge sensitive. */
309 __builtin_arc_sr(vector, QM_SS_AUX_IRQ_SELECT);
310 __builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE,
311 QM_SS_AUX_IRQ_TRIGGER);
312 }
313 }
314 #endif
qm_irq_context_t::status32_irq_threshold
uint32_t status32_irq_threshold
STATUS32 Interrupt Threshold.
Definition: qm_sensor_regs.h:97
qm_ss_isr_t
void(* qm_ss_isr_t)(struct interrupt_frame *frame)
Interrupt service routine type.
Definition: qm_ss_interrupt.h:21
qm_irq_unlock
void qm_irq_unlock(unsigned int key)
Restore previous interrupt state on the CPU saved via qm_irq_lock().
Definition: qm_interrupt.c:63
qm_irq_unmask
void qm_irq_unmask(uint32_t irq)
Unmask a given interrupt line.
Definition: qm_interrupt.c:125
qm_irq_lock
unsigned int qm_irq_lock(void)
Save interrupt state and disable all interrupts on the CPU.
Definition: qm_interrupt.c:50
qm_isr_t
void(* qm_isr_t)(struct interrupt_frame *frame)
Interrupt service routine type.
Definition: qm_interrupt.h:71
qm_irq_disable
void qm_irq_disable(void)
Unconditionally disable interrupt delivery on the CPU.
Definition: qm_interrupt.c:31
qm_ss_irq_enable
void qm_ss_irq_enable(void)
Enable interrupt delivery for the Sensor Subsystem.
Definition: qm_ss_interrupt.c:25
qm_irq_context_t::irq_ctrl
uint32_t irq_ctrl
Interrupt Context Saving Control Register.
Definition: qm_sensor_regs.h:99
qm_irq_context_t::status32_irq_enable
uint32_t status32_irq_enable
STATUS32 Interrupt Enable.
Definition: qm_sensor_regs.h:98
qm_ss_irq_disable
void qm_ss_irq_disable(void)
Disable interrupt delivery for the Sensor Subsystem.
Definition: qm_ss_interrupt.c:20
qm_irq_mask
void qm_irq_mask(uint32_t irq)
Mask a given interrupt line.
Definition: qm_interrupt.c:111
qm_irq_enable
void qm_irq_enable(void)
Unconditionally enable interrupt delivery on the CPU.
Definition: qm_interrupt.c:40
qm_irq_context_t::redtbl_entries
uint32_t redtbl_entries[QM_IOAPIC_NUM_RTES]
Redirection Table Entries.
Definition: qm_soc_regs.h:272
qm_ss_irq_mask
void qm_ss_irq_mask(uint32_t irq)
Mask a given interrupt line.
Definition: qm_ss_interrupt.c:30
qm_irq_context_t::irq_config
uint8_t irq_config[QM_SS_INT_VECTOR_NUM-QM_SS_EXCEPTION_NUM]
IRQ configuration:
Definition: qm_sensor_regs.h:107
qm_ss_irq_unmask
void qm_ss_irq_unmask(uint32_t irq)
Unmask a given interrupt line.
Definition: qm_ss_interrupt.c:36
qm_irq_context_t
SS IRQ context type.
Definition: qm_sensor_regs.h:96