1 /*
2  *  lib.c - Architecture-Specific Low-Level ACPI Support
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 
22 #include <xen/errno.h>
23 #include <xen/init.h>
24 #include <xen/acpi.h>
25 #include <asm/apic.h>
26 #include <asm/fixmap.h>
27 
28 u32 __read_mostly acpi_smi_cmd;
29 u8 __read_mostly acpi_enable_value;
30 u8 __read_mostly acpi_disable_value;
31 
32 u32 __read_mostly x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
33     {[0 ... MAX_MADT_ENTRIES - 1] = BAD_APICID };
34 
35 /*
36  * Important Safety Note:  The fixed ACPI page numbers are *subtracted*
37  * from the fixed base.  That's why we start at FIX_ACPI_END and
38  * count idx down while incrementing the phys address.
39  */
__acpi_map_table(paddr_t phys,unsigned long size)40 char *__acpi_map_table(paddr_t phys, unsigned long size)
41 {
42 	unsigned long base, offset, mapped_size;
43 	int idx;
44 
45 	/* XEN: RAM holes above 1MB are not permanently mapped. */
46 	if ((phys + size) <= (1 * 1024 * 1024))
47 		return __va(phys);
48 
49 	offset = phys & (PAGE_SIZE - 1);
50 	mapped_size = PAGE_SIZE - offset;
51 	set_fixmap(FIX_ACPI_END, phys);
52 	base = __fix_to_virt(FIX_ACPI_END);
53 
54 	/*
55 	 * Most cases can be covered by the below.
56 	 */
57 	idx = FIX_ACPI_END;
58 	while (mapped_size < size) {
59 		if (--idx < FIX_ACPI_BEGIN)
60 			return NULL;	/* cannot handle this */
61 		phys += PAGE_SIZE;
62 		set_fixmap(idx, phys);
63 		mapped_size += PAGE_SIZE;
64 	}
65 
66 	return ((char *) base + offset);
67 }
68 
acpi_get_processor_id(unsigned int cpu)69 unsigned int acpi_get_processor_id(unsigned int cpu)
70 {
71 	unsigned int acpiid, apicid;
72 
73 	if ((apicid = x86_cpu_to_apicid[cpu]) == BAD_APICID)
74 		return INVALID_ACPIID;
75 
76 	for (acpiid = 0; acpiid < ARRAY_SIZE(x86_acpiid_to_apicid); acpiid++)
77 		if (x86_acpiid_to_apicid[acpiid] == apicid)
78 			return acpiid;
79 
80 	return INVALID_ACPIID;
81 }
82 
get_mwait_ecx(void * info)83 static void get_mwait_ecx(void *info)
84 {
85 	*(u32 *)info = cpuid_ecx(CPUID_MWAIT_LEAF);
86 }
87 
arch_acpi_set_pdc_bits(u32 acpi_id,u32 * pdc,u32 mask)88 int arch_acpi_set_pdc_bits(u32 acpi_id, u32 *pdc, u32 mask)
89 {
90 	unsigned int cpu = get_cpu_id(acpi_id);
91 	struct cpuinfo_x86 *c;
92 	u32 ecx;
93 
94 	if (!(acpi_id + 1))
95 		c = &boot_cpu_data;
96 	else if (cpu >= nr_cpu_ids || !cpu_online(cpu))
97 		return -EINVAL;
98 	else
99 		c = cpu_data + cpu;
100 
101 	pdc[2] |= ACPI_PDC_C_CAPABILITY_SMP & mask;
102 
103 	if (cpu_has(c, X86_FEATURE_EIST))
104 		pdc[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP & mask;
105 
106 	if (cpu_has(c, X86_FEATURE_ACPI))
107 		pdc[2] |= ACPI_PDC_T_FFH & mask;
108 
109 	/*
110 	 * If mwait/monitor or its break-on-interrupt extension are
111 	 * unsupported, Cx_FFH will be disabled.
112 	 */
113 	if (!cpu_has(c, X86_FEATURE_MONITOR) ||
114 	    c->cpuid_level < CPUID_MWAIT_LEAF)
115 		ecx = 0;
116 	else if (c == &boot_cpu_data || cpu == smp_processor_id())
117 		ecx = cpuid_ecx(CPUID_MWAIT_LEAF);
118 	else
119 		on_selected_cpus(cpumask_of(cpu), get_mwait_ecx, &ecx, 1);
120 	if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
121 	    !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
122 		pdc[2] &= ~(ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH);
123 
124 	return 0;
125 }
126