source: mainline/kernel/arch/arm64/src/interrupt.c

Last change on this file was 4760793, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 18 months ago

Add CPU_LOCAL alongside CPU and segregate fields that are only used locally

This makes it more clear which fields can be used without synchronization
and which need more care.

  • Property mode set to 100644
File size: 4.3 KB
Line 
1/*
2 * Copyright (c) 2015 Petr Pavlu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_arm64
30 * @{
31 */
32/** @file
33 * @brief Interrupts controlling routines.
34 */
35
36#include <arch/interrupt.h>
37#include <arch/machine_func.h>
38#include <ddi/irq.h>
39#include <interrupt.h>
40#include <time/clock.h>
41
42static irq_t timer_irq;
43static uint64_t timer_increment;
44
45/** Disable interrupts.
46 *
47 * @return Old interrupt priority level.
48 */
49ipl_t interrupts_disable(void)
50{
51 uint64_t daif = DAIF_read();
52
53 DAIF_write(daif | DAIF_IRQ_FLAG);
54
55 return daif & DAIF_IRQ_FLAG;
56}
57
58/** Enable interrupts.
59 *
60 * @return Old interrupt priority level.
61 */
62ipl_t interrupts_enable(void)
63{
64 uint64_t daif = DAIF_read();
65
66 DAIF_write(daif & ~DAIF_IRQ_FLAG);
67
68 return daif & DAIF_IRQ_FLAG;
69}
70
71/** Restore interrupt priority level.
72 *
73 * @param ipl Saved interrupt priority level.
74 */
75void interrupts_restore(ipl_t ipl)
76{
77 uint64_t daif = DAIF_read();
78
79 DAIF_write((daif & ~DAIF_IRQ_FLAG) | (ipl & DAIF_IRQ_FLAG));
80}
81
82/** Read interrupt priority level.
83 *
84 * @return Current interrupt priority level.
85 */
86ipl_t interrupts_read(void)
87{
88 return DAIF_read() & DAIF_IRQ_FLAG;
89}
90
91/** Check interrupts state.
92 *
93 * @return True if interrupts are disabled.
94 */
95bool interrupts_disabled(void)
96{
97 return DAIF_read() & DAIF_IRQ_FLAG;
98}
99
100/** Suspend the virtual timer. */
101static void timer_suspend(void)
102{
103 uint64_t cntv_ctl = CNTV_CTL_EL0_read();
104
105 CNTV_CTL_EL0_write(cntv_ctl | CNTV_CTL_IMASK_FLAG);
106}
107
108/** Start the virtual timer. */
109static void timer_start(void)
110{
111 uint64_t cntfrq = CNTFRQ_EL0_read();
112 uint64_t cntvct = CNTVCT_EL0_read();
113 uint64_t cntv_ctl = CNTV_CTL_EL0_read();
114
115 /* Calculate the increment. */
116 timer_increment = cntfrq / HZ;
117
118 /* Program the timer. */
119 CNTV_CVAL_EL0_write(cntvct + timer_increment);
120 CNTV_CTL_EL0_write(
121 (cntv_ctl & ~CNTV_CTL_IMASK_FLAG) | CNTV_CTL_ENABLE_FLAG);
122}
123
124/** Claim the virtual timer interrupt. */
125static irq_ownership_t timer_claim(irq_t *irq)
126{
127 return IRQ_ACCEPT;
128}
129
130/** Handle the virtual timer interrupt. */
131static void timer_irq_handler(irq_t *irq)
132{
133 uint64_t cntvct = CNTVCT_EL0_read();
134 uint64_t cntv_cval = CNTV_CVAL_EL0_read();
135
136 uint64_t drift = cntvct - cntv_cval;
137 while (drift > timer_increment) {
138 drift -= timer_increment;
139 CPU_LOCAL->missed_clock_ticks++;
140 }
141 CNTV_CVAL_EL0_write(cntvct + timer_increment - drift);
142
143 /*
144 * We are holding a lock which prevents preemption.
145 * Release the lock, call clock() and reacquire the lock again.
146 */
147 irq_spinlock_unlock(&irq->lock, false);
148 clock();
149 irq_spinlock_lock(&irq->lock, false);
150}
151
152/** Initialize basic tables for exception dispatching. */
153void interrupt_init(void)
154{
155 size_t irq_count = machine_get_irq_count();
156 irq_init(irq_count, irq_count);
157
158 /* Initialize virtual timer. */
159 timer_suspend();
160 inr_t timer_inr = machine_enable_vtimer_irq();
161
162 irq_initialize(&timer_irq);
163 timer_irq.inr = timer_inr;
164 timer_irq.claim = timer_claim;
165 timer_irq.handler = timer_irq_handler;
166 irq_register(&timer_irq);
167
168 timer_start();
169}
170
171/** @}
172 */
Note: See TracBrowser for help on using the repository browser.