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/trace.h>
12 #include <lk/err.h>
13 #include <lk/reg.h>
14 #include <kernel/thread.h>
15 #include <platform/interrupts.h>
16 #include <arch/ops.h>
17 #include <arch/mips.h>
18 #include <platform/qemu-mips.h>
19 
20 #define LOCAL_TRACE 0
21 
22 static spin_lock_t lock;
23 
24 #define PIC1 0x20
25 #define PIC2 0xA0
26 
27 #define ICW1 0x11
28 #define ICW4 0x01
29 
30 #define PIC1_CMD                    0x20
31 #define PIC1_DATA                   0x21
32 #define PIC2_CMD                    0xA0
33 #define PIC2_DATA                   0xA1
34 #define PIC_READ_IRR                0x0a    /* OCW3 irq ready next CMD read */
35 #define PIC_READ_ISR                0x0b    /* OCW3 irq service next CMD read */
36 
37 #define ICW1_ICW4   0x01        /* ICW4 (not) needed */
38 #define ICW1_SINGLE 0x02        /* Single (cascade) mode */
39 #define ICW1_INTERVAL4  0x04    /* Call address interval 4 (8) */
40 #define ICW1_LEVEL  0x08        /* Level triggered (edge) mode */
41 #define ICW1_INIT   0x10        /* Initialization */
42 
43 #define ICW4_8086   0x01        /* 8086/88 (MCS-80/85) mode */
44 #define ICW4_AUTO   0x02        /* Auto (normal) EOI */
45 #define ICW4_BUF_SLAVE  0x08    /* Buffered mode/slave */
46 #define ICW4_BUF_MASTER 0x0C    /* Buffered mode/master */
47 #define ICW4_SFNM   0x10        /* Special fully nested (not) */
48 
49 struct int_handler_struct {
50     int_handler handler;
51     void *arg;
52 };
53 
54 #define INT_PIC2 2
55 
56 static struct int_handler_struct int_handler_table[INT_VECTORS];
57 
58 /*
59  * Cached IRQ mask (enabled/disabled)
60  */
61 static uint8_t irqMask[2];
62 
63 /*
64  * init the PICs and remap them
65  */
map(uint32_t pic1,uint32_t pic2)66 static void map(uint32_t pic1, uint32_t pic2) {
67     /* send ICW1 */
68     isa_write_8(PIC1, ICW1);
69     isa_write_8(PIC2, ICW1);
70 
71     /* send ICW2 */
72     isa_write_8(PIC1 + 1, pic1);   /* remap */
73     isa_write_8(PIC2 + 1, pic2);   /*  pics */
74 
75     /* send ICW3 */
76     isa_write_8(PIC1 + 1, 4);  /* IRQ2 -> connection to slave */
77     isa_write_8(PIC2 + 1, 2);
78 
79     /* send ICW4 */
80     isa_write_8(PIC1 + 1, 2|5);
81     isa_write_8(PIC2 + 1, 2|1);
82 
83     /* disable all IRQs */
84     isa_write_8(PIC1 + 1, 0xff);
85     isa_write_8(PIC2 + 1, 0xff);
86 
87     irqMask[0] = 0xff;
88     irqMask[1] = 0xff;
89 }
90 
enable(unsigned int vector,bool enable)91 static void enable(unsigned int vector, bool enable) {
92     if (vector < 8) {
93         uint8_t bit = 1 << vector;
94 
95         if (enable && (irqMask[0] & bit)) {
96             irqMask[0] = isa_read_8(PIC1 + 1);
97             irqMask[0] &= ~bit;
98             isa_write_8(PIC1 + 1, irqMask[0]);
99             irqMask[0] = isa_read_8(PIC1 + 1);
100         } else if (!enable && !(irqMask[0] & bit)) {
101             irqMask[0] = isa_read_8(PIC1 + 1);
102             irqMask[0] |= bit;
103             isa_write_8(PIC1 + 1, irqMask[0]);
104             irqMask[0] = isa_read_8(PIC1 + 1);
105         }
106     } else if (vector < 16) {
107         vector -= 8;
108 
109         uint8_t bit = 1 << vector;
110 
111         if (enable && (irqMask[1] & bit)) {
112             irqMask[1] = isa_read_8(PIC2 + 1);
113             irqMask[1] &= ~bit;
114             isa_write_8(PIC2 + 1, irqMask[1]);
115             irqMask[1] = isa_read_8(PIC2 + 1);
116         } else if (!enable && !(irqMask[1] & bit)) {
117             irqMask[1] = isa_read_8(PIC2 + 1);
118             irqMask[1] |= bit;
119             isa_write_8(PIC2 + 1, irqMask[1]);
120             irqMask[1] = isa_read_8(PIC2 + 1);
121         }
122 
123         bit = 1 << INT_PIC2;
124 
125         if (irqMask[1] != 0xff && (irqMask[0] & bit)) {
126             irqMask[0] = isa_read_8(PIC1 + 1);
127             irqMask[0] &= ~bit;
128             isa_write_8(PIC1 + 1, irqMask[0]);
129             irqMask[0] = isa_read_8(PIC1 + 1);
130         } else if (irqMask[1] == 0 && !(irqMask[0] & bit)) {
131             irqMask[0] = isa_read_8(PIC1 + 1);
132             irqMask[0] |= bit;
133             isa_write_8(PIC1 + 1, irqMask[0]);
134             irqMask[0] = isa_read_8(PIC1 + 1);
135         }
136     }
137 }
138 
issueEOI(unsigned int vector)139 static void issueEOI(unsigned int vector) {
140     if (vector < 8) {
141         isa_write_8(PIC1, 0x20);
142     } else if (vector < 16) {
143         isa_write_8(PIC2, 0x20);
144         isa_write_8(PIC1, 0x20);   // must issue both for the second PIC
145     }
146 }
147 
148 /* Helper func */
__pic_get_irq_reg(uint ocw3)149 static uint16_t __pic_get_irq_reg(uint ocw3) {
150     /* OCW3 to PIC CMD to get the register values.  PIC2 is chained, and
151      * represents IRQs 8-15.  PIC1 is IRQs 0-7, with 2 being the chain */
152     isa_write_8(PIC1_CMD, ocw3);
153     isa_write_8(PIC2_CMD, ocw3);
154     return (isa_read_8(PIC2_CMD) << 8) | isa_read_8(PIC1_CMD);
155 }
156 
157 /* Returns the combined value of the cascaded PICs irq request register */
pic_get_irr(void)158 static uint16_t pic_get_irr(void) {
159     return __pic_get_irq_reg(PIC_READ_IRR);
160 }
161 
162 /* Returns the combined value of the cascaded PICs in-service register */
pic_get_isr(void)163 static uint16_t pic_get_isr(void) {
164     return __pic_get_irq_reg(PIC_READ_ISR);
165 }
166 
platform_init_interrupts(void)167 void platform_init_interrupts(void) {
168     // rebase the PIC out of the way of processor exceptions
169     map(0, 8);
170 }
171 
mask_interrupt(unsigned int vector)172 status_t mask_interrupt(unsigned int vector) {
173     if (vector >= INT_VECTORS)
174         return ERR_INVALID_ARGS;
175 
176     LTRACEF("vector %d\n", vector);
177 
178     spin_lock_saved_state_t state;
179     spin_lock_irqsave(&lock, state);
180 
181     enable(vector, false);
182 
183     spin_unlock_irqrestore(&lock, state);
184 
185     return NO_ERROR;
186 }
187 
platform_mask_irqs(void)188 void platform_mask_irqs(void) {
189     irqMask[0] = isa_read_8(PIC1 + 1);
190     irqMask[1] = isa_read_8(PIC2 + 1);
191 
192     isa_write_8(PIC1 + 1, 0xff);
193     isa_write_8(PIC2 + 1, 0xff);
194 
195     irqMask[0] = isa_read_8(PIC1 + 1);
196     irqMask[1] = isa_read_8(PIC2 + 1);
197 }
198 
unmask_interrupt(unsigned int vector)199 status_t unmask_interrupt(unsigned int vector) {
200     if (vector >= INT_VECTORS)
201         return ERR_INVALID_ARGS;
202 
203     LTRACEF("vector %d\n", vector);
204 
205     spin_lock_saved_state_t state;
206     spin_lock_irqsave(&lock, state);
207 
208     enable(vector, true);
209 
210     spin_unlock_irqrestore(&lock, state);
211 
212     return NO_ERROR;
213 }
214 
platform_irq(struct mips_iframe * iframe,uint vector)215 enum handler_return platform_irq(struct mips_iframe *iframe, uint vector) {
216     // figure out which irq is pending
217     // issue OCW3 poll commands to PIC1 and (potentially) PIC2
218     isa_write_8(PIC1_CMD, (1<<3) | (1<<2));
219     uint8_t val = isa_read_8(PIC1_CMD);
220     if ((val & 0x80) == 0) {
221         // spurious?
222         return INT_NO_RESCHEDULE;
223     }
224     val &= ~0x80;
225     if (val == INT_PIC2) {
226         isa_write_8(PIC2_CMD, (1<<3) | (1<<2));
227         val = isa_read_8(PIC2_CMD);
228         if ((val & 0x80) == 0) {
229             // spurious?
230             return INT_NO_RESCHEDULE;
231         }
232         val &= ~0x80;
233     }
234     vector = val;
235     LTRACEF("poll vector 0x%x\n", vector);
236 
237     THREAD_STATS_INC(interrupts);
238 
239     // deliver the interrupt
240     enum handler_return ret = INT_NO_RESCHEDULE;
241 
242     if (int_handler_table[vector].handler)
243         ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
244 
245     return ret;
246 }
247 
register_int_handler(unsigned int vector,int_handler handler,void * arg)248 void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
249     if (vector >= INT_VECTORS)
250         panic("register_int_handler: vector out of range %d\n", vector);
251 
252     spin_lock_saved_state_t state;
253     spin_lock_irqsave(&lock, state);
254 
255     int_handler_table[vector].arg = arg;
256     int_handler_table[vector].handler = handler;
257 
258     spin_unlock_irqrestore(&lock, state);
259 }
260 
261