]> rtime.felk.cvut.cz Git - arc.git/blob - arch/arm/arm_cr4/kernel/irq.c
Fixed nested interrupts problem for Cortex R4.
[arc.git] / arch / arm / arm_cr4 / kernel / irq.c
1 /* -------------------------------- Arctic Core ------------------------------
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com
3  *
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>
5  *
6  * This source code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by the
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  * -------------------------------- Arctic Core ------------------------------*/
15
16 #include "internal.h"
17 #include "task_i.h"
18 #include "hooks.h"
19 #include "irq.h"
20 #include "core_cr4.h"
21
22 extern TaskType Os_Arc_CreateIsr( void (*entry)(void ), uint8_t prio, const char *name );
23 extern void *Irq_VectorTable[NUMBER_OF_INTERRUPTS_AND_EXCEPTIONS];
24
25
26 static inline void Irq_Setup() {
27         vimREG->FIRQPR0 = 0x0;
28         vimREG->FIRQPR1 = 0x0;
29 }
30
31 void Irq_Init( void ) {
32         Irq_Setup();
33         Irq_Enable();
34 }
35
36
37 /**
38  *
39  * @param stack_p Ptr to the current stack.
40  *
41  * The stack holds C, NVGPR, VGPR and the EXC frame.
42  *
43  */
44 #define MAX_WAIT_COUNT 1000
45 void *Irq_Entry( void *stack_p )
46 {
47         uint32_t *stack;
48
49         // This is the current hardware interrupt channel that we are processing.
50         volatile sint8 channel;
51
52         // This is the current OS-interrupt vector that we are processing.
53         volatile sint8 virtualChannel;
54
55         // Get the highest pending interrupt.
56         volatile uint32 c = 0;
57         do {
58                 channel = IrqGetCurrentInterruptSource();
59                 c++;
60         } while (channel < 0 && c < MAX_WAIT_COUNT);
61
62         if (c >= MAX_WAIT_COUNT) {
63                 // No interrupt is pending
64                 return stack_p;
65         }
66
67         // In most cases the OS-channel is the same as the hardware channel.
68         virtualChannel = channel;
69
70         // Special case for software interrupts.
71         if (channel == SSI) {
72                 // Get the emulated interrupt channel.
73                 virtualChannel = systemREG1->SSISR1;
74         }
75
76         stack = (uint32_t *)stack_p;
77         struct OsPcb * pcb = (struct OsPcb *)Irq_VectorTable[virtualChannel];
78         // Save the hardware channel in the PCB, so that Os_Isr knows which interrupt channel to deactivate.
79         pcb->vector = channel;
80         stack = Os_Isr(stack, (void *)pcb);
81
82         //Irq_Enable();
83         return stack;
84 }
85
86 /**
87  * Attach an ISR type 1 to the interrupt controller.
88  *
89  * @param entry
90  * @param int_ctrl
91  * @param vector
92  * @param prio
93  */
94 void Irq_AttachIsr1( void (*entry)(void), void *int_ctrl, uint32_t vector, uint8_t prio) {
95
96         // TODO: Use NVIC_InitVector(vector, osPrioToCpuPio(pcb->prio)); here
97 }
98
99 /**
100  * NVIC prio have priority 0-15, 0-highest priority.
101  * Autosar does it the other way around, 0-Lowest priority
102  *
103  * Autosar    NVIC
104  *   31        0
105  *   30        0
106  *   ..
107  *   0         15
108  *   0         15
109  * @param prio
110  * @return
111  */
112 static inline int osPrioToCpuPio( uint8_t prio ) {
113         assert(prio<32);
114         prio = 31 - prio;
115         return (prio>>1);
116 }
117
118 /**
119  * Attach a ISR type 2 to the interrupt controller.
120  *
121  * @param tid
122  * @param int_ctrl
123  * @param vector
124  */
125 void Irq_AttachIsr2(TaskType tid,void *int_ctrl,IrqType vector ) {
126         OsPcbType *pcb;
127
128         pcb = os_find_task(tid);
129         Irq_VectorTable[vector] = (void *)pcb;
130         IrqActivateChannel(vector);
131
132         // TOdo replace NVIC_InitVector(vector, osPrioToCpuPio(pcb->prio));
133 }
134
135 /**
136  * Generates a soft interrupt, ie sets pending bit.
137  * This could also be implemented using ISPR regs.
138  *
139  * @param vector
140  */
141 void Irq_GenerateSoftInt( IrqType vector ) {
142         IrqActivateChannel(SSI);
143         systemREG1->SSISR1 = (0x75 << 8) | vector;
144 }
145
146 /**
147  * Get the current priority from the interrupt controller.
148  * @param cpu
149  * @return
150  */
151 uint8_t Irq_GetCurrentPriority( Cpu_t cpu) {
152
153         uint8_t prio = 0;
154
155         // SCB_ICSR contains the active vector
156         return prio;
157 }
158
159 typedef struct {
160         uint32_t dummy;
161 } exc_stack_t;
162
163