xref: /aosp_15_r20/external/coreboot/src/cpu/x86/lapic/lapic.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <console/console.h>
5 #include <cpu/cpu.h>
6 #include <cpu/x86/lapic.h>
7 #include <cpu/x86/lapic_def.h>
8 #include <cpu/x86/msr.h>
9 #include <smp/node.h>
10 #include <types.h>
11 
12 static bool quirk_x2apic_allowed;
13 
enable_lapic_mode(bool try_set_x2apic)14 void enable_lapic_mode(bool try_set_x2apic)
15 {
16 	uintptr_t apic_base;
17 	bool use_x2apic = false;
18 	msr_t msr;
19 
20 	msr = rdmsr(LAPIC_BASE_MSR);
21 	if (!(msr.lo & LAPIC_BASE_MSR_ENABLE)) {
22 		msr.hi &= 0xffffff00;
23 		msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
24 		msr.lo |= LAPIC_DEFAULT_BASE;
25 		msr.lo |= LAPIC_BASE_MSR_ENABLE;
26 		wrmsr(LAPIC_BASE_MSR, msr);
27 		msr = rdmsr(LAPIC_BASE_MSR);
28 	}
29 
30 	ASSERT(msr.lo & LAPIC_BASE_MSR_ENABLE);
31 
32 	apic_base = msr.lo & LAPIC_BASE_MSR_ADDR_MASK;
33 	ASSERT(apic_base == LAPIC_DEFAULT_BASE);
34 
35 	if (try_set_x2apic)
36 		use_x2apic = !!(cpu_get_feature_flags_ecx() & CPUID_X2APIC);
37 
38 	if (use_x2apic == !!(msr.lo & LAPIC_BASE_MSR_X2APIC_MODE)) {
39 		printk(BIOS_INFO, "LAPIC 0x%x in %s mode.\n", lapicid(),
40 				  use_x2apic ? "X2APIC" : "XAPIC");
41 	} else if (use_x2apic) {
42 		msr.lo |= LAPIC_BASE_MSR_X2APIC_MODE;
43 		wrmsr(LAPIC_BASE_MSR, msr);
44 		msr = rdmsr(LAPIC_BASE_MSR);
45 		ASSERT(!!(msr.lo & LAPIC_BASE_MSR_X2APIC_MODE));
46 		printk(BIOS_INFO, "LAPIC 0x%x switched to X2APIC mode.\n", lapicid());
47 	} else {
48 		die("Switching from X2APIC to XAPIC mode is not implemented.");
49 	}
50 
51 	if (CONFIG(X2APIC_LATE_WORKAROUND) && use_x2apic)
52 		quirk_x2apic_allowed = true;
53 }
54 
enable_lapic(void)55 void enable_lapic(void)
56 {
57 	bool try_set_x2apic = true;
58 
59 	if (CONFIG(XAPIC_ONLY))
60 		try_set_x2apic = false;
61 	else if (CONFIG(X2APIC_LATE_WORKAROUND))
62 		try_set_x2apic = quirk_x2apic_allowed;
63 
64 	enable_lapic_mode(try_set_x2apic);
65 }
66 
disable_lapic(void)67 void disable_lapic(void)
68 {
69 	msr_t msr;
70 	msr = rdmsr(LAPIC_BASE_MSR);
71 	msr.lo &= ~(LAPIC_BASE_MSR_ENABLE | LAPIC_BASE_MSR_X2APIC_MODE);
72 	wrmsr(LAPIC_BASE_MSR, msr);
73 }
74 
cpu_get_lapic_addr(void)75 uintptr_t cpu_get_lapic_addr(void)
76 {
77 	return LAPIC_DEFAULT_BASE;
78 }
79 
setup_lapic_interrupts(void)80 void setup_lapic_interrupts(void)
81 {
82 	/*
83 	 * Set Task Priority to 'accept all'.
84 	 */
85 	lapic_update32(LAPIC_TASKPRI, ~LAPIC_TPRI_MASK, 0);
86 
87 	/* Set spurious interrupt vector to 0 and keep LAPIC enabled to
88 	   be able to clear LVT register mask bits. */
89 	lapic_update32(LAPIC_SPIV, ~LAPIC_VECTOR_MASK, LAPIC_SPIV_ENABLE);
90 
91 	/* Put the local APIC in virtual wire mode */
92 	uint32_t mask = LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | LAPIC_INPUT_POLARITY |
93 			LAPIC_DELIVERY_MODE_MASK;
94 
95 	if (boot_cpu())
96 		lapic_update32(LAPIC_LVT0, ~mask, LAPIC_DELIVERY_MODE_EXTINT);
97 	else
98 		lapic_update32(LAPIC_LVT0, ~mask, LAPIC_LVT_MASKED |
99 						  LAPIC_DELIVERY_MODE_EXTINT);
100 
101 	lapic_update32(LAPIC_LVT1, ~mask, LAPIC_DELIVERY_MODE_NMI);
102 }
103