make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / x86_64-pc / kernel / apic.c
blob9db3dbdff1de4a77ff92ec444a482cab1f255616
1 /*
2 Copyright � 1995-2008, The AROS Development Team. All rights reserved.
3 $Id: apic.c,v 1.7 2004/01/07 07:13:03 nicja Exp $
4 */
5 #include <inttypes.h>
7 #include "exec_intern.h"
8 #include "etask.h"
10 #include <exec/lists.h>
11 #include <exec/types.h>
12 #include <exec/tasks.h>
13 #include <exec/execbase.h>
14 #include <aros/libcall.h>
15 #include <asm/segments.h>
16 #include <asm/io.h>
18 #include "kernel_intern.h"
20 #define CONFIG_LAPICS
22 extern int kernel_cstart(struct TagItem *msg, void *entry);
24 extern struct KernelACPIData _Kern_ACPIData;
26 static ULONG usec2tick(ULONG usec)
28 ULONG ret, timer_rpr = 3599597124UL;
29 asm volatile("movl $0,%%eax; divl %2":"=a"(ret):"d"(usec),"m"(timer_rpr));
30 return ret;
33 void udelay(LONG usec)
35 int tick_start, tick;
36 usec = usec2tick(usec);
38 outb(0x80, 0x43);
39 tick_start = inb(0x42);
40 tick_start += inb(0x42) << 8;
42 while (usec > 0)
44 outb(0x80, 0x43);
45 tick = inb(0x42);
46 tick += inb(0x42) << 8;
48 usec -= (tick_start - tick);
49 if (tick > tick_start) usec -= 0x10000;
50 tick_start = tick;
55 /**********************************************************
56 HOOKS
57 **********************************************************/
58 static const char str_APICdefault[] = "default";
60 AROS_UFH1(int, probe_APIC_default,
61 AROS_UFHA(struct GenericAPIC *, hook, A0))
63 AROS_USERFUNC_INIT
65 /* Default to PIC(8259) interrupt routing model. This gets overriden later if IOAPICs are enumerated */
66 _Kern_ACPIData.kb_APIC_IRQ_Model = ACPI_IRQ_MODEL_PIC;
68 return 1; /* should be called last. */
70 AROS_USERFUNC_EXIT
73 /**********************************************************/
75 static const struct GenericAPIC apic_default = {
76 name : str_APICdefault,
77 probe : (APTR)probe_APIC_default,
80 /**********************************************************/
82 static const void * const probe_APIC[] =
84 &apic_default, /* must be last */
85 NULL,
88 /************************************************************************************************/
89 /************************************************************************************************
90 APIC RELATED FUNCTIONS
91 ************************************************************************************************/
92 /************************************************************************************************/
94 IPTR core_APICProbe()
96 int driver_count, retval, changed = 0;
98 for ( driver_count = 0; !changed && probe_APIC[driver_count]; driver_count++ )
100 if (retval = AROS_UFC1(IPTR, ((struct GenericAPIC *)probe_APIC[driver_count])->probe,
101 AROS_UFCA(struct GenericAPIC *, probe_APIC[driver_count], A0)))
103 changed = 1;
104 _Kern_ACPIData.kb_APIC_Driver = (struct GenericAPIC *)probe_APIC[driver_count];
108 if (!changed)
110 rkprintf("[Kernel] core_APICProbe: No suitable APIC driver found.\n");
112 else
114 rkprintf("[Kernel] core_APICProbe: Using APIC driver '%s'\n", ((struct GenericAPIC *) _Kern_ACPIData.kb_APIC_Driver)->name);
117 return changed;
120 IPTR core_APICGetMSRAPICBase()
122 IPTR _apic_base = NULL;
124 #warning "TODO: Obtain APIC base from MSR"
126 _apic_base = 0xfee00000;
128 rkprintf("[Kernel] core_APICGetMSRAPICBase: MSR APIC Base @ %p\n", _apic_base);
129 return _apic_base;
132 UBYTE core_APICGetID(IPTR _APICBase)
134 UBYTE _apic_id;
136 _apic_id = (*(volatile uint32_t*)(_APICBase + 0x20) & 0xFF000000) >> 24;
137 rkprintf("[Kernel] core_APICGetID: APIC ID %d\n", _apic_id);
138 return _apic_id;
141 #define APICICR_INT_LEVELTRIG 0x8000
142 #define APICICR_INT_ASSERT 0x4000
143 #define APICICR_DM_INIT 0x500
144 #define APICICR_DM_STARTUP 0x600
146 int kernel_cstart(struct TagItem *msg, void *entry);
148 void core_APICInitialise(IPTR _APICBase)
150 uint32_t APIC_VAL;
151 unsigned int apic_ver, maxlvt;
153 *(volatile uint32_t*)(_APICBase + 0xE0) = 0xFFFFFFFF; /* Put the APIC into flat delivery mode */
155 /* Set up the logical destination ID. */
156 APIC_VAL = *(volatile uint32_t*)(_APICBase + 0xD0) & ~(0xFF<<24);
157 APIC_VAL |= (1 << 24);
158 *(volatile uint32_t*)(_APICBase + 0xD0) = APIC_VAL;
160 /* Set Task Priority to 'accept all' */
161 APIC_VAL = *(volatile uint32_t*)(_APICBase + 0x80) & ~0xFF;
162 *(volatile uint32_t*)(_APICBase + 0x80) = APIC_VAL;
164 APIC_VAL = *(volatile uint32_t*)(_APICBase + 0xF0) & ~0xFF;
165 APIC_VAL |= (1 << 8); /* Enable APIC */
166 APIC_VAL |= (1 << 9); /* Disable focus processor (bit==1) */
167 APIC_VAL |= 0xFF; /* Set spurious IRQ vector */
168 *(volatile uint32_t*)(_APICBase + 0xF0) = APIC_VAL;
170 APIC_VAL = *(volatile uint32_t*)(_APICBase + 0x350) & (1<<16);
171 APIC_VAL = 0x700;
172 *(volatile uint32_t*)(_APICBase + 0x350) = APIC_VAL;
174 /* only the BP should see the LINT1 NMI signal. */
175 APIC_VAL = 0x400;
176 *(volatile uint32_t*)(_APICBase + 0x360) = APIC_VAL;
178 D(bug("[Kernel] core_APICInitialise: APIC LVT0=%08x\n", *(volatile uint32_t*)(_APICBase + 0x350)));
179 D(bug("[Kernel] core_APICInitialise: APIC LVT1=%08x\n", *(volatile uint32_t*)(_APICBase + 0x360)));
181 /* Due to the Pentium erratum 3AP. */
182 apic_ver = (*((volatile uint32_t*)(_APICBase + 0x30)) & 0xFF);
183 maxlvt = (apic_ver & 0xF0) ? ((*((volatile uint32_t*)(_APICBase + 0x30)) >> 16) & 0xFF) : 2; /* 82489DXs doesnt report no. of LVT entries. */
184 if (maxlvt > 3)
185 *(volatile uint32_t*)(_APICBase + 0x280) = 0;
187 D(bug("[Kernel] core_APICInitialise: APIC ESR before enabling vector: %08lx\n", *(volatile uint32_t*)(_APICBase + 0x280)));
189 *(volatile uint32_t*)(_APICBase + 0x370) = 0xfe; /* Enable error sending */
191 /* spec says clear errors after enabling vector. */
192 if (maxlvt > 3)
193 *(volatile uint32_t*)(_APICBase + 0x280) = 0;
195 D(bug("[Kernel] core_APICInitialise: APIC ESR after enabling vector: %08lx\n", *(volatile uint32_t*)(_APICBase + 0x280)));
198 unsigned long core_APICIPIWake(UBYTE wake_apicid, IPTR wake_apicstartrip)
200 struct KernelBase *KernelBase = TLS_GET(KernelBase);
201 unsigned long delay_time, status_ipisend, ipisend_timeout, status_ipirecv = 0;
202 unsigned int apic_ver, maxlvt, start_count, max_starts = 2;
203 IPTR _APICStackBase;
205 rkprintf("[Kernel] core_APICIPIWake(%d @ %p)\n", wake_apicid, wake_apicstartrip);
207 /* Setup stack for the new APIC */
208 _APICStackBase = AllocMem(STACK_SIZE, MEMF_CLEAR);
209 rkprintf("[Kernel] core_APICIPIWake: APIC stack allocated @ %p\n", _APICStackBase);
211 *(IPTR*)(wake_apicstartrip + 0x0018) = _APICStackBase + STACK_SIZE - SP_OFFSET;
212 *(IPTR*)(wake_apicstartrip + 0x0020) = kernel_cstart;
214 /* Send the IPI by setting APIC_ICR : Set INIT on target APIC
215 by writing the apicid to the destfield of APIC_ICR2 */
216 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x310)) = ((wake_apicid)<<24);
217 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) = APICICR_INT_LEVELTRIG | APICICR_INT_ASSERT | APICICR_DM_INIT;
219 rkprintf("[Kernel] core_APICIPIWake: Waiting for IPI INIT to complete...\n");
220 ipisend_timeout = 1000;
221 do {
222 udelay(100);
224 status_ipisend = *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) & 0x1000;
225 } while (status_ipisend && (ipisend_timeout--));
227 udelay(10 * 1000);
229 /* Send the IPI by setting APIC_ICR */
230 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x310)) = ((wake_apicid)<<24); /* Set the target APIC */
231 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) = APICICR_INT_LEVELTRIG | APICICR_DM_INIT;
233 rkprintf("[Kernel] core_APICIPIWake: Waiting for IPI INIT to deassert ...\n");
234 ipisend_timeout = 1000;
235 do {
236 udelay(100);
238 status_ipisend = *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) & 0x1000;
239 } while (status_ipisend && (ipisend_timeout--));
241 /* memory barrier */
242 do { asm volatile("mfence":::"memory"); }while(0);
244 /* check for Pentium erratum 3AP .. */
245 apic_ver = (*((volatile uint32_t*)(KernelBase->kb_APICBase + 0x30)) & 0xFF);
246 maxlvt = (apic_ver & 0xF0) ? ((*((volatile uint32_t*)(KernelBase->kb_APICBase + 0x30)) >> 16) & 0xFF) : 2; /* 82489DXs doesnt report no. of LVT entries. */
248 /* Perform IPI STARTUP loop */
249 for (start_count = 1; start_count<=max_starts; start_count++)
251 rkprintf("[Kernel] core_APICIPIWake: Attempting STARTUP .. %d\n", start_count);
252 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x280)) = 0;
253 status_ipisend = *(volatile uint32_t*)(KernelBase->kb_APICBase + 0x280);
254 rkprintf("[Kernel] core_APICIPIWake: IPI STARTUP sent\n");
256 /* STARTUP IPI */
257 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x310)) = ((wake_apicid)<<24); /* Set the target APIC */
258 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) = APICICR_DM_STARTUP | (wake_apicstartrip>>12);
260 /* Allow the target APIC to accept the IPI */
261 udelay(300);
263 rkprintf("[Kernel] core_APICIPIWake: Waiting for IPI STARTUP to complete...\n");
264 ipisend_timeout = 1000;
265 do {
266 udelay(100);
268 status_ipisend = *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x300)) & 0x1000;
269 } while (status_ipisend && (ipisend_timeout--));
271 /* Allow the target APIC to accept the IPI */
272 udelay(200);
274 if (maxlvt > 3)
275 *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x280)) = 0;
277 status_ipirecv = *((volatile uint32_t*)(KernelBase->kb_APICBase + 0x280)) & 0xEF;
278 if (status_ipisend || status_ipirecv) break;
280 rkprintf("[Kernel] core_APICIPIWake: STARTUP run finished...\n");
282 if (status_ipisend)
284 rkprintf("[Kernel] core_APICIPIWake: APIC delivery failed\n");
286 if (status_ipirecv)
288 rkprintf("[Kernel] core_APICIPIWake: APIC delivery error (%lx)\n", status_ipirecv);
291 return (status_ipisend | status_ipirecv);