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