1 /*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2015 Intel Corporation
4 *
5 * Use of this source code is governed by a MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT
8 */
9 #include <sys/types.h>
10 #include <lk/debug.h>
11 #include <lk/err.h>
12 #include <lk/reg.h>
13 #include <lk/trace.h>
14 #include <assert.h>
15 #include <kernel/thread.h>
16 #include <platform/interrupts.h>
17 #include <arch/ops.h>
18 #include <arch/x86.h>
19 #include <arch/x86/lapic.h>
20 #include <kernel/spinlock.h>
21 #include "platform_p.h"
22 #include <platform/pc.h>
23
24 #define LOCAL_TRACE 0
25
26 static spin_lock_t lock;
27
28 #define INTC_TYPE_INTERNAL 0
29 #define INTC_TYPE_PIC 1
30 #define INTC_TYPE_MSI 2
31
32 struct int_vector {
33 int_handler handler;
34 void *arg;
35 struct {
36 uint allocated : 1;
37 uint type : 2; // INTC_TYPE
38 uint edge : 1; // edge vs level
39 } flags;
40 };
41
42 static struct int_vector int_table[INT_VECTORS];
43
platform_init_interrupts(void)44 void platform_init_interrupts(void) {
45 pic_init();
46 lapic_init();
47
48 // initialize all of the vectors
49 for (int i = 0; i < INT_VECTORS; i++) {
50 if (i >= INT_PIC1_BASE && i <= INT_PIC2_BASE + 8) {
51 int_table[i].flags.type = INTC_TYPE_PIC;
52 }
53 if (i >= INT_DYNAMIC_START && i <= INT_DYNAMIC_END) {
54 int_table[i].flags.allocated = false;
55 } else {
56 int_table[i].flags.allocated = true;
57 }
58 }
59 }
60
mask_interrupt(unsigned int vector)61 status_t mask_interrupt(unsigned int vector) {
62 if (vector >= INT_VECTORS)
63 return ERR_INVALID_ARGS;
64
65 LTRACEF("vector %#x\n", vector);
66
67 spin_lock_saved_state_t state;
68 spin_lock_irqsave(&lock, state);
69
70 if (int_table[vector].flags.type == INTC_TYPE_PIC) {
71 pic_enable(vector, false);
72 }
73
74 spin_unlock_irqrestore(&lock, state);
75
76 return NO_ERROR;
77 }
78
79
unmask_interrupt(unsigned int vector)80 status_t unmask_interrupt(unsigned int vector) {
81 if (vector >= INT_VECTORS)
82 return ERR_INVALID_ARGS;
83
84 LTRACEF("vector %#x\n", vector);
85
86 spin_lock_saved_state_t state;
87 spin_lock_irqsave(&lock, state);
88
89 if (int_table[vector].flags.type == INTC_TYPE_PIC) {
90 pic_enable(vector, true);
91 }
92
93 spin_unlock_irqrestore(&lock, state);
94
95 return NO_ERROR;
96 }
97
98 enum handler_return platform_irq(x86_iframe_t *frame);
platform_irq(x86_iframe_t * frame)99 enum handler_return platform_irq(x86_iframe_t *frame) {
100 // get the current vector
101 unsigned int vector = frame->vector;
102
103 DEBUG_ASSERT(vector >= 0x20);
104
105 struct int_vector *handler = &int_table[vector];
106
107 // edge triggered interrupts are acked beforehand
108 if (handler->flags.edge) {
109 if (handler->flags.type == INTC_TYPE_MSI) {
110 lapic_eoi(vector);
111 } else {
112 pic_eoi(vector);
113 }
114 }
115
116 // call the registered interrupt handler
117 enum handler_return ret = INT_NO_RESCHEDULE;
118 if (handler->handler) {
119 ret = handler->handler(handler->arg);
120 }
121
122 // level triggered ack
123 if (!handler->flags.edge) {
124 if (handler->flags.type == INTC_TYPE_MSI) {
125 lapic_eoi(vector);
126 } else {
127 pic_eoi(vector);
128 }
129 }
130
131 return ret;
132 }
133
register_int_handler_etc(unsigned int vector,int_handler handler,void * arg,bool edge,uint type)134 static void register_int_handler_etc(unsigned int vector, int_handler handler, void *arg, bool edge, uint type) {
135 ASSERT(vector < INT_VECTORS);
136
137 spin_lock_saved_state_t state;
138 spin_lock_irqsave(&lock, state);
139
140 int_table[vector].arg = arg;
141 int_table[vector].handler = handler;
142 int_table[vector].flags.allocated = true;
143 int_table[vector].flags.edge = edge;
144 int_table[vector].flags.type = type;
145
146 spin_unlock_irqrestore(&lock, state);
147 }
148
register_int_handler(unsigned int vector,int_handler handler,void * arg)149 void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
150 register_int_handler_etc(vector, handler, arg, false, INTC_TYPE_PIC);
151 }
152
register_int_handler_msi(unsigned int vector,int_handler handler,void * arg,bool edge)153 void register_int_handler_msi(unsigned int vector, int_handler handler, void *arg, bool edge) {
154 register_int_handler_etc(vector, handler, arg, edge, INTC_TYPE_MSI);
155 }
156
platform_mask_irqs(void)157 void platform_mask_irqs(void) {
158 pic_mask_interrupts();
159 }
160
platform_pci_int_to_vector(unsigned int pci_int,unsigned int * vector)161 status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {
162 LTRACEF("pci_int %u\n", pci_int);
163
164 // pci interrupts are relative to PIC style irq #s so simply add INT_BASE to it
165 uint out_vector = pci_int + INT_BASE;
166 if (out_vector > INT_VECTORS) {
167 return ERR_INVALID_ARGS;
168 }
169
170 *vector = out_vector;
171 return NO_ERROR;
172 }
173
platform_allocate_interrupts(size_t count,uint align_log2,bool msi,unsigned int * vector)174 status_t platform_allocate_interrupts(size_t count, uint align_log2, bool msi, unsigned int *vector) {
175 LTRACEF("count %zu align %u msi %d\n", count, align_log2, msi);
176 if (align_log2 > 0) {
177 PANIC_UNIMPLEMENTED;
178 }
179
180 spin_lock_saved_state_t state;
181 spin_lock_irqsave(&lock, state);
182
183 // find a free interrupt
184 status_t err = ERR_NOT_FOUND;
185 for (unsigned int i = 0; i < INT_VECTORS; i++) {
186 if (!int_table[i].flags.allocated) {
187 int_table[i].flags.allocated = true;
188 *vector = i;
189 LTRACEF("found irq %#x\n", i);
190 err = NO_ERROR;
191 break;
192 }
193 }
194
195 spin_unlock_irqrestore(&lock, state);
196
197 return err;
198 }
199
platform_compute_msi_values(unsigned int vector,unsigned int cpu,bool edge,uint64_t * msi_address_out,uint16_t * msi_data_out)200 status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool edge,
201 uint64_t *msi_address_out, uint16_t *msi_data_out) {
202
203 // only handle edge triggered at the moment
204 DEBUG_ASSERT(edge);
205
206 *msi_data_out = (vector & 0xff) | (0<<15); // edge triggered
207 *msi_address_out = 0xfee00000 | (cpu << 12);
208
209 return NO_ERROR;
210 }
211
212