Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
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)
35 #else
36  __asm__ __volatile__("cli");
37 #endif
38 }
39 
40 void qm_irq_enable(void)
41 {
42 #if (QM_SENSOR)
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
uint32_t status32_irq_threshold
STATUS32 Interrupt Threshold.
void(* qm_ss_isr_t)(struct interrupt_frame *frame)
Interrupt service routine type.
void qm_irq_unlock(unsigned int key)
Restore previous interrupt state on the CPU saved via qm_irq_lock().
Definition: qm_interrupt.c:63
void qm_irq_unmask(uint32_t irq)
Unmask a given interrupt line.
Definition: qm_interrupt.c:125
unsigned int qm_irq_lock(void)
Save interrupt state and disable all interrupts on the CPU.
Definition: qm_interrupt.c:50
void(* qm_isr_t)(struct interrupt_frame *frame)
Interrupt service routine type.
Definition: qm_interrupt.h:71
void qm_irq_disable(void)
Unconditionally disable interrupt delivery on the CPU.
Definition: qm_interrupt.c:31
void qm_ss_irq_enable(void)
Enable interrupt delivery for the Sensor Subsystem.
uint32_t irq_ctrl
Interrupt Context Saving Control Register.
uint32_t status32_irq_enable
STATUS32 Interrupt Enable.
void qm_ss_irq_disable(void)
Disable interrupt delivery for the Sensor Subsystem.
void qm_irq_mask(uint32_t irq)
Mask a given interrupt line.
Definition: qm_interrupt.c:111
void qm_irq_enable(void)
Unconditionally enable interrupt delivery on the CPU.
Definition: qm_interrupt.c:40
uint32_t redtbl_entries[QM_IOAPIC_NUM_RTES]
Redirection Table Entries.
Definition: qm_soc_regs.h:272
void qm_ss_irq_mask(uint32_t irq)
Mask a given interrupt line.
uint8_t irq_config[QM_SS_INT_VECTOR_NUM-QM_SS_EXCEPTION_NUM]
IRQ configuration:
void qm_ss_irq_unmask(uint32_t irq)
Unmask a given interrupt line.
SS IRQ context type.