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 $
7 #include "exec_intern.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>
18 #include "kernel_intern.h"
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
));
33 void udelay(LONG usec
)
36 usec
= usec2tick(usec
);
39 tick_start
= inb(0x42);
40 tick_start
+= inb(0x42) << 8;
46 tick
+= inb(0x42) << 8;
48 usec
-= (tick_start
- tick
);
49 if (tick
> tick_start
) usec
-= 0x10000;
55 /**********************************************************
57 **********************************************************/
58 static const char str_APICdefault
[] = "default";
60 AROS_UFH1(int, probe_APIC_default
,
61 AROS_UFHA(struct GenericAPIC
*, hook
, A0
))
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. */
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 */
88 /************************************************************************************************/
89 /************************************************************************************************
90 APIC RELATED FUNCTIONS
91 ************************************************************************************************/
92 /************************************************************************************************/
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
)))
104 _Kern_ACPIData
.kb_APIC_Driver
= (struct GenericAPIC
*)probe_APIC
[driver_count
];
110 rkprintf("[Kernel] core_APICProbe: No suitable APIC driver found.\n");
114 rkprintf("[Kernel] core_APICProbe: Using APIC driver '%s'\n", ((struct GenericAPIC
*) _Kern_ACPIData
.kb_APIC_Driver
)->name
);
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
);
132 UBYTE
core_APICGetID(IPTR _APICBase
)
136 _apic_id
= (*(volatile uint32_t*)(_APICBase
+ 0x20) & 0xFF000000) >> 24;
137 rkprintf("[Kernel] core_APICGetID: APIC ID %d\n", _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
)
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);
172 *(volatile uint32_t*)(_APICBase
+ 0x350) = APIC_VAL
;
174 /* only the BP should see the LINT1 NMI signal. */
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. */
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. */
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;
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;
224 status_ipisend
= *((volatile uint32_t*)(KernelBase
->kb_APICBase
+ 0x300)) & 0x1000;
225 } while (status_ipisend
&& (ipisend_timeout
--));
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;
238 status_ipisend
= *((volatile uint32_t*)(KernelBase
->kb_APICBase
+ 0x300)) & 0x1000;
239 } while (status_ipisend
&& (ipisend_timeout
--));
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");
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 */
263 rkprintf("[Kernel] core_APICIPIWake: Waiting for IPI STARTUP to complete...\n");
264 ipisend_timeout
= 1000;
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 */
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");
284 rkprintf("[Kernel] core_APICIPIWake: APIC delivery failed\n");
288 rkprintf("[Kernel] core_APICIPIWake: APIC delivery error (%lx)\n", status_ipirecv
);
291 return (status_ipisend
| status_ipirecv
);