1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2021, Google LLC.
4 */
5
6#include "apic.h"
7
8void apic_disable(void)
9{
10	wrmsr(MSR_IA32_APICBASE,
11	      rdmsr(MSR_IA32_APICBASE) &
12		~(MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD));
13}
14
15void xapic_enable(void)
16{
17	uint64_t val = rdmsr(MSR_IA32_APICBASE);
18
19	/* Per SDM: to enable xAPIC when in x2APIC must first disable APIC */
20	if (val & MSR_IA32_APICBASE_EXTD) {
21		apic_disable();
22		wrmsr(MSR_IA32_APICBASE,
23		      rdmsr(MSR_IA32_APICBASE) | MSR_IA32_APICBASE_ENABLE);
24	} else if (!(val & MSR_IA32_APICBASE_ENABLE)) {
25		wrmsr(MSR_IA32_APICBASE, val | MSR_IA32_APICBASE_ENABLE);
26	}
27
28	/*
29	 * Per SDM: reset value of spurious interrupt vector register has the
30	 * APIC software enabled bit=0. It must be enabled in addition to the
31	 * enable bit in the MSR.
32	 */
33	val = xapic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED;
34	xapic_write_reg(APIC_SPIV, val);
35}
36
37void x2apic_enable(void)
38{
39	wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) |
40	      MSR_IA32_APICBASE_ENABLE | MSR_IA32_APICBASE_EXTD);
41	x2apic_write_reg(APIC_SPIV,
42			 x2apic_read_reg(APIC_SPIV) | APIC_SPIV_APIC_ENABLED);
43}
44