2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
6 #include <aros/asmcall.h>
7 #include <proto/acpica.h>
8 #include <proto/exec.h>
10 #include <utility/hooks.h>
15 #include "kernel_base.h"
16 #include "kernel_debug.h"
19 #include "apic_ia32.h"
23 /************************************************************************************************
24 ACPI RELATED FUNCTIONS
25 ************************************************************************************************/
27 /* Process the 'Local APIC Address Overide' MADT Table */
28 AROS_UFH3(static IPTR
, ACPI_hook_Table_LAPIC_Addr_Ovr_Parse
,
29 AROS_UFHA(struct Hook
*, table_hook
, A0
),
30 AROS_UFHA(ACPI_MADT_LOCAL_APIC_OVERRIDE
*, lapic_addr_ovr
, A2
),
31 AROS_UFHA(struct APICData
*, data
, A2
))
35 data
->lapicBase
= lapic_addr_ovr
->Address
;
36 D(bug("[APIC-ACPI] (HOOK) ACPI_hook_Table_LAPIC_Addr_Ovr_Parse: Local APIC address Override to 0x%p\n", data
->lapicBase
));
44 * Process the 'Local APIC' MADT Table.
45 * This function collects APIC IDs into already allocated CPUData array.
47 AROS_UFH3(static IPTR
, ACPI_hook_Table_LAPIC_Parse
,
48 AROS_UFHA(struct Hook
*, table_hook
, A0
),
49 AROS_UFHA(ACPI_MADT_LOCAL_APIC
*, processor
, A2
),
50 AROS_UFHA(struct APICData
*, data
, A1
))
54 if (processor
->LapicFlags
& ACPI_MADT_ENABLED
)
56 if (data
->cores
[0].lapicID
== processor
->Id
)
58 /* This is the BSP, slot 0 is always reserved for it. */
59 bug("[APIC-ACPI] Registering APIC [ID=0x%02X] for BSP\n", processor
->Id
);
61 data
->cores
[0].sysID
= processor
->ProcessorId
;
66 bug("[APIC-ACPI] Registering APIC [ID=0x%02X:0x%02X]\n", processor
->Id
, processor
->ProcessorId
);
68 data
->cores
[data
->count
].lapicID
= processor
->Id
;
69 data
->cores
[data
->count
].sysID
= processor
->ProcessorId
;
83 /* Process the 'Local APIC Non-Maskable Interrupt' MADT Table */
84 AROS_UFH3(IPTR
, ACPI_hook_Table_LAPIC_NMI_Parse
,
85 AROS_UFHA(struct Hook
*, table_hook
, A0
),
86 AROS_UFHA(ACPI_MADT_LOCAL_APIC_NMI
*, lapic_nmi
, A2
),
87 AROS_UFHA(struct APICData
*, data
, A1
))
91 IPTR cpu_num
= (IPTR
)table_hook
->h_Data
;
93 if ((lapic_nmi
->ProcessorId
== data
->cores
[cpu_num
].sysID
) || (lapic_nmi
->ProcessorId
== 0xff))
96 ULONG val
= LVT_MT_NMI
; /* This is the default (edge-triggered, active low) */
98 D(bug("[APIC-ACPI.%u] NMI LINT%u\n", cpu_num
, lapic_nmi
->Lint
));
100 switch (lapic_nmi
->Lint
)
103 reg
= APIC_LINT0_VEC
;
107 reg
= APIC_LINT1_VEC
;
111 /* Invalid LINT# value */
115 if ((lapic_nmi
->IntiFlags
& ACPI_MADT_POLARITY_MASK
) == ACPI_MADT_POLARITY_ACTIVE_LOW
)
117 D(bug("[APIC-ACPI.%u] NMI active low\n", cpu_num
));
118 val
|= LVT_ACTIVE_LOW
;
121 if ((lapic_nmi
->IntiFlags
& ACPI_MADT_TRIGGER_MASK
) == ACPI_MADT_TRIGGER_LEVEL
)
123 D(bug("[APIC-ACPI.%u] NMI level-triggered\n", cpu_num
));
124 val
|= LVT_TGM_LEVEL
;
127 APIC_REG(data
->lapicBase
, reg
) = val
;
136 /* Process the 'IO-APIC' MADT Table */
137 AROS_UFH3(IPTR
, ACPI_hook_Table_IOAPIC_Parse
,
138 AROS_UFHA(struct Hook
*, table_hook
, A0
),
139 AROS_UFHA(ACPI_MADT_IO_APIC
*, ioapic
, A2
),
140 AROS_UFHA(struct APICData
*, data
, A1
))
144 D(bug("[APIC-ACPI] (HOOK) ACPI_hook_Table_IOAPIC_Parse: IOAPIC %d @ %p [irq base = %d]\n", ioapic
->Id
, ioapic
->Address
, ioapic
->GlobalIrqBase
));
146 data
->ioapicBase
= ioapic
->Address
;
152 /* Process the 'Interrupt Source Overide' MADT Table */
153 AROS_UFH2(IPTR
, ACPI_hook_Table_Int_Src_Ovr_Parse
,
154 AROS_UFHA(struct Hook
*, table_hook
, A0
),
155 AROS_UFHA(ACPI_MADT_INTERRUPT_OVERRIDE
*, intsrc
, A2
))
159 D(bug("[APIC-ACPI] (HOOK) ACPI_hook_Table_Int_Src_Ovr_Parse: Bus %d, Source IRQ %d, Global IRQ %d, Flags 0x%x\n", intsrc
->Bus
, intsrc
->SourceIrq
,
160 intsrc
->GlobalIrq
, intsrc
->IntiFlags
));
167 /* Process the 'Non-Maskable Interrupt Source' MADT Table */
168 AROS_UFH2(IPTR
, ACPI_hook_Table_NMI_Src_Parse
,
169 AROS_UFHA(struct Hook
*, table_hook
, A0
),
170 AROS_UFHA(ACPI_MADT_NMI_SOURCE
*, nmi_src
, A2
))
174 D(bug("[APIC-ACPI] (HOOK) ACPI_hook_Table_NMI_Src_Parse()\n"));
176 /* FIXME: Uh... shouldn't we do something with this? */
183 static const struct Hook ACPI_TableParse_LAPIC_Addr_Ovr_hook
=
185 .h_Entry
= (APTR
)ACPI_hook_Table_LAPIC_Addr_Ovr_Parse
188 static const struct Hook ACPI_TableParse_LAPIC_hook
=
190 .h_Entry
= (APTR
)ACPI_hook_Table_LAPIC_Parse
193 static const struct Hook ACPI_TableParse_IOAPIC_hook
=
195 .h_Entry
= (APTR
)ACPI_hook_Table_IOAPIC_Parse
198 static const struct Hook ACPI_TableParse_Int_Src_Ovr_hook
=
200 .h_Entry
= (APTR
)ACPI_hook_Table_Int_Src_Ovr_Parse
203 static const struct Hook ACPI_TableParse_NMI_Src_hook
=
205 .h_Entry
= (APTR
)ACPI_hook_Table_NMI_Src_Parse
208 /************************************************************************************************/
209 /************************************************************************************************
210 APIC Functions used by kernel.resource from outside this file ..
211 ************************************************************************************************/
212 /************************************************************************************************/
214 static int MADT_ScanEntries(CONST ACPI_TABLE_MADT
*madt
, enum AcpiMadtType type
, const struct Hook
*hook
, APTR userdata
)
216 UINT8
*madt_entry
= (UINT8
*)&madt
[1];
217 UINT8
*madt_end
= (UINT8
*)madt
+ madt
->Header
.Length
;
220 for (count
= 0; madt_entry
< madt_end
; madt_entry
+= ((ACPI_SUBTABLE_HEADER
*)madt_entry
)->Length
) {
221 ACPI_SUBTABLE_HEADER
*sh
= (ACPI_SUBTABLE_HEADER
*)madt_entry
;
222 if (sh
->Type
== (UINT8
)type
) {
227 res
= CALLHOOKPKT((struct Hook
*)hook
, (APTR
)sh
, userdata
);
238 * Initialize APIC on a CPU core with specified number.
239 * This routine is ran by all cores.
241 void acpi_APIC_InitCPU(struct APICData
*data
, IPTR cpuNum
)
243 /* Initialize APIC to the default configuration */
244 core_APIC_Init(data
, cpuNum
);
250 /* Set up NMI for ourselves */
251 hook
.h_Entry
= (APTR
)ACPI_hook_Table_LAPIC_NMI_Parse
;
252 hook
.h_Data
= (APTR
)cpuNum
;
253 MADT_ScanEntries(data
->acpi_madt
, ACPI_MADT_TYPE_LOCAL_APIC_NMI
, &hook
, data
);
257 /* Initialize APIC from ACPI data */
258 struct APICData
*acpi_APIC_Init(void)
262 const ACPI_TABLE_MADT
*madt
;
263 struct APICData
*data
;
266 * MADT : If it exists, parse the Multiple APIC Description Table "MADT",
267 * This table provides platform SMP configuration information [the successor to MPS tables]
269 err
= AcpiGetTable("MADT", 1, (ACPI_TABLE_HEADER
**)&madt
);
271 D(bug("[APCI-ACPI] No MADT table found, err = %d\n", err
));
278 * We have MADT from ACPI.
279 * The first thing to do now is to count APICs and allocate struct APICData.
281 result
= MADT_ScanEntries(madt
, ACPI_MADT_TYPE_LOCAL_APIC
, NULL
, NULL
);
282 D(bug("[APIC-ACPI] Found %u enabled APICs\n", result
));
284 data
= AllocMem(sizeof(struct APICData
) + result
* sizeof(struct CPUData
), MEMF_CLEAR
);
288 data
->lapicBase
= madt
->Address
;
289 data
->acpi_madt
= madt
; /* Cache ACPI data for secondary cores */
290 data
->count
= 1; /* Only one CPU is running right now */
291 data
->flags
= ((madt
->Flags
& ACPI_MADT_PCAT_COMPAT
) == ACPI_MADT_MULTIPLE_APIC
) ? APF_8259
: 0;
293 bug("[APIC-ACPI] Local APIC address 0x%08x; Flags 0x%04X\n", data
->lapicBase
, data
->flags
);
296 * The local APIC base address is obtained from the MADT (32-bit value) and
297 * (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
299 MADT_ScanEntries(madt
, ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE
, &ACPI_TableParse_LAPIC_Addr_Ovr_hook
, data
);
301 /* Remember ID of the bootstrap APIC, this is CPU #0 */
302 data
->cores
[0].lapicID
= core_APIC_GetID(data
->lapicBase
);
303 D(bug("[APIC-ACPI] BSP ID: 0x%02X\n", data
->cores
[0].lapicID
));
305 /* Now fill in IDs (both HW and ACPI) of the rest APICs */
306 MADT_ScanEntries(madt
, ACPI_MADT_TYPE_LOCAL_APIC
, &ACPI_TableParse_LAPIC_hook
, data
);
307 bug("[APIC-ACPI] System Total APICs: %d\n", data
->count
);
309 /* Initialize LAPIC for ourselves (CPU #0) */
310 acpi_APIC_InitCPU(data
, 0);
312 /* TODO: The following is actually not implemented yet. IOAPIC should be configured here. */
314 result
= MADT_ScanEntries(madt
, ACPI_MADT_TYPE_IO_APIC
, &ACPI_TableParse_IOAPIC_hook
, data
);
315 D(bug("[APIC-ACPI] ACPI_ScanEntries(ACPI_MADT_IOAPIC) returned %p\n", result
));
317 MADT_ScanEntries(madt
, ACPI_MADT_TYPE_INTERRUPT_OVERRIDE
, &ACPI_TableParse_Int_Src_Ovr_hook
, data
);
319 result
= MADT_ScanEntries(madt
, ACPI_MADT_TYPE_NMI_SOURCE
, &ACPI_TableParse_NMI_Src_hook
, data
);
320 D(bug("[APIC-ACPI] ACPI_ScanEntries(ACPI_MADT_NMI_SRC) returned %p\n", result
));
322 /* Build a default routing table for legacy (ISA) interrupts. */
323 /* TODO: implement legacy irq config.. */
324 D(bug("[APIC-ACPI] Configuring Legacy IRQs .. Skipped (UNIMPLEMENTED) ..\n"));
326 /* TODO: implement check for clustered apic's..
327 core_APICClusteredCheck();