95dba5f8e5201051504f5d8c098a631812b554e6
[coreboot.git] / src / arch / i386 / lib / cpu.c
1 #include <console/console.h>
2 #include <cpu/cpu.h>
3 #include <mem.h>
4 #include <arch/io.h>
5 #include <string.h>
6 #include <cpu/cpufixup.h>
7 #include <smp/start_stop.h>
8 #include <cpu/cpufixup.h>
9 #include <cpu/p6/mtrr.h>
10 #include <cpu/p6/msr.h>
11 #include <cpu/p6/apic.h>
12 #include <cpu/p5/cpuid.h>
13 #if 0
14 #include <cpu/l2_cache.h>
15 #endif
16
17 #if CONFIG_SMP || CONFIG_IOAPIC
18 #define APIC 1
19 #endif
20
21
22 static void cache_on(struct mem_range *mem)
23 {
24         post_code(0x60);
25         printk_info("Enabling cache...");
26
27
28         /* we need an #ifdef i586 here at some point ... */
29         __asm__ __volatile__("mov %cr0, %eax\n\t"
30                              "and $0x9fffffff,%eax\n\t"
31                              "mov %eax, %cr0\n\t");
32         /* turns out cache isn't really on until you set MTRR registers on 
33          * 686 and later. 
34          * NOTHING FANCY. Linux does a much better job anyway. 
35          * so absolute minimum needed to get it going. 
36          */
37         /* OK, linux it turns out does nothing. We have to do it ... */
38 #if defined(i686) 
39         // totalram here is in linux sizing, i.e. units of KB. 
40         // set_mtrr is responsible for getting it into the right units!
41         setup_mtrrs(mem);
42 #endif
43
44         post_code(0x6A);
45         printk_info("done.\n");
46 }
47
48 static void interrupts_on()
49 {
50         /* this is so interrupts work. This is very limited scope -- 
51          * linux will do better later, we hope ...
52          */
53         /* this is the first way we learned to do it. It fails on real SMP 
54          * stuff. So we have to do things differently ... 
55          * see the Intel mp1.4 spec, page A-3
56          */
57
58 #if defined(APIC)
59         /* Only Pentium Pro and later have those MSR stuff */
60         msr_t msr;
61
62         printk_info("Setting up local apic...");
63
64         /* Enable the local apic */
65         msr = rdmsr(APIC_BASE_MSR);
66         msr.lo |= APIC_BASE_MSR_ENABLE;
67         msr.lo &= ~APIC_BASE_MSR_ADDR_MASK;
68         msr.lo |= APIC_DEFAULT_BASE;
69         wrmsr(APIC_BASE_MSR, msr);
70
71         /*
72          * Set Task Priority to 'accept all'.
73          */
74         apic_write_around(APIC_TASKPRI,
75                 apic_read_around(APIC_TASKPRI) & ~APIC_TPRI_MASK);
76
77         /* Put the local apic in virtual wire mode */
78         apic_write_around(APIC_SPIV, 
79                 (apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
80                 | APIC_SPIV_ENABLE);
81         apic_write_around(APIC_LVT0, 
82                 (apic_read_around(APIC_LVT0) & 
83                         ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | 
84                                 APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | 
85                                 APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
86                                 APIC_DELIVERY_MODE_MASK))
87                 | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | 
88                         APIC_DELIVERY_MODE_EXTINT)
89                 );
90         apic_write_around(APIC_LVT1, 
91                 (apic_read_around(APIC_LVT1) & 
92                         ~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER | 
93                                 APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY | 
94                                 APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
95                                 APIC_DELIVERY_MODE_MASK))
96                 | (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING | 
97                         APIC_DELIVERY_MODE_NMI)
98                 );
99
100         printk_debug(" apic_id: %d ",
101                 apic_read(APIC_ID));
102
103 #else /* APIC */
104 #ifdef i686
105         /* Only Pentium Pro and later have those MSR stuff */
106         msr_t msr;
107
108         printk_info("Disabling local apic...");
109
110         msr = rdmsr(APIC_BASE_MSR);
111         msr.lo &= ~APIC_BASE_MSR_ENABLE;
112         wrmsr(APIC_BASE_MSR, msr);
113 #endif /* i686 */
114 #endif /* APIC */
115         printk_info("done.\n");
116         post_code(0x9b);
117 }
118
119 unsigned long cpu_initialize(struct mem_range *mem)
120 {
121         /* Because we busy wait at the printk spinlock.
122          * It is important to keep the number of printed messages
123          * from secondary cpus to a minimum, when debugging is
124          * disabled.
125          */
126         unsigned long processor_id = this_processors_id();
127         printk_notice("Initializing CPU #%d\n", processor_id);
128         
129         /* some cpus need a fixup done. This is the hook for doing that. */
130         cpufixup(mem);
131
132         /* Turn on caching if we haven't already */
133         cache_on(mem);
134
135         display_cpuid();
136         mtrr_check();
137
138 #if 0
139         /* now that everything is really up, enable the l2 cache if desired. 
140          * The enable can wait until this point, because linuxbios and it's
141          * data areas are tiny, easily fitting into the L1 cache. 
142          */
143         configure_l2_cache();
144 #endif
145         interrupts_on();
146         processor_id = this_processors_id();
147         printk_info("CPU #%d Initialized\n", processor_id);
148         return processor_id;
149 }
150