e1000: fix resetting bug
[akaros.git] / kern / arch / i686 / apic.h
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  */
6
7 #ifndef ROS_KERN_APIC_H
8 #define ROS_KERN_APIC_H
9
10 /* 
11  * Functions and definitions for dealing with the APIC and PIC, specific to
12  * Intel.  Does not handle an x2APIC.
13  */
14
15 #include <arch/mmu.h>
16 #include <arch/x86.h>
17 #include <arch/ioapic.h>
18
19 /* PIC (8259A)
20  * When looking at the specs, A0 is our CMD line, and A1 is the DATA line.  This
21  * means that blindly writing to PIC1_DATA is an OCW1 (interrupt masks).  When
22  * writing to CMD (A0), the chip can determine betweeb OCW2 and OCW3 by the
23  * setting of a few specific bits (OCW2 has bit 3 unset, OCW3 has it set). */
24 #define PIC1_CMD                                        0x20
25 #define PIC1_DATA                                       0x21
26 #define PIC2_CMD                                        0xA0
27 #define PIC2_DATA                                       0xA1
28 // These are also hardcoded into the IRQ_HANDLERs of kern/trapentry.S
29 #define PIC1_OFFSET                                     0x20
30 #define PIC2_OFFSET                                     0x28
31 #define PIC1_SPURIOUS                           (7 + PIC1_OFFSET)
32 #define PIC2_SPURIOUS                           (7 + PIC2_OFFSET)
33 #define PIC_EOI                                         0x20    /* OCW2 EOI */
34 /* These set the next CMD read to return specific values.  Note that the chip
35  * remembers what setting we had before (IRR or ISR), if you do other reads of
36  * CMD. (not tested, written in the spec sheet) */
37 #define PIC_READ_IRR                            0x0a    /* OCW3 irq ready next CMD read */
38 #define PIC_READ_ISR                            0x0b    /* OCW3 irq service next CMD read */
39
40 // Local APIC
41 /* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE */
42 #define LAPIC_PBASE                                     0xfee00000 /* default *physical* address */
43 #define LAPIC_EOI                                       (LAPIC_BASE + 0x0b0)
44 #define LAPIC_SPURIOUS                          (LAPIC_BASE + 0x0f0)
45 #define LAPIC_VERSION                           (LAPIC_BASE + 0x030)
46 #define LAPIC_ERROR                                     (LAPIC_BASE + 0x280)
47 #define LAPIC_ID                                        (LAPIC_BASE + 0x020)
48 #define LAPIC_LOGICAL_ID                        (LAPIC_BASE + 0x0d0)
49 // LAPIC Local Vector Table
50 #define LAPIC_LVT_TIMER                         (LAPIC_BASE + 0x320)
51 #define LAPIC_LVT_LINT0                         (LAPIC_BASE + 0x350)
52 #define LAPIC_LVT_LINT1                         (LAPIC_BASE + 0x360)
53 #define LAPIC_LVT_ERROR                         (LAPIC_BASE + 0x370)
54 #define LAPIC_LVT_PERFMON                       (LAPIC_BASE + 0x340)
55 #define LAPIC_LVT_THERMAL                       (LAPIC_BASE + 0x330)
56 #define LAPIC_LVT_MASK                          0x00010000
57 // LAPIC Timer
58 #define LAPIC_TIMER_INIT                        (LAPIC_BASE + 0x380)
59 #define LAPIC_TIMER_CURRENT                     (LAPIC_BASE + 0x390)
60 #define LAPIC_TIMER_DIVIDE                      (LAPIC_BASE + 0x3e0)
61 #define LAPIC_TIMER_DEFAULT_VECTOR      0xeb            /* Aka 235, IRQ203 */
62 /* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
63  * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
64  * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
65  * and decreases the granularity of the timer.  Numbers are appx, based on 4
66  * billion ticks, vs 2^32 ticks.
67  * Ex:   1GHz bus, div 001:    4sec max,    1ns granularity
68  * Ex:   1GHz bus, div 128:  512sec max,  128ns granularity
69  * Ex: 100MHz bus, div 001:   40sec max,   10ns granularity
70  * Ex: 100MHz bus, div 128: 5120sec max, 1280ns granularity */
71 #define LAPIC_TIMER_DIVISOR_VAL         32      /* seems reasonable */
72 #define LAPIC_TIMER_DIVISOR_BITS        0x8     /* Div = 32 */
73
74 // IPI Interrupt Command Register
75 #define LAPIC_IPI_ICR_LOWER                     (LAPIC_BASE + 0x300)
76 #define LAPIC_IPI_ICR_UPPER                     (LAPIC_BASE + 0x310)
77 /* Interrupts being serviced (in-service) and pending (interrupt request reg).
78  * Note these registers are not normal bitmaps, but instead are 8 separate
79  * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
80  * space. */
81 #define LAPIC_ISR                                       (LAPIC_BASE + 0x100)
82 #define LAPIC_IRR                                       (LAPIC_BASE + 0x200)
83
84 // PIT (Programmable Interval Timer)
85 #define TIMER_REG_CNTR0 0       /* timer 0 counter port */
86 #define TIMER_REG_CNTR1 1       /* timer 1 counter port */
87 #define TIMER_REG_CNTR2 2       /* timer 2 counter port */
88 #define TIMER_REG_MODE  3       /* timer mode port */
89 #define TIMER_SEL0      0x00    /* select counter 0 */
90 #define TIMER_SEL1      0x40    /* select counter 1 */
91 #define TIMER_SEL2      0x80    /* select counter 2 */
92 #define TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
93 #define TIMER_ONESHOT   0x02    /* mode 1, one shot */
94 #define TIMER_RATEGEN   0x04    /* mode 2, rate generator */
95 #define TIMER_SQWAVE    0x06    /* mode 3, square wave */
96 #define TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
97 #define TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
98 #define TIMER_LATCH     0x00    /* latch counter for reading */
99 #define TIMER_LSB       0x10    /* r/w counter LSB */
100 #define TIMER_MSB       0x20    /* r/w counter MSB */
101 #define TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
102 #define TIMER_BCD       0x01    /* count in BCD */
103
104 #define PIT_FREQ                                        1193182
105
106 #define IO_TIMER1   0x40        /* 8253 Timer #1 */
107 #define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
108 #define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
109 #define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
110 #define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
111
112 typedef struct system_timing {
113         uint64_t tsc_freq;
114         uint64_t bus_freq;
115         uint64_t timing_overhead;
116         uint16_t pit_divisor;
117         uint8_t pit_mode;
118 } system_timing_t;
119
120 extern system_timing_t system_timing;
121
122 void pic_remap(void);
123 void pic_mask_irq(uint8_t irq);
124 void pic_unmask_irq(uint8_t irq);
125 uint16_t pic_get_mask(void);
126 uint16_t pic_get_irr(void);
127 uint16_t pic_get_isr(void);
128 bool lapic_get_isr_bit(uint8_t vector);
129 bool lapic_get_irr_bit(uint8_t vector);
130 void lapic_print_isr(void);
131 bool ipi_is_pending(uint8_t vector);
132 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
133 void lapic_set_timer(uint32_t usec, bool periodic);
134 uint32_t lapic_get_default_id(void);
135 // PIT related
136 void pit_set_timer(uint32_t freq, uint32_t mode);
137 void timer_init(void);
138 void udelay_pit(uint64_t usec);
139 // TODO: right now timer defaults to TSC
140 uint64_t gettimer(void);
141 uint64_t getfreq(void);
142
143 static inline void pic_send_eoi(uint32_t irq);
144 static inline void lapic_send_eoi(void);
145 static inline uint32_t lapic_get_version(void);
146 static inline uint32_t lapic_get_error(void);
147 static inline uint32_t lapic_get_id(void);
148 static inline void lapic_set_id(uint8_t id); // Careful, may not actually work
149 static inline uint8_t lapic_get_logid(void);
150 static inline void lapic_set_logid(uint8_t id);
151 static inline void lapic_disable_timer(void);
152 static inline void lapic_disable(void);
153 static inline void lapic_enable(void);
154 static inline void lapic_wait_to_send(void);
155 static inline void send_init_ipi(void);
156 static inline void send_startup_ipi(uint8_t vector);
157 static inline void send_self_ipi(uint8_t vector);
158 static inline void send_broadcast_ipi(uint8_t vector);
159 static inline void send_all_others_ipi(uint8_t vector);
160 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector);
161 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
162 static inline void __send_nmi(uint8_t hw_coreid);
163
164 #define mask_lapic_lvt(entry) \
165         write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
166 #define unmask_lapic_lvt(entry) \
167         write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
168
169 static inline void pic_send_eoi(uint32_t irq)
170 {
171         // all irqs beyond the first seven need to be chained to the slave
172         if (irq > 7)
173                 outb(PIC2_CMD, PIC_EOI);
174         outb(PIC1_CMD, PIC_EOI);
175 }
176
177 static inline void lapic_send_eoi(void)
178 {
179         write_mmreg32(LAPIC_EOI, 0);
180 }
181
182 static inline uint32_t lapic_get_version(void)
183 {
184         return read_mmreg32(LAPIC_VERSION);     
185 }
186
187 static inline uint32_t lapic_get_error(void)
188 {
189         write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
190         return read_mmreg32(LAPIC_ERROR);
191 }
192
193 static inline uint32_t lapic_get_id(void)
194 {
195         return read_mmreg32(LAPIC_ID) >> 24;
196 }
197
198 static inline void lapic_set_id(uint8_t id)
199 {
200         write_mmreg32(LAPIC_ID, id << 24);
201 }
202
203 static inline uint8_t lapic_get_logid(void)
204 {
205         return read_mmreg32(LAPIC_LOGICAL_ID) >> 24;
206 }
207
208 static inline void lapic_set_logid(uint8_t id)
209 {
210         write_mmreg32(LAPIC_LOGICAL_ID, id << 24);
211 }
212
213 static inline void lapic_disable_timer(void)
214 {
215         write_mmreg32(LAPIC_LVT_TIMER, 0);
216 }
217
218 /* There are a couple ways to do it.  The MSR route doesn't seem to work
219  * in KVM.  It's also a somewhat permanent thing
220  */
221 static inline void lapic_disable(void)
222 {
223         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
224         //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
225 }
226
227 /* Spins until previous IPIs are delivered.  Not sure if we want it inlined
228  * Also not sure when we really need to do this. 
229  */
230 static inline void lapic_wait_to_send(void)
231 {
232         while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
233                 __cpu_relax();
234 }
235
236 static inline void lapic_enable(void)
237 {
238         write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00000100);
239 }
240
241 static inline void send_init_ipi(void)
242 {
243         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
244         lapic_wait_to_send();
245 }
246
247 static inline void send_startup_ipi(uint8_t vector)
248 {
249         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
250         lapic_wait_to_send();
251 }
252
253 static inline void send_self_ipi(uint8_t vector)
254 {
255         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
256         lapic_wait_to_send();
257 }
258
259 static inline void send_broadcast_ipi(uint8_t vector)
260 {
261         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
262         lapic_wait_to_send();
263 }
264
265 static inline void send_all_others_ipi(uint8_t vector)
266 {
267         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
268         lapic_wait_to_send();
269 }
270
271 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
272 {
273         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
274         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | vector);
275         lapic_wait_to_send();
276 }
277
278 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
279 {
280         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_groupid << 24);
281         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004800 | vector);
282         lapic_wait_to_send();
283 }
284
285 static inline void __send_nmi(uint8_t hw_coreid)
286 {
287         if (hw_coreid == 255)
288                 return;
289         write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
290         write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004400);
291         lapic_wait_to_send();
292 }
293
294 /* To change the LAPIC Base (not recommended):
295         msr_val = read_msr(IA32_APIC_BASE);
296         msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
297         write_msr(IA32_APIC_BASE, msr_val);
298 */
299 #endif /* ROS_KERN_APIC_H */