00001
00002
00003 #ifndef apic_h
00004 #define apic_h
00005
00006 #include "types.h"
00007 #include "initcalls.h"
00008
00009
00010
00011
00012
00013
00014 class Return_frame;
00015
00016 class Apic
00017 {
00018 public:
00019 static void init() FIASCO_INIT;
00020
00021 typedef enum
00022 {
00023 APIC_NONE,
00024 APIC_P6,
00025 APIC_P4,
00026 APIC_K7
00027 } Apic_type;
00028
00029 private:
00030 Apic();
00031 Apic(const Apic&);
00032 static void error_interrupt(Return_frame *regs)
00033 asm ("apic_error_interrupt") FIASCO_FASTCALL;
00034
00035 static int present;
00036 static int good_cpu;
00037 static const Address io_base;
00038 static Address phys_base;
00039 static unsigned timer_divisor;
00040 static Apic_type type;
00041 static unsigned frequency_khz;
00042 static unsigned max_lvt;
00043 static Unsigned32 scaler_ns_to_apic;
00044
00045 enum
00046 {
00047 APIC_ID = 0x20,
00048 APIC_LVR = 0x30,
00049 APIC_TASKPRI = 0x80,
00050 APIC_TPRI_MASK = 0xFF,
00051 APIC_EOI = 0xB0,
00052 APIC_LDR = 0xD0,
00053 APIC_LDR_MASK = (0xFF<<24),
00054 APIC_DFR = 0xE0,
00055 APIC_SPIV = 0xF0,
00056 APIC_ISR = 0x100,
00057 APIC_TMR = 0x180,
00058 APIC_IRR = 0x200,
00059 APIC_ESR = 0x280,
00060 APIC_LVTT = 0x320,
00061 APIC_LVTTHMR = 0x330,
00062 APIC_LVTPC = 0x340,
00063 APIC_LVT0 = 0x350,
00064 APIC_TIMER_BASE_DIV = 0x2,
00065 APIC_LVT1 = 0x360,
00066 APIC_LVTERR = 0x370,
00067 APIC_TMICT = 0x380,
00068 APIC_TMCCT = 0x390,
00069 APIC_TDCR = 0x3E0,
00070
00071 APIC_SND_PENDING = (1<<12),
00072 APIC_INPUT_POLARITY = (1<<13),
00073 APIC_LVT_REMOTE_IRR = (1<<14),
00074 APIC_LVT_LEVEL_TRIGGER = (1<<15),
00075 APIC_LVT_MASKED = (1<<16),
00076 APIC_LVT_TIMER_PERIODIC = (1<<17),
00077 APIC_TDR_DIV_1 = 0xB,
00078 APIC_TDR_DIV_2 = 0x0,
00079 APIC_TDR_DIV_4 = 0x1,
00080 APIC_TDR_DIV_8 = 0x2,
00081 APIC_TDR_DIV_16 = 0x3,
00082 APIC_TDR_DIV_32 = 0x8,
00083 APIC_TDR_DIV_64 = 0x9,
00084 APIC_TDR_DIV_128 = 0xA,
00085 };
00086
00087 enum
00088 {
00089 MASK = 1,
00090 TRIGGER_MODE = 2,
00091 REMOTE_IRR = 4,
00092 PIN_POLARITY = 8,
00093 DELIVERY_STATE = 16,
00094 DELIVERY_MODE = 32,
00095 };
00096
00097 enum
00098 {
00099 APIC_BASE_MSR = 0x1b,
00100 };
00101
00102 public:
00103 static inline unsigned get_frequency_khz();
00104
00105 static inline Unsigned32 reg_read(unsigned reg);
00106
00107 static inline void reg_write(unsigned reg, Unsigned32 val);
00108
00109 static inline int reg_delivery_mode(Unsigned32 val);
00110
00111 static inline int reg_lvt_vector(Unsigned32 val);
00112
00113 static inline Unsigned32 timer_reg_read();
00114
00115 static inline Unsigned32 timer_reg_read_initial();
00116
00117 static inline void timer_reg_write(Unsigned32 val);
00118
00119 static inline Unsigned32 ns_to_apic(Unsigned64 ns);
00120
00121 static inline void timer_enable_irq();
00122
00123 static inline void timer_disable_irq();
00124
00125 static inline int timer_is_irq_enabled();
00126
00127 static inline void timer_set_periodic();
00128
00129 static inline void timer_set_one_shot();
00130
00131 static inline void timer_assign_irq_vector(unsigned vector);
00132
00133 static inline void irq_ack();
00134
00135 static inline int have_pcint();
00136
00137 static inline int have_tsint();
00138
00139
00140 static int test_present_but_disabled();
00141
00142
00143 static FIASCO_INIT int check_still_getting_interrupts();
00144
00145 static inline int is_present();
00146
00147 static inline int cpu_type();
00148
00149 static void set_perf_nmi();
00150
00151
00152 static void done();
00153
00154 static void reg_show(unsigned reg);
00155
00156 static void regs_show(void);
00157
00158 static void timer_show(void);
00159
00160 static void id_show(void);
00161
00162 static void irr_show();
00163
00164 static void isr_show();
00165
00166 private:
00167 static inline Unsigned32 get_id();
00168
00169 static inline Unsigned32 get_version();
00170
00171 static inline int is_integrated();
00172
00173 static inline Unsigned32 get_max_lvt();
00174
00175 static inline Unsigned32 get_num_errors();
00176
00177 static inline void clear_num_errors();
00178
00179
00180 static FIASCO_INIT void map_apic_page();
00181
00182
00183 static FIASCO_INIT int test_cpu();
00184
00185
00186 static inline int test_present();
00187
00188 static void timer_set_divisor(unsigned newdiv);
00189
00190 static FIASCO_INIT int get_maxlvt();
00191
00192
00193 static FIASCO_INIT int check_working();
00194
00195 static FIASCO_INIT void init_spiv();
00196
00197
00198 static FIASCO_INIT void enable_errors();
00199
00200
00201
00202
00203 static FIASCO_INIT void route_pic_through_apic();
00204
00205 static FIASCO_INIT void init_lvt();
00206
00207
00208 static FIASCO_INIT void activate_by_msr();
00209
00210 static FIASCO_INIT void calibrate_timer();
00211
00212 static const char* reg_lvt_bit_str(unsigned reg, Unsigned32 val, int bit);
00213
00214 static void bitfield_show(unsigned reg, const char *name, char flag);
00215 };
00216
00217 extern unsigned apic_spurious_interrupt_bug_cnt;
00218 extern unsigned apic_spurious_interrupt_cnt;
00219 extern unsigned apic_error_cnt;
00220
00221
00222
00223
00224
00225
00226
00227
00228 inline unsigned
00229 Apic::get_frequency_khz()
00230 {
00231 return frequency_khz;
00232 }
00233
00234
00235
00236 inline Unsigned32
00237 Apic::reg_read(unsigned reg)
00238 {
00239 return *((volatile unsigned*)(io_base + reg));
00240 }
00241
00242
00243
00244 inline void
00245 Apic::reg_write(unsigned reg, Unsigned32 val)
00246 {
00247 *((volatile Unsigned32*)(io_base + reg)) = val;
00248 }
00249
00250
00251
00252 inline int
00253 Apic::reg_delivery_mode(Unsigned32 val)
00254 {
00255 return (val >> 8) & 7;
00256 }
00257
00258
00259
00260 inline int
00261 Apic::reg_lvt_vector(Unsigned32 val)
00262 {
00263 return val & 0xff;
00264 }
00265
00266
00267
00268 inline Unsigned32
00269 Apic::timer_reg_read()
00270 {
00271 return reg_read(APIC_TMCCT);
00272 }
00273
00274
00275
00276 inline Unsigned32
00277 Apic::timer_reg_read_initial()
00278 {
00279 return reg_read(APIC_TMICT);
00280 }
00281
00282
00283
00284 inline void
00285 Apic::timer_reg_write(Unsigned32 val)
00286 {
00287 reg_read(APIC_TMICT);
00288 reg_write(APIC_TMICT, val);
00289 }
00290
00291
00292
00293 inline Unsigned32
00294 Apic::ns_to_apic(Unsigned64 ns)
00295 {
00296 Unsigned32 apic, dummy1, dummy2;
00297 asm ("movl %%edx, %%ecx \n\t"
00298 "mull %4 \n\t"
00299 "movl %%ecx, %%eax \n\t"
00300 "movl %%edx, %%ecx \n\t"
00301 "mull %4 \n\t"
00302 "addl %%ecx, %%eax \n\t"
00303 :"=a" (apic), "=d" (dummy1), "=&c" (dummy2)
00304 : "A" (ns), "g" (scaler_ns_to_apic)
00305 );
00306 return apic;
00307 }
00308
00309
00310
00311 inline void
00312 Apic::timer_enable_irq()
00313 {
00314 Unsigned32 tmp_val;
00315
00316 tmp_val = reg_read(APIC_LVTT);
00317 tmp_val &= ~(APIC_LVT_MASKED);
00318 reg_write(APIC_LVTT, tmp_val);
00319 }
00320
00321
00322
00323 inline void
00324 Apic::timer_disable_irq()
00325 {
00326 Unsigned32 tmp_val;
00327
00328 tmp_val = reg_read(APIC_LVTT);
00329 tmp_val |= APIC_LVT_MASKED;
00330 reg_write(APIC_LVTT, tmp_val);
00331 }
00332
00333
00334
00335 inline int
00336 Apic::timer_is_irq_enabled()
00337 {
00338 return ~reg_read(APIC_LVTT) & APIC_LVT_MASKED;
00339 }
00340
00341
00342
00343 inline void
00344 Apic::timer_set_periodic()
00345 {
00346 Unsigned32 tmp_val = reg_read(APIC_LVTT);
00347 tmp_val |= APIC_LVT_TIMER_PERIODIC;
00348 reg_write(APIC_LVTT, tmp_val);
00349 }
00350
00351
00352
00353 inline void
00354 Apic::timer_set_one_shot()
00355 {
00356 Unsigned32 tmp_val = reg_read(APIC_LVTT);
00357 tmp_val &= ~APIC_LVT_TIMER_PERIODIC;
00358 reg_write(APIC_LVTT, tmp_val);
00359 }
00360
00361
00362
00363 inline void
00364 Apic::timer_assign_irq_vector(unsigned vector)
00365 {
00366 Unsigned32 tmp_val = reg_read(APIC_LVTT);
00367 tmp_val &= 0xffffff00;
00368 tmp_val |= vector;
00369 reg_write(APIC_LVTT, tmp_val);
00370 }
00371
00372
00373
00374 inline void
00375 Apic::irq_ack()
00376 {
00377 reg_read(APIC_SPIV);
00378 reg_write(APIC_EOI, 0);
00379 }
00380
00381
00382
00383 inline int
00384 Apic::have_pcint()
00385 {
00386 return (present && (max_lvt >= 4));
00387 }
00388
00389
00390
00391 inline int
00392 Apic::have_tsint()
00393 {
00394 return (present && (max_lvt >= 5));
00395 }
00396
00397
00398
00399 inline int
00400 Apic::is_present()
00401 {
00402 return present;
00403 }
00404
00405
00406
00407 inline int
00408 Apic::cpu_type()
00409 {
00410 return type;
00411 }
00412
00413 #endif // apic_h